From e856ab4abaf0ed862d006065002ac45327731add Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Vo=C5=99=C3=AD=C5=A1ek?= Date: Fri, 23 Feb 2024 19:58:56 +0100 Subject: [PATCH] WIP add parsed colum/select --- .../Sql/Optimizer/ParsedColumn.php | 39 ++++++++++++++++ .../Sql/Optimizer/ParsedSelect.php | 45 +++++++++++++++++++ src/Persistence/Sql/Optimizer/Util.php | 28 ++++++++++++ src/Persistence/Sql/Query.php | 19 ++++++++ 4 files changed, 131 insertions(+) create mode 100644 src/Persistence/Sql/Optimizer/ParsedColumn.php create mode 100644 src/Persistence/Sql/Optimizer/ParsedSelect.php diff --git a/src/Persistence/Sql/Optimizer/ParsedColumn.php b/src/Persistence/Sql/Optimizer/ParsedColumn.php new file mode 100644 index 000000000..8c9b84adb --- /dev/null +++ b/src/Persistence/Sql/Optimizer/ParsedColumn.php @@ -0,0 +1,39 @@ +exprTableAlias = $exprIdentifier[0]; + $this->expr = $exprIdentifier[1]; + } else { + $this->expr = $expr; + } + + $this->columnAlias = Util::parseSingleIdentifier($columnAlias); + } + + public function getDsqlExpression(): Expression + { + if ($this->exprTableAlias !== null) { + return new Expression('{}.{} {}', [$this->expr, $this->exprTableAlias, $this->columnAlias]); // @phpstan-ignore-line @TODO not sure what to do here !!! + } + + return new Expression('{} {}', [$this->expr, $this->columnAlias]); // @phpstan-ignore-line @TODO not sure what to do here !!! + } +} diff --git a/src/Persistence/Sql/Optimizer/ParsedSelect.php b/src/Persistence/Sql/Optimizer/ParsedSelect.php new file mode 100644 index 000000000..ada01d56b --- /dev/null +++ b/src/Persistence/Sql/Optimizer/ParsedSelect.php @@ -0,0 +1,45 @@ +expr = Util::parseSingleIdentifier($expr); + } else { + $this->expr = $expr; + } + + $this->tableAlias = Util::parseSingleIdentifier($tableAlias); + } + + /* + public function getDsqlExpression(): Expression + { + if ($this->tableAlias === self::TOP_QUERY_ALIAS) { + return new Expression('{}', [$this->expr]); + } + + return new Expression('{} {}', [$this->expr, $this->tableAlias]); + } + */ +} diff --git a/src/Persistence/Sql/Optimizer/Util.php b/src/Persistence/Sql/Optimizer/Util.php index 32cfbf21d..ed42ece4f 100644 --- a/src/Persistence/Sql/Optimizer/Util.php +++ b/src/Persistence/Sql/Optimizer/Util.php @@ -107,4 +107,32 @@ public static function parseSingleIdentifier($expr): string return $v[1]; } + + public static function parseSelectQuery(Query $query, string $tableAlias): ParsedSelect + { + $query->args['is_select_parsed'] = [true]; + $select = new ParsedSelect($query, $tableAlias); + if (is_string($select->expr)) { + return $select; + } + + // traverse $query and parse everything into ParsedSelect/ParsedColumn + foreach ($query->args as $argK => $argV) { + // TODO + } + + return $select; + } + + public static function isSelectQueryParsed(Query $query): bool + { + return ($query->args['is_select_parsed'] ?? [])[0] ?? false; + } + + public static function parseColumn(Expression $expr, string $columnAlias): ParsedColumn + { + $column = new ParsedColumn($expr, $columnAlias); + + return $column; + } } diff --git a/src/Persistence/Sql/Query.php b/src/Persistence/Sql/Query.php index bdf063040..41276ba5b 100644 --- a/src/Persistence/Sql/Query.php +++ b/src/Persistence/Sql/Query.php @@ -954,12 +954,31 @@ public function __debugInfo(): array // {{{ Miscelanious + protected function toParsedSelect(): Optimizer\ParsedSelect + { + return Optimizer\Util::parseSelectQuery($this, Optimizer\ParsedSelect::TOP_QUERY_ALIAS); + } + + /** + * Deduplicate same subselects, field rereads to produce optimized select query + * using CTE/WITH. + */ + protected function transformSelectUsingCte(): Optimizer\ParsedSelect + { + throw new Exception('Not implemented yet'); + } + /** * @return array{string, array} */ private function callParentRender(): array { $firstRender = parent::render(); + if ($this->mode === 'select' && !Optimizer\Util::isSelectQueryParsed($this)) { + $parsedSelect = $this->toParsedSelect(); + $firstRender = $parsedSelect->expr->render(); + } + if (($this->args['first_render'] ?? null) === null) { $this->args['first_render'] = $firstRender; $secondRender = $this->render();