@quereus/quereus 4.8.0 → 4.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/core/database.d.ts +6 -0
- package/dist/src/core/database.d.ts.map +1 -1
- package/dist/src/core/database.js +26 -1
- package/dist/src/core/database.js.map +1 -1
- package/dist/src/func/builtins/aggregate.d.ts.map +1 -1
- package/dist/src/func/builtins/aggregate.js +3 -2
- package/dist/src/func/builtins/aggregate.js.map +1 -1
- package/dist/src/func/builtins/conversion.d.ts +5 -0
- package/dist/src/func/builtins/conversion.d.ts.map +1 -1
- package/dist/src/func/builtins/conversion.js +16 -2
- package/dist/src/func/builtins/conversion.js.map +1 -1
- package/dist/src/func/builtins/index.d.ts.map +1 -1
- package/dist/src/func/builtins/index.js +5 -2
- package/dist/src/func/builtins/index.js.map +1 -1
- package/dist/src/func/builtins/string.d.ts +2 -0
- package/dist/src/func/builtins/string.d.ts.map +1 -1
- package/dist/src/func/builtins/string.js +60 -4
- package/dist/src/func/builtins/string.js.map +1 -1
- package/dist/src/index.d.ts +6 -3
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +15 -2
- package/dist/src/index.js.map +1 -1
- package/dist/src/planner/building/constraint-builder.js +1 -1
- package/dist/src/planner/building/constraint-builder.js.map +1 -1
- package/dist/src/planner/rules/retrieve/rule-grow-retrieve.d.ts.map +1 -1
- package/dist/src/planner/rules/retrieve/rule-grow-retrieve.js +121 -51
- package/dist/src/planner/rules/retrieve/rule-grow-retrieve.js.map +1 -1
- package/dist/src/planner/rules/shared/index-style-context.d.ts +14 -4
- package/dist/src/planner/rules/shared/index-style-context.d.ts.map +1 -1
- package/dist/src/planner/rules/shared/index-style-context.js +14 -4
- package/dist/src/planner/rules/shared/index-style-context.js.map +1 -1
- package/dist/src/runtime/emit/alter-table.d.ts.map +1 -1
- package/dist/src/runtime/emit/alter-table.js +212 -155
- package/dist/src/runtime/emit/alter-table.js.map +1 -1
- package/dist/src/runtime/emit/assertion-drop-guard.d.ts +26 -12
- package/dist/src/runtime/emit/assertion-drop-guard.d.ts.map +1 -1
- package/dist/src/runtime/emit/assertion-drop-guard.js +45 -26
- package/dist/src/runtime/emit/assertion-drop-guard.js.map +1 -1
- package/dist/src/runtime/emit/assertion-rename-helpers.d.ts +6 -6
- package/dist/src/runtime/emit/assertion-rename-helpers.d.ts.map +1 -1
- package/dist/src/runtime/emit/assertion-rename-helpers.js +18 -20
- package/dist/src/runtime/emit/assertion-rename-helpers.js.map +1 -1
- package/dist/src/runtime/emit/binary.d.ts.map +1 -1
- package/dist/src/runtime/emit/binary.js +12 -10
- package/dist/src/runtime/emit/binary.js.map +1 -1
- package/dist/src/runtime/emit/column-rename-cascade.d.ts +84 -0
- package/dist/src/runtime/emit/column-rename-cascade.d.ts.map +1 -0
- package/dist/src/runtime/emit/column-rename-cascade.js +134 -0
- package/dist/src/runtime/emit/column-rename-cascade.js.map +1 -0
- package/dist/src/runtime/emit/drop-column-guards.d.ts +82 -53
- package/dist/src/runtime/emit/drop-column-guards.d.ts.map +1 -1
- package/dist/src/runtime/emit/drop-column-guards.js +155 -90
- package/dist/src/runtime/emit/drop-column-guards.js.map +1 -1
- package/dist/src/runtime/emit/drop-table.d.ts.map +1 -1
- package/dist/src/runtime/emit/drop-table.js +5 -0
- package/dist/src/runtime/emit/drop-table.js.map +1 -1
- package/dist/src/runtime/emit/drop-view.d.ts.map +1 -1
- package/dist/src/runtime/emit/drop-view.js +5 -0
- package/dist/src/runtime/emit/drop-view.js.map +1 -1
- package/dist/src/runtime/emit/expression-drop-guard.d.ts +57 -0
- package/dist/src/runtime/emit/expression-drop-guard.d.ts.map +1 -0
- package/dist/src/runtime/emit/expression-drop-guard.js +82 -0
- package/dist/src/runtime/emit/expression-drop-guard.js.map +1 -0
- package/dist/src/runtime/emit/materialized-view-helpers.d.ts +26 -9
- package/dist/src/runtime/emit/materialized-view-helpers.d.ts.map +1 -1
- package/dist/src/runtime/emit/materialized-view-helpers.js +37 -17
- package/dist/src/runtime/emit/materialized-view-helpers.js.map +1 -1
- package/dist/src/runtime/emit/materialized-view.d.ts.map +1 -1
- package/dist/src/runtime/emit/materialized-view.js +3 -0
- package/dist/src/runtime/emit/materialized-view.js.map +1 -1
- package/dist/src/schema/assertion.d.ts +58 -0
- package/dist/src/schema/assertion.d.ts.map +1 -1
- package/dist/src/schema/assertion.js +78 -0
- package/dist/src/schema/assertion.js.map +1 -1
- package/dist/src/schema/catalog-persistability.d.ts +11 -3
- package/dist/src/schema/catalog-persistability.d.ts.map +1 -1
- package/dist/src/schema/catalog-persistability.js +48 -29
- package/dist/src/schema/catalog-persistability.js.map +1 -1
- package/dist/src/schema/catalog.d.ts +22 -0
- package/dist/src/schema/catalog.d.ts.map +1 -1
- package/dist/src/schema/catalog.js +4 -1
- package/dist/src/schema/catalog.js.map +1 -1
- package/dist/src/schema/column-republication.d.ts +126 -0
- package/dist/src/schema/column-republication.d.ts.map +1 -0
- package/dist/src/schema/column-republication.js +121 -0
- package/dist/src/schema/column-republication.js.map +1 -0
- package/dist/src/schema/column-source-resolver.d.ts +29 -6
- package/dist/src/schema/column-source-resolver.d.ts.map +1 -1
- package/dist/src/schema/column-source-resolver.js +78 -9
- package/dist/src/schema/column-source-resolver.js.map +1 -1
- package/dist/src/schema/expression-dependents.d.ts +160 -0
- package/dist/src/schema/expression-dependents.d.ts.map +1 -0
- package/dist/src/schema/expression-dependents.js +228 -0
- package/dist/src/schema/expression-dependents.js.map +1 -0
- package/dist/src/schema/object-dependency-closure.d.ts +127 -0
- package/dist/src/schema/object-dependency-closure.d.ts.map +1 -0
- package/dist/src/schema/object-dependency-closure.js +117 -0
- package/dist/src/schema/object-dependency-closure.js.map +1 -0
- package/dist/src/schema/object-ref-resolver.d.ts +83 -0
- package/dist/src/schema/object-ref-resolver.d.ts.map +1 -0
- package/dist/src/schema/object-ref-resolver.js +135 -0
- package/dist/src/schema/object-ref-resolver.js.map +1 -0
- package/dist/src/schema/rename/column-rename.d.ts +228 -0
- package/dist/src/schema/rename/column-rename.d.ts.map +1 -0
- package/dist/src/schema/rename/column-rename.js +1225 -0
- package/dist/src/schema/rename/column-rename.js.map +1 -0
- package/dist/src/schema/rename/self-qualifier-strip.d.ts +29 -0
- package/dist/src/schema/rename/self-qualifier-strip.d.ts.map +1 -0
- package/dist/src/schema/rename/self-qualifier-strip.js +267 -0
- package/dist/src/schema/rename/self-qualifier-strip.js.map +1 -0
- package/dist/src/schema/rename/shared.d.ts +108 -0
- package/dist/src/schema/rename/shared.d.ts.map +1 -0
- package/dist/src/schema/rename/shared.js +49 -0
- package/dist/src/schema/rename/shared.js.map +1 -0
- package/dist/src/schema/rename/table-rename.d.ts +263 -0
- package/dist/src/schema/rename/table-rename.d.ts.map +1 -0
- package/dist/src/schema/rename/table-rename.js +860 -0
- package/dist/src/schema/rename/table-rename.js.map +1 -0
- package/dist/src/schema/rename-rewriter.d.ts +18 -278
- package/dist/src/schema/rename-rewriter.d.ts.map +1 -1
- package/dist/src/schema/rename-rewriter.js +17 -1506
- package/dist/src/schema/rename-rewriter.js.map +1 -1
- package/dist/src/schema/schema-differ.d.ts.map +1 -1
- package/dist/src/schema/schema-differ.js +228 -21
- package/dist/src/schema/schema-differ.js.map +1 -1
- package/dist/src/types/builtin-types.d.ts.map +1 -1
- package/dist/src/types/builtin-types.js +12 -28
- package/dist/src/types/builtin-types.js.map +1 -1
- package/dist/src/types/cast-semantics.d.ts +7 -5
- package/dist/src/types/cast-semantics.d.ts.map +1 -1
- package/dist/src/types/cast-semantics.js +20 -9
- package/dist/src/types/cast-semantics.js.map +1 -1
- package/dist/src/types/index.d.ts +1 -1
- package/dist/src/types/index.d.ts.map +1 -1
- package/dist/src/types/index.js +1 -1
- package/dist/src/types/index.js.map +1 -1
- package/dist/src/types/registry.d.ts.map +1 -1
- package/dist/src/types/registry.js +2 -1
- package/dist/src/types/registry.js.map +1 -1
- package/dist/src/types/temporal-types.d.ts +11 -0
- package/dist/src/types/temporal-types.d.ts.map +1 -1
- package/dist/src/types/temporal-types.js +82 -0
- package/dist/src/types/temporal-types.js.map +1 -1
- package/dist/src/util/affinity.d.ts +2 -1
- package/dist/src/util/affinity.d.ts.map +1 -1
- package/dist/src/util/affinity.js +16 -5
- package/dist/src/util/affinity.js.map +1 -1
- package/dist/src/util/ast-spine-clone.d.ts +2 -2
- package/dist/src/util/ast-spine-clone.js +2 -2
- package/dist/src/util/value-text.d.ts +48 -0
- package/dist/src/util/value-text.d.ts.map +1 -0
- package/dist/src/util/value-text.js +35 -0
- package/dist/src/util/value-text.js.map +1 -0
- package/dist/src/vtab/memory/layer/manager.d.ts.map +1 -1
- package/dist/src/vtab/memory/layer/manager.js +14 -5
- package/dist/src/vtab/memory/layer/manager.js.map +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import { expressionToString } from '../emit/ast-stringify.js';
|
|
2
|
+
import { columnReferencedInAst, columnReferencedInCheckExpression, objectRefKey, } from './rename-rewriter.js';
|
|
3
|
+
import { buildColumnSourceResolver } from './column-source-resolver.js';
|
|
4
|
+
import { snapshotObjectRefResolvers } from './object-ref-resolver.js';
|
|
5
|
+
import { reachableObjects } from './object-dependency-closure.js';
|
|
6
|
+
import { collectColumnRepublication } from './column-republication.js';
|
|
7
|
+
/**
|
|
8
|
+
* The FIRST table in ANY schema whose `arm` expressions name
|
|
9
|
+
* `<tableSchema.schemaName>.<tableSchema.name>.<columnName>`, or `undefined` when none
|
|
10
|
+
* does. The probed table itself is scanned first, so a self-reference is always the one
|
|
11
|
+
* reported and the guards' own-table messages never change spelling because an unrelated
|
|
12
|
+
* schema happens to sort earlier.
|
|
13
|
+
*
|
|
14
|
+
* Only the first hit is returned: every caller is a guard that throws on it, and stopping
|
|
15
|
+
* early keeps the walk off the remaining schemas.
|
|
16
|
+
*
|
|
17
|
+
* Two expressions are skipped on the probed table itself, both deliberately:
|
|
18
|
+
*
|
|
19
|
+
* - The dropped column's **own** DEFAULT / generated body — it goes away with the column,
|
|
20
|
+
* so a self-naming default (`a integer default (new.a)`) is not something the drop
|
|
21
|
+
* orphans.
|
|
22
|
+
* - **Every** own-table generated body — `runDropColumn` already refuses off
|
|
23
|
+
* `generatedColumnDependencies`, the resolved column-index map
|
|
24
|
+
* `extractGeneratedColumnDependencies` builds, and reporting it twice would only change
|
|
25
|
+
* which of two messages the user sees. A generated body on ANOTHER table is not covered
|
|
26
|
+
* by that map and IS reported here.
|
|
27
|
+
*/
|
|
28
|
+
export function findColumnExpressionDependent(db, tableSchema, columnName, arm) {
|
|
29
|
+
const resolvers = snapshotObjectRefResolvers(db);
|
|
30
|
+
const resolveColumnInSource = buildColumnSourceResolver(db);
|
|
31
|
+
const targetKey = objectRefKey(tableSchema.schemaName, tableSchema.name);
|
|
32
|
+
// One republication fixpoint per drop (seed first), shared by every probe below:
|
|
33
|
+
// a view republishing the column by a star (`select * from t`) is a target its
|
|
34
|
+
// readers reference the column THROUGH, without any body spelling the name.
|
|
35
|
+
const republication = collectColumnRepublication(db, { targetKey, tableName: tableSchema.name }, columnName, resolvers, resolveColumnInSource);
|
|
36
|
+
for (const table of tablesProbedTargetFirst(db, targetKey)) {
|
|
37
|
+
const ownTable = objectRefKey(table.schemaName, table.name) === targetKey;
|
|
38
|
+
const names = columnProbe(db, resolvers, table.schemaName, ownTable, republication, columnName, resolveColumnInSource);
|
|
39
|
+
const found = arm === 'check'
|
|
40
|
+
? findInChecks(table, names)
|
|
41
|
+
: findInColumnExpressions(table, ownTable, columnName, names);
|
|
42
|
+
if (found)
|
|
43
|
+
return { table, ownTable, ...found };
|
|
44
|
+
}
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* The FIRST table in ANY schema whose CHECK / DEFAULT / `GENERATED ALWAYS AS` expressions
|
|
49
|
+
* name `<schemaName>.<objectName>`, or `undefined` when none does.
|
|
50
|
+
*
|
|
51
|
+
* The dropped object itself is skipped: its own CHECKs naming itself vanish with it, so
|
|
52
|
+
* refusing on them would make every self-referencing table undroppable. (The column verb
|
|
53
|
+
* keeps its target in the walk — a column drop leaves the rest of the table behind.)
|
|
54
|
+
*
|
|
55
|
+
* All three arms run with the walker's `rowImageContext` on the ROOT expression, exactly as
|
|
56
|
+
* `renameTableInCheckConstraints` / `renameTableInColumnExpressions` do: these
|
|
57
|
+
* expressions evaluate against a written row, so a bare `new.` / `old.` qualifier names
|
|
58
|
+
* that row image rather than a table literally called `new`.
|
|
59
|
+
*
|
|
60
|
+
* The match is `namerOf` over the expression's whole reach, so a CHECK that reads a view
|
|
61
|
+
* whose body reads the dropped object matches too, and `path` carries the shortest chain
|
|
62
|
+
* for the error to quote — empty exactly when the expression names the object itself.
|
|
63
|
+
*/
|
|
64
|
+
export function findTableExpressionDependent(db, schemaName, objectName) {
|
|
65
|
+
const resolvers = snapshotObjectRefResolvers(db);
|
|
66
|
+
const targetKey = objectRefKey(schemaName, objectName);
|
|
67
|
+
for (const table of tablesProbedTargetFirst(db, targetKey)) {
|
|
68
|
+
if (objectRefKey(table.schemaName, table.name) === targetKey)
|
|
69
|
+
continue;
|
|
70
|
+
const names = expr => {
|
|
71
|
+
if (expr === undefined)
|
|
72
|
+
return undefined;
|
|
73
|
+
const path = reachableObjects(db, expr, table.schemaName, resolvers, { rowImageContext: true })
|
|
74
|
+
.namerOf(targetKey)?.path;
|
|
75
|
+
return path === undefined ? undefined : { path };
|
|
76
|
+
};
|
|
77
|
+
const found = findInChecks(table, names) ?? findInColumnExpressions(table, false, undefined, names);
|
|
78
|
+
if (found)
|
|
79
|
+
return { table, ownTable: false, ...found };
|
|
80
|
+
}
|
|
81
|
+
return undefined;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* How an error should spell `table` when the object being dropped lives in `homeSchemaName`:
|
|
85
|
+
* bare when the two share a schema, schema-qualified when they do not — the same rule the
|
|
86
|
+
* rest of the engine's messages follow, and the only way a cross-schema refusal names a
|
|
87
|
+
* table the user can actually find.
|
|
88
|
+
*/
|
|
89
|
+
export function describeDependentTable(table, homeSchemaName) {
|
|
90
|
+
return table.schemaName.toLowerCase() === homeSchemaName.toLowerCase()
|
|
91
|
+
? `'${table.name}'`
|
|
92
|
+
: `'${table.schemaName}.${table.name}'`;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Every table in every schema, with the probed table (if it exists) first.
|
|
96
|
+
*
|
|
97
|
+
* Order is not cosmetic: the guards report the FIRST hit, and the own-table messages are
|
|
98
|
+
* the ones users and tests already know. Scanning the target first keeps a self-reference
|
|
99
|
+
* winning over an unrelated schema's.
|
|
100
|
+
*
|
|
101
|
+
* NOTE: past the probed table the order is `_getAllSchemas()` × `getAllTables()` insertion
|
|
102
|
+
* order, so with TWO referencing tables which one the refusal names follows catalog
|
|
103
|
+
* insertion rather than any user-visible rule. Harmless while the message is advisory —
|
|
104
|
+
* every referencing table has to be dealt with anyway. If a caller ever needs to *list*
|
|
105
|
+
* dependents (a `CASCADE` arm, an introspection function), give it a collect-all entry
|
|
106
|
+
* point with a defined order rather than calling this in a loop.
|
|
107
|
+
*/
|
|
108
|
+
function* tablesProbedTargetFirst(db, targetKey) {
|
|
109
|
+
const rest = [];
|
|
110
|
+
for (const schema of db.schemaManager._getAllSchemas()) {
|
|
111
|
+
for (const table of schema.getAllTables()) {
|
|
112
|
+
if (objectRefKey(table.schemaName, table.name) === targetKey)
|
|
113
|
+
yield table;
|
|
114
|
+
else
|
|
115
|
+
rest.push(table);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
yield* rest;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* The column probe for one scanned table — seeded on the probed table itself, unseeded
|
|
122
|
+
* everywhere else. See this module's header for why that split is load-bearing.
|
|
123
|
+
*
|
|
124
|
+
* The column question is not "does the reach CONTAIN this key?" (which is all the table
|
|
125
|
+
* verb needs) but "does any body in the reach NAME this column?", so this loops the reach's
|
|
126
|
+
* bodies the way `assertNoAssertionNamesColumn` already does, each under its own resolver.
|
|
127
|
+
* `homeSchemaName` is the SCANNED table's schema — the root expression's own — because that
|
|
128
|
+
* is what its unqualified names resolve against.
|
|
129
|
+
*
|
|
130
|
+
* Each body is probed against EVERY republication target, not the base table alone: a
|
|
131
|
+
* reference through `create view v as select * from t` spells the column against `v`, and
|
|
132
|
+
* only the target sweep sees it. Targets are swept OUTER, bodies inner, base table first —
|
|
133
|
+
* so every match the base-table sweep finds is found at the body it always was, and the
|
|
134
|
+
* existing message spellings (`reaches it through view 'v'`) do not move; the widened
|
|
135
|
+
* targets only ever ADD refusals.
|
|
136
|
+
*
|
|
137
|
+
* After the target sweep, the broken-listed arm: a view / MV with an explicit column list
|
|
138
|
+
* over a `*` covering the column breaks OUTRIGHT on the drop (the star's arity changes),
|
|
139
|
+
* so an expression whose reach names such an object at all refuses, marked
|
|
140
|
+
* {@link ProbeMatch.breaksEntirely} so the guard can phrase it honestly.
|
|
141
|
+
*/
|
|
142
|
+
function columnProbe(db, resolvers, homeSchemaName, ownTable, republication, columnName, resolveColumnInSource) {
|
|
143
|
+
return expr => {
|
|
144
|
+
if (!expr)
|
|
145
|
+
return undefined;
|
|
146
|
+
const reach = reachableObjects(db, expr, homeSchemaName, resolvers, { rowImageContext: true });
|
|
147
|
+
for (const [targetIndex, target] of republication.targets.entries()) {
|
|
148
|
+
for (const reached of reach.bodies) {
|
|
149
|
+
// Seeded ONLY on the probed table's own ROOT body, probing the BASE target: a
|
|
150
|
+
// CHECK / DEFAULT there is written against the row being written, so an
|
|
151
|
+
// unqualified name binds the owning table implicitly. A view body below it is
|
|
152
|
+
// a relation with no such seed, the root body of ANOTHER table's expression
|
|
153
|
+
// binds that table's row, not ours — and no expression ever binds a VIEW
|
|
154
|
+
// target implicitly, so a republication target takes the unseeded probe even
|
|
155
|
+
// at the root (a reference to it can only sit inside a subquery FROM).
|
|
156
|
+
const seeded = targetIndex === 0 && ownTable && reached.ownerKey === undefined;
|
|
157
|
+
// Row-image mode, the one non-constant site: a ROOT body is a table's CHECK /
|
|
158
|
+
// DEFAULT / generated expression and therefore always written-row context —
|
|
159
|
+
// `'own'` only for the seeded base-target case, `'foreign'` otherwise (another
|
|
160
|
+
// table's root body binds that table's image; a republication target at the
|
|
161
|
+
// root still binds the OWNING table's image, not the view being probed).
|
|
162
|
+
// Anything REACHED below the root is a view / MV body — a relation with no
|
|
163
|
+
// written row — so `'none'`.
|
|
164
|
+
const rowImage = reached.ownerKey === undefined ? (seeded ? 'own' : 'foreign') : 'none';
|
|
165
|
+
const hit = seeded
|
|
166
|
+
? columnReferencedInCheckExpression(reached.body, target.tableName, columnName, reached.resolve, target.targetKey, rowImage, resolveColumnInSource)
|
|
167
|
+
: columnReferencedInAst(reached.body, target.tableName, columnName, reached.resolve, target.targetKey, rowImage, resolveColumnInSource);
|
|
168
|
+
if (hit)
|
|
169
|
+
return { path: reached.path };
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
for (const broken of republication.brokenListed) {
|
|
173
|
+
const namer = reach.namerOf(broken.key);
|
|
174
|
+
if (namer)
|
|
175
|
+
return { path: namer.path, breaksEntirely: broken.describe };
|
|
176
|
+
}
|
|
177
|
+
return undefined;
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
/** The first CHECK constraint of `table` the probe matches, described for an error. */
|
|
181
|
+
function findInChecks(table, names) {
|
|
182
|
+
for (const check of table.checkConstraints ?? []) {
|
|
183
|
+
// `!== undefined`, not truthiness: a match with an EMPTY path is a direct match.
|
|
184
|
+
const match = names(check.expr);
|
|
185
|
+
if (match !== undefined)
|
|
186
|
+
return { describe: describeCheck(check), ...match };
|
|
187
|
+
}
|
|
188
|
+
return undefined;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* The first column DEFAULT / generated body of `table` the probe matches, described for
|
|
192
|
+
* an error. `skipColumnName` is the column being dropped, skipped only on the probed
|
|
193
|
+
* table itself; own-table generated bodies are skipped outright (see
|
|
194
|
+
* {@link findColumnExpressionDependent}).
|
|
195
|
+
*/
|
|
196
|
+
function findInColumnExpressions(table, ownTable, skipColumnName, names) {
|
|
197
|
+
const lowerSkip = ownTable ? skipColumnName?.toLowerCase() : undefined;
|
|
198
|
+
for (const col of table.columns) {
|
|
199
|
+
if (lowerSkip !== undefined && col.name.toLowerCase() === lowerSkip)
|
|
200
|
+
continue;
|
|
201
|
+
// `!== undefined` for the same reason as in {@link findInChecks}: an empty-path
|
|
202
|
+
// match is a direct hit.
|
|
203
|
+
const defaultMatch = names(col.defaultValue ?? undefined);
|
|
204
|
+
if (defaultMatch !== undefined) {
|
|
205
|
+
return { describe: `the DEFAULT of column '${col.name}'`, ...defaultMatch };
|
|
206
|
+
}
|
|
207
|
+
if (ownTable)
|
|
208
|
+
continue;
|
|
209
|
+
const generatedMatch = names(col.generatedExpr);
|
|
210
|
+
if (generatedMatch !== undefined) {
|
|
211
|
+
return { describe: `the GENERATED expression of column '${col.name}'`, ...generatedMatch };
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
return undefined;
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* A table-level unnamed CHECK genuinely carries `name: undefined` — the `_check_<table>`
|
|
218
|
+
* spelling `manager.ts` produces is error text, not stored identity — so there is no name
|
|
219
|
+
* to quote and the expression stands in for one. That is also the only handle the user
|
|
220
|
+
* has on it: `DROP CONSTRAINT` resolves by name only, so an unnamed CHECK can only be
|
|
221
|
+
* removed by rebuilding its table.
|
|
222
|
+
*/
|
|
223
|
+
function describeCheck(check) {
|
|
224
|
+
return check.name
|
|
225
|
+
? `CHECK constraint '${check.name}'`
|
|
226
|
+
: `the CHECK constraint (${expressionToString(check.expr)})`;
|
|
227
|
+
}
|
|
228
|
+
//# sourceMappingURL=expression-dependents.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"expression-dependents.js","sourceRoot":"","sources":["../../../src/schema/expression-dependents.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EACN,qBAAqB,EACrB,iCAAiC,EACjC,YAAY,GAEZ,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAC;AACxE,OAAO,EAAE,0BAA0B,EAA2B,MAAM,0BAA0B,CAAC;AAC/F,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAClE,OAAO,EAAE,0BAA0B,EAA4B,MAAM,2BAA2B,CAAC;AAmHjG;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,6BAA6B,CAC5C,EAAY,EACZ,WAAwB,EACxB,UAAkB,EAClB,GAAwB;IAExB,MAAM,SAAS,GAAG,0BAA0B,CAAC,EAAE,CAAC,CAAC;IACjD,MAAM,qBAAqB,GAAG,yBAAyB,CAAC,EAAE,CAAC,CAAC;IAC5D,MAAM,SAAS,GAAG,YAAY,CAAC,WAAW,CAAC,UAAU,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC;IACzE,iFAAiF;IACjF,+EAA+E;IAC/E,4EAA4E;IAC5E,MAAM,aAAa,GAAG,0BAA0B,CAAC,EAAE,EAClD,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,CAAC,IAAI,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,qBAAqB,CAAC,CAAC;IAE3F,KAAK,MAAM,KAAK,IAAI,uBAAuB,CAAC,EAAE,EAAE,SAAS,CAAC,EAAE,CAAC;QAC5D,MAAM,QAAQ,GAAG,YAAY,CAAC,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC,KAAK,SAAS,CAAC;QAC1E,MAAM,KAAK,GAAG,WAAW,CACxB,EAAE,EAAE,SAAS,EAAE,KAAK,CAAC,UAAU,EAAE,QAAQ,EAAE,aAAa,EAAE,UAAU,EAAE,qBAAqB,CAAC,CAAC;QAC9F,MAAM,KAAK,GAAG,GAAG,KAAK,OAAO;YAC5B,CAAC,CAAC,YAAY,CAAC,KAAK,EAAE,KAAK,CAAC;YAC5B,CAAC,CAAC,uBAAuB,CAAC,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,KAAK,CAAC,CAAC;QAC/D,IAAI,KAAK;YAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,KAAK,EAAE,CAAC;IACjD,CAAC;IACD,OAAO,SAAS,CAAC;AAClB,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,4BAA4B,CAC3C,EAAY,EACZ,UAAkB,EAClB,UAAkB;IAElB,MAAM,SAAS,GAAG,0BAA0B,CAAC,EAAE,CAAC,CAAC;IACjD,MAAM,SAAS,GAAG,YAAY,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;IAEvD,KAAK,MAAM,KAAK,IAAI,uBAAuB,CAAC,EAAE,EAAE,SAAS,CAAC,EAAE,CAAC;QAC5D,IAAI,YAAY,CAAC,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC,KAAK,SAAS;YAAE,SAAS;QACvE,MAAM,KAAK,GAAoB,IAAI,CAAC,EAAE;YACrC,IAAI,IAAI,KAAK,SAAS;gBAAE,OAAO,SAAS,CAAC;YACzC,MAAM,IAAI,GAAG,gBAAgB,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,UAAU,EAAE,SAAS,EAAE,EAAE,eAAe,EAAE,IAAI,EAAE,CAAC;iBAC7F,OAAO,CAAC,SAAS,CAAC,EAAE,IAAI,CAAC;YAC3B,OAAO,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;QAClD,CAAC,CAAC;QACF,MAAM,KAAK,GAAG,YAAY,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,uBAAuB,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;QACpG,IAAI,KAAK;YAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,KAAK,EAAE,CAAC;IACxD,CAAC;IACD,OAAO,SAAS,CAAC;AAClB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,sBAAsB,CAAC,KAAkB,EAAE,cAAsB;IAChF,OAAO,KAAK,CAAC,UAAU,CAAC,WAAW,EAAE,KAAK,cAAc,CAAC,WAAW,EAAE;QACrE,CAAC,CAAC,IAAI,KAAK,CAAC,IAAI,GAAG;QACnB,CAAC,CAAC,IAAI,KAAK,CAAC,UAAU,IAAI,KAAK,CAAC,IAAI,GAAG,CAAC;AAC1C,CAAC;AAuBD;;;;;;;;;;;;;GAaG;AACH,QAAQ,CAAC,CAAC,uBAAuB,CAAC,EAAY,EAAE,SAAiB;IAChE,MAAM,IAAI,GAAkB,EAAE,CAAC;IAC/B,KAAK,MAAM,MAAM,IAAI,EAAE,CAAC,aAAa,CAAC,cAAc,EAAE,EAAE,CAAC;QACxD,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,YAAY,EAAE,EAAE,CAAC;YAC3C,IAAI,YAAY,CAAC,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC,KAAK,SAAS;gBAAE,MAAM,KAAK,CAAC;;gBACrE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACvB,CAAC;IACF,CAAC;IACD,KAAK,CAAC,CAAC,IAAI,CAAC;AACb,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,SAAS,WAAW,CACnB,EAAY,EACZ,SAA6B,EAC7B,cAAsB,EACtB,QAAiB,EACjB,aAAkC,EAClC,UAAkB,EAClB,qBAA4C;IAE5C,OAAO,IAAI,CAAC,EAAE;QACb,IAAI,CAAC,IAAI;YAAE,OAAO,SAAS,CAAC;QAC5B,MAAM,KAAK,GAAG,gBAAgB,CAAC,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE,SAAS,EAAE,EAAE,eAAe,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/F,KAAK,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,IAAI,aAAa,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;YACrE,KAAK,MAAM,OAAO,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;gBACpC,8EAA8E;gBAC9E,wEAAwE;gBACxE,8EAA8E;gBAC9E,4EAA4E;gBAC5E,yEAAyE;gBACzE,6EAA6E;gBAC7E,uEAAuE;gBACvE,MAAM,MAAM,GAAG,WAAW,KAAK,CAAC,IAAI,QAAQ,IAAI,OAAO,CAAC,QAAQ,KAAK,SAAS,CAAC;gBAC/E,8EAA8E;gBAC9E,4EAA4E;gBAC5E,+EAA+E;gBAC/E,4EAA4E;gBAC5E,yEAAyE;gBACzE,2EAA2E;gBAC3E,6BAA6B;gBAC7B,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;gBACxF,MAAM,GAAG,GAAG,MAAM;oBACjB,CAAC,CAAC,iCAAiC,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,SAAS,EAAE,UAAU,EAC7E,OAAO,CAAC,OAAO,EAAE,MAAM,CAAC,SAAS,EAAE,QAAQ,EAAE,qBAAqB,CAAC;oBACpE,CAAC,CAAC,qBAAqB,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,SAAS,EAAE,UAAU,EACjE,OAAO,CAAC,OAAO,EAAE,MAAM,CAAC,SAAS,EAAE,QAAQ,EAAE,qBAAqB,CAAC,CAAC;gBACtE,IAAI,GAAG;oBAAE,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC;YACxC,CAAC;QACF,CAAC;QACD,KAAK,MAAM,MAAM,IAAI,aAAa,CAAC,YAAY,EAAE,CAAC;YACjD,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACxC,IAAI,KAAK;gBAAE,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,cAAc,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC;QACzE,CAAC;QACD,OAAO,SAAS,CAAC;IAClB,CAAC,CAAC;AACH,CAAC;AAED,uFAAuF;AACvF,SAAS,YAAY,CAAC,KAAkB,EAAE,KAAsB;IAC/D,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,gBAAgB,IAAI,EAAE,EAAE,CAAC;QAClD,iFAAiF;QACjF,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAChC,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO,EAAE,QAAQ,EAAE,aAAa,CAAC,KAAK,CAAC,EAAE,GAAG,KAAK,EAAE,CAAC;IAC9E,CAAC;IACD,OAAO,SAAS,CAAC;AAClB,CAAC;AAED;;;;;GAKG;AACH,SAAS,uBAAuB,CAC/B,KAAkB,EAClB,QAAiB,EACjB,cAAkC,EAClC,KAAsB;IAEtB,MAAM,SAAS,GAAG,QAAQ,CAAC,CAAC,CAAC,cAAc,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;IACvE,KAAK,MAAM,GAAG,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;QACjC,IAAI,SAAS,KAAK,SAAS,IAAI,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,SAAS;YAAE,SAAS;QAC9E,gFAAgF;QAChF,yBAAyB;QACzB,MAAM,YAAY,GAAG,KAAK,CAAC,GAAG,CAAC,YAAY,IAAI,SAAS,CAAC,CAAC;QAC1D,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;YAChC,OAAO,EAAE,QAAQ,EAAE,0BAA0B,GAAG,CAAC,IAAI,GAAG,EAAE,GAAG,YAAY,EAAE,CAAC;QAC7E,CAAC;QACD,IAAI,QAAQ;YAAE,SAAS;QACvB,MAAM,cAAc,GAAG,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;QAChD,IAAI,cAAc,KAAK,SAAS,EAAE,CAAC;YAClC,OAAO,EAAE,QAAQ,EAAE,uCAAuC,GAAG,CAAC,IAAI,GAAG,EAAE,GAAG,cAAc,EAAE,CAAC;QAC5F,CAAC;IACF,CAAC;IACD,OAAO,SAAS,CAAC;AAClB,CAAC;AAED;;;;;;GAMG;AACH,SAAS,aAAa,CAAC,KAA0B;IAChD,OAAO,KAAK,CAAC,IAAI;QAChB,CAAC,CAAC,qBAAqB,KAAK,CAAC,IAAI,GAAG;QACpC,CAAC,CAAC,yBAAyB,kBAAkB,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC;AAC/D,CAAC"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import type * as AST from '../parser/ast.js';
|
|
2
|
+
import type { Database } from '../core/database.js';
|
|
3
|
+
import { type ResolveObjectRef, type TableRenameOpts } from './rename-rewriter.js';
|
|
4
|
+
import type { ObjectRefResolvers } from './object-ref-resolver.js';
|
|
5
|
+
/**
|
|
6
|
+
* The catalog query "can this stored body REACH that object?", as opposed to the
|
|
7
|
+
* one-hop "does this stored body NAME that object?" the rename walkers answer.
|
|
8
|
+
*
|
|
9
|
+
* A DROP guard that only asks the one-hop question is defeated by a view: an
|
|
10
|
+
* assertion body reading `v` where `create view v as select * from t` names `t`
|
|
11
|
+
* nowhere, so `drop table t` is accepted and every later write to the whole
|
|
12
|
+
* database fails on an assertion whose text does not mention `t`. Reach is the
|
|
13
|
+
* closure over STORED bodies — an assertion body names views and materialized
|
|
14
|
+
* views, whose bodies name further views and base tables — and this module is
|
|
15
|
+
* the one place that closure is computed, so the guard families that consume it
|
|
16
|
+
* cannot end up disagreeing about what "reaches" means.
|
|
17
|
+
*
|
|
18
|
+
* Each body is walked under ITS OWN home-schema resolver, so an unqualified
|
|
19
|
+
* name in a view body means what the planner would make of it *in that body*,
|
|
20
|
+
* not what it would mean in the root body. That is the whole reason
|
|
21
|
+
* {@link ObjectRefResolvers} is a per-home-schema factory over one snapshot.
|
|
22
|
+
*
|
|
23
|
+
* Scope-awareness survives the widening because the walk is
|
|
24
|
+
* {@link collectTableRefsInAst}, the third sink over the very traversal the
|
|
25
|
+
* rename uses: a body whose `with t as (…)` merely shadows the name still
|
|
26
|
+
* contributes no reference, so the closure cannot false-refuse where the direct
|
|
27
|
+
* probe already does not.
|
|
28
|
+
*/
|
|
29
|
+
/**
|
|
30
|
+
* One stored body the closure walked, and how the root got to it.
|
|
31
|
+
*
|
|
32
|
+
* The root body itself is a `ReachedBody` with an empty {@link path} and no
|
|
33
|
+
* {@link ownerKey} — it is an assertion's CHECK, or a table's CHECK / DEFAULT /
|
|
34
|
+
* generated expression, none of which is a catalog object with a key of its own.
|
|
35
|
+
*/
|
|
36
|
+
export interface ReachedBody {
|
|
37
|
+
/**
|
|
38
|
+
* Canonical `<schema>.<name>` key of the view / materialized view owning this
|
|
39
|
+
* body, or `undefined` for the ROOT body the closure started from.
|
|
40
|
+
*/
|
|
41
|
+
ownerKey: string | undefined;
|
|
42
|
+
/**
|
|
43
|
+
* The stored bodies traversed from the root to this one INCLUSIVE, root-first,
|
|
44
|
+
* each described for an error message: `view 'v'`, `materialized view 'm'`.
|
|
45
|
+
* Empty for the root body itself, which is what tells a caller its match is
|
|
46
|
+
* direct and needs no "reaches it through …" clause.
|
|
47
|
+
*/
|
|
48
|
+
path: ReadonlyArray<string>;
|
|
49
|
+
/** The AST to walk — an assertion/CHECK expression at the root, a view body below it. */
|
|
50
|
+
body: AST.AstNode;
|
|
51
|
+
/** Planner-parity resolver for THIS body's home schema. */
|
|
52
|
+
resolve: ResolveObjectRef;
|
|
53
|
+
}
|
|
54
|
+
/** What {@link reachableObjects} returns: the walked bodies, and who named what. */
|
|
55
|
+
export interface ObjectReach {
|
|
56
|
+
/**
|
|
57
|
+
* The root body followed by every stored body reached from it, breadth-first.
|
|
58
|
+
* A caller asking a question the closure does not answer itself — "does any
|
|
59
|
+
* body in the reach name `t.x`?" — probes these in order.
|
|
60
|
+
*/
|
|
61
|
+
readonly bodies: ReadonlyArray<ReachedBody>;
|
|
62
|
+
/**
|
|
63
|
+
* The body that NAMES `key`, or `undefined` when nothing in the reach does.
|
|
64
|
+
* Breadth-first, so the answer is the shortest chain from the root and its
|
|
65
|
+
* {@link ReachedBody.path} is the shortest path to quote in an error.
|
|
66
|
+
*
|
|
67
|
+
* NOTE: two chains of EQUAL length to the same object tie on queue order,
|
|
68
|
+
* i.e. the order the parent bodies happened to name their children. Harmless
|
|
69
|
+
* while the path is advisory — either chain is a true one, and dropping the
|
|
70
|
+
* rule is the escape hatch for both — but a caller that ever needs a
|
|
71
|
+
* deterministic chain (a stable error-message fixture, say) has to order the
|
|
72
|
+
* candidates itself.
|
|
73
|
+
*/
|
|
74
|
+
namerOf(key: string): ReachedBody | undefined;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Every object reachable from `root` through stored view / materialized-view
|
|
78
|
+
* bodies, plus the bodies traversed to get there.
|
|
79
|
+
*
|
|
80
|
+
* `homeSchemaName` is the root body's OWN schema — the assertion's schema, or
|
|
81
|
+
* the schema of the table carrying the CHECK / DEFAULT — because that is what
|
|
82
|
+
* the root's unqualified names resolve against.
|
|
83
|
+
*
|
|
84
|
+
* `resolvers` is REQUIRED rather than built here, and the reason is snapshot
|
|
85
|
+
* discipline (see {@link import('./object-ref-resolver.js').snapshotObjectRefResolvers}):
|
|
86
|
+
* a caller looping over many roots must share ONE pre-mutation snapshot, and a
|
|
87
|
+
* default would silently give each root its own.
|
|
88
|
+
*
|
|
89
|
+
* Termination is a visited set of object keys, so a mutually-referencing or
|
|
90
|
+
* otherwise malformed catalog is walked once per object rather than forever. A
|
|
91
|
+
* body naming an object that does not exist is not an error: the resolver's
|
|
92
|
+
* miss→home fallback keys it stably and the expansion below simply finds
|
|
93
|
+
* nothing to expand.
|
|
94
|
+
*
|
|
95
|
+
* `rootOpts` applies to the ROOT body's collection ONLY, never to a body
|
|
96
|
+
* reached below it. Every reached body is a view / materialized-view body — a
|
|
97
|
+
* relation, with no written-row context — so
|
|
98
|
+
* {@link import('./rename/table-rename.js').TableRenameOpts.rowImageContext}
|
|
99
|
+
* would be wrong there. It is REQUIRED at a root that is a table's CHECK
|
|
100
|
+
* constraint or column DEFAULT / generated body, where a bare `new.a` names the
|
|
101
|
+
* row image: rooted there without the flag, a table literally called `new`
|
|
102
|
+
* would land in the reach and false-refuse its own drop
|
|
103
|
+
* (`schema/expression-dependents.ts` passes it for exactly that reason). The
|
|
104
|
+
* assertion guards pass nothing: an assertion CHECK owns no `new.` / `old.`
|
|
105
|
+
* namespace either.
|
|
106
|
+
*
|
|
107
|
+
* Root-only stays correct even though a reached body CAN carry a bare unbound
|
|
108
|
+
* `new.` qualifier — a `with inverse` / `with defaults` expression holds one
|
|
109
|
+
* legitimately (`CREATE VIEW` accepts it there; the refs name the enclosing
|
|
110
|
+
* select's output row) — because the walker suppresses those SUBTREES itself,
|
|
111
|
+
* unconditionally, wherever the walk entered (`rename/table-rename.ts`,
|
|
112
|
+
* `visitRowImageSubtree`). The suppression travels with the position, not with
|
|
113
|
+
* this flag, so a reached view body self-suppresses and leaking `rootOpts`
|
|
114
|
+
* downward would change no answer. Pinned by
|
|
115
|
+
* `test/logic/41.10.4-drop-object-expression-dependents.sqllogic` (drop of a
|
|
116
|
+
* table named `new` reached through a `with inverse` view).
|
|
117
|
+
*/
|
|
118
|
+
export declare function reachableObjects(db: Database, root: AST.AstNode, homeSchemaName: string, resolvers: ObjectRefResolvers, rootOpts?: TableRenameOpts): ObjectReach;
|
|
119
|
+
/**
|
|
120
|
+
* The `reaches it through view 'v2' -> view 'v1'` clause for a
|
|
121
|
+
* {@link ReachedBody.path}, or the empty string when the match is direct.
|
|
122
|
+
* Shared so every guard consuming the closure phrases an indirect refusal the
|
|
123
|
+
* same way — a user told to fix a rule whose body does not mention the dropped
|
|
124
|
+
* object needs the chain, or the message is unactionable.
|
|
125
|
+
*/
|
|
126
|
+
export declare function describeReachPath(path: ReadonlyArray<string>): string;
|
|
127
|
+
//# sourceMappingURL=object-dependency-closure.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"object-dependency-closure.d.ts","sourceRoot":"","sources":["../../../src/schema/object-dependency-closure.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,GAAG,MAAM,kBAAkB,CAAC;AAC7C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAA6C,KAAK,gBAAgB,EAAE,KAAK,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC9H,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAGnE;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH;;;;;;GAMG;AACH,MAAM,WAAW,WAAW;IAC3B;;;OAGG;IACH,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B;;;;;OAKG;IACH,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAC5B,yFAAyF;IACzF,IAAI,EAAE,GAAG,CAAC,OAAO,CAAC;IAClB,2DAA2D;IAC3D,OAAO,EAAE,gBAAgB,CAAC;CAC1B;AAED,oFAAoF;AACpF,MAAM,WAAW,WAAW;IAC3B;;;;OAIG;IACH,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,WAAW,CAAC,CAAC;IAC5C;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAAC;CAC9C;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,wBAAgB,gBAAgB,CAC/B,EAAE,EAAE,QAAQ,EACZ,IAAI,EAAE,GAAG,CAAC,OAAO,EACjB,cAAc,EAAE,MAAM,EACtB,SAAS,EAAE,kBAAkB,EAC7B,QAAQ,CAAC,EAAE,eAAe,GACxB,WAAW,CA+Bb;AAgDD;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,MAAM,CAErE"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { collectTableRefsInAst, objectRefKeySchema } from './rename-rewriter.js';
|
|
2
|
+
import { isMaintainedTable } from './derivation.js';
|
|
3
|
+
/**
|
|
4
|
+
* Every object reachable from `root` through stored view / materialized-view
|
|
5
|
+
* bodies, plus the bodies traversed to get there.
|
|
6
|
+
*
|
|
7
|
+
* `homeSchemaName` is the root body's OWN schema — the assertion's schema, or
|
|
8
|
+
* the schema of the table carrying the CHECK / DEFAULT — because that is what
|
|
9
|
+
* the root's unqualified names resolve against.
|
|
10
|
+
*
|
|
11
|
+
* `resolvers` is REQUIRED rather than built here, and the reason is snapshot
|
|
12
|
+
* discipline (see {@link import('./object-ref-resolver.js').snapshotObjectRefResolvers}):
|
|
13
|
+
* a caller looping over many roots must share ONE pre-mutation snapshot, and a
|
|
14
|
+
* default would silently give each root its own.
|
|
15
|
+
*
|
|
16
|
+
* Termination is a visited set of object keys, so a mutually-referencing or
|
|
17
|
+
* otherwise malformed catalog is walked once per object rather than forever. A
|
|
18
|
+
* body naming an object that does not exist is not an error: the resolver's
|
|
19
|
+
* miss→home fallback keys it stably and the expansion below simply finds
|
|
20
|
+
* nothing to expand.
|
|
21
|
+
*
|
|
22
|
+
* `rootOpts` applies to the ROOT body's collection ONLY, never to a body
|
|
23
|
+
* reached below it. Every reached body is a view / materialized-view body — a
|
|
24
|
+
* relation, with no written-row context — so
|
|
25
|
+
* {@link import('./rename/table-rename.js').TableRenameOpts.rowImageContext}
|
|
26
|
+
* would be wrong there. It is REQUIRED at a root that is a table's CHECK
|
|
27
|
+
* constraint or column DEFAULT / generated body, where a bare `new.a` names the
|
|
28
|
+
* row image: rooted there without the flag, a table literally called `new`
|
|
29
|
+
* would land in the reach and false-refuse its own drop
|
|
30
|
+
* (`schema/expression-dependents.ts` passes it for exactly that reason). The
|
|
31
|
+
* assertion guards pass nothing: an assertion CHECK owns no `new.` / `old.`
|
|
32
|
+
* namespace either.
|
|
33
|
+
*
|
|
34
|
+
* Root-only stays correct even though a reached body CAN carry a bare unbound
|
|
35
|
+
* `new.` qualifier — a `with inverse` / `with defaults` expression holds one
|
|
36
|
+
* legitimately (`CREATE VIEW` accepts it there; the refs name the enclosing
|
|
37
|
+
* select's output row) — because the walker suppresses those SUBTREES itself,
|
|
38
|
+
* unconditionally, wherever the walk entered (`rename/table-rename.ts`,
|
|
39
|
+
* `visitRowImageSubtree`). The suppression travels with the position, not with
|
|
40
|
+
* this flag, so a reached view body self-suppresses and leaking `rootOpts`
|
|
41
|
+
* downward would change no answer. Pinned by
|
|
42
|
+
* `test/logic/41.10.4-drop-object-expression-dependents.sqllogic` (drop of a
|
|
43
|
+
* table named `new` reached through a `with inverse` view).
|
|
44
|
+
*/
|
|
45
|
+
export function reachableObjects(db, root, homeSchemaName, resolvers, rootOpts) {
|
|
46
|
+
const bodies = [];
|
|
47
|
+
const namer = new Map();
|
|
48
|
+
/** Object keys already expanded (or found not to be a stored body). */
|
|
49
|
+
const visited = new Set();
|
|
50
|
+
const queue = [{
|
|
51
|
+
ownerKey: undefined,
|
|
52
|
+
path: [],
|
|
53
|
+
body: root,
|
|
54
|
+
resolve: resolvers.forHomeSchema(homeSchemaName),
|
|
55
|
+
}];
|
|
56
|
+
// Breadth-first: `namer` and `path` then carry the SHORTEST chain to each
|
|
57
|
+
// object, which is the one an error message should quote.
|
|
58
|
+
for (let head = 0; head < queue.length; head++) {
|
|
59
|
+
const current = queue[head];
|
|
60
|
+
bodies.push(current);
|
|
61
|
+
// `ownerKey === undefined` identifies the ROOT uniquely — every body reached
|
|
62
|
+
// below it gets one from `childBody`.
|
|
63
|
+
const opts = current.ownerKey === undefined ? rootOpts : undefined;
|
|
64
|
+
for (const [key, nameLower] of collectTableRefsInAst(current.body, current.resolve, opts)) {
|
|
65
|
+
if (!namer.has(key))
|
|
66
|
+
namer.set(key, current);
|
|
67
|
+
if (visited.has(key))
|
|
68
|
+
continue;
|
|
69
|
+
visited.add(key);
|
|
70
|
+
const child = expandStoredBody(db, key, nameLower, resolvers, current);
|
|
71
|
+
if (child)
|
|
72
|
+
queue.push(child);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return { bodies, namerOf: key => namer.get(key) };
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* The stored body of the object `key` names, as a child of `parent` — or
|
|
79
|
+
* `undefined` when the key names something with no body to follow: a base table,
|
|
80
|
+
* or nothing at all.
|
|
81
|
+
*
|
|
82
|
+
* A materialized view is looked up as a TABLE (one `TableSchema`, one catalog
|
|
83
|
+
* name) and its body hangs off `derivation.selectAst`; see `schema/derivation.ts`.
|
|
84
|
+
*/
|
|
85
|
+
function expandStoredBody(db, key, nameLower, resolvers, parent) {
|
|
86
|
+
const schema = db.schemaManager.getSchema(objectRefKeySchema(key, nameLower));
|
|
87
|
+
if (!schema)
|
|
88
|
+
return undefined;
|
|
89
|
+
const view = schema.getView(nameLower);
|
|
90
|
+
if (view)
|
|
91
|
+
return childBody(key, `view '${view.name}'`, view.selectAst, view.schemaName, resolvers, parent);
|
|
92
|
+
const table = schema.getTable(nameLower);
|
|
93
|
+
if (isMaintainedTable(table)) {
|
|
94
|
+
return childBody(key, `materialized view '${table.name}'`, table.derivation.selectAst, table.schemaName, resolvers, parent);
|
|
95
|
+
}
|
|
96
|
+
return undefined;
|
|
97
|
+
}
|
|
98
|
+
/** A reached stored body, with the parent's path extended by its own description. */
|
|
99
|
+
function childBody(ownerKey, describe, body, ownerSchemaName, resolvers, parent) {
|
|
100
|
+
return {
|
|
101
|
+
ownerKey,
|
|
102
|
+
path: [...parent.path, describe],
|
|
103
|
+
body,
|
|
104
|
+
resolve: resolvers.forHomeSchema(ownerSchemaName),
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* The `reaches it through view 'v2' -> view 'v1'` clause for a
|
|
109
|
+
* {@link ReachedBody.path}, or the empty string when the match is direct.
|
|
110
|
+
* Shared so every guard consuming the closure phrases an indirect refusal the
|
|
111
|
+
* same way — a user told to fix a rule whose body does not mention the dropped
|
|
112
|
+
* object needs the chain, or the message is unactionable.
|
|
113
|
+
*/
|
|
114
|
+
export function describeReachPath(path) {
|
|
115
|
+
return path.length === 0 ? '' : ` through ${path.join(' -> ')}`;
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=object-dependency-closure.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"object-dependency-closure.js","sourceRoot":"","sources":["../../../src/schema/object-dependency-closure.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { Database } from '../core/database.js';
|
|
2
|
+
import { type ResolveObjectRef, type TableRenameTarget } from './rename-rewriter.js';
|
|
3
|
+
/**
|
|
4
|
+
* Per-home-schema {@link ResolveObjectRef} factory over ONE catalog snapshot.
|
|
5
|
+
* The rename propagation walks dependents living in many schemas, and each
|
|
6
|
+
* dependent's unqualified names resolve under ITS OWN home schema path — so
|
|
7
|
+
* one statement needs one snapshot and many resolvers derived from it.
|
|
8
|
+
*/
|
|
9
|
+
export interface ObjectRefResolvers {
|
|
10
|
+
/** Resolver for a stored body owned by `homeSchemaName`. Cached per home schema. */
|
|
11
|
+
forHomeSchema(homeSchemaName: string): ResolveObjectRef;
|
|
12
|
+
/**
|
|
13
|
+
* A sibling snapshot with one table rename applied — the catalog as it will
|
|
14
|
+
* look AFTER the statement. Used only to check the rename post-condition
|
|
15
|
+
* ({@link import('./rename/table-rename.js').renameTableInAst}: a rewritten
|
|
16
|
+
* reference must still resolve to the renamed object). Derived from this
|
|
17
|
+
* snapshot's name sets, never the live catalog, so the SNAPSHOT DISCIPLINE
|
|
18
|
+
* below holds for both.
|
|
19
|
+
*/
|
|
20
|
+
withTableRenamed(schemaName: string, oldName: string, newName: string): ObjectRefResolvers;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* The catalog-backed {@link ResolveObjectRef} the rename walkers consult to decide
|
|
24
|
+
* whether a table/view reference written in a stored body denotes the object being
|
|
25
|
+
* renamed / probed. It answers the way the PLANNER answers for that body — against
|
|
26
|
+
* the owning object's home schema path ({@link Database._homeSchemaPath}:
|
|
27
|
+
* `[homeSchema, ...session default path]`) — not against a single "default schema".
|
|
28
|
+
*
|
|
29
|
+
* Resolution rules:
|
|
30
|
+
* - **Qualified** (`schema` present) → `objectRefKey(schema, name)`, no catalog
|
|
31
|
+
* lookup. A qualified name means what it says even when the object does not
|
|
32
|
+
* exist (it may be the one about to be created, or the one just renamed away).
|
|
33
|
+
* - **Unqualified** → the first schema in the home path holding a table or view
|
|
34
|
+
* (a materialized view is a table) of that name.
|
|
35
|
+
* - **Miss in every schema** → the home schema's key, so a body naming an object
|
|
36
|
+
* that does not exist still gets a stable key rather than `undefined` —
|
|
37
|
+
* `undefined` is reserved for "no resolver could be consulted at all".
|
|
38
|
+
*
|
|
39
|
+
* NOTE: "the way the planner answers" is exact for the body kinds that plan under
|
|
40
|
+
* {@link Database._homeSchemaPath} — view bodies, materialized-view bodies, and
|
|
41
|
+
* assertion checks (`planner/stored-body-context.ts`). A CHECK constraint or a
|
|
42
|
+
* column DEFAULT / generated expression is stricter still: it plans under
|
|
43
|
+
* `schemaAuthoredContext` (`planner/building/schema-authored-context.ts`), the
|
|
44
|
+
* owning schema and NOTHING else, so an unqualified name the owning schema does
|
|
45
|
+
* not hold is an error there rather than a fallthrough down the session path.
|
|
46
|
+
* This resolver applies the looser home-path rule to all of them, which is
|
|
47
|
+
* deliberately safe rather than exact: the two rules can only disagree when the
|
|
48
|
+
* home schema lacks the name, and such a CHECK / DEFAULT cannot be evaluated at
|
|
49
|
+
* all — so no VALID body is ever matched (or missed) differently. Tighten to a
|
|
50
|
+
* per-body-kind path only if a rename ever needs to be right about a body the
|
|
51
|
+
* planner itself rejects.
|
|
52
|
+
*
|
|
53
|
+
* SNAPSHOT DISCIPLINE — the single most likely way to get this wrong: build the
|
|
54
|
+
* snapshot (`snapshotObjectRefResolvers` / `buildObjectRefResolver`) BEFORE the
|
|
55
|
+
* statement's first catalog mutation, and pass the same instance through the whole
|
|
56
|
+
* statement. Name-set lookups answer from the snapshot, NOT the live catalog, and
|
|
57
|
+
* that is load-bearing: rename propagation runs after the catalog swap, when the
|
|
58
|
+
* old name is gone — a live lookup of a bare `t` under `[main, temp]` after
|
|
59
|
+
* `main.t` was renamed would fall through to `temp.t` and silently match (or miss)
|
|
60
|
+
* the wrong object. The pre-mutation snapshot resolves every reference the way the
|
|
61
|
+
* body planned before the statement started, which is the question the rename is
|
|
62
|
+
* asking. (The session `schema_path` option is read at resolver-derivation time;
|
|
63
|
+
* it cannot change mid-statement.)
|
|
64
|
+
*/
|
|
65
|
+
export declare function snapshotObjectRefResolvers(db: Database): ObjectRefResolvers;
|
|
66
|
+
/**
|
|
67
|
+
* Per-home-schema {@link TableRenameTarget} factory for one `ALTER TABLE … RENAME TO`
|
|
68
|
+
* statement: binds the renamed object's identity to a pre-mutation `resolve` and a
|
|
69
|
+
* post-rename `resolveAfter` (the {@link ObjectRefResolvers.withTableRenamed} sibling),
|
|
70
|
+
* both derived per body-owning home schema. One statement builds this once and hands
|
|
71
|
+
* every walk the target for the walked body's owner, which is what lets the rewrite
|
|
72
|
+
* enforce its post-condition — a rewritten reference must still resolve to the renamed
|
|
73
|
+
* object — at the sink.
|
|
74
|
+
*/
|
|
75
|
+
export declare function tableRenameTargetsFor(resolvers: ObjectRefResolvers, schemaName: string, oldName: string, newName: string): (homeSchemaName: string) => TableRenameTarget;
|
|
76
|
+
/**
|
|
77
|
+
* Single-home convenience over {@link snapshotObjectRefResolvers}, for callers
|
|
78
|
+
* that walk bodies of one owning schema only (the DROP guards, a store module's
|
|
79
|
+
* own-table rewrite). Same snapshot discipline: build before the statement's
|
|
80
|
+
* first catalog mutation.
|
|
81
|
+
*/
|
|
82
|
+
export declare function buildObjectRefResolver(db: Database, homeSchemaName: string): ResolveObjectRef;
|
|
83
|
+
//# sourceMappingURL=object-ref-resolver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"object-ref-resolver.d.ts","sourceRoot":"","sources":["../../../src/schema/object-ref-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAgB,KAAK,gBAAgB,EAAE,KAAK,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAEnG;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IAClC,oFAAoF;IACpF,aAAa,CAAC,cAAc,EAAE,MAAM,GAAG,gBAAgB,CAAC;IACxD;;;;;;;OAOG;IACH,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,kBAAkB,CAAC;CAC3F;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AACH,wBAAgB,0BAA0B,CAAC,EAAE,EAAE,QAAQ,GAAG,kBAAkB,CAa3E;AAqCD;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CACpC,SAAS,EAAE,kBAAkB,EAC7B,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,GACb,CAAC,cAAc,EAAE,MAAM,KAAK,iBAAiB,CAiB/C;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,EAAE,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,GAAG,gBAAgB,CAE7F"}
|