mirror of
https://github.com/silverstripe/silverstripe-postgresql
synced 2024-10-22 17:05:45 +02:00
API Ensure table aliases longer than max characters are safely re-written
This commit is contained in:
parent
512f10d745
commit
e941f0b122
@ -3,7 +3,6 @@ language: php
|
||||
sudo: false
|
||||
|
||||
php:
|
||||
- 5.5
|
||||
- 5.6
|
||||
|
||||
env:
|
||||
|
@ -2,12 +2,20 @@
|
||||
|
||||
namespace SilverStripe\PostgreSQL;
|
||||
|
||||
use SilverStripe\ORM\Queries\SQLConditionalExpression;
|
||||
use SilverStripe\ORM\Queries\SQLExpression;
|
||||
use SilverStripe\ORM\Queries\SQLSelect;
|
||||
use SilverStripe\ORM\Connect\DBQueryBuilder;
|
||||
use InvalidArgumentException;
|
||||
|
||||
class PostgreSQLQueryBuilder extends DBQueryBuilder
|
||||
{
|
||||
/**
|
||||
* Max table length.
|
||||
* Aliases longer than this will be re-written
|
||||
*/
|
||||
const MAX_TABLE = 63;
|
||||
|
||||
/**
|
||||
* Return the LIMIT clause ready for inserting into a query.
|
||||
*
|
||||
@ -47,4 +55,53 @@ class PostgreSQLQueryBuilder extends DBQueryBuilder
|
||||
}
|
||||
return $clause;
|
||||
}
|
||||
|
||||
public function buildSQL(SQLExpression $query, &$parameters)
|
||||
{
|
||||
$sql = parent::buildSQL($query, $parameters);
|
||||
return $this->rewriteLongIdentifiers($query, $sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find and generate table aliases necessary in the given query
|
||||
*
|
||||
* @param SQLConditionalExpression $query
|
||||
* @return array List of replacements
|
||||
*/
|
||||
protected function findRewrites(SQLConditionalExpression $query)
|
||||
{
|
||||
$rewrites = [];
|
||||
foreach ($query->getFrom() as $alias => $from) {
|
||||
$table = is_array($from) ? $from['table'] : $from;
|
||||
if ($alias === $table || "\"{$alias}\"" === $table) {
|
||||
continue;
|
||||
}
|
||||
// Don't complain about aliases shorter than max length
|
||||
if (strlen($alias) <= self::MAX_TABLE) {
|
||||
continue;
|
||||
}
|
||||
$replacement = substr(sha1($alias), 0, 7) . '_' . substr($alias, 8 - self::MAX_TABLE);
|
||||
$rewrites["\"{$alias}\""] = "\"{$replacement}\"";
|
||||
}
|
||||
return $rewrites;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rewrite all ` AS "Identifier"` with strlen(Identifier) > 63
|
||||
*
|
||||
* @param SQLExpression $query
|
||||
* @param string $sql
|
||||
* @return string
|
||||
*/
|
||||
protected function rewriteLongIdentifiers(SQLExpression $query, $sql)
|
||||
{
|
||||
// Check if this query has aliases
|
||||
if ($query instanceof SQLConditionalExpression) {
|
||||
$rewrites = $this->findRewrites($query);
|
||||
if ($rewrites) {
|
||||
return str_replace(array_keys($rewrites), array_values($rewrites), $sql);
|
||||
}
|
||||
}
|
||||
return $sql;
|
||||
}
|
||||
}
|
||||
|
41
tests/PostgreSQLQueryBuilderTest.php
Normal file
41
tests/PostgreSQLQueryBuilderTest.php
Normal file
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
|
||||
use SilverStripe\Dev\SapphireTest;
|
||||
use SilverStripe\ORM\Queries\SQLSelect;
|
||||
use SilverStripe\PostgreSQL\PostgreSQLQueryBuilder;
|
||||
|
||||
class PostgreSQLQueryBuilderTest extends SapphireTest
|
||||
{
|
||||
public function testLongAliases()
|
||||
{
|
||||
$query = new SQLSelect();
|
||||
$longstring = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||
$alias2 = $longstring . $longstring;
|
||||
$query->selectField('*');
|
||||
$query->addFrom('"Base"');
|
||||
$query->addLeftJoin(
|
||||
'Joined',
|
||||
"\"Base\".\"ID\" = \"{$alias2}\".\"ID\"",
|
||||
$alias2
|
||||
);
|
||||
$query->addWhere([
|
||||
"\"{$alias2}\".\"Title\" = ?" => 'Value',
|
||||
]);
|
||||
|
||||
$identifier = "c4afb43_hijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||
$this->assertEquals(PostgreSQLQueryBuilder::MAX_TABLE, strlen($identifier));
|
||||
|
||||
$expected = <<<SQL
|
||||
SELECT *
|
||||
FROM "Base" LEFT JOIN "Joined" AS "c4afb43_hijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||
ON "Base"."ID" = "c4afb43_hijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"."ID"
|
||||
WHERE ("c4afb43_hijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"."Title" = ?)
|
||||
SQL;
|
||||
$builder = new PostgreSQLQueryBuilder();
|
||||
$sql = $builder->buildSQL($query, $params);
|
||||
|
||||
$this->assertSQLEquals($expected, $sql);
|
||||
$this->assertEquals(['Value'], $params);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user