@quereus/store 4.5.0 → 4.7.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/README.md +34 -6
- package/dist/src/common/encoding.d.ts +4 -3
- package/dist/src/common/encoding.d.ts.map +1 -1
- package/dist/src/common/encoding.js +17 -13
- package/dist/src/common/encoding.js.map +1 -1
- package/dist/src/common/events.d.ts +31 -25
- package/dist/src/common/events.d.ts.map +1 -1
- package/dist/src/common/events.js +38 -39
- package/dist/src/common/events.js.map +1 -1
- package/dist/src/common/implicit-unique-index.d.ts +80 -0
- package/dist/src/common/implicit-unique-index.d.ts.map +1 -0
- package/dist/src/common/implicit-unique-index.js +148 -0
- package/dist/src/common/implicit-unique-index.js.map +1 -0
- package/dist/src/common/index.d.ts +7 -3
- package/dist/src/common/index.d.ts.map +1 -1
- package/dist/src/common/index.js +5 -2
- package/dist/src/common/index.js.map +1 -1
- package/dist/src/common/json-key.d.ts +30 -2
- package/dist/src/common/json-key.d.ts.map +1 -1
- package/dist/src/common/json-key.js +49 -2
- package/dist/src/common/json-key.js.map +1 -1
- package/dist/src/common/key-builder.d.ts +40 -20
- package/dist/src/common/key-builder.d.ts.map +1 -1
- package/dist/src/common/key-builder.js +31 -23
- package/dist/src/common/key-builder.js.map +1 -1
- package/dist/src/common/kv-store.d.ts +10 -0
- package/dist/src/common/kv-store.d.ts.map +1 -1
- package/dist/src/common/pk-key-resolution.d.ts +348 -0
- package/dist/src/common/pk-key-resolution.d.ts.map +1 -0
- package/dist/src/common/pk-key-resolution.js +481 -0
- package/dist/src/common/pk-key-resolution.js.map +1 -0
- package/dist/src/common/store-module-access-plan.d.ts +32 -0
- package/dist/src/common/store-module-access-plan.d.ts.map +1 -0
- package/dist/src/common/store-module-access-plan.js +428 -0
- package/dist/src/common/store-module-access-plan.js.map +1 -0
- package/dist/src/common/store-module-alter-column.d.ts +23 -0
- package/dist/src/common/store-module-alter-column.d.ts.map +1 -0
- package/dist/src/common/store-module-alter-column.js +389 -0
- package/dist/src/common/store-module-alter-column.js.map +1 -0
- package/dist/src/common/store-module-alter.d.ts +55 -0
- package/dist/src/common/store-module-alter.d.ts.map +1 -0
- package/dist/src/common/store-module-alter.js +504 -0
- package/dist/src/common/store-module-alter.js.map +1 -0
- package/dist/src/common/store-module-base.d.ts +268 -0
- package/dist/src/common/store-module-base.d.ts.map +1 -0
- package/dist/src/common/store-module-base.js +362 -0
- package/dist/src/common/store-module-base.js.map +1 -0
- package/dist/src/common/store-module-catalog.d.ts +269 -0
- package/dist/src/common/store-module-catalog.d.ts.map +1 -0
- package/dist/src/common/store-module-catalog.js +462 -0
- package/dist/src/common/store-module-catalog.js.map +1 -0
- package/dist/src/common/store-module-index-build.d.ts +88 -0
- package/dist/src/common/store-module-index-build.d.ts.map +1 -0
- package/dist/src/common/store-module-index-build.js +280 -0
- package/dist/src/common/store-module-index-build.js.map +1 -0
- package/dist/src/common/store-module-index.d.ts +116 -0
- package/dist/src/common/store-module-index.d.ts.map +1 -0
- package/dist/src/common/store-module-index.js +373 -0
- package/dist/src/common/store-module-index.js.map +1 -0
- package/dist/src/common/store-module-rename.d.ts +49 -0
- package/dist/src/common/store-module-rename.d.ts.map +1 -0
- package/dist/src/common/store-module-rename.js +268 -0
- package/dist/src/common/store-module-rename.js.map +1 -0
- package/dist/src/common/store-module-schema-rewrite.d.ts +57 -0
- package/dist/src/common/store-module-schema-rewrite.d.ts.map +1 -0
- package/dist/src/common/store-module-schema-rewrite.js +140 -0
- package/dist/src/common/store-module-schema-rewrite.js.map +1 -0
- package/dist/src/common/store-module-schema-sync.d.ts +232 -0
- package/dist/src/common/store-module-schema-sync.d.ts.map +1 -0
- package/dist/src/common/store-module-schema-sync.js +529 -0
- package/dist/src/common/store-module-schema-sync.js.map +1 -0
- package/dist/src/common/store-module.d.ts +43 -909
- package/dist/src/common/store-module.d.ts.map +1 -1
- package/dist/src/common/store-module.js +184 -3276
- package/dist/src/common/store-module.js.map +1 -1
- package/dist/src/common/store-table-base.d.ts +539 -0
- package/dist/src/common/store-table-base.d.ts.map +1 -0
- package/dist/src/common/store-table-base.js +900 -0
- package/dist/src/common/store-table-base.js.map +1 -0
- package/dist/src/common/store-table-constraints.d.ts +237 -0
- package/dist/src/common/store-table-constraints.d.ts.map +1 -0
- package/dist/src/common/store-table-constraints.js +624 -0
- package/dist/src/common/store-table-constraints.js.map +1 -0
- package/dist/src/common/store-table-scan.d.ts +452 -0
- package/dist/src/common/store-table-scan.d.ts.map +1 -0
- package/dist/src/common/store-table-scan.js +901 -0
- package/dist/src/common/store-table-scan.js.map +1 -0
- package/dist/src/common/store-table.d.ts +71 -1144
- package/dist/src/common/store-table.d.ts.map +1 -1
- package/dist/src/common/store-table.js +168 -2385
- package/dist/src/common/store-table.js.map +1 -1
- package/dist/src/testing/index.d.ts +12 -0
- package/dist/src/testing/index.d.ts.map +1 -0
- package/dist/src/testing/index.js +12 -0
- package/dist/src/testing/index.js.map +1 -0
- package/dist/src/testing/kv-assert.d.ts +19 -0
- package/dist/src/testing/kv-assert.d.ts.map +1 -0
- package/dist/src/testing/kv-assert.js +25 -0
- package/dist/src/testing/kv-assert.js.map +1 -0
- package/dist/src/testing/kv-conformance.d.ts.map +1 -1
- package/dist/src/testing/kv-conformance.js +1 -15
- package/dist/src/testing/kv-conformance.js.map +1 -1
- package/dist/src/testing/kv-provider-conformance.d.ts +54 -0
- package/dist/src/testing/kv-provider-conformance.d.ts.map +1 -0
- package/dist/src/testing/kv-provider-conformance.js +183 -0
- package/dist/src/testing/kv-provider-conformance.js.map +1 -0
- package/package.json +8 -8
|
@@ -11,57 +11,30 @@
|
|
|
11
11
|
* - Index stores: {schema}.{table}_idx_{name} - one per secondary index
|
|
12
12
|
* - {prefix}.__stats__ - Unified stats store (row counts for all tables)
|
|
13
13
|
* - Catalog store: __catalog__ - DDL metadata keyed by {schema}.{table}
|
|
14
|
-
*/
|
|
15
|
-
import type { Database, TableSchema, TableIndexSchema, VirtualTableModule, BaseModuleConfig, BestAccessPlanRequest, BestAccessPlanResult, ModuleCapabilities, SchemaChangeInfo, Schema, MappingAdvertisement, ViewSchema, MaintainedTableSchema, BackingHost, LensDeploymentSnapshot, CatalogObjectKind } from '@quereus/quereus';
|
|
16
|
-
import type { EffectiveRowSource } from '@quereus/quereus';
|
|
17
|
-
import type { KVStore, KVStoreProvider } from './kv-store.js';
|
|
18
|
-
import type { StoreEventEmitter } from './events.js';
|
|
19
|
-
import { TransactionCoordinator } from './transaction.js';
|
|
20
|
-
import { StoreTable, type StoreTableConfig, type StoreTableModule } from './store-table.js';
|
|
21
|
-
/**
|
|
22
|
-
* Result of catalog rehydration.
|
|
23
14
|
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
*
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Listener the host binds via {@link StoreModule.setLensDeploymentListener} to
|
|
43
|
-
* forward a logical `apply schema` lens deployment onward (typically to the sync
|
|
44
|
-
* layer's basis-table lifecycle bookkeeping). Kept as a plain callback so
|
|
45
|
-
* `@quereus/store` stays free of a `@quereus/sync` dependency; the worker — which
|
|
46
|
-
* depends on both — wires the two together.
|
|
47
|
-
*/
|
|
48
|
-
export type LensDeploymentListener = (db: Database, logicalSchemaName: string, snapshot: LensDeploymentSnapshot) => void | Promise<void>;
|
|
49
|
-
/**
|
|
50
|
-
* Configuration options for StoreModule tables.
|
|
15
|
+
* The class is layered across eight files, each adding one job to the one below:
|
|
16
|
+
* `store-module-base.ts` - module state, store handles, coordinator, name collisions
|
|
17
|
+
* `store-module-catalog.ts` - the catalog store: DDL entries, shutdown marker, stale-MV set
|
|
18
|
+
* `store-module-schema-sync.ts` - rehydration, lazy reconnect, engine schema-change subscription
|
|
19
|
+
* `store-module-index.ts` - CREATE / DROP INDEX and the implicit `_uc_*` store reconcile
|
|
20
|
+
* `store-module-alter-column.ts` - ALTER TABLE ... ALTER COLUMN
|
|
21
|
+
* `store-module-alter.ts` - ALTER TABLE dispatch and every other arm
|
|
22
|
+
* `store-module-rename.ts` - ALTER TABLE ... RENAME TO (two-phase)
|
|
23
|
+
* `store-module.ts` - this file: module lifecycle, capabilities, backing host
|
|
24
|
+
*
|
|
25
|
+
* Three groups read no module state and are free functions instead of layers:
|
|
26
|
+
* `store-module-access-plan.ts` - which access path this module advertises
|
|
27
|
+
* `store-module-index-build.ts` - index population + UNIQUE validation over a row stream
|
|
28
|
+
* `store-module-schema-rewrite.ts` - pure schema-to-schema rewrites around DDL
|
|
29
|
+
*
|
|
30
|
+
* A layer may call downward, never upward. Nothing enforces that explicitly — it holds
|
|
31
|
+
* because a base class cannot name a subclass member, so an upward call fails to compile.
|
|
51
32
|
*/
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
* {@link StoreModule.buildIndexEntries}). Set from the `max_batch_bytes`
|
|
58
|
-
* module arg; a missing / non-positive value falls back to
|
|
59
|
-
* {@link DEFAULT_MAX_BATCH_BYTES}. Module-wide, not per-index.
|
|
60
|
-
*/
|
|
61
|
-
maxBatchBytes?: number;
|
|
62
|
-
/** Additional platform-specific options. */
|
|
63
|
-
[key: string]: unknown;
|
|
64
|
-
}
|
|
33
|
+
import type { BackingHost, BestAccessPlanRequest, BestAccessPlanResult, Database, LensDeploymentSnapshot, MappingAdvertisement, ModuleCapabilities, Schema, TableSchema, VirtualTableModule } from '@quereus/quereus';
|
|
34
|
+
import { StoreTable } from './store-table.js';
|
|
35
|
+
import type { StoreTableModule } from './store-table-base.js';
|
|
36
|
+
import { StoreModuleRename } from './store-module-rename.js';
|
|
37
|
+
import type { LensDeploymentListener, StoreModuleConfig } from './store-module-base.js';
|
|
65
38
|
/**
|
|
66
39
|
* Generic store module that works with any KVStoreProvider.
|
|
67
40
|
*
|
|
@@ -75,62 +48,7 @@ export interface StoreModuleConfig extends BaseModuleConfig {
|
|
|
75
48
|
* db.registerModule('store', module);
|
|
76
49
|
* ```
|
|
77
50
|
*/
|
|
78
|
-
export declare class StoreModule implements VirtualTableModule<StoreTable, StoreModuleConfig>, StoreTableModule {
|
|
79
|
-
private provider;
|
|
80
|
-
private stores;
|
|
81
|
-
/**
|
|
82
|
-
* The single transaction coordinator shared by every {@link StoreTable} this
|
|
83
|
-
* module owns — the unit of cross-table atomicity (see {@link getCoordinator}).
|
|
84
|
-
* Lives for the module's lifetime: a single table's drop must NOT evict it
|
|
85
|
-
* (sibling tables still use it); only {@link closeAll} clears it.
|
|
86
|
-
*/
|
|
87
|
-
private moduleCoordinator?;
|
|
88
|
-
private tables;
|
|
89
|
-
private eventEmitter?;
|
|
90
|
-
/**
|
|
91
|
-
* Optional listener wired by the host (the worker) to forward a logical
|
|
92
|
-
* `apply schema` lens deployment to the sync layer's lifecycle bookkeeping.
|
|
93
|
-
* The store module is the only basis-backing host with both persistence and a
|
|
94
|
-
* `db` handle, so it is the forwarder; `@quereus/store` must not depend on
|
|
95
|
-
* `@quereus/sync`, so the listener is a plain callback the worker binds.
|
|
96
|
-
*/
|
|
97
|
-
private lensDeploymentListener?;
|
|
98
|
-
/** Unsubscribe thunk for the engine `SchemaChangeNotifier` listener, set on first hook with a `db`. */
|
|
99
|
-
private schemaListenerUnsub?;
|
|
100
|
-
/** The `Database` whose notifier we subscribed to. One module instance serves one `Database`. */
|
|
101
|
-
private subscribedDb?;
|
|
102
|
-
/**
|
|
103
|
-
* Serialized chain of pending catalog writes triggered by engine schema-change
|
|
104
|
-
* events (catalog-only tag swaps). `notifyChange` invokes listeners synchronously
|
|
105
|
-
* and does not await them, so the actual read-compare-write runs here, in order,
|
|
106
|
-
* and is drained by `closeAll` (and `whenCatalogPersisted`) before the provider closes.
|
|
107
|
-
*/
|
|
108
|
-
private persistQueue;
|
|
109
|
-
/**
|
|
110
|
-
* The JSON-serialized stale-MV set last enqueued onto {@link persistQueue} (the
|
|
111
|
-
* `\x00meta\x00stale_mvs` value), or `undefined` when no baseline is established
|
|
112
|
-
* for the current subscription. The schema-change listener compares each
|
|
113
|
-
* recomputed set against this so an unrelated `table_modified` (e.g. a tag swap
|
|
114
|
-
* that changes no MV's staleness) costs no extra fsync. Reset to `undefined`
|
|
115
|
-
* whenever a fresh `Database` is subscribed ({@link ensureSchemaSubscription}) so
|
|
116
|
-
* a reopened module re-establishes the baseline from the first relevant event (or
|
|
117
|
-
* the rehydrate tail).
|
|
118
|
-
*/
|
|
119
|
-
private lastPersistedStaleMvs;
|
|
120
|
-
/**
|
|
121
|
-
* Whether the provider exposes an atomic cross-store commit domain
|
|
122
|
-
* ({@link KVStoreProvider.beginAtomicBatch}) — the capability the MV adopt fast
|
|
123
|
-
* path's gate-5 drop hinges on. Fixed for the provider's lifetime, so cached at
|
|
124
|
-
* construction (and used as the single gate for both writing AND reading the durable
|
|
125
|
-
* stale-MV set). Gating the **write** on it is load-bearing for soundness, not just an
|
|
126
|
-
* fsync saving: only an atomic-capable session — whose commits can never tear a source
|
|
127
|
-
* from its same-module backing — ever writes the durable set, so the set a later atomic
|
|
128
|
-
* session reads was necessarily written under that same no-tear guarantee. A persistent
|
|
129
|
-
* non-atomic provider therefore can never leave a torn-but-"not-stale" set for an atomic
|
|
130
|
-
* reopen to trust (it writes none); such a store falls back to the clean-shutdown marker.
|
|
131
|
-
*/
|
|
132
|
-
private readonly atomicProvider;
|
|
133
|
-
constructor(provider: KVStoreProvider, eventEmitter?: StoreEventEmitter);
|
|
51
|
+
export declare class StoreModule extends StoreModuleRename implements VirtualTableModule<StoreTable, StoreModuleConfig>, StoreTableModule {
|
|
134
52
|
/**
|
|
135
53
|
* Returns capability flags for this module.
|
|
136
54
|
*
|
|
@@ -169,7 +87,7 @@ export declare class StoreModule implements VirtualTableModule<StoreTable, Store
|
|
|
169
87
|
* pair — `destroy` evicts both maps, so a drop+recreate yields fresh instances
|
|
170
88
|
* and the returned host is pinned to one backing-table incarnation (the engine
|
|
171
89
|
* resolves hosts fresh per call, never caching them). Resolution goes through
|
|
172
|
-
*
|
|
90
|
+
* `StoreModuleSchemaSync.getOrReconnectTable` so a rehydrated-but-untouched (or rename-evicted)
|
|
173
91
|
* backing still resolves; the ownership pre-check keeps the reconnect fallback
|
|
174
92
|
* from adopting a registered table owned by a different module (`vtabModule`
|
|
175
93
|
* must be this StoreModule, or a wrapper — IsolationModule — exposing it as
|
|
@@ -181,7 +99,7 @@ export declare class StoreModule implements VirtualTableModule<StoreTable, Store
|
|
|
181
99
|
/**
|
|
182
100
|
* Resolve a {@link StoreTable} this module owns, reconnecting a
|
|
183
101
|
* rehydrated-but-untouched (or rename-evicted) table via
|
|
184
|
-
*
|
|
102
|
+
* `StoreModuleSchemaSync.getOrReconnectTable`. The ownership pre-check keeps the reconnect
|
|
185
103
|
* fallback from adopting a registered table owned by a DIFFERENT module:
|
|
186
104
|
* `vtabModule` must be this StoreModule, or a wrapper (IsolationModule)
|
|
187
105
|
* exposing it as `underlying`. Returns undefined for an unknown/non-owned
|
|
@@ -203,16 +121,27 @@ export declare class StoreModule implements VirtualTableModule<StoreTable, Store
|
|
|
203
121
|
* pending state on its own (none when the table is freshly reconnected).
|
|
204
122
|
*/
|
|
205
123
|
getTableForExternalWrite(db: Database, schemaName: string, tableName: string): StoreTable | undefined;
|
|
206
|
-
/**
|
|
207
|
-
* Get the event emitter for this module.
|
|
208
|
-
*/
|
|
209
|
-
getEventEmitter(): StoreEventEmitter | undefined;
|
|
210
124
|
/**
|
|
211
125
|
* Bind (or clear, with `undefined`) the lens-deployment forwarder. The host
|
|
212
126
|
* (worker) calls this to route a logical `apply schema`'s deployment to the
|
|
213
127
|
* sync layer; see {@link notifyLensDeployment}.
|
|
214
128
|
*/
|
|
215
129
|
setLensDeploymentListener(listener: LensDeploymentListener | undefined): void;
|
|
130
|
+
/**
|
|
131
|
+
* Engine `onRegister` hook: subscribe to the database's schema-change notifier the
|
|
132
|
+
* moment this module is registered, before any statement can run.
|
|
133
|
+
*
|
|
134
|
+
* Views and materialized views never route through a module table hook, so without
|
|
135
|
+
* this the module would only learn its `Database` from the first
|
|
136
|
+
* `create`/`connect`/`alterTable`/`rehydrateCatalog` — and a `create view` issued
|
|
137
|
+
* before that (the first statement of a brand-new database, say) would fire
|
|
138
|
+
* `view_added` at a module that is not listening yet and silently never persist.
|
|
139
|
+
*
|
|
140
|
+
* Idempotent with the lazy call sites; a second `Database` logs
|
|
141
|
+
* `ensureSchemaSubscription`'s "different Database" warning here rather than at first
|
|
142
|
+
* table use (a warning, not a throw — one module instance still serves one Database).
|
|
143
|
+
*/
|
|
144
|
+
onRegister(db: Database, _moduleName: string): void;
|
|
216
145
|
/**
|
|
217
146
|
* Engine `notifyLensDeployment` hook: a logical `apply schema X` fires this on
|
|
218
147
|
* every registered module once the lens catalog mutation + snapshot rotation
|
|
@@ -227,60 +156,6 @@ export declare class StoreModule implements VirtualTableModule<StoreTable, Store
|
|
|
227
156
|
* warning, not a failed deploy.
|
|
228
157
|
*/
|
|
229
158
|
notifyLensDeployment(db: Database, logicalSchemaName: string, snapshot: LensDeploymentSnapshot): Promise<void>;
|
|
230
|
-
/**
|
|
231
|
-
* Get the KVStoreProvider used by this module.
|
|
232
|
-
*/
|
|
233
|
-
getProvider(): KVStoreProvider;
|
|
234
|
-
/**
|
|
235
|
-
* Build the set of physical store names this module's data/index stores
|
|
236
|
-
* currently occupy in `schemaName`, mapping each name to a human description
|
|
237
|
-
* of the logical object that owns it (for sited collision messages).
|
|
238
|
-
*
|
|
239
|
-
* Physical store names are built by string concatenation (`{schema}.{table}` /
|
|
240
|
-
* `{schema}.{table}_idx_{index}`) and the `_idx_` delimiter is itself a legal
|
|
241
|
-
* substring of any identifier, so two distinct logical objects (e.g. index
|
|
242
|
-
* `archive` on `t` and a sibling table `t_idx_archive`) can collapse to the
|
|
243
|
-
* same physical name. This set is the authoritative occupancy used by
|
|
244
|
-
* {@link assertStoreNameFree} to reject such a collision at CREATE time.
|
|
245
|
-
*
|
|
246
|
-
* The occupancy is the union of two sources, robust to lazy connection and the
|
|
247
|
-
* isolation wrapper (see the ticket's "Enumeration source" section):
|
|
248
|
-
* 1. `this.tables` — every store table this module touched this session.
|
|
249
|
-
* 2. the target schema's catalog tables whose `vtabModule === this` and which
|
|
250
|
-
* are not views — store-backed tables not yet lazily connected.
|
|
251
|
-
* Names embed the schema prefix, so cross-schema entries never collide and no
|
|
252
|
-
* per-schema filter on `this.tables` is needed. Memory-backed siblings and
|
|
253
|
-
* views own no store in this provider and are excluded (the `=== this` /
|
|
254
|
-
* `!isView` filter) to avoid false-positive rejects.
|
|
255
|
-
*
|
|
256
|
-
* No self-exclusion: at each guarded call the candidate object is not yet
|
|
257
|
-
* registered (create/createIndex run before the engine adds it) so it cannot
|
|
258
|
-
* self-collide; and for renameTable the renamed table's OWN stores stay in the
|
|
259
|
-
* set deliberately. Any overlap between a name the rename introduces and an
|
|
260
|
-
* own current store is a footprint-swap rename (`t` with index `x` → `t_idx_x`,
|
|
261
|
-
* or table `u_idx_x` with index `x` → `u`) that providers cannot relocate
|
|
262
|
-
* safely — relocation order determines whether a source is clobbered before it
|
|
263
|
-
* is moved — while no benign rename produces such an overlap. Keeping own
|
|
264
|
-
* stores in the set therefore causes no false rejects and keeps the
|
|
265
|
-
* reject-before-any-side-effect guarantee uniform.
|
|
266
|
-
*/
|
|
267
|
-
private collectOccupiedStoreNames;
|
|
268
|
-
/**
|
|
269
|
-
* Throws `StatusCode.ERROR` when `candidate` (a physical store name produced by
|
|
270
|
-
* the key-builder for an object about to be created/renamed) already names an
|
|
271
|
-
* existing data or index store in `schemaName`. `candidateDesc` describes the
|
|
272
|
-
* incoming logical object; the message names the candidate physical store and
|
|
273
|
-
* both conflicting logical objects and is actionable (rename one of them).
|
|
274
|
-
*
|
|
275
|
-
* Must run BEFORE any storage side-effect (`getStore` / `getIndexStore` / the
|
|
276
|
-
* physical relocation): the provider opens/creates the store eagerly, so a
|
|
277
|
-
* guard that ran after would already have aliased the colliding object's store.
|
|
278
|
-
*
|
|
279
|
-
* Callers checking several candidates against the same occupancy (renameTable
|
|
280
|
-
* checks the new data store plus every relocated index store) pass a
|
|
281
|
-
* precomputed `occupied` map so the occupancy is collected once, not per call.
|
|
282
|
-
*/
|
|
283
|
-
private assertStoreNameFree;
|
|
284
159
|
/**
|
|
285
160
|
* Creates a new store-backed table.
|
|
286
161
|
* Called by CREATE TABLE.
|
|
@@ -334,330 +209,6 @@ export declare class StoreModule implements VirtualTableModule<StoreTable, Store
|
|
|
334
209
|
* provider no-ops on absent stores and `removeTableDDL` no-ops on an absent key.
|
|
335
210
|
*/
|
|
336
211
|
private tearDownTableStorage;
|
|
337
|
-
/**
|
|
338
|
-
* Returns the connected StoreTable for `schemaName.tableName`, lazily
|
|
339
|
-
* reconnecting from the engine's schema registry when absent.
|
|
340
|
-
*
|
|
341
|
-
* `renameTable` evicts the old key from `this.tables` and expects the next
|
|
342
|
-
* `connect()` to repopulate under the new name, but `apply schema` can run
|
|
343
|
-
* follow-up DDL (ALTER TABLE, CREATE/DROP INDEX) against the new name
|
|
344
|
-
* without an intervening connect. Mirror connect()'s schemaManager lookup
|
|
345
|
-
* so that DDL finds the moved table. Safe for the index paths because
|
|
346
|
-
* SchemaManager calls the module BEFORE mutating the registered table
|
|
347
|
-
* schema, so the reconnected cache matches what a connected instance holds.
|
|
348
|
-
*/
|
|
349
|
-
private getOrReconnectTable;
|
|
350
|
-
/**
|
|
351
|
-
* Creates an index on a store-backed table.
|
|
352
|
-
*
|
|
353
|
-
* `rows` — an {@link EffectiveRowSource} supplied by a wrapper module (the isolation
|
|
354
|
-
* layer) — replaces this module's own rows as the set the UNIQUE duplicate check judges.
|
|
355
|
-
* When present the check runs UP FRONT, before `getIndexStore` opens the index-store
|
|
356
|
-
* directory, so a rejection leaves no directory behind; and `buildIndexEntries` then
|
|
357
|
-
* populates the physical index from this module's own (committed) rows with its in-pass
|
|
358
|
-
* dup check disabled. Those two row sets legitimately differ — the wrapper's transaction
|
|
359
|
-
* may have deleted a committed duplicate — and an index entry with no live row behind it
|
|
360
|
-
* is harmless (see the entry-resolution note in `buildIndexEntries`).
|
|
361
|
-
*/
|
|
362
|
-
createIndex(db: Database, schemaName: string, tableName: string, indexSchema: TableIndexSchema, rows?: EffectiveRowSource): Promise<void>;
|
|
363
|
-
/**
|
|
364
|
-
* Drops an index on a store-backed table.
|
|
365
|
-
*
|
|
366
|
-
* Mirrors createIndex: refreshes the connected StoreTable's cached
|
|
367
|
-
* tableSchema (removing the index entry and any UNIQUE constraint
|
|
368
|
-
* synthesized from it, tagged with `derivedFromIndex`), releases the
|
|
369
|
-
* cached index-store handle, and tears down the underlying index store.
|
|
370
|
-
*/
|
|
371
|
-
dropIndex(db: Database, schemaName: string, tableName: string, indexName: string): Promise<void>;
|
|
372
|
-
/**
|
|
373
|
-
* Build index entries for all existing rows in a table.
|
|
374
|
-
*
|
|
375
|
-
* `dataEntries` is the row stream to index. Callers choose its visibility:
|
|
376
|
-
* `createIndex` passes the table's EFFECTIVE stream (committed + pending, so
|
|
377
|
-
* an open transaction's rows are indexed too), while `rebuildSecondaryIndexes`
|
|
378
|
-
* passes the raw committed stream — it runs immediately after an ALTER has
|
|
379
|
-
* re-encoded the data store in place, and any pending ops still address the
|
|
380
|
-
* pre-ALTER key bytes.
|
|
381
|
-
*
|
|
382
|
-
* For UNIQUE indexes, performs an in-pass duplicate check (honoring partial
|
|
383
|
-
* predicates and SQL NULL semantics: multiple NULLs are allowed) and throws
|
|
384
|
-
* CONSTRAINT before any entries are written. Mirrors the memory module's
|
|
385
|
-
* populateNewIndex so `CREATE UNIQUE INDEX` over duplicated data fails
|
|
386
|
-
* atomically. `skipDuplicateCheck` suppresses it: `createIndex` sets it when a
|
|
387
|
-
* wrapper module supplied the rows to judge, having already validated them (see
|
|
388
|
-
* {@link validateUniqueIndexOverRows}). Judging `dataEntries` too would reject a
|
|
389
|
-
* committed duplicate the wrapper's transaction has already deleted.
|
|
390
|
-
*
|
|
391
|
-
* `normalizers` MUST be the owning connection's `db.getKeyNormalizerResolver()` —
|
|
392
|
-
* the same resolver `StoreTable.encodeOptions` carries. A rebuild that resolved
|
|
393
|
-
* collations any other way would re-encode the PK suffix under different bytes than
|
|
394
|
-
* the table writes at maintenance time, silently corrupting the index.
|
|
395
|
-
*/
|
|
396
|
-
private buildIndexEntries;
|
|
397
|
-
/**
|
|
398
|
-
* Clear and rebuild every secondary index of `schema` against the (already
|
|
399
|
-
* re-encoded) data store. Secondary-index keys embed the PK suffix, so they must
|
|
400
|
-
* be rewritten whenever the data-store PK key bytes change — which happens both
|
|
401
|
-
* on `ALTER PRIMARY KEY` (the PK columns change) and on an `ALTER COLUMN … SET
|
|
402
|
-
* COLLATE` on a PK member (a PK column's key collation changes). Shared by both
|
|
403
|
-
* arms so the clear-then-rebuild stays identical. `schema` must already be the
|
|
404
|
-
* post-ALTER schema (its `primaryKeyDefinition` + column collations drive the new
|
|
405
|
-
* PK-suffix encoding via {@link buildIndexEntries}). `normalizers` is the owning
|
|
406
|
-
* connection's `db.getKeyNormalizerResolver()` — see {@link buildIndexEntries}.
|
|
407
|
-
*
|
|
408
|
-
* NOTE: reads the data store committed-only and writes the index stores outside the
|
|
409
|
-
* coordinator. Sound only because every caller calls {@link ddlCommitPendingOps}
|
|
410
|
-
* first, so this module's "committed" is "everything live". A caller that skips that
|
|
411
|
-
* flush would rebuild an index missing its transaction's pending rows.
|
|
412
|
-
*
|
|
413
|
-
* `skipDuplicateCheck` suppresses {@link buildIndexEntries}' in-pass UNIQUE check.
|
|
414
|
-
* The value-rewriting / key-transform ALTER COLUMN arm sets it: its pre-mutation
|
|
415
|
-
* UNIQUE re-validation already judged the ISSUING connection's effective rows (a
|
|
416
|
-
* wrapper's overlay included), and this rebuild sees only THIS module's committed
|
|
417
|
-
* rows — a superset that may retain a row the wrapper's transaction has deleted, so
|
|
418
|
-
* judging it here would spuriously reject a duplicate pair the probe correctly
|
|
419
|
-
* accepted. Mirrors the memory module's deliberately non-enforcing base rebuild
|
|
420
|
-
* (the probe is the only guard).
|
|
421
|
-
*/
|
|
422
|
-
private rebuildSecondaryIndexes;
|
|
423
|
-
/**
|
|
424
|
-
* Validates `rows` against a UNIQUE constraint, throwing `CONSTRAINT` on the first
|
|
425
|
-
* duplicate before any schema mutation. Used by `ADD CONSTRAINT UNIQUE` (validate
|
|
426
|
-
* against the current collation) and by `SET COLLATE` (pass an `updatedSchema` whose
|
|
427
|
-
* altered column carries the NEW collation, so the dedup is performed under it).
|
|
428
|
-
* Mirrors the duplicate detection in {@link buildIndexEntries}: a `seen` Set keyed on
|
|
429
|
-
* a per-column collation-aware signature of the constrained values, with SQL NULL
|
|
430
|
-
* semantics (a row with any NULL constrained value never counts as a duplicate) and
|
|
431
|
-
* the partial `predicate` honored.
|
|
432
|
-
*
|
|
433
|
-
* `rows` MUST be the rows the DDL-issuing connection can SEE. Ordinarily that is this
|
|
434
|
-
* table's EFFECTIVE stream (committed rows merged with the open transaction's own
|
|
435
|
-
* pending puts/deletes — `StoreTable.iterateEffectiveEntries`, adapted by
|
|
436
|
-
* {@link rowsFromEntries}); when a wrapper module holds the pending rows outside this
|
|
437
|
-
* module it hands them down as an `EffectiveRowSource` instead. Either way, a
|
|
438
|
-
* committed-only stream would let a duplicate inserted earlier in the same transaction
|
|
439
|
-
* slip past validation and land in the table once the transaction commits.
|
|
440
|
-
*
|
|
441
|
-
* No index store is written — store UNIQUE enforcement is a full-scan over
|
|
442
|
-
* `uniqueConstraints` at write time. The signature is built by
|
|
443
|
-
* {@link dedupeRowSignature} with one normalizer per constrained column, resolved from
|
|
444
|
-
* `tableSchema.columns[idx].collation` through the connection's
|
|
445
|
-
* `db.getKeyNormalizerResolver()`, so a per-column collation registered with
|
|
446
|
-
* `db.registerCollation` is honored (matching write-time `compareSqlValues`
|
|
447
|
-
* enforcement). A comparator-only collation raises: rows that cannot be bucketed
|
|
448
|
-
* cannot be deduped. Columns whose declared type can never hold text take the
|
|
449
|
-
* identity normalizer and so never raise.
|
|
450
|
-
*/
|
|
451
|
-
private validateUniqueOverExistingRows;
|
|
452
|
-
/**
|
|
453
|
-
* Index-shaped twin of {@link validateUniqueOverExistingRows}, used by
|
|
454
|
-
* {@link createIndex} when a wrapper module supplies the rows to judge. Dedupes on the
|
|
455
|
-
* index's own columns under the index column's COLLATE (falling back to the table
|
|
456
|
-
* column's), so it enforces exactly what `buildIndexEntries`' suppressed in-pass check
|
|
457
|
-
* would have — over the wrapper's rows instead of this module's committed ones.
|
|
458
|
-
*/
|
|
459
|
-
private validateUniqueIndexOverRows;
|
|
460
|
-
/**
|
|
461
|
-
* Flush the module's buffered writes before a DDL operation that physically
|
|
462
|
-
* rewrites or relocates storage.
|
|
463
|
-
*
|
|
464
|
-
* Such a DDL cannot honor the coordinator's buffer: pending ops are
|
|
465
|
-
* `(keyBytes, valueBytes, store)` triples computed at DML time under the
|
|
466
|
-
* PRE-DDL schema, and every physical rewrite (`StoreTable.rekeyRows` /
|
|
467
|
-
* `migrateRows`, the provider's directory move) reads and writes the COMMITTED
|
|
468
|
-
* store directly. Replaying stale-schema ops over the rewritten store on the
|
|
469
|
-
* eventual commit corrupts, loses, or misfiles those rows. So an `ALTER TABLE`
|
|
470
|
-
* that touches storage is effectively DDL-committing on a store-backed table:
|
|
471
|
-
* flush NOW, before the first physical read, so the rewrite sees every live row
|
|
472
|
-
* and there is nothing left to replay afterwards.
|
|
473
|
-
*
|
|
474
|
-
* Consequences, both deliberate:
|
|
475
|
-
* - The coordinator is module-wide, so this commits the WHOLE module
|
|
476
|
-
* transaction — every table's pending ops, not just the altered/renamed
|
|
477
|
-
* table's — in one all-or-nothing batch. An ALTER cannot half-commit some
|
|
478
|
-
* sibling tables.
|
|
479
|
-
* - Validation running AFTER this point (e.g. `rekeyRows`' duplicate-key pass,
|
|
480
|
-
* which must see pending rows because a pending insert can itself be the
|
|
481
|
-
* duplicate) throws with the enclosing transaction already flushed. The store
|
|
482
|
-
* stays unmutated — only the transaction is gone. Validation that does NOT
|
|
483
|
-
* need pending rows belongs before the call, so the transaction survives it.
|
|
484
|
-
*
|
|
485
|
-
* Subsequent `commit()` calls on the same coordinator are no-ops
|
|
486
|
-
* (`inTransaction` is cleared), which keeps the enclosing transaction safe.
|
|
487
|
-
* The savepoint stack is cleared too, so a later `ROLLBACK TO` / `RELEASE` that
|
|
488
|
-
* the engine still broadcasts warns and degrades rather than throwing — see
|
|
489
|
-
* `TransactionCoordinator.rollbackToSavepoint`, which mirrors the memory
|
|
490
|
-
* module's identical posture.
|
|
491
|
-
*/
|
|
492
|
-
private ddlCommitPendingOps;
|
|
493
|
-
/**
|
|
494
|
-
* Alters an existing store table's structure. Resolves the table, captures the
|
|
495
|
-
* pre-alter schema, and dispatches to the per-change-type `alter*` helper below;
|
|
496
|
-
* the helper does the arm's work (row migration, physical re-key, constraint
|
|
497
|
-
* validation, DDL persist) and returns the updated TableSchema for the engine to
|
|
498
|
-
* register. The shared preamble (schema subscription, reconnect, not-found throw,
|
|
499
|
-
* `defaultNotNull`) lives here so every arm sees the same resolved state.
|
|
500
|
-
*/
|
|
501
|
-
alterTable(db: Database, schemaName: string, tableName: string, change: SchemaChangeInfo, rows?: EffectiveRowSource): Promise<TableSchema>;
|
|
502
|
-
/**
|
|
503
|
-
* Build / tear down the physical index stores backing implicit UNIQUE indexes
|
|
504
|
-
* (`_uc_*`) after an ALTER, by diffing the implicit-index NAMES of the old vs new
|
|
505
|
-
* constraint sets:
|
|
506
|
-
* - a name newly PRESENT (ADD CONSTRAINT UNIQUE, or the target half of a
|
|
507
|
-
* RENAME CONSTRAINT / rename of an unnamed UC's column) has its physical store
|
|
508
|
-
* populated from this module's effective rows;
|
|
509
|
-
* - a name newly ABSENT (DROP CONSTRAINT UNIQUE, or the source half of a rename)
|
|
510
|
-
* has its store torn down, so a later re-ADD does not reopen stale entries.
|
|
511
|
-
*
|
|
512
|
-
* The SCHEMA entry itself is materialized/removed by `withImplicitUniqueIndexes`
|
|
513
|
-
* on the arm's `table.updateSchema`; only the physical store needs this. Runs after
|
|
514
|
-
* every ALTER but is a no-op whenever the implicit-index name set is unchanged
|
|
515
|
-
* (incl. PK / collation / data-type ALTERs, whose same-name physical re-encode is
|
|
516
|
-
* already done by {@link rebuildSecondaryIndexes}).
|
|
517
|
-
*
|
|
518
|
-
* `oldSchema` carries the pre-ALTER `uniqueConstraints` (its `.indexes` may be
|
|
519
|
-
* de-materialized — the diff reads `uniqueConstraints`, not `.indexes`).
|
|
520
|
-
*
|
|
521
|
-
* NOTE: the build populates from THIS module's own effective rows (committed + this
|
|
522
|
-
* transaction's pending), never a wrapper's — mirroring `createIndex`. Under the
|
|
523
|
-
* isolation layer the wrapper's rows are what ADD CONSTRAINT's validation judged;
|
|
524
|
-
* the physical index legitimately fills from this module's committed rows and an
|
|
525
|
-
* entry with no live row behind it is harmless (both readers resolve to the live
|
|
526
|
-
* row). Duplicates were already rejected by `validateUniqueOverExistingRows` (ADD)
|
|
527
|
-
* or cannot exist (RENAME leaves data unchanged), so the in-pass check is skipped.
|
|
528
|
-
*/
|
|
529
|
-
private reconcileImplicitUniqueIndexStores;
|
|
530
|
-
/**
|
|
531
|
-
* The physical index-store names a table owns for DROP / RENAME TABLE to relocate
|
|
532
|
-
* or reclaim: the MATERIALIZED index set — every explicit `CREATE INDEX` PLUS the
|
|
533
|
-
* hidden `_uc_*` realizing each plain UNIQUE. Reading only `getSchema().indexes`
|
|
534
|
-
* (the engine-facing schema, which carries no `_uc_*`) would strand a `_uc_*` store
|
|
535
|
-
* on disk after DROP TABLE, and — worse — after RENAME TABLE leave the renamed
|
|
536
|
-
* table seeking a freshly-created EMPTY `_uc_*` store, silently accepting a
|
|
537
|
-
* duplicate of a pre-rename row. Prefers the cached StoreTable's own materialized
|
|
538
|
-
* schema; falls back to materializing the schema-manager copy when the instance is
|
|
539
|
-
* already gone.
|
|
540
|
-
*/
|
|
541
|
-
private materializedIndexNames;
|
|
542
|
-
/** Close + delete the physical store of an implicit UNIQUE index. Mirrors `dropIndex`. */
|
|
543
|
-
private tearDownImplicitUniqueIndexStore;
|
|
544
|
-
/**
|
|
545
|
-
* ADD COLUMN arm of {@link alterTable}: append the new column, eagerly migrate
|
|
546
|
-
* each row (literal or per-row backfill), and persist. Behavior-preserving
|
|
547
|
-
* extraction of the former `switch` arm.
|
|
548
|
-
*
|
|
549
|
-
* The store always appends. A caller-chosen `insertAtIndex` (module-API only; SQL never
|
|
550
|
-
* produces one) is rejected unless it names the append position, rather than silently
|
|
551
|
-
* landing the column somewhere the caller did not ask for.
|
|
552
|
-
*/
|
|
553
|
-
private alterAddColumn;
|
|
554
|
-
/** DROP COLUMN arm of {@link alterTable}: drop the column slot, reindex PK / indexes /
|
|
555
|
-
* UNIQUE, migrate rows, and persist. Behavior-preserving extraction. */
|
|
556
|
-
private alterDropColumn;
|
|
557
|
-
/** RENAME COLUMN arm of {@link alterTable}: schema-only rewrite (columns, indexes, self-FK,
|
|
558
|
-
* in-place predicate / CHECK AST rewrite) and persist. Behavior-preserving extraction. */
|
|
559
|
-
private alterRenameColumn;
|
|
560
|
-
/** ALTER PRIMARY KEY arm of {@link alterTable}: physically re-key the data store, rebuild
|
|
561
|
-
* secondary indexes, and persist. Behavior-preserving extraction. */
|
|
562
|
-
private alterPrimaryKeyChange;
|
|
563
|
-
/** ADD CONSTRAINT arm of {@link alterTable}: validate existing rows as the constraint kind
|
|
564
|
-
* (UNIQUE / FOREIGN KEY / CHECK) requires, then persist. Behavior-preserving extraction. */
|
|
565
|
-
private alterAddConstraint;
|
|
566
|
-
/** DROP CONSTRAINT arm of {@link alterTable}: schema-only catalog rewrite dropping a named
|
|
567
|
-
* constraint, then persist. Behavior-preserving extraction. */
|
|
568
|
-
private alterDropConstraint;
|
|
569
|
-
/** RENAME CONSTRAINT arm of {@link alterTable}: schema-only rename of a named constraint,
|
|
570
|
-
* then persist. A renamed named-UNIQUE changes its implicit `_uc_*` index name, so
|
|
571
|
-
* `reconcileImplicitUniqueIndexStores` (run after this arm) MOVES the physical store —
|
|
572
|
-
* tears down the old-named store and rebuilds the new-named one from effective rows. */
|
|
573
|
-
private alterRenameConstraint;
|
|
574
|
-
/** ALTER COLUMN arm of {@link alterTable}: change one attribute (NOT NULL / data type /
|
|
575
|
-
* default / collation), running the physical re-key + existing-row re-validation the
|
|
576
|
-
* collation / PK paths require, then persist. Behavior-preserving extraction. */
|
|
577
|
-
private alterColumnChange;
|
|
578
|
-
/**
|
|
579
|
-
* SET NOT NULL / DROP NOT NULL sub-branch of {@link alterColumnChange}. Returns the
|
|
580
|
-
* new column schema, or null when the column is already in the desired nullability
|
|
581
|
-
* (the pre-refactor `return oldSchema` no-op). Mutates nothing: the NULL-backfill
|
|
582
|
-
* probe is throw-only, and the backfill itself is returned as a deferred
|
|
583
|
-
* `valueConvert` (null → DEFAULT) the caller applies only after every throw-only
|
|
584
|
-
* check — including the UNIQUE re-validation over the backfilled values — has passed.
|
|
585
|
-
*
|
|
586
|
-
* `rows` is the wrapper-supplied effective row source (the isolation overlay). When present,
|
|
587
|
-
* the reject-vs-backfill decision scans it instead of `table.rowsWithNullAtIndex`: behind the
|
|
588
|
-
* isolation layer the issuer's pending inserts live in the wrapper's overlay, not this store,
|
|
589
|
-
* so the store's own count would miss them and wrongly accept the ALTER. The committed-store
|
|
590
|
-
* `mapRowsAtIndex` backfill is unchanged — the overlay-resident pending rows are the isolation
|
|
591
|
-
* layer's job (its overlay migration), this store only owns its committed rows.
|
|
592
|
-
*/
|
|
593
|
-
private alterColumnSetNotNull;
|
|
594
|
-
/**
|
|
595
|
-
* SET DATA TYPE sub-branch of {@link alterColumnChange}. Returns the retyped column
|
|
596
|
-
* schema. Mutates nothing: for every retype between DIFFERENT logical types, a
|
|
597
|
-
* throw-only convert pass over the live rows proves every value convertible, and the
|
|
598
|
-
* conversion itself is returned as a deferred `valueConvert` the caller applies only
|
|
599
|
-
* after every throw-only check — including the UNIQUE re-validation over the converted
|
|
600
|
-
* values — has passed. Gated on logical-type IDENTITY, not the physical storage class:
|
|
601
|
-
* `inferType` flattens aliases to the shared type object (`varchar(50)` IS `TEXT_TYPE`),
|
|
602
|
-
* so an alias retype is schema-only, while a same-class retype (text → date) still
|
|
603
|
-
* rejects values the new type refuses and rewrites the rest to the new type's
|
|
604
|
-
* canonical spelling ('2024-06-05T00:00:00Z' → '2024-06-05') — exactly as an INSERT
|
|
605
|
-
* would have stored them.
|
|
606
|
-
*
|
|
607
|
-
* A retype of a PRIMARY KEY member is refused here rather than converted: the rewrite
|
|
608
|
-
* below is `mapRowsAtIndex`, a payload-only rewrite that reuses `entry.key` verbatim, so
|
|
609
|
-
* a PK column's physical key bytes would stay encoded under the OLD type while the value
|
|
610
|
-
* moves to the new one — unfindable by any lookup under the new encoding, and the same
|
|
611
|
-
* `keyTransformChanged` path in the caller would re-key from the pre-rewrite values before
|
|
612
|
-
* this rewrite ever ran (see the NOTE above the `valueConvert` block in
|
|
613
|
-
* {@link alterColumnChange}). Every live SQL caller already refuses this earlier (the
|
|
614
|
-
* engine's `runAlterColumn` and the materialized-view reshape's inexpressibility check),
|
|
615
|
-
* so this only guards a direct module call — mirrors the memory backend's carve-out
|
|
616
|
-
* (`MemoryTableManager.alterColumn`).
|
|
617
|
-
*/
|
|
618
|
-
private alterColumnSetDataType;
|
|
619
|
-
/**
|
|
620
|
-
* SET COLLATE sub-branch of {@link alterColumnChange}. Returns the recollated column
|
|
621
|
-
* schema with `collationChanged` set when the collation bytes actually change (a bare
|
|
622
|
-
* metadata flip keeps it false), or null when the column is already explicit in the
|
|
623
|
-
* desired collation (the pre-refactor `return oldSchema` no-op). Synchronous — no
|
|
624
|
-
* row scan happens here; the caller runs the re-validation / re-key the flag gates.
|
|
625
|
-
*/
|
|
626
|
-
private alterColumnSetCollation;
|
|
627
|
-
/**
|
|
628
|
-
* Rename a store-backed table.
|
|
629
|
-
*
|
|
630
|
-
* Drops every in-memory reference to the old name (so the coordinator, open
|
|
631
|
-
* handles, and cached StoreTable instance don't linger with stale paths),
|
|
632
|
-
* delegates physical storage relocation to the provider, then rewrites the
|
|
633
|
-
* persistent catalog DDL under the new key. After this returns, the next
|
|
634
|
-
* access to `newName` will reconnect via `connect()` and open fresh stores
|
|
635
|
-
* against the moved directories.
|
|
636
|
-
*/
|
|
637
|
-
renameTable(db: Database, schemaName: string, oldName: string, newName: string): Promise<void>;
|
|
638
|
-
/**
|
|
639
|
-
* Second phase of a two-phase RENAME TABLE (see {@link renameTable}). The engine calls
|
|
640
|
-
* this at the END of ALTER TABLE ... RENAME TO — AFTER its `propagateTableRename` has
|
|
641
|
-
* rewritten every dependent object that named `oldName` and enqueued their corrective
|
|
642
|
-
* catalog writes onto {@link persistQueue}. `renameTable` deliberately left `oldName`'s
|
|
643
|
-
* catalog entry in place; here we drain those dependent writes to durability and only
|
|
644
|
-
* THEN drop the old entry. During the window both entries coexist on disk, so every
|
|
645
|
-
* dependent resolves against one of them and every intermediate catalog set rehydrates
|
|
646
|
-
* into a working database.
|
|
647
|
-
*
|
|
648
|
-
* The old-entry delete rides `persistQueue` behind the dependents' already-enqueued
|
|
649
|
-
* writes (FIFO), so it can only run after them, and the drain below awaits the whole
|
|
650
|
-
* chain. Errors are swallowed+logged (the {@link enqueuePersist} contract): a failed
|
|
651
|
-
* delete leaves the old entry present — a visible, droppable orphan, strictly safer
|
|
652
|
-
* than a dependent stranded against a vanished table.
|
|
653
|
-
*
|
|
654
|
-
* NOTE: full cross-table atomicity — bundling this old-entry delete together with every
|
|
655
|
-
* dependent rewrite into one `provider.beginAtomicBatch` commit — would eliminate even
|
|
656
|
-
* the transient two-entry window (and the physical-move orphan `renameTableStores`
|
|
657
|
-
* leaves), but only on atomic providers, and the dependent set is known only to the
|
|
658
|
-
* engine post-propagate. That is the atomic-provider hardening path; out of scope here.
|
|
659
|
-
*/
|
|
660
|
-
finalizeRename(_db: Database, schemaName: string, oldName: string, _newName: string): Promise<void>;
|
|
661
212
|
/**
|
|
662
213
|
* Modern access planning interface.
|
|
663
214
|
*
|
|
@@ -679,431 +230,14 @@ export declare class StoreModule implements VirtualTableModule<StoreTable, Store
|
|
|
679
230
|
* ORDER-PRESERVING — byte order and comparator order must coincide, or the seek would
|
|
680
231
|
* under-fetch and the ordering advertisement would elide a Sort it must not. That gate
|
|
681
232
|
* needs the connection's collation registry, hence `db` is threaded down.
|
|
682
|
-
*/
|
|
683
|
-
getBestAccessPlan(db: Database, tableInfo: TableSchema, request: BestAccessPlanRequest): BestAccessPlanResult;
|
|
684
|
-
private computeBestAccessPlan;
|
|
685
|
-
/**
|
|
686
|
-
* Build the access plan for one secondary index against `request`, or null when
|
|
687
|
-
* the index is not usable for this predicate.
|
|
688
|
-
*
|
|
689
|
-
* Usable = a contiguous leading-prefix EQ on the index columns (an index seek /
|
|
690
|
-
* point), or a LT/LE/GT/GE range on the LEADING index column. These mirror the
|
|
691
|
-
* two windows {@link StoreTable.analyzeIndexAccess} can build.
|
|
692
|
-
*
|
|
693
|
-
* **Collation-safety guard against under-fetch.** The store's index-column
|
|
694
|
-
* window is encoded under the table key collation K, but `matchesFilters`
|
|
695
|
-
* compares under the COLUMN's declared collation. Marking a filter handled drops
|
|
696
|
-
* the residual Filter, so the K-window must be a guaranteed SUPERSET of the
|
|
697
|
-
* qualifying rows. That holds only when K is coarser-or-equal to the column's
|
|
698
|
-
* declared collation. To stay provably safe with minimal logic we mark the
|
|
699
|
-
* covered filters handled — setting `indexName` + `seekColumns` — only when every
|
|
700
|
-
* seek column is non-text, OR its declared collation equals K, OR (K = NOCASE
|
|
701
|
-
* while the column is BINARY, i.e. K strictly coarser). Otherwise we return a
|
|
702
|
-
* cost-only plan (cheaper cost, filters unhandled, residual retained — correct,
|
|
703
|
-
* just not sped up). K itself always keys: `StoreTable`'s constructor rejects a
|
|
704
|
-
* table whose key encoding would need a collation it cannot resolve to a normalizer.
|
|
705
|
-
*
|
|
706
|
-
* NOTE: the coarser-K relaxation is sound for EQUALITY only. A RANGE window equates
|
|
707
|
-
* memcmp of K-normalized bytes with C's comparator order, which a merely coarser K does
|
|
708
|
-
* not give — under K = NOCASE and C = BINARY, 'K' (U+212A) is `> 'z'` yet keys as 'k',
|
|
709
|
-
* before 'z'. So the range arm demands `C === K` *and* K's `orderPreserving` assertion,
|
|
710
|
-
* via the shared {@link keyOrderMatchesCollation}; `StoreTable.analyzeIndexAccess`
|
|
711
|
-
* declines the same windows, so the two decisions cannot disagree. The cost is that a
|
|
712
|
-
* default-K (NOCASE) table with an index on a plain BINARY text column loses its index
|
|
713
|
-
* RANGE seek and falls back to the cost-only plan; EQ seeks are unchanged.
|
|
714
|
-
*/
|
|
715
|
-
private tryIndexAccessPlan;
|
|
716
|
-
/**
|
|
717
|
-
* Compute the PK-ordering advertisement for a scan-style plan. Returns the
|
|
718
|
-
* `providesOrdering` / `monotonicOn` / `supportsAsofRight` fields for a plan
|
|
719
|
-
* whose iteration is driven by the primary-key key order (full scan or PK
|
|
720
|
-
* range scan).
|
|
721
|
-
*
|
|
722
|
-
* `providesOrdering` is set only when it actually matches what the caller
|
|
723
|
-
* needs:
|
|
724
|
-
* - When the request carries `requiredOrdering`, claim it only if the
|
|
725
|
-
* requested keys form a prefix of the PK with matching directions.
|
|
726
|
-
* Claiming PK order against an `ORDER BY <other column>` would cause
|
|
727
|
-
* the absorb-Sort rule to drop the Sort and yield wrong-order rows.
|
|
728
|
-
* - When no `requiredOrdering` is present, advertise the full PK
|
|
729
|
-
* ordering so downstream rules (merge-join, sort elision after a
|
|
730
|
-
* filter) can opportunistically use it.
|
|
731
|
-
*
|
|
732
|
-
* `monotonicOn` reflects the access path itself and is independent of any
|
|
733
|
-
* `requiredOrdering`; it always advertises the leading PK column. Strict
|
|
734
|
-
* monotonicity is claimed iff the PK is single-column — composite PKs can
|
|
735
|
-
* repeat values on the leading column.
|
|
736
|
-
*
|
|
737
|
-
* Returns an empty object when there is no PK (heap-only table) — without a
|
|
738
|
-
* leading key column there is no natural emit order.
|
|
739
|
-
*
|
|
740
|
-
* Every claim here is about the PHYSICAL key-byte order the store iterates in, but the
|
|
741
|
-
* consumers of `providesOrdering` / `monotonicOn` reason in the columns' COLLATION order.
|
|
742
|
-
* `orderPreservingPrefix` (from {@link pkOrderPreservingPrefixLength}) is how many leading
|
|
743
|
-
* PK members those two orders provably agree on: the advertisement is truncated to that
|
|
744
|
-
* prefix, and voided entirely when even the leading member disagrees — otherwise the
|
|
745
|
-
* absorb-Sort rule would elide a Sort and hand the caller byte-ordered rows.
|
|
746
|
-
*/
|
|
747
|
-
private buildPkOrderingAdvertisement;
|
|
748
|
-
/**
|
|
749
|
-
* Get or create a data store for a table.
|
|
750
|
-
*/
|
|
751
|
-
getStore(schemaName: string, tableName: string, _config: StoreTableConfig): Promise<KVStore>;
|
|
752
|
-
/**
|
|
753
|
-
* Get or create an index store for a table.
|
|
754
|
-
*/
|
|
755
|
-
getIndexStore(schemaName: string, tableName: string, indexName: string): Promise<KVStore>;
|
|
756
|
-
/**
|
|
757
|
-
* Get or create a stats store for a table.
|
|
758
|
-
*/
|
|
759
|
-
getStatsStore(schemaName: string, tableName: string): Promise<KVStore>;
|
|
760
|
-
/**
|
|
761
|
-
* Get (lazily constructing) the SINGLE transaction coordinator shared by every
|
|
762
|
-
* table this module owns — the unit of cross-table atomicity. Every
|
|
763
|
-
* {@link StoreTable} attaches to the same instance, so a transaction touching
|
|
764
|
-
* several of the module's tables commits/rolls back as one all-or-nothing
|
|
765
|
-
* batch.
|
|
766
|
-
*
|
|
767
|
-
* Synchronously constructible: ops are addressed by explicit store handle, so
|
|
768
|
-
* the coordinator never needs to open a store to be created. This lets callers
|
|
769
|
-
* that must stay synchronous (e.g. a `BackingHost.connect()`) obtain a working
|
|
770
|
-
* coordinator before any table's store has been opened.
|
|
771
|
-
*/
|
|
772
|
-
getCoordinator(): TransactionCoordinator;
|
|
773
|
-
/**
|
|
774
|
-
* Build the catalog entry for a table: its CREATE TABLE DDL, one
|
|
775
|
-
* `CREATE [UNIQUE] INDEX` statement per persistable secondary index, and one
|
|
776
|
-
* `alter index … set tags (…)` statement per exposed implicit index carrying
|
|
777
|
-
* user tags, newline-joined into a single multi-statement bundle keyed by
|
|
778
|
-
* `{schema}.{table}`.
|
|
779
|
-
*
|
|
780
|
-
* Bundling the indexes into the table's own entry means every existing
|
|
781
|
-
* re-persist path — `saveTableDDL` (each `alterTable` arm, `renameTable`) and
|
|
782
|
-
* the `table_modified` listener (`persistCatalogIfChanged`) — carries the
|
|
783
|
-
* indexes along for free, and `removeTableDDL` drops them with the table. The
|
|
784
|
-
* bundle is consumed on reopen by `rehydrateCatalog` → `importCatalog`, whose
|
|
785
|
-
* `parser.parseAll` splits it AST-by-AST (never on `\n`) and imports each
|
|
786
|
-
* statement in document order, so the table registers before its indexes.
|
|
787
|
-
*
|
|
788
|
-
* Both the table DDL and the index DDL are emitted without a `db` arg, keeping
|
|
789
|
-
* the persistence-safe fully-qualified form. Hidden implicit covering indexes
|
|
790
|
-
* (the auto-built BTree backing a declared UNIQUE constraint) are excluded —
|
|
791
|
-
* they are a backing detail that round-trips via the table's UNIQUE constraint,
|
|
792
|
-
* not as a standalone CREATE INDEX. For store tables `buildTableSchemaFromAST`
|
|
793
|
-
* synthesizes none of those, so in practice every index is included; the guard
|
|
794
|
-
* is defensive. A `CREATE UNIQUE INDEX`'s derived UNIQUE constraint is already
|
|
795
|
-
* excluded from the table DDL by the generator, so it round-trips solely via
|
|
796
|
-
* its own `CREATE UNIQUE INDEX` line — no doubling.
|
|
797
|
-
*
|
|
798
|
-
* An *exposed* implicit index (a non-derived UNIQUE constraint tagged
|
|
799
|
-
* `quereus.expose_implicit_index = true`, never materialized in store mode)
|
|
800
|
-
* must NOT get a synthetic `CREATE INDEX` line — re-import would materialize a
|
|
801
|
-
* real `IndexSchema` and change the store-mode shape. Its user tags
|
|
802
|
-
* (`UniqueConstraintSchema.exposedIndexTags`) instead ride a trailing
|
|
803
|
-
* `alter index … set tags` line, which `importDDL` re-applies silently after
|
|
804
|
-
* the CREATE TABLE in the same entry has registered the constraint. Empty tag
|
|
805
|
-
* records emit no line, and `exposedImplicitIndexes` returns `[]` for
|
|
806
|
-
* memory-mode tables (name materialized) and orders descriptors by the
|
|
807
|
-
* `uniqueConstraints` array, so the bundle stays byte-deterministic — which
|
|
808
|
-
* the compare-write in `persistCatalogIfChanged` relies on.
|
|
809
|
-
*/
|
|
810
|
-
private buildCatalogEntry;
|
|
811
|
-
/**
|
|
812
|
-
* Encode a bundle of persisted schema text (DDL) for the catalog store.
|
|
813
|
-
* The guard is {@link assertPersistableDdlText} — see it for why the FULL text
|
|
814
|
-
* is checked, not just the object's name.
|
|
815
|
-
*/
|
|
816
|
-
private encodeCatalogDDL;
|
|
817
|
-
/**
|
|
818
|
-
* Save table DDL (bundled with its secondary index DDL) to the catalog store.
|
|
819
|
-
*/
|
|
820
|
-
saveTableDDL(tableSchema: TableSchema): Promise<void>;
|
|
821
|
-
/**
|
|
822
|
-
* Load all DDL **values** from the catalog store (keys discarded).
|
|
823
|
-
* Used to restore persisted tables on startup and by tests asserting persisted DDL.
|
|
824
|
-
* Note: this returns table, view, AND materialized-view entries intermixed —
|
|
825
|
-
* {@link rehydrateCatalog} uses {@link loadCatalogEntries} (keys retained) to
|
|
826
|
-
* classify them. Meta entries (e.g. the clean-shutdown marker) are not DDL
|
|
827
|
-
* and are filtered out.
|
|
828
|
-
*/
|
|
829
|
-
loadAllDDL(): Promise<string[]>;
|
|
830
|
-
/**
|
|
831
|
-
* Load every catalog entry as `{ key, ddl }`. Unlike {@link loadAllDDL} (values
|
|
832
|
-
* only) this retains the key so {@link rehydrateCatalog} can classify each entry
|
|
833
|
-
* (table / view / materialized view) by its reserved key prefix.
|
|
834
|
-
*/
|
|
835
|
-
private loadCatalogEntries;
|
|
836
|
-
/**
|
|
837
|
-
* Rehydrate the persisted catalog into the in-memory schema manager, in
|
|
838
|
-
* dependency order.
|
|
839
|
-
*
|
|
840
|
-
* Establishes the engine schema-change subscription up front (so a reopened DB
|
|
841
|
-
* persists subsequent DDL even when its first post-reopen statement is a view/MV,
|
|
842
|
-
* which never routes through a module hook — all the lazy subscription points are
|
|
843
|
-
* table hooks). Then loads every catalog entry once, classifies each by its key
|
|
844
|
-
* prefix into {tables, views, materialized views}, and imports in three phases:
|
|
845
|
-
*
|
|
846
|
-
* 1. **Tables** — `importCatalog` (connect to existing storage; refresh connected
|
|
847
|
-
* `StoreTable` schemas).
|
|
848
|
-
* 2. **Views** — `importCatalog` (engine silent-register; body validation deferred
|
|
849
|
-
* to query time, so order among views — and view-over-MV / view-over-view —
|
|
850
|
-
* does not matter, and no schema-change event fires → phase 2 writes nothing).
|
|
851
|
-
* 3. **Materialized views** — `importCatalog` per entry (engine re-materialize:
|
|
852
|
-
* rebuilds the memory backing from current source data, re-registers row-time
|
|
853
|
-
* maintenance, re-runs the eligibility gate — the same core the create emitter
|
|
854
|
-
* uses, but silent: no `materialized_view_added` fires, so phase 3 writes
|
|
855
|
-
* nothing back to the catalog). A store-hosted backing that phase 1 already
|
|
856
|
-
* rehydrated is **adopted without the refill** when the engine's adopt gates
|
|
857
|
-
* pass — see the clean-shutdown marker below.
|
|
858
|
-
*
|
|
859
|
-
* **Clean-shutdown marker.** Before anything loads, the reserved
|
|
860
|
-
* `\x00meta\x00clean_shutdown` catalog entry (written by {@link closeAll} after
|
|
861
|
-
* every batch flushed) is consumed: parsed into `{ trusted, staleAtClose }`, then
|
|
862
|
-
* **deleted immediately** — single-use, so a crash later in this session (or a
|
|
863
|
-
* second rehydrate without an intervening clean close) is detected at the next open
|
|
864
|
-
* and every adopt falls back to the always-correct drop+refill, self-healing any
|
|
865
|
-
* crash-window divergence (coordinated commit is not 2PC across stores). The marker
|
|
866
|
-
* payload is the JSON set of MVs that were **stale-at-close** (row-time maintenance
|
|
867
|
-
* detached, so the durable backing may be behind); phase 3 withholds trust per-entry
|
|
868
|
-
* for those — `trustBackings: trusted && !staleAtClose.has(name)` — so a
|
|
869
|
-
* stale-at-close MV refills (recomputing content and re-arming maintenance) while
|
|
870
|
-
* every live-at-close MV keeps the fast path. The one shared `adoptedBackings` set
|
|
871
|
-
* composes across fixpoint rounds (an upstream MV adopted in round 1 enables its
|
|
872
|
-
* dependent in round 2, while a refilled — or stale-at-close — upstream is never
|
|
873
|
-
* added to it, forcing dependents to refill).
|
|
874
|
-
*
|
|
875
|
-
* **MV-over-MV ordering** is handled by a fixpoint retry rather than a static topo
|
|
876
|
-
* sort: an MV's resolved `sourceTables` are computed at import time, not serialized
|
|
877
|
-
* in the DDL, so they are unavailable before import. Each round passes the names of
|
|
878
|
-
* every OTHER still-pending MV entry as `pendingDerivations`; the engine defers any
|
|
879
|
-
* entry whose body reads one (its source already pre-exists as a phase-1 plain
|
|
880
|
-
* table, so the body would otherwise plan against content the upstream's own import
|
|
881
|
-
* may be about to replace). The loop repeats while any MV makes progress — robust to
|
|
882
|
-
* arbitrary nesting depth. A genuinely unbuildable MV — a missing (e.g. memory)
|
|
883
|
-
* source, or an unresolvable cycle — makes no progress in a round and is recorded in
|
|
884
|
-
* `errors`.
|
|
885
|
-
*
|
|
886
|
-
* Per-entry errors in any phase are collected (not fatal) so one bad object does not
|
|
887
|
-
* abort the rest.
|
|
888
|
-
*
|
|
889
|
-
* Call after `db.registerModule()` (and `db.setDefaultVtabName()` if DDL may lack a
|
|
890
|
-
* USING clause).
|
|
891
|
-
*/
|
|
892
|
-
rehydrateCatalog(db: Database): Promise<RehydrationResult>;
|
|
893
|
-
/**
|
|
894
|
-
* Consume the clean-shutdown marker, deleting it in the same breath (single-use).
|
|
895
|
-
*
|
|
896
|
-
* Returns `{ trusted, staleAtClose }`:
|
|
897
|
-
* - `trusted` — the marker was present AND its payload parsed as a string array.
|
|
898
|
-
* Absence (a fresh store, a crash, or a prior rehydrate without an intervening
|
|
899
|
-
* {@link closeAll}) yields `false`, so every adopt this session falls back to
|
|
900
|
-
* refill.
|
|
901
|
-
* - `staleAtClose` — the qualified lowercased `schema.mv` names that were
|
|
902
|
-
* stale-at-close (written by {@link closeAll}); those MVs refill even under trust.
|
|
903
|
-
*
|
|
904
|
-
* Conservative parse: any unparseable / wrong-shape payload (including a legacy
|
|
905
|
-
* bare `'1'`, which parses to a number, not an array) degrades to
|
|
906
|
-
* `{ trusted: false, staleAtClose: ∅ }` — refill everything — rather than
|
|
907
|
-
* trust-everything. The marker is deleted regardless of parse outcome.
|
|
908
|
-
*/
|
|
909
|
-
private consumeCleanShutdownMarker;
|
|
910
|
-
/**
|
|
911
|
-
* Remove DDL from the catalog store when a table is dropped.
|
|
912
|
-
*/
|
|
913
|
-
removeTableDDL(schemaName: string, tableName: string): Promise<void>;
|
|
914
|
-
/**
|
|
915
|
-
* Persist a plain view's catalog entry (DDL via `generateViewDDL`), keyed by its
|
|
916
|
-
* reserved view prefix. Compare-write (skip identical) — see
|
|
917
|
-
* {@link persistObjectCatalogEntryIfChanged}.
|
|
918
|
-
*/
|
|
919
|
-
saveViewDDL(view: ViewSchema): Promise<void>;
|
|
920
|
-
/** Remove a plain view's catalog entry (on DROP VIEW). */
|
|
921
|
-
removeViewDDL(schemaName: string, viewName: string): Promise<void>;
|
|
922
|
-
/**
|
|
923
|
-
* Persist a materialized view's catalog entry (DDL via `generateMaintainedTableDDL`
|
|
924
|
-
* over the maintained table — the unified record), keyed by its reserved MV
|
|
925
|
-
* prefix. Compare-write (skip identical) — see
|
|
926
|
-
* {@link persistObjectCatalogEntryIfChanged}.
|
|
927
|
-
*/
|
|
928
|
-
saveMaterializedViewDDL(mv: MaintainedTableSchema): Promise<void>;
|
|
929
|
-
/** Remove a materialized view's catalog entry (on DROP MATERIALIZED VIEW). */
|
|
930
|
-
removeMaterializedViewDDL(schemaName: string, mvName: string): Promise<void>;
|
|
931
|
-
/**
|
|
932
|
-
* Pre-flight veto (see `VirtualTableModule.assertCatalogObjectPersistable`): refuse a
|
|
933
|
-
* view / materialized view whose catalog entry this module could not durably write.
|
|
934
|
-
*
|
|
935
|
-
* It runs exactly the derivation the write path runs — {@link viewCatalogEntry} /
|
|
936
|
-
* {@link maintainedViewCatalogEntry} build the key (rejecting an unencodable
|
|
937
|
-
* identifier) and {@link assertPersistableDdlText} checks the generated DDL text —
|
|
938
|
-
* so the veto and the write cannot disagree about what is persistable. It is the only
|
|
939
|
-
* synchronous path a rejection can travel: the actual save is chained onto
|
|
940
|
-
* `persistQueue` behind a `SchemaChangeNotifier` listener, and both layers swallow.
|
|
941
233
|
*
|
|
942
|
-
*
|
|
943
|
-
*
|
|
944
|
-
* first `create`/`connect`/`alterTable`/`rehydrateCatalog`). A module registered but
|
|
945
|
-
* never handed a `db` writes nothing, so vetoing there would reject a definition that
|
|
946
|
-
* loses nothing. The gate becomes removable if persistence is ever made unconditional
|
|
947
|
-
* (`bug-store-untouched-table-and-early-view-never-persisted`).
|
|
234
|
+
* The request is sized from the table's own maintained row count when the planner
|
|
235
|
+
* supplied no estimate — see {@link sizeRequestFromLiveCount}.
|
|
948
236
|
*/
|
|
949
|
-
|
|
950
|
-
/**
|
|
951
|
-
* Compare-write a view/MV catalog entry: write only when the entry is absent or its
|
|
952
|
-
* DDL differs from `newDDL` (skip identical). Unlike the table path's
|
|
953
|
-
* {@link persistCatalogIfChanged} there is **no** absent→skip self-filter — a view/MV
|
|
954
|
-
* belongs to this db's catalog unconditionally (one module instance serves one
|
|
955
|
-
* Database). Skipping identical writes makes any event whose regenerated DDL is
|
|
956
|
-
* unchanged (e.g. a `materialized_view_refreshed`) a no-op, so a second consecutive
|
|
957
|
-
* reopen yields identical catalog bytes. (Rehydration itself fires no view/MV events
|
|
958
|
-
* at all — `importCatalog` is silent.)
|
|
959
|
-
*/
|
|
960
|
-
private persistObjectCatalogEntryIfChanged;
|
|
961
|
-
/**
|
|
962
|
-
* Parse module configuration from vtab args.
|
|
963
|
-
*/
|
|
964
|
-
private parseConfig;
|
|
965
|
-
/**
|
|
966
|
-
* Subscribe (once) to the engine's `SchemaChangeNotifier` so catalog-only
|
|
967
|
-
* mutations that bypass `module.alterTable` — notably `ALTER … SET TAGS` and the
|
|
968
|
-
* programmatic `setTableTags`/`setColumnTags`/`setConstraintTags` — still re-persist
|
|
969
|
-
* the table's catalog DDL. Called lazily from the first `create`/`connect`/
|
|
970
|
-
* `alterTable` hook that hands us a `db`.
|
|
971
|
-
*
|
|
972
|
-
* One `StoreModule` instance is assumed to serve one `Database`. A later hook
|
|
973
|
-
* carrying a *different* `db` keeps the existing subscription (multi-database
|
|
974
|
-
* sharing of a single module instance is out of scope) and logs.
|
|
975
|
-
*/
|
|
976
|
-
private ensureSchemaSubscription;
|
|
977
|
-
/**
|
|
978
|
-
* Engine schema-change listener. Persists the catalog incrementally for the events
|
|
979
|
-
* that bypass `module.alterTable` / `module.destroy`:
|
|
980
|
-
*
|
|
981
|
-
* - `table_modified` — every catalog-only tag swap (and the redundant follow-up a
|
|
982
|
-
* structural ALTER fires). Keeps a connected `StoreTable`'s cached schema consistent
|
|
983
|
-
* (SET TAGS does not call `updateSchema`) then read-compare-writes the table bundle.
|
|
984
|
-
* - `view_added` / `view_modified` / `view_removed` — plain `CREATE`/`ALTER … SET TAGS`/
|
|
985
|
-
* `DROP VIEW` (the engine fires these from the runtime emitters).
|
|
986
|
-
* - `materialized_view_added` / `_modified` / `_refreshed` / `_removed` — MV lifecycle.
|
|
987
|
-
* Like `table_modified`, the `_added`/`_modified`/`_refreshed` arms also synchronously
|
|
988
|
-
* refresh the connected `StoreTable`'s cached schema so a tag change (e.g.
|
|
989
|
-
* `quereus.sync.replicate`) takes effect immediately without reopen.
|
|
990
|
-
*
|
|
991
|
-
* Unlike the table path there is **no** catalog-absent self-filter for view/MV
|
|
992
|
-
* add/remove: one `StoreModule` instance serves one `Database`, so that database's
|
|
993
|
-
* views/MVs belong in its catalog unconditionally. A MEMORY-hosted maintained table
|
|
994
|
-
* fires `table_added`/`table_removed`/`table_modified` like any table; those stay
|
|
995
|
-
* ignored (`table_added`/`table_removed` fall through; its `table_modified` is
|
|
996
|
-
* catalog-absent → skipped), so only the MV entry persists for it. A STORE-hosted
|
|
997
|
-
* maintained table additionally persists its own table bundle through the ordinary
|
|
998
|
-
* store-table machinery (which phase-1 rehydrate connects for the adopt fast path).
|
|
999
|
-
*
|
|
1000
|
-
* Synchronous by contract (`notifyChange` does not await listeners); every async write
|
|
1001
|
-
* rides `persistQueue`, drained by `closeAll`/`whenCatalogPersisted`.
|
|
1002
|
-
*
|
|
1003
|
-
* After dispatching the event's own catalog persistence, the listener recomputes the
|
|
1004
|
-
* durable stale-MV set and compare-writes it (see {@link persistStaleMvSetIfChanged}).
|
|
1005
|
-
* Because the engine's MV manager subscribes to the same notifier in the `Database`
|
|
1006
|
-
* constructor — before this lazy subscription — its listener runs first, so the
|
|
1007
|
-
* `derivation.stale` flags are already current when this recompute reads them.
|
|
1008
|
-
*/
|
|
1009
|
-
private onEngineSchemaChange;
|
|
1010
|
-
/** Dispatch a single engine schema-change event to its catalog-persistence arm. */
|
|
1011
|
-
private dispatchSchemaChange;
|
|
1012
|
-
/**
|
|
1013
|
-
* The qualified lowercased `schema.mv` names of every maintained table currently
|
|
1014
|
-
* marked `derivation.stale` — an MV whose row-time maintenance detached mid-session
|
|
1015
|
-
* (a body-relevant `table_modified`/`table_removed` on a source, or a cascade
|
|
1016
|
-
* backing-invalidation), so its durable backing may be behind. The single source of
|
|
1017
|
-
* truth for both the clean-shutdown marker payload and the durable stale-MV set.
|
|
1018
|
-
*
|
|
1019
|
-
* No subscribed db ⇒ the empty set: every path that can mark an MV stale requires a
|
|
1020
|
-
* session in which this module observed the db (a store source create/connect or
|
|
1021
|
-
* `rehydrateCatalog`, both of which subscribe), so a session without `subscribedDb`
|
|
1022
|
-
* never detached any persisted MV's maintenance. Memory-backed MVs that appear here
|
|
1023
|
-
* are harmless — their catalog entries always refill (no phase-1 pre-existing
|
|
1024
|
-
* backing), so withholding trust from them is a no-op.
|
|
1025
|
-
*/
|
|
1026
|
-
private computeStaleMvSet;
|
|
1027
|
-
/**
|
|
1028
|
-
* Recompute the durable stale-MV set and, only when it differs from the last value
|
|
1029
|
-
* enqueued this subscription ({@link lastPersistedStaleMvs}), enqueue a `sync: true`
|
|
1030
|
-
* point-write of it onto {@link persistQueue}. The compare-skip keeps an unrelated
|
|
1031
|
-
* `table_modified` (a tag swap that changes no MV's staleness) from costing an fsync.
|
|
1032
|
-
*
|
|
1033
|
-
* The recompute reads `derivation.stale` synchronously (the flags are current at
|
|
1034
|
-
* listener-dispatch time); the field is updated synchronously at enqueue time, and
|
|
1035
|
-
* `persistQueue` serializes the writes in order, so the field always names the last
|
|
1036
|
-
* enqueued value. Riding `persistQueue` (rather than a bare `put`) also serializes
|
|
1037
|
-
* this `sync` behind the triggering event's own source-DDL compare-write, so the
|
|
1038
|
-
* stale-set becomes durable no-later-than the source DDL that caused the staleness —
|
|
1039
|
-
* the ordering the adopt soundness argument depends on.
|
|
1040
|
-
*/
|
|
1041
|
-
private persistStaleMvSetIfChanged;
|
|
1042
|
-
/**
|
|
1043
|
-
* Write the durable stale-MV set (`\x00meta\x00stale_mvs`) with `sync: true`. Unlike
|
|
1044
|
-
* the clean-shutdown marker this entry is persistent current-truth — overwritten as
|
|
1045
|
-
* staleness changes, never deleted — so a crash leaves the last synced value intact.
|
|
1046
|
-
* The `sync` mirrors the marker-consume delete's durability discipline (and carries
|
|
1047
|
-
* the same documented backend caveat: a backend without a durability knob no-ops it).
|
|
1048
|
-
*/
|
|
1049
|
-
private writeDurableStaleMvSet;
|
|
1050
|
-
/**
|
|
1051
|
-
* Read + conservative-parse the durable stale-MV set, mirroring
|
|
1052
|
-
* {@link consumeCleanShutdownMarker}'s parse discipline (but READ-only — never
|
|
1053
|
-
* deleted). Returns:
|
|
1054
|
-
* - `{ present: false }` — no entry on disk (a pre-atomic store, or an upgrade where
|
|
1055
|
-
* the capability was gained but no stale-set has been written yet) → the caller
|
|
1056
|
-
* falls back to the clean-shutdown marker path.
|
|
1057
|
-
* - `{ present: true, stale }` — the parsed set of qualified `schema.mv` names.
|
|
1058
|
-
* - `{ present: true, stale: null }` — a present but unparseable / wrong-shape payload
|
|
1059
|
-
* → the caller refills everything (the always-safe posture).
|
|
1060
|
-
*/
|
|
1061
|
-
private readDurableStaleMvSet;
|
|
1062
|
-
/**
|
|
1063
|
-
* Shared MV add/modify/refresh handling. Narrow defensively — a derivation-less
|
|
1064
|
-
* payload would be an engine bug, so skip. Otherwise, mirror `table_modified`:
|
|
1065
|
-
* synchronously refresh a connected `StoreTable`'s cached schema (so a tag change
|
|
1066
|
-
* such as `quereus.sync.replicate` takes effect immediately without reopen) before
|
|
1067
|
-
* enqueuing the catalog DDL persist.
|
|
1068
|
-
*/
|
|
1069
|
-
private refreshConnectedMaterializedView;
|
|
1070
|
-
/**
|
|
1071
|
-
* Append a catalog-persistence task to the serialized `persistQueue`, so successive
|
|
1072
|
-
* mutations (e.g. SET TAGS (a=1) then SET TAGS ()) apply in order and are drained by
|
|
1073
|
-
* `closeAll`/`whenCatalogPersisted` before the provider closes. Errors are
|
|
1074
|
-
* swallowed+logged to mirror `notifyChange`'s own try/catch contract — a listener
|
|
1075
|
-
* rejection must never escape.
|
|
1076
|
-
*/
|
|
1077
|
-
private enqueuePersist;
|
|
1078
|
-
/**
|
|
1079
|
-
* Read-compare-write the catalog DDL for a table that just fired `table_modified`.
|
|
1080
|
-
*
|
|
1081
|
-
* - **Absent** catalog entry → the table is not store-backed in this catalog (a
|
|
1082
|
-
* memory table in the same `db`, or a store table never persisted) → skip. This
|
|
1083
|
-
* self-filters foreign-module tables without relying on `vtabModule` identity
|
|
1084
|
-
* (which points at the isolation wrapper when wrapped).
|
|
1085
|
-
* - **Present** but identical DDL → skip (no redundant write). This is what makes a
|
|
1086
|
-
* structural ALTER — whose own `alterTable` already wrote the final DDL, then fires
|
|
1087
|
-
* `table_modified` with that same final schema — a no-op here (no double-write).
|
|
1088
|
-
* - **Present** and different DDL → re-persist (the tag swap; or a beneficial
|
|
1089
|
-
* propagated rewrite of a dependent store table).
|
|
1090
|
-
*/
|
|
1091
|
-
private persistCatalogIfChanged;
|
|
1092
|
-
/**
|
|
1093
|
-
* Resolve once all catalog writes queued by async schema-change listeners
|
|
1094
|
-
* (catalog-only tag swaps) have settled. A durability barrier: `closeAll` awaits
|
|
1095
|
-
* it internally; callers/tests that need the persisted catalog current without a
|
|
1096
|
-
* full close can await it directly. Never rejects — queued errors are logged in
|
|
1097
|
-
* the chain.
|
|
1098
|
-
*/
|
|
1099
|
-
whenCatalogPersisted(): Promise<void>;
|
|
237
|
+
getBestAccessPlan(db: Database, tableInfo: TableSchema, request: BestAccessPlanRequest): BestAccessPlanResult;
|
|
1100
238
|
/**
|
|
1101
239
|
* Close all stores.
|
|
1102
240
|
*/
|
|
1103
241
|
closeAll(): Promise<void>;
|
|
1104
|
-
/**
|
|
1105
|
-
* Get a table by schema and name.
|
|
1106
|
-
*/
|
|
1107
|
-
getTable(schemaName: string, tableName: string): StoreTable | undefined;
|
|
1108
242
|
}
|
|
1109
243
|
//# sourceMappingURL=store-module.d.ts.map
|