FIX Don't generate table alias for "from" statement that are not column names.

This commit is contained in:
Maxime Rainville 2024-07-25 13:17:37 +12:00
parent d9bccaff3d
commit f91b279ef0
No known key found for this signature in database
2 changed files with 109 additions and 1 deletions

View File

@ -78,7 +78,18 @@ abstract class SQLConditionalExpression extends SQLExpression
if (is_array($from)) { if (is_array($from)) {
$this->from = array_merge($this->from, $from); $this->from = array_merge($this->from, $from);
} elseif (!empty($from)) { } elseif (!empty($from)) {
$this->from[str_replace(['"','`'], '', $from)] = $from; // Check if the from clause looks like a regular table name
// Table name most be an uninterrupted string, with no spaces.
// It may be padded with spaces. e.g. ` TableName ` will be
// treated as Table Name, but not ` Table Name `.
if (preg_match('/^\s*[^\s]+\s*$/', $from)) {
// Add an alias for the table name, stripping any quotes
$this->from[str_replace(['"','`'], '', $from)] = $from;
} else {
// Add from clause without an alias - this is probably a full
// sub-select with its own explicit alias.
$this->from[] = $from;
}
} }
return $this; return $this;

View File

@ -1327,4 +1327,101 @@ class SQLSelectTest extends SapphireTest
$select->addWith('cte', new SQLSelect()); $select->addWith('cte', new SQLSelect());
} }
public function subqueryProvider()
{
return [
'no-explicit-alias-string' => ['( SELECT DISTINCT "SQLSelectTest_DO"."ClassName" FROM "SQLSelectTest_DO") AS "FINAL"'],
'no-alias-array' => [['( SELECT DISTINCT "SQLSelectTest_DO"."ClassName" FROM "SQLSelectTest_DO") AS "FINAL"']],
'no-alias-array-numeric-key' => [[0 => '( SELECT DISTINCT "SQLSelectTest_DO"."ClassName" FROM "SQLSelectTest_DO") AS "FINAL"']],
'explicit-alias-string' => [['FINAL' => '( SELECT DISTINCT "SQLSelectTest_DO"."ClassName" FROM "SQLSelectTest_DO")']],
];
}
/**
* @dataProvider subqueryProvider
*/
public function testSubqueries($subquery)
{
$query = new SQLSelect('*', $subquery);
$actualSQL = $query->sql();
$this->assertSQLEquals(
'SELECT * FROM ( SELECT DISTINCT "SQLSelectTest_DO"."ClassName" FROM "SQLSelectTest_DO") AS "FINAL"',
$actualSQL
);
}
public function addFromProvider()
{
return [
'string' => [
'MyTable', ['MyTable' => 'MyTable'],
'Plain table name get alias automatic alias'
],
'string padded with spaces' => [
' MyTable ', [' MyTable ' => ' MyTable '],
'Plain table name get alias automatic alias'
],
'quoted string' => [
'"MyTable"', ['MyTable' => '"MyTable"'],
'Quoted table name get alias without the quotes'
],
'underscore in table name string' => [
'"My_Table_123"', ['My_Table_123' => '"My_Table_123"'],
'Numbers and underscores are allowed in table names'
],
'backtick string' => [
'`MyTable`', ['MyTable' => '`MyTable`'],
'Backtick quoted table name get alias without the quotes'
],
'subquery string' => [
' (SELECT * from "FooBar") as FooBar ', [' (SELECT * from "FooBar") as FooBar '],
'String that don\'t look like table name don\'t get alias'
],
'array' => [
['MyTable'], ['MyTable'],
'Arrays are passed through as is'
],
'array-associative-key' => [
['MyTableAlias' => 'MyTable'], ['MyTableAlias' => 'MyTable'],
'Associative arrays are passed through as is and aliases are preserved'
],
];
}
/**
* @dataProvider addFromProvider
*/
public function testAddFrom($input, $out, $message = ""): void
{
$query = new SQLSelect();
$query->addFrom($input);
$this->assertEquals($out, $query->getFrom(), $message);
}
public function testAddFromRetainPreviousData()
{
// Initial setup
$query = new SQLSelect();
$query->addFrom('MyTable');
$query->addFrom('"MyOtherTable"');
// This will override some value and add a new one
$query->addFrom([
'MyTable' => '(SELECT * FROM "MyTable" where "Foo" = "Bar")',
'ThirdTable',
]);
$this->assertEquals(
[
'MyTable' => '(SELECT * FROM "MyTable" where "Foo" = "Bar")',
'MyOtherTable' => '"MyOtherTable"',
'ThirdTable',
],
$query->getFrom(),
'MyTable entry got merge over, MyOtherTable was retained, ThirdTable was added'
);
}
} }