Skip to content

Commit

Permalink
Optional aliases for subqueries in FROM
Browse files Browse the repository at this point in the history
  • Loading branch information
sad-spirit committed Aug 29, 2023
1 parent ac5879a commit df13663
Show file tree
Hide file tree
Showing 5 changed files with 25 additions and 44 deletions.
3 changes: 2 additions & 1 deletion Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@

### Added

Support new syntax of PostgreSQL 16 (as of beta 3)
Support for new syntax of PostgreSQL 16 (as of beta 3)
* SQL/JSON functions and expressions:
* `IS JSON` predicate represented by `nodes\expressions\IsJsonExpression`;
* Aggregate functions `json_arrayagg()` and `json_objectagg()` represented by `nodes\json\JsonArrayAgg` and
`nodes\json\JsonObjectAgg`;
* Constructor functions `json_array()` and `json_object()` represented by
`nodes\json\JsonArrayValueList`, `nodes\json\JsonArraySubselect`, `nodes\json\JsonObject` classes.
* Aliases for subqueries in `FROM` are now optional.
* `SYSTEM_USER` server variable backed by `nodes\expressions\SQLValueFunction`.
* `[NO] INDENT` option for `XMLSERIALIZE()` expression.

Expand Down
10 changes: 2 additions & 8 deletions src/sad_spirit/pg_builder/Parser.php
Original file line number Diff line number Diff line change
Expand Up @@ -3582,17 +3582,11 @@ protected function TableReference(): nodes\range\FromElement

protected function RangeSubselect(): nodes\range\Subselect
{
$token = $this->stream->getCurrent();
$reference = new nodes\range\Subselect($this->SelectWithParentheses());

if (!($alias = $this->OptionalAliasClause())) {
throw exceptions\SyntaxException::atPosition(
'Subselects in FROM clause should have an alias',
$this->stream->getSource(),
$token->getPosition()
);
if (null !== ($alias = $this->OptionalAliasClause())) {
$reference->setAlias($alias[0], $alias[1]);
}
$reference->setAlias($alias[0], $alias[1]);

return $reference;
}
Expand Down
35 changes: 11 additions & 24 deletions src/sad_spirit/pg_builder/SqlBuilderWalker.php
Original file line number Diff line number Diff line change
Expand Up @@ -1166,6 +1166,9 @@ public function walkColumnDefinition(nodes\range\ColumnDefinition $node): string

protected function getFromItemAliases(nodes\range\FromElement $rangeItem): string
{
if (null === $rangeItem->tableAlias && null === $rangeItem->columnAliases) {
return '';
}
return ' as'
. (null !== $rangeItem->tableAlias ? ' ' . $rangeItem->tableAlias->dispatch($this) : '')
. (
Expand All @@ -1179,23 +1182,15 @@ public function walkRangeFunctionCall(nodes\range\FunctionCall $rangeItem): stri
{
return ($rangeItem->lateral ? 'lateral ' : '') . $rangeItem->function->dispatch($this)
. ($rangeItem->withOrdinality ? ' with ordinality' : '')
. (
null !== $rangeItem->tableAlias || null !== $rangeItem->columnAliases
? $this->getFromItemAliases($rangeItem)
: ''
);
. $this->getFromItemAliases($rangeItem);
}

public function walkRowsFrom(nodes\range\RowsFrom $rangeItem): string
{
return ($rangeItem->lateral ? 'lateral ' : '') . 'rows from('
. implode(', ', $rangeItem->functions->dispatch($this)) . ')'
. ($rangeItem->withOrdinality ? ' with ordinality' : '')
. (
null !== $rangeItem->tableAlias || null !== $rangeItem->columnAliases
? $this->getFromItemAliases($rangeItem)
: ''
);
. $this->getFromItemAliases($rangeItem);
}

public function walkRowsFromElement(nodes\range\RowsFromElement $node): string
Expand Down Expand Up @@ -1226,21 +1221,16 @@ public function walkJoinExpression(nodes\range\JoinExpression $rangeItem): strin
$sql .= ' ' . $rangeItem->using->dispatch($this);
}

return null !== $rangeItem->tableAlias || null !== $rangeItem->columnAliases
? '(' . $sql . ')' . $this->getFromItemAliases($rangeItem)
: $sql;
$alias = $this->getFromItemAliases($rangeItem);
return '' === $alias ? $sql : '(' . $sql . ')' . $alias;
}

public function walkRelationReference(nodes\range\RelationReference $rangeItem): string
{
return (false === $rangeItem->inherit ? 'only ' : '')
. $rangeItem->name->dispatch($this)
. (true === $rangeItem->inherit ? ' *' : '')
. (
null !== $rangeItem->tableAlias || null !== $rangeItem->columnAliases
? $this->getFromItemAliases($rangeItem)
: ''
);
. $this->getFromItemAliases($rangeItem);
}

public function walkRangeSubselect(nodes\range\Subselect $rangeItem): string
Expand Down Expand Up @@ -1354,13 +1344,10 @@ public function walkXmlTable(nodes\range\XmlTable $table): string
$lines[] = $this->getIndent() . 'columns ' . implode($glue, $this->walkGenericNodeList($table->columns));

$this->indentLevel--;
$sql = implode($this->options['linebreak'] ?: ' ', $lines)
. $this->options['linebreak'] . $this->getIndent() . ')';
if ($table->tableAlias || $table->columnAliases) {
$sql .= $this->getFromItemAliases($table);
}

return $sql;
return implode($this->options['linebreak'] ?: ' ', $lines)
. $this->options['linebreak'] . $this->getIndent() . ')'
. $this->getFromItemAliases($table);
}

