Merge pull request #4022 from tractorcow/pulls/3.1/fix-subselect

BUG Fix joins on tables containing "select" being mistaken for sub-selects
This commit is contained in:
Daniel Hensby 2015-03-18 23:10:45 +00:00
commit 2b1e5d13cf
2 changed files with 36 additions and 21 deletions

View File

@ -239,10 +239,10 @@ class SQLQuery {
/** /**
* Set table for the SELECT clause. * Set table for the SELECT clause.
* *
* @example $query->setFrom("MyTable"); // SELECT * FROM MyTable * @example $query->setFrom('"MyTable"'); // SELECT * FROM "MyTable"
* *
* @param string|array $from Escaped SQL statement, usually an unquoted table name * @param string|array $from Single, or list of, ANSI quoted table names
* @return SQLQuery * @return self
*/ */
public function setFrom($from) { public function setFrom($from) {
$this->from = array(); $this->from = array();
@ -252,10 +252,10 @@ class SQLQuery {
/** /**
* Add a table to the SELECT clause. * Add a table to the SELECT clause.
* *
* @example $query->addFrom("MyTable"); // SELECT * FROM MyTable * @example $query->addFrom('"MyTable"'); // SELECT * FROM "MyTable"
* *
* @param string|array $from Escaped SQL statement, usually an unquoted table name * @param string|array $from Single, or list of, ANSI quoted table names
* @return SQLQuery * @return self Self reference
*/ */
public function addFrom($from) { public function addFrom($from) {
if(is_array($from)) { if(is_array($from)) {
@ -903,9 +903,13 @@ class SQLQuery {
else if(sizeof($join['filter']) == 1) $filter = $join['filter'][0]; else if(sizeof($join['filter']) == 1) $filter = $join['filter'][0];
else $filter = "(" . implode(") AND (", $join['filter']) . ")"; else $filter = "(" . implode(") AND (", $join['filter']) . ")";
$table = strpos(strtoupper($join['table']), 'SELECT') ? $join['table'] : "\"" // Ensure tables are quoted, unless the table is actually a sub-select
. $join['table'] . "\""; $table = preg_match('/\bSELECT\b/i', $join['table'])
$aliasClause = ($alias != $join['table']) ? " AS \"" . Convert::raw2sql($alias) . "\"" : ""; ? $join['table']
: "\"{$join['table']}\"";
$aliasClause = ($alias != $join['table'])
? " AS \"{$alias}\""
: "";
$this->from[$alias] = strtoupper($join['type']) . " JOIN " $this->from[$alias] = strtoupper($join['type']) . " JOIN "
. $table . "$aliasClause ON $filter"; . $table . "$aliasClause ON $filter";
} }

View File

@ -341,26 +341,37 @@ class SQLQueryTest extends SapphireTest {
$query->sql() $query->sql()
); );
} }
public function testJoinSubSelect() { public function testJoinSubSelect() {
// Test sub-select works
$query = new SQLQuery(); $query = new SQLQuery();
$query->setFrom('MyTable'); $query->setFrom('"MyTable"');
$query->addInnerJoin('(SELECT * FROM MyOtherTable)', $query->addInnerJoin('(SELECT * FROM "MyOtherTable")',
'Mot.MyTableID = MyTable.ID', 'Mot'); '"Mot"."MyTableID" = "MyTable"."ID"', 'Mot');
$query->addLeftJoin('(SELECT MyLastTable.MyOtherTableID, COUNT(1) as MyLastTableCount FROM MyLastTable ' $query->addLeftJoin('(SELECT "MyLastTable"."MyOtherTableID", COUNT(1) as "MyLastTableCount" '
. 'GROUP BY MyOtherTableID)', . 'FROM "MyLastTable" GROUP BY "MyOtherTableID")',
'Mlt.MyOtherTableID = Mot.ID', 'Mlt'); '"Mlt"."MyOtherTableID" = "Mot"."ID"', 'Mlt');
$query->setOrderBy('COALESCE(Mlt.MyLastTableCount, 0) DESC'); $query->setOrderBy('COALESCE("Mlt"."MyLastTableCount", 0) DESC');
$this->assertEquals('SELECT *, COALESCE(Mlt.MyLastTableCount, 0) AS "_SortColumn0" FROM MyTable '. $this->assertEquals('SELECT *, COALESCE("Mlt"."MyLastTableCount", 0) AS "_SortColumn0" FROM "MyTable" '.
'INNER JOIN (SELECT * FROM MyOtherTable) AS "Mot" ON Mot.MyTableID = MyTable.ID ' . 'INNER JOIN (SELECT * FROM "MyOtherTable") AS "Mot" ON "Mot"."MyTableID" = "MyTable"."ID" ' .
'LEFT JOIN (SELECT MyLastTable.MyOtherTableID, COUNT(1) as MyLastTableCount FROM MyLastTable ' 'LEFT JOIN (SELECT "MyLastTable"."MyOtherTableID", COUNT(1) as "MyLastTableCount" FROM "MyLastTable" '
. 'GROUP BY MyOtherTableID) AS "Mlt" ON Mlt.MyOtherTableID = Mot.ID ' . . 'GROUP BY "MyOtherTableID") AS "Mlt" ON "Mlt"."MyOtherTableID" = "Mot"."ID" ' .
'ORDER BY "_SortColumn0" DESC', 'ORDER BY "_SortColumn0" DESC',
$query->sql() $query->sql()
); );
// Test that table names do not get mistakenly identified as sub-selects
$query = new SQLQuery();
$query->setFrom('"MyTable"');
$query->addInnerJoin('NewsArticleSelected', '"News"."MyTableID" = "MyTable"."ID"', 'News');
$this->assertEquals(
'SELECT * FROM "MyTable" INNER JOIN "NewsArticleSelected" AS "News" ON '.
'"News"."MyTableID" = "MyTable"."ID"',
$query->sql()
);
} }
public function testSetWhereAny() { public function testSetWhereAny() {