pgsql-deparser 17.8.1 → 17.8.2
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/deparser.d.ts +2 -0
- package/deparser.js +486 -149
- package/esm/deparser.js +486 -149
- package/package.json +3 -3
- package/visitors/base.d.ts +1 -0
package/deparser.js
CHANGED
|
@@ -4,6 +4,62 @@ exports.Deparser = void 0;
|
|
|
4
4
|
const sql_formatter_1 = require("./utils/sql-formatter");
|
|
5
5
|
const quote_utils_1 = require("./utils/quote-utils");
|
|
6
6
|
const list_utils_1 = require("./utils/list-utils");
|
|
7
|
+
/**
|
|
8
|
+
* List of real PostgreSQL built-in types as they appear in pg_catalog.pg_type.typname.
|
|
9
|
+
* These are stored in lowercase in PostgreSQL system catalogs.
|
|
10
|
+
* Use these for lookups, validations, or introspection logic.
|
|
11
|
+
*/
|
|
12
|
+
const pgCatalogTypes = [
|
|
13
|
+
// Integers
|
|
14
|
+
'int2', // smallint
|
|
15
|
+
'int4', // integer
|
|
16
|
+
'int8', // bigint
|
|
17
|
+
// Floating-point & numeric
|
|
18
|
+
'float4', // real
|
|
19
|
+
'float8', // double precision
|
|
20
|
+
'numeric', // arbitrary precision (aka "decimal")
|
|
21
|
+
// Text & string
|
|
22
|
+
'varchar', // variable-length string
|
|
23
|
+
'char', // internal one-byte type (used in special cases)
|
|
24
|
+
'bpchar', // blank-padded char(n)
|
|
25
|
+
'text', // unlimited string
|
|
26
|
+
'bool', // boolean
|
|
27
|
+
// Dates & times
|
|
28
|
+
'date', // calendar date
|
|
29
|
+
'time', // time without time zone
|
|
30
|
+
'timetz', // time with time zone
|
|
31
|
+
'timestamp', // timestamp without time zone
|
|
32
|
+
'timestamptz', // timestamp with time zone
|
|
33
|
+
'interval', // duration
|
|
34
|
+
// Binary & structured
|
|
35
|
+
'bytea', // binary data
|
|
36
|
+
'uuid', // universally unique identifier
|
|
37
|
+
// JSON & XML
|
|
38
|
+
'json', // textual JSON
|
|
39
|
+
'jsonb', // binary JSON
|
|
40
|
+
'xml', // XML format
|
|
41
|
+
// Money & bitstrings
|
|
42
|
+
'money', // currency value
|
|
43
|
+
'bit', // fixed-length bit string
|
|
44
|
+
'varbit', // variable-length bit string
|
|
45
|
+
// Network types
|
|
46
|
+
'inet', // IPv4 or IPv6 address
|
|
47
|
+
'cidr', // network address
|
|
48
|
+
'macaddr', // MAC address (6 bytes)
|
|
49
|
+
'macaddr8' // MAC address (8 bytes)
|
|
50
|
+
];
|
|
51
|
+
/**
|
|
52
|
+
* Parser-level type aliases accepted by PostgreSQL SQL syntax,
|
|
53
|
+
* but not present in pg_catalog.pg_type. These are resolved to
|
|
54
|
+
* real types during parsing and never appear in introspection.
|
|
55
|
+
*/
|
|
56
|
+
const pgCatalogTypeAliases = [
|
|
57
|
+
['numeric', ['decimal', 'dec']],
|
|
58
|
+
['int4', ['int', 'integer']],
|
|
59
|
+
['float8', ['float']],
|
|
60
|
+
['bpchar', ['character']],
|
|
61
|
+
['varchar', ['character varying']]
|
|
62
|
+
];
|
|
7
63
|
// Type guards for better type safety
|
|
8
64
|
function isParseResult(obj) {
|
|
9
65
|
// A ParseResult is an object that could have stmts (but not required)
|
|
@@ -261,17 +317,36 @@ class Deparser {
|
|
|
261
317
|
if (node.targetList) {
|
|
262
318
|
const targetList = list_utils_1.ListUtils.unwrapList(node.targetList);
|
|
263
319
|
if (this.formatter.isPretty()) {
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
const
|
|
267
|
-
if
|
|
268
|
-
|
|
320
|
+
if (targetList.length === 1) {
|
|
321
|
+
const targetNode = targetList[0];
|
|
322
|
+
const target = this.visit(targetNode, { ...context, select: true });
|
|
323
|
+
// Check if single target is complex - if so, use multiline format
|
|
324
|
+
if (this.isComplexSelectTarget(targetNode)) {
|
|
325
|
+
output.push('SELECT' + distinctPart);
|
|
326
|
+
if (this.containsMultilineStringLiteral(target)) {
|
|
327
|
+
output.push(target);
|
|
328
|
+
}
|
|
329
|
+
else {
|
|
330
|
+
output.push(this.formatter.indent(target));
|
|
331
|
+
}
|
|
269
332
|
}
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
333
|
+
else {
|
|
334
|
+
output.push('SELECT' + distinctPart + ' ' + target);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
else {
|
|
338
|
+
const targetStrings = targetList
|
|
339
|
+
.map(e => {
|
|
340
|
+
const targetStr = this.visit(e, { ...context, select: true });
|
|
341
|
+
if (this.containsMultilineStringLiteral(targetStr)) {
|
|
342
|
+
return targetStr;
|
|
343
|
+
}
|
|
344
|
+
return this.formatter.indent(targetStr);
|
|
345
|
+
});
|
|
346
|
+
const formattedTargets = targetStrings.join(',' + this.formatter.newline());
|
|
347
|
+
output.push('SELECT' + distinctPart);
|
|
348
|
+
output.push(formattedTargets);
|
|
349
|
+
}
|
|
275
350
|
}
|
|
276
351
|
else {
|
|
277
352
|
const targets = targetList
|
|
@@ -310,12 +385,28 @@ class Deparser {
|
|
|
310
385
|
}
|
|
311
386
|
}
|
|
312
387
|
if (node.valuesLists) {
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
const
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
388
|
+
if (this.formatter.isPretty()) {
|
|
389
|
+
output.push('VALUES');
|
|
390
|
+
const lists = list_utils_1.ListUtils.unwrapList(node.valuesLists).map(list => {
|
|
391
|
+
const values = list_utils_1.ListUtils.unwrapList(list).map(val => this.visit(val, context));
|
|
392
|
+
return this.formatter.parens(values.join(', '));
|
|
393
|
+
});
|
|
394
|
+
const indentedTuples = lists.map(tuple => {
|
|
395
|
+
if (this.containsMultilineStringLiteral(tuple)) {
|
|
396
|
+
return tuple;
|
|
397
|
+
}
|
|
398
|
+
return this.formatter.indent(tuple);
|
|
399
|
+
});
|
|
400
|
+
output.push(indentedTuples.join(',\n'));
|
|
401
|
+
}
|
|
402
|
+
else {
|
|
403
|
+
output.push('VALUES');
|
|
404
|
+
const lists = list_utils_1.ListUtils.unwrapList(node.valuesLists).map(list => {
|
|
405
|
+
const values = list_utils_1.ListUtils.unwrapList(list).map(val => this.visit(val, context));
|
|
406
|
+
return this.formatter.parens(values.join(', '));
|
|
407
|
+
});
|
|
408
|
+
output.push(lists.join(', '));
|
|
409
|
+
}
|
|
319
410
|
}
|
|
320
411
|
if (node.groupClause) {
|
|
321
412
|
const groupList = list_utils_1.ListUtils.unwrapList(node.groupClause);
|
|
@@ -684,6 +775,64 @@ class Deparser {
|
|
|
684
775
|
node.SubLink ||
|
|
685
776
|
node.A_Expr);
|
|
686
777
|
}
|
|
778
|
+
isComplexSelectTarget(node) {
|
|
779
|
+
if (!node)
|
|
780
|
+
return false;
|
|
781
|
+
if (node.ResTarget?.val) {
|
|
782
|
+
return this.isComplexExpression(node.ResTarget.val);
|
|
783
|
+
}
|
|
784
|
+
// Always complex: CASE expressions
|
|
785
|
+
if (node.CaseExpr)
|
|
786
|
+
return true;
|
|
787
|
+
// Always complex: Subqueries and subselects
|
|
788
|
+
if (node.SubLink)
|
|
789
|
+
return true;
|
|
790
|
+
// Always complex: Boolean tests and expressions
|
|
791
|
+
if (node.NullTest || node.BooleanTest || node.BoolExpr)
|
|
792
|
+
return true;
|
|
793
|
+
// COALESCE and similar functions - complex if multiple arguments
|
|
794
|
+
if (node.CoalesceExpr) {
|
|
795
|
+
const args = node.CoalesceExpr.args;
|
|
796
|
+
if (args && Array.isArray(args) && args.length > 1)
|
|
797
|
+
return true;
|
|
798
|
+
}
|
|
799
|
+
// Function calls - complex if multiple args or has clauses
|
|
800
|
+
if (node.FuncCall) {
|
|
801
|
+
const funcCall = node.FuncCall;
|
|
802
|
+
const args = funcCall.args ? (Array.isArray(funcCall.args) ? funcCall.args : [funcCall.args]) : [];
|
|
803
|
+
// Complex if has window clause, filter, order by, etc.
|
|
804
|
+
if (funcCall.over || funcCall.agg_filter || funcCall.agg_order || funcCall.agg_distinct) {
|
|
805
|
+
return true;
|
|
806
|
+
}
|
|
807
|
+
// Complex if multiple arguments
|
|
808
|
+
if (args.length > 1)
|
|
809
|
+
return true;
|
|
810
|
+
if (args.length === 1) {
|
|
811
|
+
return this.isComplexSelectTarget(args[0]);
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
if (node.A_Expr) {
|
|
815
|
+
const expr = node.A_Expr;
|
|
816
|
+
// Check if operands are complex
|
|
817
|
+
if (expr.lexpr && this.isComplexSelectTarget(expr.lexpr))
|
|
818
|
+
return true;
|
|
819
|
+
if (expr.rexpr && this.isComplexSelectTarget(expr.rexpr))
|
|
820
|
+
return true;
|
|
821
|
+
return false;
|
|
822
|
+
}
|
|
823
|
+
if (node.TypeCast) {
|
|
824
|
+
return this.isComplexSelectTarget(node.TypeCast.arg);
|
|
825
|
+
}
|
|
826
|
+
if (node.A_ArrayExpr)
|
|
827
|
+
return true;
|
|
828
|
+
if (node.A_Indirection) {
|
|
829
|
+
return this.isComplexSelectTarget(node.A_Indirection.arg);
|
|
830
|
+
}
|
|
831
|
+
if (node.A_Const || node.ColumnRef || node.ParamRef || node.A_Star) {
|
|
832
|
+
return false;
|
|
833
|
+
}
|
|
834
|
+
return false;
|
|
835
|
+
}
|
|
687
836
|
visitBetweenRange(rexpr, context) {
|
|
688
837
|
if (rexpr && 'List' in rexpr && rexpr.List?.items) {
|
|
689
838
|
const items = rexpr.List.items.map((item) => this.visit(item, context));
|
|
@@ -702,7 +851,14 @@ class Deparser {
|
|
|
702
851
|
const cols = list_utils_1.ListUtils.unwrapList(node.cols);
|
|
703
852
|
const insertContext = { ...context, insertColumns: true };
|
|
704
853
|
const columnNames = cols.map(col => this.visit(col, insertContext));
|
|
705
|
-
|
|
854
|
+
if (this.formatter.isPretty()) {
|
|
855
|
+
// Always format columns in multiline parentheses for pretty printing
|
|
856
|
+
const indentedColumns = columnNames.map(col => this.formatter.indent(col));
|
|
857
|
+
output.push('(\n' + indentedColumns.join(',\n') + '\n)');
|
|
858
|
+
}
|
|
859
|
+
else {
|
|
860
|
+
output.push(this.formatter.parens(columnNames.join(', ')));
|
|
861
|
+
}
|
|
706
862
|
}
|
|
707
863
|
if (node.selectStmt) {
|
|
708
864
|
output.push(this.visit(node.selectStmt, context));
|
|
@@ -1494,9 +1650,6 @@ class Deparser {
|
|
|
1494
1650
|
return output.join(' ');
|
|
1495
1651
|
}
|
|
1496
1652
|
if (catalog === 'pg_catalog') {
|
|
1497
|
-
const builtinTypes = ['int2', 'int4', 'int8', 'float4', 'float8', 'numeric', 'decimal',
|
|
1498
|
-
'varchar', 'char', 'bpchar', 'text', 'bool', 'date', 'time', 'timestamp',
|
|
1499
|
-
'timestamptz', 'interval', 'bytea', 'uuid', 'json', 'jsonb'];
|
|
1500
1653
|
let typeName = `${catalog}.${type}`;
|
|
1501
1654
|
if (type === 'bpchar' && args) {
|
|
1502
1655
|
typeName = 'char';
|
|
@@ -1791,6 +1944,18 @@ class Deparser {
|
|
|
1791
1944
|
return `pg_catalog.${typeName}`;
|
|
1792
1945
|
}
|
|
1793
1946
|
}
|
|
1947
|
+
isPgCatalogType(typeName) {
|
|
1948
|
+
const cleanTypeName = typeName.replace(/^pg_catalog\./, '');
|
|
1949
|
+
if (pgCatalogTypes.includes(cleanTypeName)) {
|
|
1950
|
+
return true;
|
|
1951
|
+
}
|
|
1952
|
+
for (const [realType, aliases] of pgCatalogTypeAliases) {
|
|
1953
|
+
if (aliases.includes(cleanTypeName)) {
|
|
1954
|
+
return true;
|
|
1955
|
+
}
|
|
1956
|
+
}
|
|
1957
|
+
return false;
|
|
1958
|
+
}
|
|
1794
1959
|
A_ArrayExpr(node, context) {
|
|
1795
1960
|
const elements = list_utils_1.ListUtils.unwrapList(node.elements);
|
|
1796
1961
|
const elementStrs = elements.map(el => this.visit(el, context));
|
|
@@ -1884,28 +2049,29 @@ class Deparser {
|
|
|
1884
2049
|
TypeCast(node, context) {
|
|
1885
2050
|
const arg = this.visit(node.arg, context);
|
|
1886
2051
|
const typeName = this.TypeName(node.typeName, context);
|
|
1887
|
-
// Check if this is a bpchar typecast that should
|
|
1888
|
-
if (typeName === 'bpchar'
|
|
1889
|
-
const names =
|
|
1890
|
-
|
|
1891
|
-
names[0]
|
|
1892
|
-
names[1]
|
|
1893
|
-
|
|
2052
|
+
// Check if this is a bpchar typecast that should preserve original syntax for AST consistency
|
|
2053
|
+
if (typeName === 'bpchar' || typeName === 'pg_catalog.bpchar') {
|
|
2054
|
+
const names = node.typeName?.names;
|
|
2055
|
+
const isQualifiedBpchar = names && names.length === 2 &&
|
|
2056
|
+
names[0]?.String?.sval === 'pg_catalog' &&
|
|
2057
|
+
names[1]?.String?.sval === 'bpchar';
|
|
2058
|
+
if (isQualifiedBpchar) {
|
|
2059
|
+
return `CAST(${arg} AS ${typeName})`;
|
|
1894
2060
|
}
|
|
1895
2061
|
}
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
2062
|
+
if (this.isPgCatalogType(typeName)) {
|
|
2063
|
+
const argType = this.getNodeType(node.arg);
|
|
2064
|
+
const isSimpleArgument = argType === 'A_Const' || argType === 'ColumnRef';
|
|
2065
|
+
const isFunctionCall = argType === 'FuncCall';
|
|
2066
|
+
if (isSimpleArgument || isFunctionCall) {
|
|
2067
|
+
// For simple arguments, avoid :: syntax if they have complex structure
|
|
2068
|
+
if (isSimpleArgument && (arg.includes('(') || arg.startsWith('-'))) {
|
|
2069
|
+
}
|
|
2070
|
+
else {
|
|
2071
|
+
const cleanTypeName = typeName.replace('pg_catalog.', '');
|
|
2072
|
+
return `${arg}::${cleanTypeName}`;
|
|
2073
|
+
}
|
|
2074
|
+
}
|
|
1909
2075
|
}
|
|
1910
2076
|
return `CAST(${arg} AS ${typeName})`;
|
|
1911
2077
|
}
|
|
@@ -2088,7 +2254,14 @@ class Deparser {
|
|
|
2088
2254
|
return this.deparse(el, context);
|
|
2089
2255
|
});
|
|
2090
2256
|
if (this.formatter.isPretty()) {
|
|
2091
|
-
const formattedElements = elementStrs.map(el =>
|
|
2257
|
+
const formattedElements = elementStrs.map(el => {
|
|
2258
|
+
const trimmedEl = el.trim();
|
|
2259
|
+
// Remove leading newlines from constraint elements to avoid extra blank lines
|
|
2260
|
+
if (trimmedEl.startsWith('\n')) {
|
|
2261
|
+
return this.formatter.indent(trimmedEl.substring(1));
|
|
2262
|
+
}
|
|
2263
|
+
return this.formatter.indent(trimmedEl);
|
|
2264
|
+
}).join(',' + this.formatter.newline());
|
|
2092
2265
|
output.push('(' + this.formatter.newline() + formattedElements + this.formatter.newline() + ')');
|
|
2093
2266
|
}
|
|
2094
2267
|
else {
|
|
@@ -2250,9 +2423,25 @@ class Deparser {
|
|
|
2250
2423
|
}
|
|
2251
2424
|
break;
|
|
2252
2425
|
case 'CONSTR_CHECK':
|
|
2253
|
-
|
|
2426
|
+
if (this.formatter.isPretty() && !context.isColumnConstraint) {
|
|
2427
|
+
output.push('\n' + this.formatter.indent('CHECK'));
|
|
2428
|
+
}
|
|
2429
|
+
else {
|
|
2430
|
+
output.push('CHECK');
|
|
2431
|
+
}
|
|
2254
2432
|
if (node.raw_expr) {
|
|
2255
|
-
|
|
2433
|
+
if (this.formatter.isPretty()) {
|
|
2434
|
+
const checkExpr = this.visit(node.raw_expr, context);
|
|
2435
|
+
if (checkExpr.includes('\n')) {
|
|
2436
|
+
output.push('(\n' + this.formatter.indent(checkExpr) + '\n)');
|
|
2437
|
+
}
|
|
2438
|
+
else {
|
|
2439
|
+
output.push(`(${checkExpr})`);
|
|
2440
|
+
}
|
|
2441
|
+
}
|
|
2442
|
+
else {
|
|
2443
|
+
output.push(this.formatter.parens(this.visit(node.raw_expr, context)));
|
|
2444
|
+
}
|
|
2256
2445
|
}
|
|
2257
2446
|
// Handle NOT VALID for check constraints
|
|
2258
2447
|
if (node.skip_validation) {
|
|
@@ -2331,7 +2520,12 @@ class Deparser {
|
|
|
2331
2520
|
}
|
|
2332
2521
|
break;
|
|
2333
2522
|
case 'CONSTR_UNIQUE':
|
|
2334
|
-
|
|
2523
|
+
if (this.formatter.isPretty() && !context.isColumnConstraint) {
|
|
2524
|
+
output.push('\n' + this.formatter.indent('UNIQUE'));
|
|
2525
|
+
}
|
|
2526
|
+
else {
|
|
2527
|
+
output.push('UNIQUE');
|
|
2528
|
+
}
|
|
2335
2529
|
if (node.nulls_not_distinct) {
|
|
2336
2530
|
output.push('NULLS NOT DISTINCT');
|
|
2337
2531
|
}
|
|
@@ -2349,33 +2543,77 @@ class Deparser {
|
|
|
2349
2543
|
case 'CONSTR_FOREIGN':
|
|
2350
2544
|
// Only add "FOREIGN KEY" for table-level constraints, not column-level constraints
|
|
2351
2545
|
if (!context.isColumnConstraint) {
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2546
|
+
if (this.formatter.isPretty()) {
|
|
2547
|
+
output.push('\n' + this.formatter.indent('FOREIGN KEY'));
|
|
2548
|
+
if (node.fk_attrs && node.fk_attrs.length > 0) {
|
|
2549
|
+
const fkAttrs = list_utils_1.ListUtils.unwrapList(node.fk_attrs)
|
|
2550
|
+
.map(attr => this.visit(attr, context))
|
|
2551
|
+
.join(', ');
|
|
2552
|
+
output.push(`(${fkAttrs})`);
|
|
2553
|
+
}
|
|
2554
|
+
output.push('\n' + this.formatter.indent('REFERENCES'));
|
|
2358
2555
|
}
|
|
2556
|
+
else {
|
|
2557
|
+
output.push('FOREIGN KEY');
|
|
2558
|
+
if (node.fk_attrs && node.fk_attrs.length > 0) {
|
|
2559
|
+
const fkAttrs = list_utils_1.ListUtils.unwrapList(node.fk_attrs)
|
|
2560
|
+
.map(attr => this.visit(attr, context))
|
|
2561
|
+
.join(', ');
|
|
2562
|
+
output.push(`(${fkAttrs})`);
|
|
2563
|
+
}
|
|
2564
|
+
output.push('REFERENCES');
|
|
2565
|
+
}
|
|
2566
|
+
}
|
|
2567
|
+
else {
|
|
2568
|
+
output.push('REFERENCES');
|
|
2359
2569
|
}
|
|
2360
|
-
output.push('REFERENCES');
|
|
2361
2570
|
if (node.pktable) {
|
|
2362
|
-
|
|
2571
|
+
if (this.formatter.isPretty() && !context.isColumnConstraint) {
|
|
2572
|
+
const lastIndex = output.length - 1;
|
|
2573
|
+
if (lastIndex >= 0 && output[lastIndex].includes('REFERENCES')) {
|
|
2574
|
+
output[lastIndex] += ' ' + this.RangeVar(node.pktable, context);
|
|
2575
|
+
}
|
|
2576
|
+
else {
|
|
2577
|
+
output.push(this.RangeVar(node.pktable, context));
|
|
2578
|
+
}
|
|
2579
|
+
}
|
|
2580
|
+
else {
|
|
2581
|
+
output.push(this.RangeVar(node.pktable, context));
|
|
2582
|
+
}
|
|
2363
2583
|
}
|
|
2364
2584
|
if (node.pk_attrs && node.pk_attrs.length > 0) {
|
|
2365
2585
|
const pkAttrs = list_utils_1.ListUtils.unwrapList(node.pk_attrs)
|
|
2366
2586
|
.map(attr => this.visit(attr, context))
|
|
2367
2587
|
.join(', ');
|
|
2368
|
-
|
|
2588
|
+
if (this.formatter.isPretty() && !context.isColumnConstraint) {
|
|
2589
|
+
const lastIndex = output.length - 1;
|
|
2590
|
+
if (lastIndex >= 0) {
|
|
2591
|
+
output[lastIndex] += ` (${pkAttrs})`;
|
|
2592
|
+
}
|
|
2593
|
+
else {
|
|
2594
|
+
output.push(`(${pkAttrs})`);
|
|
2595
|
+
}
|
|
2596
|
+
}
|
|
2597
|
+
else {
|
|
2598
|
+
output.push(`(${pkAttrs})`);
|
|
2599
|
+
}
|
|
2369
2600
|
}
|
|
2370
2601
|
if (node.fk_matchtype && node.fk_matchtype !== 's') {
|
|
2602
|
+
let matchClause = '';
|
|
2371
2603
|
switch (node.fk_matchtype) {
|
|
2372
2604
|
case 'f':
|
|
2373
|
-
|
|
2605
|
+
matchClause = 'MATCH FULL';
|
|
2374
2606
|
break;
|
|
2375
2607
|
case 'p':
|
|
2376
|
-
|
|
2608
|
+
matchClause = 'MATCH PARTIAL';
|
|
2377
2609
|
break;
|
|
2378
2610
|
}
|
|
2611
|
+
if (this.formatter.isPretty() && !context.isColumnConstraint) {
|
|
2612
|
+
output.push('\n' + this.formatter.indent(matchClause));
|
|
2613
|
+
}
|
|
2614
|
+
else {
|
|
2615
|
+
output.push(matchClause);
|
|
2616
|
+
}
|
|
2379
2617
|
}
|
|
2380
2618
|
if (node.fk_upd_action && node.fk_upd_action !== 'a') {
|
|
2381
2619
|
let updateClause = 'ON UPDATE ';
|
|
@@ -2427,7 +2665,12 @@ class Deparser {
|
|
|
2427
2665
|
}
|
|
2428
2666
|
// Handle NOT VALID for foreign key constraints - only for table constraints, not domain constraints
|
|
2429
2667
|
if (node.skip_validation && !context.isDomainConstraint) {
|
|
2430
|
-
|
|
2668
|
+
if (this.formatter.isPretty() && !context.isColumnConstraint) {
|
|
2669
|
+
output.push('\n' + this.formatter.indent('NOT VALID'));
|
|
2670
|
+
}
|
|
2671
|
+
else {
|
|
2672
|
+
output.push('NOT VALID');
|
|
2673
|
+
}
|
|
2431
2674
|
}
|
|
2432
2675
|
break;
|
|
2433
2676
|
case 'CONSTR_ATTR_DEFERRABLE':
|
|
@@ -3426,8 +3669,8 @@ class Deparser {
|
|
|
3426
3669
|
else if (nodeData.sval !== undefined) {
|
|
3427
3670
|
// Handle nested sval structure: { sval: { sval: "value" } }
|
|
3428
3671
|
const svalValue = typeof nodeData.sval === 'object' ? nodeData.sval.sval : nodeData.sval;
|
|
3429
|
-
const stringValue = svalValue.replace(/'/g, '')
|
|
3430
|
-
boolValue = stringValue === 'on' || stringValue === 'true';
|
|
3672
|
+
const stringValue = svalValue.replace(/'/g, '');
|
|
3673
|
+
boolValue = stringValue.toLowerCase() === 'on' || stringValue.toLowerCase() === 'true';
|
|
3431
3674
|
}
|
|
3432
3675
|
}
|
|
3433
3676
|
return boolValue ? 'READ ONLY' : 'READ WRITE';
|
|
@@ -3450,8 +3693,8 @@ class Deparser {
|
|
|
3450
3693
|
else if (nodeData.sval !== undefined) {
|
|
3451
3694
|
// Handle nested sval structure: { sval: { sval: "value" } }
|
|
3452
3695
|
const svalValue = typeof nodeData.sval === 'object' ? nodeData.sval.sval : nodeData.sval;
|
|
3453
|
-
const stringValue = svalValue.replace(/'/g, '')
|
|
3454
|
-
boolValue = stringValue === 'on' || stringValue === 'true';
|
|
3696
|
+
const stringValue = svalValue.replace(/'/g, '');
|
|
3697
|
+
boolValue = stringValue.toLowerCase() === 'on' || stringValue.toLowerCase() === 'true';
|
|
3455
3698
|
}
|
|
3456
3699
|
}
|
|
3457
3700
|
return boolValue ? 'DEFERRABLE' : 'NOT DEFERRABLE';
|
|
@@ -3518,8 +3761,8 @@ class Deparser {
|
|
|
3518
3761
|
else if (nodeData.sval !== undefined) {
|
|
3519
3762
|
// Handle nested sval structure: { sval: { sval: "value" } }
|
|
3520
3763
|
const svalValue = typeof nodeData.sval === 'object' ? nodeData.sval.sval : nodeData.sval;
|
|
3521
|
-
const stringValue = svalValue.replace(/'/g, '')
|
|
3522
|
-
boolValue = stringValue === 'on' || stringValue === 'true';
|
|
3764
|
+
const stringValue = svalValue.replace(/'/g, '');
|
|
3765
|
+
boolValue = stringValue.toLowerCase() === 'on' || stringValue.toLowerCase() === 'true';
|
|
3523
3766
|
}
|
|
3524
3767
|
}
|
|
3525
3768
|
transactionOptions.push(boolValue ? 'READ ONLY' : 'READ WRITE');
|
|
@@ -3537,8 +3780,8 @@ class Deparser {
|
|
|
3537
3780
|
else if (nodeData.sval !== undefined) {
|
|
3538
3781
|
// Handle nested sval structure: { sval: { sval: "value" } }
|
|
3539
3782
|
const svalValue = typeof nodeData.sval === 'object' ? nodeData.sval.sval : nodeData.sval;
|
|
3540
|
-
const stringValue = svalValue.replace(/'/g, '')
|
|
3541
|
-
boolValue = stringValue === 'on' || stringValue === 'true';
|
|
3783
|
+
const stringValue = svalValue.replace(/'/g, '');
|
|
3784
|
+
boolValue = stringValue.toLowerCase() === 'on' || stringValue.toLowerCase() === 'true';
|
|
3542
3785
|
}
|
|
3543
3786
|
}
|
|
3544
3787
|
transactionOptions.push(boolValue ? 'DEFERRABLE' : 'NOT DEFERRABLE');
|
|
@@ -3604,7 +3847,7 @@ class Deparser {
|
|
|
3604
3847
|
}
|
|
3605
3848
|
switch (node.roletype) {
|
|
3606
3849
|
case 'ROLESPEC_PUBLIC':
|
|
3607
|
-
return '
|
|
3850
|
+
return 'PUBLIC';
|
|
3608
3851
|
case 'ROLESPEC_CURRENT_USER':
|
|
3609
3852
|
return 'CURRENT_USER';
|
|
3610
3853
|
case 'ROLESPEC_SESSION_USER':
|
|
@@ -3612,7 +3855,7 @@ class Deparser {
|
|
|
3612
3855
|
case 'ROLESPEC_CURRENT_ROLE':
|
|
3613
3856
|
return 'CURRENT_ROLE';
|
|
3614
3857
|
default:
|
|
3615
|
-
return '
|
|
3858
|
+
return 'PUBLIC';
|
|
3616
3859
|
}
|
|
3617
3860
|
}
|
|
3618
3861
|
roletype(node, context) {
|
|
@@ -4076,10 +4319,25 @@ class Deparser {
|
|
|
4076
4319
|
output.push(relationStr);
|
|
4077
4320
|
}
|
|
4078
4321
|
if (node.cmds && node.cmds.length > 0) {
|
|
4079
|
-
const
|
|
4080
|
-
|
|
4081
|
-
|
|
4082
|
-
|
|
4322
|
+
const commands = list_utils_1.ListUtils.unwrapList(node.cmds);
|
|
4323
|
+
if (this.formatter.isPretty()) {
|
|
4324
|
+
const commandsStr = commands
|
|
4325
|
+
.map(cmd => {
|
|
4326
|
+
const cmdStr = this.visit(cmd, alterContext);
|
|
4327
|
+
if (cmdStr.startsWith('ADD CONSTRAINT') || cmdStr.startsWith('ADD ')) {
|
|
4328
|
+
return this.formatter.newline() + this.formatter.indent(cmdStr);
|
|
4329
|
+
}
|
|
4330
|
+
return cmdStr;
|
|
4331
|
+
})
|
|
4332
|
+
.join(',');
|
|
4333
|
+
output.push(commandsStr);
|
|
4334
|
+
}
|
|
4335
|
+
else {
|
|
4336
|
+
const commandsStr = commands
|
|
4337
|
+
.map(cmd => this.visit(cmd, alterContext))
|
|
4338
|
+
.join(', ');
|
|
4339
|
+
output.push(commandsStr);
|
|
4340
|
+
}
|
|
4083
4341
|
}
|
|
4084
4342
|
return output.join(' ');
|
|
4085
4343
|
}
|
|
@@ -6055,7 +6313,7 @@ class Deparser {
|
|
|
6055
6313
|
const output = [];
|
|
6056
6314
|
const initialParts = ['CREATE', 'POLICY'];
|
|
6057
6315
|
if (node.policy_name) {
|
|
6058
|
-
initialParts.push(
|
|
6316
|
+
initialParts.push(quote_utils_1.QuoteUtils.quote(node.policy_name));
|
|
6059
6317
|
}
|
|
6060
6318
|
output.push(initialParts.join(' '));
|
|
6061
6319
|
// Add ON clause on new line in pretty mode
|
|
@@ -6132,7 +6390,7 @@ class Deparser {
|
|
|
6132
6390
|
AlterPolicyStmt(node, context) {
|
|
6133
6391
|
const output = ['ALTER', 'POLICY'];
|
|
6134
6392
|
if (node.policy_name) {
|
|
6135
|
-
output.push(
|
|
6393
|
+
output.push(quote_utils_1.QuoteUtils.quote(node.policy_name));
|
|
6136
6394
|
}
|
|
6137
6395
|
if (node.table) {
|
|
6138
6396
|
output.push('ON');
|
|
@@ -7630,7 +7888,12 @@ class Deparser {
|
|
|
7630
7888
|
}
|
|
7631
7889
|
if (node.action) {
|
|
7632
7890
|
const actionStr = this.GrantStmt(node.action, context);
|
|
7633
|
-
|
|
7891
|
+
if (this.formatter.isPretty()) {
|
|
7892
|
+
return output.join(' ') + this.formatter.newline() + this.formatter.indent(actionStr);
|
|
7893
|
+
}
|
|
7894
|
+
else {
|
|
7895
|
+
output.push(actionStr);
|
|
7896
|
+
}
|
|
7634
7897
|
}
|
|
7635
7898
|
return output.join(' ');
|
|
7636
7899
|
}
|
|
@@ -7777,84 +8040,158 @@ class Deparser {
|
|
|
7777
8040
|
if (node.trigname) {
|
|
7778
8041
|
output.push(quote_utils_1.QuoteUtils.quote(node.trigname));
|
|
7779
8042
|
}
|
|
7780
|
-
|
|
7781
|
-
|
|
7782
|
-
timing
|
|
7783
|
-
|
|
7784
|
-
|
|
7785
|
-
|
|
7786
|
-
|
|
7787
|
-
|
|
7788
|
-
|
|
7789
|
-
|
|
7790
|
-
events
|
|
7791
|
-
|
|
7792
|
-
events
|
|
7793
|
-
|
|
7794
|
-
events
|
|
7795
|
-
|
|
7796
|
-
|
|
7797
|
-
|
|
7798
|
-
|
|
7799
|
-
|
|
7800
|
-
|
|
7801
|
-
|
|
7802
|
-
.
|
|
7803
|
-
|
|
7804
|
-
|
|
7805
|
-
|
|
7806
|
-
|
|
7807
|
-
|
|
7808
|
-
|
|
7809
|
-
|
|
7810
|
-
|
|
7811
|
-
|
|
7812
|
-
|
|
7813
|
-
|
|
7814
|
-
|
|
7815
|
-
|
|
7816
|
-
|
|
7817
|
-
|
|
7818
|
-
|
|
7819
|
-
|
|
7820
|
-
|
|
7821
|
-
|
|
7822
|
-
|
|
7823
|
-
.
|
|
7824
|
-
|
|
7825
|
-
|
|
7826
|
-
|
|
7827
|
-
|
|
7828
|
-
|
|
7829
|
-
|
|
7830
|
-
|
|
7831
|
-
|
|
7832
|
-
|
|
7833
|
-
|
|
7834
|
-
|
|
7835
|
-
|
|
7836
|
-
|
|
7837
|
-
|
|
7838
|
-
|
|
7839
|
-
|
|
7840
|
-
|
|
7841
|
-
|
|
7842
|
-
|
|
7843
|
-
|
|
7844
|
-
|
|
7845
|
-
|
|
7846
|
-
|
|
7847
|
-
|
|
7848
|
-
|
|
7849
|
-
|
|
7850
|
-
|
|
7851
|
-
output.push(args);
|
|
7852
|
-
output.push(')');
|
|
8043
|
+
if (this.formatter.isPretty()) {
|
|
8044
|
+
const components = [];
|
|
8045
|
+
const timing = [];
|
|
8046
|
+
if (node.timing & 2)
|
|
8047
|
+
timing.push('BEFORE');
|
|
8048
|
+
else if (node.timing & 64)
|
|
8049
|
+
timing.push('INSTEAD OF');
|
|
8050
|
+
else
|
|
8051
|
+
timing.push('AFTER');
|
|
8052
|
+
const events = [];
|
|
8053
|
+
if (node.events & 4)
|
|
8054
|
+
events.push('INSERT');
|
|
8055
|
+
if (node.events & 8)
|
|
8056
|
+
events.push('DELETE');
|
|
8057
|
+
if (node.events & 16) {
|
|
8058
|
+
let updateStr = 'UPDATE';
|
|
8059
|
+
if (node.columns && node.columns.length > 0) {
|
|
8060
|
+
const columnNames = list_utils_1.ListUtils.unwrapList(node.columns)
|
|
8061
|
+
.map(col => this.visit(col, context))
|
|
8062
|
+
.join(', ');
|
|
8063
|
+
updateStr += ' OF ' + columnNames;
|
|
8064
|
+
}
|
|
8065
|
+
events.push(updateStr);
|
|
8066
|
+
}
|
|
8067
|
+
if (node.events & 32)
|
|
8068
|
+
events.push('TRUNCATE');
|
|
8069
|
+
components.push(this.formatter.indent(timing.join(' ') + ' ' + events.join(' OR ')));
|
|
8070
|
+
if (node.relation) {
|
|
8071
|
+
components.push(this.formatter.indent('ON ' + this.RangeVar(node.relation, context)));
|
|
8072
|
+
}
|
|
8073
|
+
if (node.transitionRels && node.transitionRels.length > 0) {
|
|
8074
|
+
const transitionClauses = list_utils_1.ListUtils.unwrapList(node.transitionRels)
|
|
8075
|
+
.map(rel => this.visit(rel, context))
|
|
8076
|
+
.join(' ');
|
|
8077
|
+
components.push(this.formatter.indent('REFERENCING ' + transitionClauses));
|
|
8078
|
+
}
|
|
8079
|
+
if (node.deferrable) {
|
|
8080
|
+
components.push(this.formatter.indent('DEFERRABLE'));
|
|
8081
|
+
}
|
|
8082
|
+
if (node.initdeferred) {
|
|
8083
|
+
components.push(this.formatter.indent('INITIALLY DEFERRED'));
|
|
8084
|
+
}
|
|
8085
|
+
if (node.row) {
|
|
8086
|
+
components.push(this.formatter.indent('FOR EACH ROW'));
|
|
8087
|
+
}
|
|
8088
|
+
else {
|
|
8089
|
+
components.push(this.formatter.indent('FOR EACH STATEMENT'));
|
|
8090
|
+
}
|
|
8091
|
+
if (node.whenClause) {
|
|
8092
|
+
const whenStr = 'WHEN (' + this.visit(node.whenClause, context) + ')';
|
|
8093
|
+
components.push(this.formatter.indent(whenStr));
|
|
8094
|
+
}
|
|
8095
|
+
let executeStr = 'EXECUTE';
|
|
8096
|
+
if (node.funcname && node.funcname.length > 0) {
|
|
8097
|
+
const funcName = list_utils_1.ListUtils.unwrapList(node.funcname)
|
|
8098
|
+
.map(name => this.visit(name, context))
|
|
8099
|
+
.join('.');
|
|
8100
|
+
executeStr += ' PROCEDURE ' + funcName;
|
|
8101
|
+
}
|
|
8102
|
+
if (node.args && node.args.length > 0) {
|
|
8103
|
+
const argContext = { ...context, isStringLiteral: true };
|
|
8104
|
+
const args = list_utils_1.ListUtils.unwrapList(node.args)
|
|
8105
|
+
.map(arg => this.visit(arg, argContext))
|
|
8106
|
+
.join(', ');
|
|
8107
|
+
executeStr += '(' + args + ')';
|
|
8108
|
+
}
|
|
8109
|
+
else {
|
|
8110
|
+
executeStr += '()';
|
|
8111
|
+
}
|
|
8112
|
+
components.push(this.formatter.indent(executeStr));
|
|
8113
|
+
return output.join(' ') + this.formatter.newline() + components.join(this.formatter.newline());
|
|
7853
8114
|
}
|
|
7854
8115
|
else {
|
|
7855
|
-
|
|
8116
|
+
const timing = [];
|
|
8117
|
+
if (node.timing & 2)
|
|
8118
|
+
timing.push('BEFORE');
|
|
8119
|
+
else if (node.timing & 64)
|
|
8120
|
+
timing.push('INSTEAD OF');
|
|
8121
|
+
else
|
|
8122
|
+
timing.push('AFTER');
|
|
8123
|
+
output.push(timing.join(' '));
|
|
8124
|
+
const events = [];
|
|
8125
|
+
if (node.events & 4)
|
|
8126
|
+
events.push('INSERT');
|
|
8127
|
+
if (node.events & 8)
|
|
8128
|
+
events.push('DELETE');
|
|
8129
|
+
if (node.events & 16)
|
|
8130
|
+
events.push('UPDATE');
|
|
8131
|
+
if (node.events & 32)
|
|
8132
|
+
events.push('TRUNCATE');
|
|
8133
|
+
output.push(events.join(' OR '));
|
|
8134
|
+
if (node.columns && node.columns.length > 0) {
|
|
8135
|
+
output.push('OF');
|
|
8136
|
+
const columnNames = list_utils_1.ListUtils.unwrapList(node.columns)
|
|
8137
|
+
.map(col => this.visit(col, context))
|
|
8138
|
+
.join(', ');
|
|
8139
|
+
output.push(columnNames);
|
|
8140
|
+
}
|
|
8141
|
+
output.push('ON');
|
|
8142
|
+
if (node.relation) {
|
|
8143
|
+
output.push(this.RangeVar(node.relation, context));
|
|
8144
|
+
}
|
|
8145
|
+
if (node.constrrel) {
|
|
8146
|
+
output.push('FROM');
|
|
8147
|
+
output.push(this.RangeVar(node.constrrel, context));
|
|
8148
|
+
}
|
|
8149
|
+
if (node.deferrable) {
|
|
8150
|
+
output.push('DEFERRABLE');
|
|
8151
|
+
}
|
|
8152
|
+
if (node.initdeferred) {
|
|
8153
|
+
output.push('INITIALLY DEFERRED');
|
|
8154
|
+
}
|
|
8155
|
+
if (node.transitionRels && node.transitionRels.length > 0) {
|
|
8156
|
+
output.push('REFERENCING');
|
|
8157
|
+
const transitionClauses = list_utils_1.ListUtils.unwrapList(node.transitionRels)
|
|
8158
|
+
.map(rel => this.visit(rel, context))
|
|
8159
|
+
.join(' ');
|
|
8160
|
+
output.push(transitionClauses);
|
|
8161
|
+
}
|
|
8162
|
+
if (node.row) {
|
|
8163
|
+
output.push('FOR EACH ROW');
|
|
8164
|
+
}
|
|
8165
|
+
else {
|
|
8166
|
+
output.push('FOR EACH STATEMENT');
|
|
8167
|
+
}
|
|
8168
|
+
if (node.whenClause) {
|
|
8169
|
+
output.push('WHEN');
|
|
8170
|
+
output.push('(');
|
|
8171
|
+
output.push(this.visit(node.whenClause, context));
|
|
8172
|
+
output.push(')');
|
|
8173
|
+
}
|
|
8174
|
+
output.push('EXECUTE');
|
|
8175
|
+
if (node.funcname && node.funcname.length > 0) {
|
|
8176
|
+
const funcName = list_utils_1.ListUtils.unwrapList(node.funcname)
|
|
8177
|
+
.map(name => this.visit(name, context))
|
|
8178
|
+
.join('.');
|
|
8179
|
+
output.push('FUNCTION', funcName);
|
|
8180
|
+
}
|
|
8181
|
+
if (node.args && node.args.length > 0) {
|
|
8182
|
+
output.push('(');
|
|
8183
|
+
const argContext = { ...context, isStringLiteral: true };
|
|
8184
|
+
const args = list_utils_1.ListUtils.unwrapList(node.args)
|
|
8185
|
+
.map(arg => this.visit(arg, argContext))
|
|
8186
|
+
.join(', ');
|
|
8187
|
+
output.push(args);
|
|
8188
|
+
output.push(')');
|
|
8189
|
+
}
|
|
8190
|
+
else {
|
|
8191
|
+
output.push('()');
|
|
8192
|
+
}
|
|
8193
|
+
return output.join(' ');
|
|
7856
8194
|
}
|
|
7857
|
-
return output.join(' ');
|
|
7858
8195
|
}
|
|
7859
8196
|
TriggerTransition(node, context) {
|
|
7860
8197
|
const output = [];
|
|
@@ -8432,7 +8769,7 @@ class Deparser {
|
|
|
8432
8769
|
AccessPriv(node, context) {
|
|
8433
8770
|
const output = [];
|
|
8434
8771
|
if (node.priv_name) {
|
|
8435
|
-
output.push(node.priv_name);
|
|
8772
|
+
output.push(node.priv_name.toUpperCase());
|
|
8436
8773
|
}
|
|
8437
8774
|
else {
|
|
8438
8775
|
output.push('ALL');
|