@pgsql/transform 18.15.3 → 18.16.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/esm/index.js +1 -1
- package/esm/transform.js +111 -0
- package/index.d.ts +1 -1
- package/index.js +3 -1
- package/package.json +2 -2
- package/transform.d.ts +14 -0
- package/transform.js +113 -0
package/esm/index.js
CHANGED
|
@@ -10,4 +10,4 @@ export { createRoleResult, createRoleVisitor, transformRoles, } from './role-tra
|
|
|
10
10
|
export { captureAstsFromSql, captureTransformAsts, firstDifference, normalizeParseTree, validateRoundTrip, } from './round-trip';
|
|
11
11
|
export { CLEAN_TREE_VOLATILE_KEYS, cleanTree, normalizeTree, trimDefElemBody, } from './round-trip-core';
|
|
12
12
|
export { SchemaRouter } from './router';
|
|
13
|
-
export { createPlpgsqlVisitor, createSqlVisitor, escapeRegexp, extractPgpmHeader, shouldTransformSchema, transformComments, transformJsonStringValues, transformNameList, transformPlpgsqlTypeAst, transformPlpgsqlTypeString, transformRelation, transformSchemaName, transformSql, transformSqlStatement, transformVerifyCalls, validateNoUntransformedSchemas, walkPlpgsqlForSchemas, } from './transform';
|
|
13
|
+
export { createPlpgsqlVisitor, createSqlVisitor, escapeRegexp, extractPgpmHeader, identityCastNamespace, shouldTransformSchema, transformComments, transformIdentityCastLiteral, transformJsonStringValues, transformNameList, transformPlpgsqlTypeAst, transformPlpgsqlTypeString, transformRelation, transformSchemaName, transformSql, transformSqlStatement, transformVerifyCalls, validateNoUntransformedSchemas, walkPlpgsqlForSchemas, } from './transform';
|
package/esm/transform.js
CHANGED
|
@@ -209,6 +209,98 @@ export function transformSchemaRefsInString(str, schemaMapping, result) {
|
|
|
209
209
|
}
|
|
210
210
|
return out;
|
|
211
211
|
}
|
|
212
|
+
/**
|
|
213
|
+
* Cast types whose string operand is an object reference rather than opaque
|
|
214
|
+
* text. `'sch.tbl'::regclass` is a relation the parser resolves, and the cast
|
|
215
|
+
* names the namespace it resolves in — so the reference can be routed from the
|
|
216
|
+
* cast, semantically, instead of pattern-matched. This reaches what the string
|
|
217
|
+
* passes cannot: a bare `'sch'::regnamespace` has no dot to match on.
|
|
218
|
+
*/
|
|
219
|
+
const IDENTITY_CAST_NAMESPACES = {
|
|
220
|
+
regclass: 'relation',
|
|
221
|
+
regcollation: 'unknown',
|
|
222
|
+
regconfig: 'unknown',
|
|
223
|
+
regdictionary: 'unknown',
|
|
224
|
+
regnamespace: 'schema',
|
|
225
|
+
regoper: 'unknown',
|
|
226
|
+
regoperator: 'unknown',
|
|
227
|
+
regproc: 'function',
|
|
228
|
+
regprocedure: 'function',
|
|
229
|
+
regtype: 'type'
|
|
230
|
+
};
|
|
231
|
+
/**
|
|
232
|
+
* The namespace a cast resolves its operand in, or `undefined` when the target
|
|
233
|
+
* type is not an object-identity type.
|
|
234
|
+
*/
|
|
235
|
+
export function identityCastNamespace(typeName) {
|
|
236
|
+
const names = typeName?.names;
|
|
237
|
+
if (!Array.isArray(names) || names.length === 0)
|
|
238
|
+
return undefined;
|
|
239
|
+
// Only `pg_catalog`-qualified (or unqualified) reg* types are the built-ins.
|
|
240
|
+
if (names.length > 1 && names[0]?.String?.sval !== 'pg_catalog')
|
|
241
|
+
return undefined;
|
|
242
|
+
const typeIdent = names[names.length - 1]?.String?.sval;
|
|
243
|
+
if (typeof typeIdent !== 'string')
|
|
244
|
+
return undefined;
|
|
245
|
+
return IDENTITY_CAST_NAMESPACES[typeIdent.toLowerCase()];
|
|
246
|
+
}
|
|
247
|
+
const IDENTITY_TOKEN = String.raw `(?:"(?:[^"]|"")*"|[^\s".,()[\]]+)`;
|
|
248
|
+
const BARE_IDENTITY_RE = new RegExp(`^\\s*(${IDENTITY_TOKEN})\\s*$`);
|
|
249
|
+
const QUALIFIED_IDENTITY_RE = new RegExp(`^\\s*(${IDENTITY_TOKEN})\\.([\\s\\S]+)$`);
|
|
250
|
+
function unquoteIdentifier(token) {
|
|
251
|
+
if (token.length > 1 && token.startsWith('"') && token.endsWith('"')) {
|
|
252
|
+
return token.slice(1, -1).replace(/""/g, '"');
|
|
253
|
+
}
|
|
254
|
+
return token;
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Route the object reference carried in the string operand of an identity
|
|
258
|
+
* cast. `ns` comes from the cast's target type.
|
|
259
|
+
*
|
|
260
|
+
* Unqualified operands (`'tbl'::regclass`) name no schema — they resolve
|
|
261
|
+
* through `search_path` — so they are returned unchanged.
|
|
262
|
+
*/
|
|
263
|
+
export function transformIdentityCastLiteral(sval, ns, schemaMapping, result) {
|
|
264
|
+
const router = asRouter(schemaMapping);
|
|
265
|
+
if (ns === 'schema') {
|
|
266
|
+
const bare = BARE_IDENTITY_RE.exec(sval);
|
|
267
|
+
if (!bare)
|
|
268
|
+
return sval;
|
|
269
|
+
const schemaName = unquoteIdentifier(bare[1]);
|
|
270
|
+
const newName = router.resolve(schemaName, undefined, 'schema');
|
|
271
|
+
if (!newName || newName === schemaName)
|
|
272
|
+
return sval;
|
|
273
|
+
result.schemasFound.add(schemaName);
|
|
274
|
+
result.schemasTransformed.set(schemaName, newName);
|
|
275
|
+
return QuoteUtils.quoteIdentifier(newName);
|
|
276
|
+
}
|
|
277
|
+
// `regprocedure` and `regoperator` carry an argument list after the name, and
|
|
278
|
+
// an argument type can itself be schema-qualified
|
|
279
|
+
// (`fn("my-schema".row_type)`), so the list is routed as ordinary schema refs.
|
|
280
|
+
const argsAt = sval.indexOf('(');
|
|
281
|
+
const head = argsAt === -1 ? sval : sval.slice(0, argsAt);
|
|
282
|
+
const args = argsAt === -1 ? '' : transformSchemaRefsInString(sval.slice(argsAt), router, result);
|
|
283
|
+
const qualified = QUALIFIED_IDENTITY_RE.exec(head);
|
|
284
|
+
if (!qualified)
|
|
285
|
+
return `${head}${args}`;
|
|
286
|
+
const schemaName = unquoteIdentifier(qualified[1]);
|
|
287
|
+
const objName = unquoteIdentifier(qualified[2].trim());
|
|
288
|
+
const target = router.resolveObject(schemaName, objName, ns);
|
|
289
|
+
if (!target)
|
|
290
|
+
return `${head}${args}`;
|
|
291
|
+
const rebound = target.name !== undefined && target.name !== objName;
|
|
292
|
+
const requalified = target.schema === null || (!!target.schema && target.schema !== schemaName);
|
|
293
|
+
if (!rebound && !requalified)
|
|
294
|
+
return `${head}${args}`;
|
|
295
|
+
result.schemasFound.add(schemaName);
|
|
296
|
+
const nameToken = QuoteUtils.quoteIdentifier(rebound ? target.name : objName);
|
|
297
|
+
if (target.schema === null)
|
|
298
|
+
return `${nameToken}${args}`;
|
|
299
|
+
if (target.schema && target.schema !== schemaName) {
|
|
300
|
+
result.schemasTransformed.set(schemaName, target.schema);
|
|
301
|
+
}
|
|
302
|
+
return `${QuoteUtils.quoteIdentifier(target.schema ?? schemaName)}.${nameToken}${args}`;
|
|
303
|
+
}
|
|
212
304
|
/**
|
|
213
305
|
* Create a SQL AST visitor that transforms schema names.
|
|
214
306
|
*
|
|
@@ -461,9 +553,28 @@ export function createSqlVisitor(schemaMapping, result, visitorOptions) {
|
|
|
461
553
|
A_Const: (path) => {
|
|
462
554
|
const node = path.node;
|
|
463
555
|
if (typeof node.sval?.sval === 'string' && node.sval.sval.includes('.')) {
|
|
556
|
+
if (!claimSite(result, node.sval, 'sval'))
|
|
557
|
+
return;
|
|
464
558
|
node.sval.sval = transformSchemaRefsInString(node.sval.sval, schemaMapping, result);
|
|
465
559
|
}
|
|
466
560
|
},
|
|
561
|
+
// Object identities carried as the operand of an identity cast
|
|
562
|
+
// ('sch.tbl'::regclass, 'sch.fn(uuid)'::regprocedure, 'sch'::regnamespace).
|
|
563
|
+
// The cast names the namespace, so these route through the same object
|
|
564
|
+
// routes as a RangeVar rather than through a string pattern — and the bare
|
|
565
|
+
// schema form, invisible to every string pass, routes here.
|
|
566
|
+
TypeCast: (path) => {
|
|
567
|
+
const node = path.node;
|
|
568
|
+
const sval = node?.arg?.A_Const?.sval;
|
|
569
|
+
if (typeof sval?.sval !== 'string')
|
|
570
|
+
return;
|
|
571
|
+
const ns = identityCastNamespace(node.typeName);
|
|
572
|
+
if (!ns)
|
|
573
|
+
return;
|
|
574
|
+
if (!claimSite(result, sval, 'sval'))
|
|
575
|
+
return;
|
|
576
|
+
sval.sval = transformIdentityCastLiteral(sval.sval, ns, router, result);
|
|
577
|
+
},
|
|
467
578
|
// Transform DefineStmt (CREATE TYPE schema.name, CREATE AGGREGATE schema.agg)
|
|
468
579
|
DefineStmt: (path) => {
|
|
469
580
|
const node = path.node;
|
package/index.d.ts
CHANGED
|
@@ -23,4 +23,4 @@ export { CLEAN_TREE_VOLATILE_KEYS, cleanTree, normalizeTree, trimDefElemBody, }
|
|
|
23
23
|
export type { ObjectNamespace, ObjectRoute, ObjectRouteTarget, RouteNamespace, RouteSpec, SchemaRoute, } from './router';
|
|
24
24
|
export { SchemaRouter } from './router';
|
|
25
25
|
export type { SchemaMappingInput, SchemaTransformPass, SchemaTransformResult, TransformSqlOptions, } from './transform';
|
|
26
|
-
export { createPlpgsqlVisitor, createSqlVisitor, escapeRegexp, extractPgpmHeader, shouldTransformSchema, transformComments, transformJsonStringValues, transformNameList, transformPlpgsqlTypeAst, transformPlpgsqlTypeString, transformRelation, transformSchemaName, transformSql, transformSqlStatement, transformVerifyCalls, validateNoUntransformedSchemas, walkPlpgsqlForSchemas, } from './transform';
|
|
26
|
+
export { createPlpgsqlVisitor, createSqlVisitor, escapeRegexp, extractPgpmHeader, identityCastNamespace, shouldTransformSchema, transformComments, transformIdentityCastLiteral, transformJsonStringValues, transformNameList, transformPlpgsqlTypeAst, transformPlpgsqlTypeString, transformRelation, transformSchemaName, transformSql, transformSqlStatement, transformVerifyCalls, validateNoUntransformedSchemas, walkPlpgsqlForSchemas, } from './transform';
|
package/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.walkPlpgsqlForSchemas = exports.validateNoUntransformedSchemas = exports.transformVerifyCalls = exports.transformSqlStatement = exports.transformSql = exports.transformSchemaName = exports.transformRelation = exports.transformPlpgsqlTypeString = exports.transformPlpgsqlTypeAst = exports.transformNameList = exports.transformJsonStringValues = exports.transformComments = exports.shouldTransformSchema = exports.extractPgpmHeader = exports.escapeRegexp = exports.createSqlVisitor = exports.createPlpgsqlVisitor = exports.SchemaRouter = exports.trimDefElemBody = exports.normalizeTree = exports.cleanTree = exports.CLEAN_TREE_VOLATILE_KEYS = exports.validateRoundTrip = exports.normalizeParseTree = exports.firstDifference = exports.captureTransformAsts = exports.captureAstsFromSql = exports.transformRoles = exports.createRoleVisitor = exports.createRoleResult = exports.RoleRouter = exports.restructureSql = exports.orderStatements = exports.qualifyUnqualified = exports.mergeInventories = exports.createQualifyVisitor = exports.collectCreatedObjects = exports.identityOf = exports.buildStatementGraph = exports.classifyStatements = exports.transformExtensions = exports.createExtensionVisitor = exports.createExtensionResult = exports.ExtensionRouter = exports.COMMON_EXTENSIONS = void 0;
|
|
3
|
+
exports.walkPlpgsqlForSchemas = exports.validateNoUntransformedSchemas = exports.transformVerifyCalls = exports.transformSqlStatement = exports.transformSql = exports.transformSchemaName = exports.transformRelation = exports.transformPlpgsqlTypeString = exports.transformPlpgsqlTypeAst = exports.transformNameList = exports.transformJsonStringValues = exports.transformIdentityCastLiteral = exports.transformComments = exports.shouldTransformSchema = exports.identityCastNamespace = exports.extractPgpmHeader = exports.escapeRegexp = exports.createSqlVisitor = exports.createPlpgsqlVisitor = exports.SchemaRouter = exports.trimDefElemBody = exports.normalizeTree = exports.cleanTree = exports.CLEAN_TREE_VOLATILE_KEYS = exports.validateRoundTrip = exports.normalizeParseTree = exports.firstDifference = exports.captureTransformAsts = exports.captureAstsFromSql = exports.transformRoles = exports.createRoleVisitor = exports.createRoleResult = exports.RoleRouter = exports.restructureSql = exports.orderStatements = exports.qualifyUnqualified = exports.mergeInventories = exports.createQualifyVisitor = exports.collectCreatedObjects = exports.identityOf = exports.buildStatementGraph = exports.classifyStatements = exports.transformExtensions = exports.createExtensionVisitor = exports.createExtensionResult = exports.ExtensionRouter = exports.COMMON_EXTENSIONS = void 0;
|
|
4
4
|
var extension_router_1 = require("./extension-router");
|
|
5
5
|
Object.defineProperty(exports, "COMMON_EXTENSIONS", { enumerable: true, get: function () { return extension_router_1.COMMON_EXTENSIONS; } });
|
|
6
6
|
Object.defineProperty(exports, "ExtensionRouter", { enumerable: true, get: function () { return extension_router_1.ExtensionRouter; } });
|
|
@@ -46,8 +46,10 @@ Object.defineProperty(exports, "createPlpgsqlVisitor", { enumerable: true, get:
|
|
|
46
46
|
Object.defineProperty(exports, "createSqlVisitor", { enumerable: true, get: function () { return transform_1.createSqlVisitor; } });
|
|
47
47
|
Object.defineProperty(exports, "escapeRegexp", { enumerable: true, get: function () { return transform_1.escapeRegexp; } });
|
|
48
48
|
Object.defineProperty(exports, "extractPgpmHeader", { enumerable: true, get: function () { return transform_1.extractPgpmHeader; } });
|
|
49
|
+
Object.defineProperty(exports, "identityCastNamespace", { enumerable: true, get: function () { return transform_1.identityCastNamespace; } });
|
|
49
50
|
Object.defineProperty(exports, "shouldTransformSchema", { enumerable: true, get: function () { return transform_1.shouldTransformSchema; } });
|
|
50
51
|
Object.defineProperty(exports, "transformComments", { enumerable: true, get: function () { return transform_1.transformComments; } });
|
|
52
|
+
Object.defineProperty(exports, "transformIdentityCastLiteral", { enumerable: true, get: function () { return transform_1.transformIdentityCastLiteral; } });
|
|
51
53
|
Object.defineProperty(exports, "transformJsonStringValues", { enumerable: true, get: function () { return transform_1.transformJsonStringValues; } });
|
|
52
54
|
Object.defineProperty(exports, "transformNameList", { enumerable: true, get: function () { return transform_1.transformNameList; } });
|
|
53
55
|
Object.defineProperty(exports, "transformPlpgsqlTypeAst", { enumerable: true, get: function () { return transform_1.transformPlpgsqlTypeAst; } });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pgsql/transform",
|
|
3
|
-
"version": "18.
|
|
3
|
+
"version": "18.16.0",
|
|
4
4
|
"author": "Constructive <developers@constructive.io>",
|
|
5
5
|
"description": "AST-based SQL transformation, qualification, classification and closure analysis for PostgreSQL",
|
|
6
6
|
"main": "index.js",
|
|
@@ -50,5 +50,5 @@
|
|
|
50
50
|
"classify",
|
|
51
51
|
"plpgsql"
|
|
52
52
|
],
|
|
53
|
-
"gitHead": "
|
|
53
|
+
"gitHead": "9ecd247f9f0ef696a95e1f582d7353eb6bb693d4"
|
|
54
54
|
}
|
package/transform.d.ts
CHANGED
|
@@ -123,6 +123,19 @@ export declare function transformRelation(relation: any, schemaMapping: SchemaMa
|
|
|
123
123
|
* followed by a dot are rewritten.
|
|
124
124
|
*/
|
|
125
125
|
export declare function transformSchemaRefsInString(str: string, schemaMapping: SchemaMappingInput, result: SchemaTransformResult): string;
|
|
126
|
+
/**
|
|
127
|
+
* The namespace a cast resolves its operand in, or `undefined` when the target
|
|
128
|
+
* type is not an object-identity type.
|
|
129
|
+
*/
|
|
130
|
+
export declare function identityCastNamespace(typeName: any): RouteNamespace | undefined;
|
|
131
|
+
/**
|
|
132
|
+
* Route the object reference carried in the string operand of an identity
|
|
133
|
+
* cast. `ns` comes from the cast's target type.
|
|
134
|
+
*
|
|
135
|
+
* Unqualified operands (`'tbl'::regclass`) name no schema — they resolve
|
|
136
|
+
* through `search_path` — so they are returned unchanged.
|
|
137
|
+
*/
|
|
138
|
+
export declare function transformIdentityCastLiteral(sval: string, ns: RouteNamespace, schemaMapping: SchemaMappingInput, result: SchemaTransformResult): string;
|
|
126
139
|
/**
|
|
127
140
|
* Create a SQL AST visitor that transforms schema names.
|
|
128
141
|
*
|
|
@@ -148,6 +161,7 @@ export declare function createSqlVisitor(schemaMapping: SchemaMappingInput, resu
|
|
|
148
161
|
CreateTrigStmt: (path: any) => void;
|
|
149
162
|
CommentStmt: (path: any) => void;
|
|
150
163
|
A_Const: (path: any) => void;
|
|
164
|
+
TypeCast: (path: any) => void;
|
|
151
165
|
DefineStmt: (path: any) => void;
|
|
152
166
|
CreateDomainStmt: (path: any) => void;
|
|
153
167
|
CreateEnumStmt: (path: any) => void;
|
package/transform.js
CHANGED
|
@@ -31,6 +31,8 @@ exports.transformNameList = transformNameList;
|
|
|
31
31
|
exports.transformSchemaNameField = transformSchemaNameField;
|
|
32
32
|
exports.transformRelation = transformRelation;
|
|
33
33
|
exports.transformSchemaRefsInString = transformSchemaRefsInString;
|
|
34
|
+
exports.identityCastNamespace = identityCastNamespace;
|
|
35
|
+
exports.transformIdentityCastLiteral = transformIdentityCastLiteral;
|
|
34
36
|
exports.createSqlVisitor = createSqlVisitor;
|
|
35
37
|
exports.validateNoUntransformedSchemas = validateNoUntransformedSchemas;
|
|
36
38
|
exports.createPlpgsqlVisitor = createPlpgsqlVisitor;
|
|
@@ -230,6 +232,98 @@ function transformSchemaRefsInString(str, schemaMapping, result) {
|
|
|
230
232
|
}
|
|
231
233
|
return out;
|
|
232
234
|
}
|
|
235
|
+
/**
|
|
236
|
+
* Cast types whose string operand is an object reference rather than opaque
|
|
237
|
+
* text. `'sch.tbl'::regclass` is a relation the parser resolves, and the cast
|
|
238
|
+
* names the namespace it resolves in — so the reference can be routed from the
|
|
239
|
+
* cast, semantically, instead of pattern-matched. This reaches what the string
|
|
240
|
+
* passes cannot: a bare `'sch'::regnamespace` has no dot to match on.
|
|
241
|
+
*/
|
|
242
|
+
const IDENTITY_CAST_NAMESPACES = {
|
|
243
|
+
regclass: 'relation',
|
|
244
|
+
regcollation: 'unknown',
|
|
245
|
+
regconfig: 'unknown',
|
|
246
|
+
regdictionary: 'unknown',
|
|
247
|
+
regnamespace: 'schema',
|
|
248
|
+
regoper: 'unknown',
|
|
249
|
+
regoperator: 'unknown',
|
|
250
|
+
regproc: 'function',
|
|
251
|
+
regprocedure: 'function',
|
|
252
|
+
regtype: 'type'
|
|
253
|
+
};
|
|
254
|
+
/**
|
|
255
|
+
* The namespace a cast resolves its operand in, or `undefined` when the target
|
|
256
|
+
* type is not an object-identity type.
|
|
257
|
+
*/
|
|
258
|
+
function identityCastNamespace(typeName) {
|
|
259
|
+
const names = typeName?.names;
|
|
260
|
+
if (!Array.isArray(names) || names.length === 0)
|
|
261
|
+
return undefined;
|
|
262
|
+
// Only `pg_catalog`-qualified (or unqualified) reg* types are the built-ins.
|
|
263
|
+
if (names.length > 1 && names[0]?.String?.sval !== 'pg_catalog')
|
|
264
|
+
return undefined;
|
|
265
|
+
const typeIdent = names[names.length - 1]?.String?.sval;
|
|
266
|
+
if (typeof typeIdent !== 'string')
|
|
267
|
+
return undefined;
|
|
268
|
+
return IDENTITY_CAST_NAMESPACES[typeIdent.toLowerCase()];
|
|
269
|
+
}
|
|
270
|
+
const IDENTITY_TOKEN = String.raw `(?:"(?:[^"]|"")*"|[^\s".,()[\]]+)`;
|
|
271
|
+
const BARE_IDENTITY_RE = new RegExp(`^\\s*(${IDENTITY_TOKEN})\\s*$`);
|
|
272
|
+
const QUALIFIED_IDENTITY_RE = new RegExp(`^\\s*(${IDENTITY_TOKEN})\\.([\\s\\S]+)$`);
|
|
273
|
+
function unquoteIdentifier(token) {
|
|
274
|
+
if (token.length > 1 && token.startsWith('"') && token.endsWith('"')) {
|
|
275
|
+
return token.slice(1, -1).replace(/""/g, '"');
|
|
276
|
+
}
|
|
277
|
+
return token;
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Route the object reference carried in the string operand of an identity
|
|
281
|
+
* cast. `ns` comes from the cast's target type.
|
|
282
|
+
*
|
|
283
|
+
* Unqualified operands (`'tbl'::regclass`) name no schema — they resolve
|
|
284
|
+
* through `search_path` — so they are returned unchanged.
|
|
285
|
+
*/
|
|
286
|
+
function transformIdentityCastLiteral(sval, ns, schemaMapping, result) {
|
|
287
|
+
const router = asRouter(schemaMapping);
|
|
288
|
+
if (ns === 'schema') {
|
|
289
|
+
const bare = BARE_IDENTITY_RE.exec(sval);
|
|
290
|
+
if (!bare)
|
|
291
|
+
return sval;
|
|
292
|
+
const schemaName = unquoteIdentifier(bare[1]);
|
|
293
|
+
const newName = router.resolve(schemaName, undefined, 'schema');
|
|
294
|
+
if (!newName || newName === schemaName)
|
|
295
|
+
return sval;
|
|
296
|
+
result.schemasFound.add(schemaName);
|
|
297
|
+
result.schemasTransformed.set(schemaName, newName);
|
|
298
|
+
return quotes_1.QuoteUtils.quoteIdentifier(newName);
|
|
299
|
+
}
|
|
300
|
+
// `regprocedure` and `regoperator` carry an argument list after the name, and
|
|
301
|
+
// an argument type can itself be schema-qualified
|
|
302
|
+
// (`fn("my-schema".row_type)`), so the list is routed as ordinary schema refs.
|
|
303
|
+
const argsAt = sval.indexOf('(');
|
|
304
|
+
const head = argsAt === -1 ? sval : sval.slice(0, argsAt);
|
|
305
|
+
const args = argsAt === -1 ? '' : transformSchemaRefsInString(sval.slice(argsAt), router, result);
|
|
306
|
+
const qualified = QUALIFIED_IDENTITY_RE.exec(head);
|
|
307
|
+
if (!qualified)
|
|
308
|
+
return `${head}${args}`;
|
|
309
|
+
const schemaName = unquoteIdentifier(qualified[1]);
|
|
310
|
+
const objName = unquoteIdentifier(qualified[2].trim());
|
|
311
|
+
const target = router.resolveObject(schemaName, objName, ns);
|
|
312
|
+
if (!target)
|
|
313
|
+
return `${head}${args}`;
|
|
314
|
+
const rebound = target.name !== undefined && target.name !== objName;
|
|
315
|
+
const requalified = target.schema === null || (!!target.schema && target.schema !== schemaName);
|
|
316
|
+
if (!rebound && !requalified)
|
|
317
|
+
return `${head}${args}`;
|
|
318
|
+
result.schemasFound.add(schemaName);
|
|
319
|
+
const nameToken = quotes_1.QuoteUtils.quoteIdentifier(rebound ? target.name : objName);
|
|
320
|
+
if (target.schema === null)
|
|
321
|
+
return `${nameToken}${args}`;
|
|
322
|
+
if (target.schema && target.schema !== schemaName) {
|
|
323
|
+
result.schemasTransformed.set(schemaName, target.schema);
|
|
324
|
+
}
|
|
325
|
+
return `${quotes_1.QuoteUtils.quoteIdentifier(target.schema ?? schemaName)}.${nameToken}${args}`;
|
|
326
|
+
}
|
|
233
327
|
/**
|
|
234
328
|
* Create a SQL AST visitor that transforms schema names.
|
|
235
329
|
*
|
|
@@ -482,9 +576,28 @@ function createSqlVisitor(schemaMapping, result, visitorOptions) {
|
|
|
482
576
|
A_Const: (path) => {
|
|
483
577
|
const node = path.node;
|
|
484
578
|
if (typeof node.sval?.sval === 'string' && node.sval.sval.includes('.')) {
|
|
579
|
+
if (!claimSite(result, node.sval, 'sval'))
|
|
580
|
+
return;
|
|
485
581
|
node.sval.sval = transformSchemaRefsInString(node.sval.sval, schemaMapping, result);
|
|
486
582
|
}
|
|
487
583
|
},
|
|
584
|
+
// Object identities carried as the operand of an identity cast
|
|
585
|
+
// ('sch.tbl'::regclass, 'sch.fn(uuid)'::regprocedure, 'sch'::regnamespace).
|
|
586
|
+
// The cast names the namespace, so these route through the same object
|
|
587
|
+
// routes as a RangeVar rather than through a string pattern — and the bare
|
|
588
|
+
// schema form, invisible to every string pass, routes here.
|
|
589
|
+
TypeCast: (path) => {
|
|
590
|
+
const node = path.node;
|
|
591
|
+
const sval = node?.arg?.A_Const?.sval;
|
|
592
|
+
if (typeof sval?.sval !== 'string')
|
|
593
|
+
return;
|
|
594
|
+
const ns = identityCastNamespace(node.typeName);
|
|
595
|
+
if (!ns)
|
|
596
|
+
return;
|
|
597
|
+
if (!claimSite(result, sval, 'sval'))
|
|
598
|
+
return;
|
|
599
|
+
sval.sval = transformIdentityCastLiteral(sval.sval, ns, router, result);
|
|
600
|
+
},
|
|
488
601
|
// Transform DefineStmt (CREATE TYPE schema.name, CREATE AGGREGATE schema.agg)
|
|
489
602
|
DefineStmt: (path) => {
|
|
490
603
|
const node = path.node;
|