@pgsql/transform 18.4.1 → 18.5.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/facts.js +41 -1
- package/facts.js +40 -0
- package/package.json +2 -2
package/esm/facts.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { walk as walkSql } from '@pgsql/traverse';
|
|
2
|
-
import { transformSync, walk as walkPlpgsql } from 'plpgsql-parser';
|
|
2
|
+
import { parseSql, transformSync, walk as walkPlpgsql } from 'plpgsql-parser';
|
|
3
3
|
const SECURITY_TAGS = new Set([
|
|
4
4
|
'CreatePolicyStmt',
|
|
5
5
|
'AlterPolicyStmt',
|
|
@@ -241,6 +241,43 @@ function classifyOne(nodeTag, node) {
|
|
|
241
241
|
collectRoles(node, facts.roles);
|
|
242
242
|
return facts;
|
|
243
243
|
}
|
|
244
|
+
/** Read a `CreateFunctionStmt` DefElem option's scalar/list value. */
|
|
245
|
+
function functionOption(node, defname) {
|
|
246
|
+
for (const opt of node.options ?? []) {
|
|
247
|
+
if (opt?.DefElem?.defname === defname)
|
|
248
|
+
return opt.DefElem.arg;
|
|
249
|
+
}
|
|
250
|
+
return undefined;
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Collect references from a `LANGUAGE sql` function body supplied as a string
|
|
254
|
+
* literal (`AS $$ ... $$`). That body is an opaque String node the AST walker
|
|
255
|
+
* never parses, so — mirroring the schema transformer's body rewrite — parse
|
|
256
|
+
* it standalone and walk each statement with the facts visitor. The standard
|
|
257
|
+
* `BEGIN ATOMIC` / `RETURN` `sql_body` form is already part of the AST and is
|
|
258
|
+
* covered by the outer walk, so only the string form needs this.
|
|
259
|
+
*/
|
|
260
|
+
function collectSqlBodyReferences(node, facts) {
|
|
261
|
+
const language = functionOption(node, 'language')?.String?.sval;
|
|
262
|
+
if (typeof language !== 'string' || language.toLowerCase() !== 'sql')
|
|
263
|
+
return;
|
|
264
|
+
const asArg = functionOption(node, 'as');
|
|
265
|
+
const items = asArg?.List?.items ?? [];
|
|
266
|
+
const body = items[0]?.String?.sval;
|
|
267
|
+
if (typeof body !== 'string')
|
|
268
|
+
return;
|
|
269
|
+
try {
|
|
270
|
+
const stmts = parseSql(body)?.stmts ?? [];
|
|
271
|
+
const visitor = createFactsVisitor(facts, facts.bodyReferences);
|
|
272
|
+
for (const stmt of stmts) {
|
|
273
|
+
if (stmt?.stmt)
|
|
274
|
+
walkSql(stmt.stmt, visitor);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
catch {
|
|
278
|
+
// A non-parseable body (C symbol name, etc.) contributes no references.
|
|
279
|
+
}
|
|
280
|
+
}
|
|
244
281
|
/**
|
|
245
282
|
* Classify each top-level statement in a SQL script into {@link StatementFacts}.
|
|
246
283
|
*
|
|
@@ -260,6 +297,9 @@ export function classifyStatements(sql) {
|
|
|
260
297
|
if (stmtNode) {
|
|
261
298
|
walkSql(stmtNode, createFactsVisitor(facts));
|
|
262
299
|
}
|
|
300
|
+
if (nodeTag === 'CreateFunctionStmt') {
|
|
301
|
+
collectSqlBodyReferences(node, facts);
|
|
302
|
+
}
|
|
263
303
|
allFacts.push(facts);
|
|
264
304
|
}
|
|
265
305
|
for (const fn of ctx.functions ?? []) {
|
package/facts.js
CHANGED
|
@@ -244,6 +244,43 @@ function classifyOne(nodeTag, node) {
|
|
|
244
244
|
collectRoles(node, facts.roles);
|
|
245
245
|
return facts;
|
|
246
246
|
}
|
|
247
|
+
/** Read a `CreateFunctionStmt` DefElem option's scalar/list value. */
|
|
248
|
+
function functionOption(node, defname) {
|
|
249
|
+
for (const opt of node.options ?? []) {
|
|
250
|
+
if (opt?.DefElem?.defname === defname)
|
|
251
|
+
return opt.DefElem.arg;
|
|
252
|
+
}
|
|
253
|
+
return undefined;
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Collect references from a `LANGUAGE sql` function body supplied as a string
|
|
257
|
+
* literal (`AS $$ ... $$`). That body is an opaque String node the AST walker
|
|
258
|
+
* never parses, so — mirroring the schema transformer's body rewrite — parse
|
|
259
|
+
* it standalone and walk each statement with the facts visitor. The standard
|
|
260
|
+
* `BEGIN ATOMIC` / `RETURN` `sql_body` form is already part of the AST and is
|
|
261
|
+
* covered by the outer walk, so only the string form needs this.
|
|
262
|
+
*/
|
|
263
|
+
function collectSqlBodyReferences(node, facts) {
|
|
264
|
+
const language = functionOption(node, 'language')?.String?.sval;
|
|
265
|
+
if (typeof language !== 'string' || language.toLowerCase() !== 'sql')
|
|
266
|
+
return;
|
|
267
|
+
const asArg = functionOption(node, 'as');
|
|
268
|
+
const items = asArg?.List?.items ?? [];
|
|
269
|
+
const body = items[0]?.String?.sval;
|
|
270
|
+
if (typeof body !== 'string')
|
|
271
|
+
return;
|
|
272
|
+
try {
|
|
273
|
+
const stmts = (0, plpgsql_parser_1.parseSql)(body)?.stmts ?? [];
|
|
274
|
+
const visitor = createFactsVisitor(facts, facts.bodyReferences);
|
|
275
|
+
for (const stmt of stmts) {
|
|
276
|
+
if (stmt?.stmt)
|
|
277
|
+
(0, traverse_1.walk)(stmt.stmt, visitor);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
catch {
|
|
281
|
+
// A non-parseable body (C symbol name, etc.) contributes no references.
|
|
282
|
+
}
|
|
283
|
+
}
|
|
247
284
|
/**
|
|
248
285
|
* Classify each top-level statement in a SQL script into {@link StatementFacts}.
|
|
249
286
|
*
|
|
@@ -263,6 +300,9 @@ function classifyStatements(sql) {
|
|
|
263
300
|
if (stmtNode) {
|
|
264
301
|
(0, traverse_1.walk)(stmtNode, createFactsVisitor(facts));
|
|
265
302
|
}
|
|
303
|
+
if (nodeTag === 'CreateFunctionStmt') {
|
|
304
|
+
collectSqlBodyReferences(node, facts);
|
|
305
|
+
}
|
|
266
306
|
allFacts.push(facts);
|
|
267
307
|
}
|
|
268
308
|
for (const fn of ctx.functions ?? []) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pgsql/transform",
|
|
3
|
-
"version": "18.
|
|
3
|
+
"version": "18.5.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",
|
|
@@ -49,5 +49,5 @@
|
|
|
49
49
|
"classify",
|
|
50
50
|
"plpgsql"
|
|
51
51
|
],
|
|
52
|
-
"gitHead": "
|
|
52
|
+
"gitHead": "a2b52f04fca42931150378d5b4966b7d5a922de6"
|
|
53
53
|
}
|