diff --git a/.travis.yml b/.travis.yml index 7a14863..c87ed37 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,6 @@ language: php sudo: false php: - - 5.5 - 5.6 env: diff --git a/code/PostgreSQLQueryBuilder.php b/code/PostgreSQLQueryBuilder.php index 90b7b3e..9bbefd5 100644 --- a/code/PostgreSQLQueryBuilder.php +++ b/code/PostgreSQLQueryBuilder.php @@ -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 @@ public function buildLimitFragment(SQLSelect $query, array &$parameters) } 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; + } } diff --git a/tests/PostgreSQLQueryBuilderTest.php b/tests/PostgreSQLQueryBuilderTest.php new file mode 100644 index 0000000..f480eeb --- /dev/null +++ b/tests/PostgreSQLQueryBuilderTest.php @@ -0,0 +1,41 @@ +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 = <<buildSQL($query, $params); + + $this->assertSQLEquals($expected, $sql); + $this->assertEquals(['Value'], $params); + } +}