|
36 | 36 | use MariaStan\Ast\Query\UpdateQuery; |
37 | 37 | use MariaStan\Ast\SelectExpr\AllColumns; |
38 | 38 | use MariaStan\Ast\SelectExpr\RegularExpr; |
| 39 | +use MariaStan\Ast\SelectExpr\SelectExpr; |
39 | 40 | use MariaStan\Ast\SelectExpr\SelectExprTypeEnum; |
40 | 41 | use MariaStan\Database\FunctionInfo\FunctionInfoHelper; |
41 | 42 | use MariaStan\Database\FunctionInfo\FunctionInfoRegistry; |
@@ -380,43 +381,8 @@ private function analyseSingleSelectQuery(SimpleSelectQuery $select): array |
380 | 381 | $this->columnResolver->addKnowledge($whereResult->knowledgeBase); |
381 | 382 | } |
382 | 383 |
|
383 | | - $fields = []; |
384 | 384 | $this->fieldBehavior = ColumnResolverFieldBehaviorEnum::FIELD_LIST; |
385 | | - |
386 | | - foreach ($select->select as $selectExpr) { |
387 | | - switch ($selectExpr::getSelectExprType()) { |
388 | | - case SelectExprTypeEnum::REGULAR_EXPR: |
389 | | - assert($selectExpr instanceof RegularExpr); |
390 | | - $expr = $this->removeUnaryPlusPrefix($selectExpr->expr); |
391 | | - $resolvedExpr = $this->resolveExprType($expr, null, $select->groupBy !== null, true); |
392 | | - $resolvedField = new QueryResultField( |
393 | | - $selectExpr->alias ?? $this->getDefaultFieldNameForExpr($expr), |
394 | | - $resolvedExpr, |
395 | | - ); |
396 | | - $fields[] = $resolvedField; |
397 | | - $this->columnResolver->registerField( |
398 | | - $resolvedField, |
399 | | - $selectExpr->expr::getExprType() === Expr\ExprTypeEnum::COLUMN, |
400 | | - ); |
401 | | - break; |
402 | | - case SelectExprTypeEnum::ALL_COLUMNS: |
403 | | - assert($selectExpr instanceof AllColumns); |
404 | | - $allFields = $this->columnResolver->resolveAllColumns( |
405 | | - $selectExpr->tableName?->name, |
406 | | - $selectExpr->tableName?->databaseName, |
407 | | - ); |
408 | | - |
409 | | - foreach ($allFields as $field) { |
410 | | - $this->columnResolver->registerField($field, true); |
411 | | - $this->recordColumnReference($field->exprType->column); |
412 | | - } |
413 | | - |
414 | | - $fields = array_merge($fields, $allFields); |
415 | | - unset($allFields); |
416 | | - break; |
417 | | - } |
418 | | - } |
419 | | - |
| 385 | + $fields = $this->analyseSelectExpressions($select->select, $select->groupBy !== null); |
420 | 386 | $this->fieldBehavior = ColumnResolverFieldBehaviorEnum::GROUP_BY; |
421 | 387 |
|
422 | 388 | foreach ($select->groupBy->expressions ?? [] as $groupByExpr) { |
@@ -467,6 +433,52 @@ private function analyseSingleSelectQuery(SimpleSelectQuery $select): array |
467 | 433 | return [$fields, $rowCount]; |
468 | 434 | } |
469 | 435 |
|
| 436 | + /** |
| 437 | + * @param list<SelectExpr> $selectExpressions |
| 438 | + * @return list<QueryResultField> |
| 439 | + * @throws AnalyserException |
| 440 | + */ |
| 441 | + private function analyseSelectExpressions(array $selectExpressions, bool $isNonEmptyAggResultSet): array |
| 442 | + { |
| 443 | + $fields = []; |
| 444 | + |
| 445 | + foreach ($selectExpressions as $selectExpr) { |
| 446 | + switch ($selectExpr::getSelectExprType()) { |
| 447 | + case SelectExprTypeEnum::REGULAR_EXPR: |
| 448 | + assert($selectExpr instanceof RegularExpr); |
| 449 | + $expr = $this->removeUnaryPlusPrefix($selectExpr->expr); |
| 450 | + $resolvedExpr = $this->resolveExprType($expr, null, $isNonEmptyAggResultSet, true); |
| 451 | + $resolvedField = new QueryResultField( |
| 452 | + $selectExpr->alias ?? $this->getDefaultFieldNameForExpr($expr), |
| 453 | + $resolvedExpr, |
| 454 | + ); |
| 455 | + $fields[] = $resolvedField; |
| 456 | + $this->columnResolver->registerField( |
| 457 | + $resolvedField, |
| 458 | + $selectExpr->expr::getExprType() === Expr\ExprTypeEnum::COLUMN, |
| 459 | + ); |
| 460 | + break; |
| 461 | + case SelectExprTypeEnum::ALL_COLUMNS: |
| 462 | + assert($selectExpr instanceof AllColumns); |
| 463 | + $allFields = $this->columnResolver->resolveAllColumns( |
| 464 | + $selectExpr->tableName?->name, |
| 465 | + $selectExpr->tableName?->databaseName, |
| 466 | + ); |
| 467 | + |
| 468 | + foreach ($allFields as $field) { |
| 469 | + $this->columnResolver->registerField($field, true); |
| 470 | + $this->recordColumnReference($field->exprType->column); |
| 471 | + } |
| 472 | + |
| 473 | + $fields = array_merge($fields, $allFields); |
| 474 | + unset($allFields); |
| 475 | + break; |
| 476 | + } |
| 477 | + } |
| 478 | + |
| 479 | + return $fields; |
| 480 | + } |
| 481 | + |
470 | 482 | /** @throws AnalyserException|DbReflectionException */ |
471 | 483 | private function analyseTableReference(TableReference $fromClause, ColumnResolver $columnResolver): ColumnResolver |
472 | 484 | { |
@@ -595,8 +607,7 @@ private function analyseDeleteQuery(DeleteQuery $query): array |
595 | 607 | $this->resolveExprType($query->limit); |
596 | 608 | } |
597 | 609 |
|
598 | | - // TODO: DELETE ... RETURNING |
599 | | - return []; |
| 610 | + return $this->analyseSelectExpressions($query->returning, false); |
600 | 611 | } |
601 | 612 |
|
602 | 613 | /** @throws AnalyserException */ |
@@ -764,9 +775,17 @@ private function analyseInsertOrReplaceQuery(InsertQuery|ReplaceQuery $query): a |
764 | 775 | $this->errors[] = AnalyserErrorBuilder::createMissingValueForColumnError($name); |
765 | 776 | } |
766 | 777 |
|
767 | | - // TODO: INSERT ... ON DUPLICATE KEY |
768 | | - // TODO: INSERT ... RETURNING |
769 | | - return []; |
| 778 | + $this->fieldBehavior = ColumnResolverFieldBehaviorEnum::FIELD_LIST; |
| 779 | + |
| 780 | + if ($query->returning === [] || $tableSchema === null) { |
| 781 | + return []; |
| 782 | + } |
| 783 | + |
| 784 | + // Make sure that the RETURNING clause doesn't have access to any table other than the insert target. |
| 785 | + $cleanAnalyser = $this->getSubqueryAnalyser($query); |
| 786 | + $cleanAnalyser->columnResolver->registerInsertReplaceTargetTable($tableSchema, $tableSchema->database); |
| 787 | + |
| 788 | + return $cleanAnalyser->analyseSelectExpressions($query->returning, false); |
770 | 789 | } |
771 | 790 |
|
772 | 791 | /** @throws AnalyserException */ |
@@ -1675,7 +1694,7 @@ private function getNodeContent(Node $node): string |
1675 | 1694 | return $node->getStartPosition()->findSubstringToEndPosition($this->query, $node->getEndPosition()); |
1676 | 1695 | } |
1677 | 1696 |
|
1678 | | - private function getSubqueryAnalyser(SelectQuery $subquery, bool $canReferenceGrandParent = false): self |
| 1697 | + private function getSubqueryAnalyser(Query $subquery, bool $canReferenceGrandParent = false): self |
1679 | 1698 | { |
1680 | 1699 | $other = new self( |
1681 | 1700 | $this->dbReflection, |
|
0 commit comments