packages/sql-faker/src/PostgreSql/Generation/Rewrite/Name/AnyRelationNameRule.php
1<?php
2
3declare(strict_types=1);
4
5namespace SqlFaker\PostgreSql\Generation\Rewrite\Name;
6
7use Override;
8use SqlFaker\Generation\Token\RewriteRule;
9use SqlFaker\Generation\Token\TerminalSequence;
10
11/**
12 * gram.y/makeRangeVarFromAnyName limits composite type relation names to three components.
13 * @see https://github.com/postgres/postgres/blob/REL_17_2/src/backend/parser/gram.y
14 */
15final class AnyRelationNameRule implements RewriteRule
16{
17 /**
18 * Limits only the three grammar actions constructing a RangeVar from any_name.
19 */
20 #[Override]
21 public function rewrite(TerminalSequence $sequence): TerminalSequence
22 {
23 foreach ($sequence->occurrences('any_name') as $id) {
24 $range = $sequence->range($id);
25 if ($range === null) {
26 continue;
27 }
28 $origin = $sequence->terminals[$range[0]];
29 $position = array_search('any_name', $origin->rules, true);
30 if ($position === false || $position === 0) {
31 continue;
32 }
33 $parent = $origin->ancestors[$position - 1];
34 $rule = $origin->rules[$position - 1];
35 if ($rule !== 'AlterCompositeTypeStmt'
36 && !($rule === 'DefineStmt' && $sequence->child($parent, 'OptTableFuncElementList') !== null)
37 && !($rule === 'RenameStmt' && $sequence->nameAt($range[1]) === 'RENAME' && $sequence->nameAt($range[1] + 1) === 'ATTRIBUTE')) {
38 continue;
39 }
40 $count = 0;
41 foreach (array_reverse($sequence->occurrences('attr_name')) as $attribute) {
42 $part = $sequence->range($attribute);
43 if ($part === null || $sequence->terminals[$part[0]]->ancestor('any_name') !== $id) {
44 continue;
45 }
46 if (++$count > 2) {
47 $sequence = $sequence->replace($part[0] - 1, $part[1] - $part[0] + 1, [], 'gram.y:makeRangeVarFromAnyName');
48 }
49 }
50 }
51 return $sequence;
52 }
53}
54