public function walkXmlTypedColumnDefinition(nodes\xml\XmlTypedColumnDefinition $column): string
Expand Down
20 changes: 9 additions & 11 deletions tests/ParseFromClauseTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,13 @@
};
use sad_spirit\pg_builder\exceptions\SyntaxException;
use sad_spirit\pg_builder\nodes\{
Star,
TargetElement,
FunctionCall,
ColumnReference,
Identifier,
TypeName,
QualifiedName
};
QualifiedName};
use sad_spirit\pg_builder\nodes\expressions\{
KeywordConstant,
NumericConstant,
Expand Down Expand Up @@ -90,21 +90,26 @@ protected function setUp(): void
public function testBasicItems(): void
{
$list = $this->parser->parseFromList(<<<QRY
foo.bar, baz(1, 'string'), (select 'quux') as quux
foo.bar, baz(1, 'string'), (select 'quux') as quux, (select * from unaliased)
QRY
);
$select = new Select(new TargetList([new TargetElement(new StringConstant('quux'))]));
$subselect = new Subselect($select);
$subselect->setAlias(new Identifier('quux'));

$select = new Select(new TargetList([new Star()]));
$select->from[] = new RelationReference(new QualifiedName('unaliased'));
$unaliased = new Subselect($select);

$this->assertEquals(
new FromList([
new RelationReference(new QualifiedName('foo', 'bar')),
new RangeFunctionCall(new FunctionCall(
new QualifiedName('baz'),
new FunctionArgumentList([new NumericConstant('1'), new StringConstant('string')])
)),
$subselect
$subselect,
$unaliased
]),
$list
);
Expand Down Expand Up @@ -247,13 +252,6 @@ public function testNoMoreThanTwoDots(): void
$this->parser->parseFromList('foo.bar.baz.quux');
}

public function testSubselectsRequireAnAlias(): void
{
$this->expectException(SyntaxException::class);
$this->expectExceptionMessage('should have an alias');
$this->parser->parseFromList("(select 'foo')");
}

public function testWithOrdinality(): void
{
$list = $this->parser->parseFromList(
Expand Down
1 change: 1 addition & 0 deletions tests/SqlBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ public function testBuildSelectStatement(): void
as three on xyzzy.id = three.xyzzy_id,
some_function(1, 'two', array[3, 4]) with ordinality as sf (id integer, name text collate somecollation),
(select five, six, seven from yetanothertable where id = $2) as ya,
(select * from unaliased),
rows from (generate_series(1,5), generate_series(1,10) as (gs integer)) with ordinality,
xyzzy as a (b,c) tablesample bernoulli (50) repeatable (seed),
LATERAL XMLTABLE(
Expand Down

0 comments on commit df13663

Please sign in to comment.