pgsql-deparser 14.0.1 → 14.1.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 +12 -6
- package/deparser/deparser.d.ts +4 -3
- package/deparser/deparser.js +883 -437
- package/deparser/utils/sql-formatter.js +1 -1
- package/deparser/visitors/base.d.ts +49 -2
- package/deparser/visitors/base.js +89 -1
- package/esm/deparser/deparser.js +883 -437
- package/esm/deparser/utils/sql-formatter.js +1 -1
- package/esm/deparser/visitors/base.js +87 -0
- package/esm/v14-to-v15.js +3 -0
- package/esm/v15-to-v16.js +60 -1
- package/package.json +1 -1
- package/v14-to-v15.js +3 -0
- package/v15-to-v16.d.ts +6 -0
- package/v15-to-v16.js +60 -1
package/esm/deparser/deparser.js
CHANGED
|
@@ -2,9 +2,66 @@
|
|
|
2
2
|
* Auto-generated file with types stripped for better tree-shaking
|
|
3
3
|
* DO NOT EDIT - Generated by strip-deparser-types.ts
|
|
4
4
|
*/
|
|
5
|
+
import { DeparserContext } from './visitors/base';
|
|
5
6
|
import { SqlFormatter } from './utils/sql-formatter';
|
|
6
7
|
import { QuoteUtils } from './utils/quote-utils';
|
|
7
8
|
import { ListUtils } from './utils/list-utils';
|
|
9
|
+
/**
|
|
10
|
+
* List of real PostgreSQL built-in types as they appear in pg_catalog.pg_type.typname.
|
|
11
|
+
* These are stored in lowercase in PostgreSQL system catalogs.
|
|
12
|
+
* Use these for lookups, validations, or introspection logic.
|
|
13
|
+
*/
|
|
14
|
+
const pgCatalogTypes = [
|
|
15
|
+
// Integers
|
|
16
|
+
'int2', // smallint
|
|
17
|
+
'int4', // integer
|
|
18
|
+
'int8', // bigint
|
|
19
|
+
// Floating-point & numeric
|
|
20
|
+
'float4', // real
|
|
21
|
+
'float8', // double precision
|
|
22
|
+
'numeric', // arbitrary precision (aka "decimal")
|
|
23
|
+
// Text & string
|
|
24
|
+
'varchar', // variable-length string
|
|
25
|
+
'char', // internal one-byte type (used in special cases)
|
|
26
|
+
'bpchar', // blank-padded char(n)
|
|
27
|
+
'text', // unlimited string
|
|
28
|
+
'bool', // boolean
|
|
29
|
+
// Dates & times
|
|
30
|
+
'date', // calendar date
|
|
31
|
+
'time', // time without time zone
|
|
32
|
+
'timetz', // time with time zone
|
|
33
|
+
'timestamp', // timestamp without time zone
|
|
34
|
+
'timestamptz', // timestamp with time zone
|
|
35
|
+
'interval', // duration
|
|
36
|
+
// Binary & structured
|
|
37
|
+
'bytea', // binary data
|
|
38
|
+
'uuid', // universally unique identifier
|
|
39
|
+
// JSON & XML
|
|
40
|
+
'json', // textual JSON
|
|
41
|
+
'jsonb', // binary JSON
|
|
42
|
+
'xml', // XML format
|
|
43
|
+
// Money & bitstrings
|
|
44
|
+
'money', // currency value
|
|
45
|
+
'bit', // fixed-length bit string
|
|
46
|
+
'varbit', // variable-length bit string
|
|
47
|
+
// Network types
|
|
48
|
+
'inet', // IPv4 or IPv6 address
|
|
49
|
+
'cidr', // network address
|
|
50
|
+
'macaddr', // MAC address (6 bytes)
|
|
51
|
+
'macaddr8' // MAC address (8 bytes)
|
|
52
|
+
];
|
|
53
|
+
/**
|
|
54
|
+
* Parser-level type aliases accepted by PostgreSQL SQL syntax,
|
|
55
|
+
* but not present in pg_catalog.pg_type. These are resolved to
|
|
56
|
+
* real types during parsing and never appear in introspection.
|
|
57
|
+
*/
|
|
58
|
+
const pgCatalogTypeAliases = [
|
|
59
|
+
['numeric', ['decimal', 'dec']],
|
|
60
|
+
['int4', ['int', 'integer']],
|
|
61
|
+
['float8', ['float']],
|
|
62
|
+
['bpchar', ['character']],
|
|
63
|
+
['varchar', ['character varying']]
|
|
64
|
+
];
|
|
8
65
|
// Type guards for better type safety
|
|
9
66
|
function isParseResult(obj) {
|
|
10
67
|
// A ParseResult is an object that could have stmts (but not required)
|
|
@@ -48,11 +105,9 @@ function isWrappedParseResult(obj) {
|
|
|
48
105
|
* compatibility and wraps them internally for consistent processing.
|
|
49
106
|
*/
|
|
50
107
|
export class Deparser {
|
|
51
|
-
formatter;
|
|
52
108
|
tree;
|
|
53
109
|
options;
|
|
54
110
|
constructor(tree, opts = {}) {
|
|
55
|
-
this.formatter = new SqlFormatter(opts.newline, opts.tab, opts.pretty);
|
|
56
111
|
// Set default options
|
|
57
112
|
this.options = {
|
|
58
113
|
functionDelimiter: '$$',
|
|
@@ -89,15 +144,17 @@ export class Deparser {
|
|
|
89
144
|
return new Deparser(query, opts).deparseQuery();
|
|
90
145
|
}
|
|
91
146
|
deparseQuery() {
|
|
147
|
+
const formatter = new SqlFormatter(this.options.newline, this.options.tab, this.options.pretty);
|
|
148
|
+
const context = new DeparserContext({ formatter, prettyMode: this.options.pretty });
|
|
92
149
|
return this.tree
|
|
93
150
|
.map(node => {
|
|
94
151
|
// All nodes should go through the standard deparse method
|
|
95
152
|
// which will route to the appropriate handler
|
|
96
|
-
const result = this.deparse(node);
|
|
153
|
+
const result = this.deparse(node, context);
|
|
97
154
|
return result || '';
|
|
98
155
|
})
|
|
99
156
|
.filter(result => result !== '')
|
|
100
|
-
.join(
|
|
157
|
+
.join(context.newline() + context.newline());
|
|
101
158
|
}
|
|
102
159
|
/**
|
|
103
160
|
* Get the appropriate function delimiter based on the body content
|
|
@@ -111,10 +168,14 @@ export class Deparser {
|
|
|
111
168
|
}
|
|
112
169
|
return delimiter;
|
|
113
170
|
}
|
|
114
|
-
deparse(node, context
|
|
171
|
+
deparse(node, context) {
|
|
115
172
|
if (node == null) {
|
|
116
173
|
return null;
|
|
117
174
|
}
|
|
175
|
+
if (!context) {
|
|
176
|
+
const formatter = new SqlFormatter(this.options.newline, this.options.tab, this.options.pretty);
|
|
177
|
+
context = new DeparserContext({ formatter, prettyMode: this.options.pretty });
|
|
178
|
+
}
|
|
118
179
|
if (typeof node === 'number' || node instanceof Number) {
|
|
119
180
|
return node.toString();
|
|
120
181
|
}
|
|
@@ -126,7 +187,11 @@ export class Deparser {
|
|
|
126
187
|
throw new Error(`Error deparsing ${nodeType}: ${error.message}`);
|
|
127
188
|
}
|
|
128
189
|
}
|
|
129
|
-
visit(node, context
|
|
190
|
+
visit(node, context) {
|
|
191
|
+
if (!context) {
|
|
192
|
+
const formatter = new SqlFormatter(this.options.newline, this.options.tab, this.options.pretty);
|
|
193
|
+
context = new DeparserContext({ formatter, prettyMode: this.options.pretty });
|
|
194
|
+
}
|
|
130
195
|
const nodeType = this.getNodeType(node);
|
|
131
196
|
// Handle empty objects
|
|
132
197
|
if (!nodeType) {
|
|
@@ -135,11 +200,7 @@ export class Deparser {
|
|
|
135
200
|
const nodeData = this.getNodeData(node);
|
|
136
201
|
const methodName = nodeType;
|
|
137
202
|
if (typeof this[methodName] === 'function') {
|
|
138
|
-
const
|
|
139
|
-
...context,
|
|
140
|
-
parentNodeTypes: [...context.parentNodeTypes, nodeType]
|
|
141
|
-
};
|
|
142
|
-
const result = this[methodName](nodeData, childContext);
|
|
203
|
+
const result = this[methodName](nodeData, context);
|
|
143
204
|
return result;
|
|
144
205
|
}
|
|
145
206
|
throw new Error(`Deparser does not handle node type: ${nodeType}`);
|
|
@@ -165,7 +226,7 @@ export class Deparser {
|
|
|
165
226
|
.filter((rawStmt) => rawStmt != null)
|
|
166
227
|
.map((rawStmt) => this.RawStmt(rawStmt, context))
|
|
167
228
|
.filter((result) => result !== '')
|
|
168
|
-
.join(
|
|
229
|
+
.join(context.newline() + context.newline());
|
|
169
230
|
}
|
|
170
231
|
RawStmt(node, context) {
|
|
171
232
|
if (!node.stmt) {
|
|
@@ -185,7 +246,7 @@ export class Deparser {
|
|
|
185
246
|
}
|
|
186
247
|
if (!node.op || node.op === 'SETOP_NONE') {
|
|
187
248
|
if (node.valuesLists == null) {
|
|
188
|
-
if (!
|
|
249
|
+
if (!context.isPretty() || !node.targetList) {
|
|
189
250
|
output.push('SELECT');
|
|
190
251
|
}
|
|
191
252
|
}
|
|
@@ -205,7 +266,7 @@ export class Deparser {
|
|
|
205
266
|
(node.rarg).limitOffset ||
|
|
206
267
|
(node.rarg).withClause);
|
|
207
268
|
if (leftNeedsParens) {
|
|
208
|
-
output.push(
|
|
269
|
+
output.push(context.parens(leftStmt));
|
|
209
270
|
}
|
|
210
271
|
else {
|
|
211
272
|
output.push(leftStmt);
|
|
@@ -227,7 +288,7 @@ export class Deparser {
|
|
|
227
288
|
output.push('ALL');
|
|
228
289
|
}
|
|
229
290
|
if (rightNeedsParens) {
|
|
230
|
-
output.push(
|
|
291
|
+
output.push(context.parens(rightStmt));
|
|
231
292
|
}
|
|
232
293
|
else {
|
|
233
294
|
output.push(rightStmt);
|
|
@@ -239,20 +300,20 @@ export class Deparser {
|
|
|
239
300
|
const distinctClause = ListUtils.unwrapList(node.distinctClause);
|
|
240
301
|
if (distinctClause.length > 0 && Object.keys(distinctClause[0]).length > 0) {
|
|
241
302
|
const clause = distinctClause
|
|
242
|
-
.map(e => this.visit(e,
|
|
303
|
+
.map(e => this.visit(e, context.spawn('SelectStmt', { select: true })))
|
|
243
304
|
.join(', ');
|
|
244
|
-
distinctPart = ' DISTINCT ON ' +
|
|
305
|
+
distinctPart = ' DISTINCT ON ' + context.parens(clause);
|
|
245
306
|
}
|
|
246
307
|
else {
|
|
247
308
|
distinctPart = ' DISTINCT';
|
|
248
309
|
}
|
|
249
|
-
if (!
|
|
310
|
+
if (!context.isPretty()) {
|
|
250
311
|
if (distinctClause.length > 0 && Object.keys(distinctClause[0]).length > 0) {
|
|
251
312
|
output.push('DISTINCT ON');
|
|
252
313
|
const clause = distinctClause
|
|
253
|
-
.map(e => this.visit(e,
|
|
314
|
+
.map(e => this.visit(e, context.spawn('SelectStmt', { select: true })))
|
|
254
315
|
.join(', ');
|
|
255
|
-
output.push(
|
|
316
|
+
output.push(context.parens(clause));
|
|
256
317
|
}
|
|
257
318
|
else {
|
|
258
319
|
output.push('DISTINCT');
|
|
@@ -261,22 +322,41 @@ export class Deparser {
|
|
|
261
322
|
}
|
|
262
323
|
if (node.targetList) {
|
|
263
324
|
const targetList = ListUtils.unwrapList(node.targetList);
|
|
264
|
-
if (
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
const
|
|
268
|
-
if
|
|
269
|
-
|
|
325
|
+
if (context.isPretty()) {
|
|
326
|
+
if (targetList.length === 1) {
|
|
327
|
+
const targetNode = targetList[0];
|
|
328
|
+
const target = this.visit(targetNode, context.spawn('SelectStmt', { select: true }));
|
|
329
|
+
// Check if single target is complex - if so, use multiline format
|
|
330
|
+
if (this.isComplexSelectTarget(targetNode)) {
|
|
331
|
+
output.push('SELECT' + distinctPart);
|
|
332
|
+
if (this.containsMultilineStringLiteral(target)) {
|
|
333
|
+
output.push(target);
|
|
334
|
+
}
|
|
335
|
+
else {
|
|
336
|
+
output.push(context.indent(target));
|
|
337
|
+
}
|
|
270
338
|
}
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
339
|
+
else {
|
|
340
|
+
output.push('SELECT' + distinctPart + ' ' + target);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
else {
|
|
344
|
+
const targetStrings = targetList
|
|
345
|
+
.map(e => {
|
|
346
|
+
const targetStr = this.visit(e, context.spawn('SelectStmt', { select: true }));
|
|
347
|
+
if (this.containsMultilineStringLiteral(targetStr)) {
|
|
348
|
+
return targetStr;
|
|
349
|
+
}
|
|
350
|
+
return context.indent(targetStr);
|
|
351
|
+
});
|
|
352
|
+
const formattedTargets = targetStrings.join(',' + context.newline());
|
|
353
|
+
output.push('SELECT' + distinctPart);
|
|
354
|
+
output.push(formattedTargets);
|
|
355
|
+
}
|
|
276
356
|
}
|
|
277
357
|
else {
|
|
278
358
|
const targets = targetList
|
|
279
|
-
.map(e => this.visit(e,
|
|
359
|
+
.map(e => this.visit(e, context.spawn('SelectStmt', { select: true })))
|
|
280
360
|
.join(', ');
|
|
281
361
|
output.push(targets);
|
|
282
362
|
}
|
|
@@ -288,22 +368,22 @@ export class Deparser {
|
|
|
288
368
|
if (node.fromClause) {
|
|
289
369
|
const fromList = ListUtils.unwrapList(node.fromClause);
|
|
290
370
|
const fromItems = fromList
|
|
291
|
-
.map(e => this.deparse(e,
|
|
371
|
+
.map(e => this.deparse(e, context.spawn('SelectStmt', { from: true })))
|
|
292
372
|
.join(', ');
|
|
293
373
|
output.push('FROM ' + fromItems.trim());
|
|
294
374
|
}
|
|
295
375
|
if (node.whereClause) {
|
|
296
|
-
if (
|
|
376
|
+
if (context.isPretty()) {
|
|
297
377
|
output.push('WHERE');
|
|
298
378
|
const whereExpr = this.visit(node.whereClause, context);
|
|
299
|
-
const lines = whereExpr.split(
|
|
379
|
+
const lines = whereExpr.split(context.newline());
|
|
300
380
|
const indentedLines = lines.map((line, index) => {
|
|
301
381
|
if (index === 0) {
|
|
302
|
-
return
|
|
382
|
+
return context.indent(line);
|
|
303
383
|
}
|
|
304
384
|
return line;
|
|
305
385
|
});
|
|
306
|
-
output.push(indentedLines.join(
|
|
386
|
+
output.push(indentedLines.join(context.newline()));
|
|
307
387
|
}
|
|
308
388
|
else {
|
|
309
389
|
output.push('WHERE');
|
|
@@ -311,45 +391,61 @@ export class Deparser {
|
|
|
311
391
|
}
|
|
312
392
|
}
|
|
313
393
|
if (node.valuesLists) {
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
const
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
394
|
+
if (context.isPretty()) {
|
|
395
|
+
output.push('VALUES');
|
|
396
|
+
const lists = ListUtils.unwrapList(node.valuesLists).map(list => {
|
|
397
|
+
const values = ListUtils.unwrapList(list).map(val => this.visit(val, context));
|
|
398
|
+
return context.parens(values.join(', '));
|
|
399
|
+
});
|
|
400
|
+
const indentedTuples = lists.map(tuple => {
|
|
401
|
+
if (this.containsMultilineStringLiteral(tuple)) {
|
|
402
|
+
return tuple;
|
|
403
|
+
}
|
|
404
|
+
return context.indent(tuple);
|
|
405
|
+
});
|
|
406
|
+
output.push(indentedTuples.join(',\n'));
|
|
407
|
+
}
|
|
408
|
+
else {
|
|
409
|
+
output.push('VALUES');
|
|
410
|
+
const lists = ListUtils.unwrapList(node.valuesLists).map(list => {
|
|
411
|
+
const values = ListUtils.unwrapList(list).map(val => this.visit(val, context));
|
|
412
|
+
return context.parens(values.join(', '));
|
|
413
|
+
});
|
|
414
|
+
output.push(lists.join(', '));
|
|
415
|
+
}
|
|
320
416
|
}
|
|
321
417
|
if (node.groupClause) {
|
|
322
418
|
const groupList = ListUtils.unwrapList(node.groupClause);
|
|
323
|
-
if (
|
|
419
|
+
if (context.isPretty()) {
|
|
324
420
|
const groupItems = groupList
|
|
325
421
|
.map(e => {
|
|
326
|
-
const groupStr = this.visit(e,
|
|
422
|
+
const groupStr = this.visit(e, context.spawn('SelectStmt', { group: true, indentLevel: context.indentLevel + 1 }));
|
|
327
423
|
if (this.containsMultilineStringLiteral(groupStr)) {
|
|
328
424
|
return groupStr;
|
|
329
425
|
}
|
|
330
|
-
return
|
|
426
|
+
return context.indent(groupStr);
|
|
331
427
|
})
|
|
332
|
-
.join(',' +
|
|
428
|
+
.join(',' + context.newline());
|
|
333
429
|
output.push('GROUP BY');
|
|
334
430
|
output.push(groupItems);
|
|
335
431
|
}
|
|
336
432
|
else {
|
|
337
433
|
output.push('GROUP BY');
|
|
338
434
|
const groupItems = groupList
|
|
339
|
-
.map(e => this.visit(e,
|
|
435
|
+
.map(e => this.visit(e, context.spawn('SelectStmt', { group: true })))
|
|
340
436
|
.join(', ');
|
|
341
437
|
output.push(groupItems);
|
|
342
438
|
}
|
|
343
439
|
}
|
|
344
440
|
if (node.havingClause) {
|
|
345
|
-
if (
|
|
441
|
+
if (context.isPretty()) {
|
|
346
442
|
output.push('HAVING');
|
|
347
443
|
const havingStr = this.visit(node.havingClause, context);
|
|
348
444
|
if (this.containsMultilineStringLiteral(havingStr)) {
|
|
349
445
|
output.push(havingStr);
|
|
350
446
|
}
|
|
351
447
|
else {
|
|
352
|
-
output.push(
|
|
448
|
+
output.push(context.indent(havingStr));
|
|
353
449
|
}
|
|
354
450
|
}
|
|
355
451
|
else {
|
|
@@ -367,23 +463,23 @@ export class Deparser {
|
|
|
367
463
|
}
|
|
368
464
|
if (node.sortClause) {
|
|
369
465
|
const sortList = ListUtils.unwrapList(node.sortClause);
|
|
370
|
-
if (
|
|
466
|
+
if (context.isPretty()) {
|
|
371
467
|
const sortItems = sortList
|
|
372
468
|
.map(e => {
|
|
373
|
-
const sortStr = this.visit(e,
|
|
469
|
+
const sortStr = this.visit(e, context.spawn('SelectStmt', { sort: true, indentLevel: context.indentLevel + 1 }));
|
|
374
470
|
if (this.containsMultilineStringLiteral(sortStr)) {
|
|
375
471
|
return sortStr;
|
|
376
472
|
}
|
|
377
|
-
return
|
|
473
|
+
return context.indent(sortStr);
|
|
378
474
|
})
|
|
379
|
-
.join(',' +
|
|
475
|
+
.join(',' + context.newline());
|
|
380
476
|
output.push('ORDER BY');
|
|
381
477
|
output.push(sortItems);
|
|
382
478
|
}
|
|
383
479
|
else {
|
|
384
480
|
output.push('ORDER BY');
|
|
385
481
|
const sortItems = sortList
|
|
386
|
-
.map(e => this.visit(e,
|
|
482
|
+
.map(e => this.visit(e, context.spawn('SelectStmt', { sort: true })))
|
|
387
483
|
.join(', ');
|
|
388
484
|
output.push(sortItems);
|
|
389
485
|
}
|
|
@@ -401,9 +497,9 @@ export class Deparser {
|
|
|
401
497
|
.join(' ');
|
|
402
498
|
output.push(lockingClauses);
|
|
403
499
|
}
|
|
404
|
-
if (
|
|
500
|
+
if (context.isPretty()) {
|
|
405
501
|
const filteredOutput = output.filter(item => item.trim() !== '');
|
|
406
|
-
return filteredOutput.join(
|
|
502
|
+
return filteredOutput.join(context.newline());
|
|
407
503
|
}
|
|
408
504
|
return output.join(' ');
|
|
409
505
|
}
|
|
@@ -415,13 +511,13 @@ export class Deparser {
|
|
|
415
511
|
switch (kind) {
|
|
416
512
|
case 'AEXPR_OP':
|
|
417
513
|
if (lexpr && rexpr) {
|
|
418
|
-
const operator = this.deparseOperatorName(name);
|
|
514
|
+
const operator = this.deparseOperatorName(name, context);
|
|
419
515
|
let leftExpr = this.visit(lexpr, context);
|
|
420
516
|
let rightExpr = this.visit(rexpr, context);
|
|
421
517
|
// Check if left expression needs parentheses
|
|
422
518
|
let leftNeedsParens = false;
|
|
423
519
|
if (lexpr && 'A_Expr' in lexpr && lexpr.A_Expr?.kind === 'AEXPR_OP') {
|
|
424
|
-
const leftOp = this.deparseOperatorName(ListUtils.unwrapList(lexpr.A_Expr.name));
|
|
520
|
+
const leftOp = this.deparseOperatorName(ListUtils.unwrapList(lexpr.A_Expr.name), context);
|
|
425
521
|
if (this.needsParentheses(leftOp, operator, 'left')) {
|
|
426
522
|
leftNeedsParens = true;
|
|
427
523
|
}
|
|
@@ -430,12 +526,12 @@ export class Deparser {
|
|
|
430
526
|
leftNeedsParens = true;
|
|
431
527
|
}
|
|
432
528
|
if (leftNeedsParens) {
|
|
433
|
-
leftExpr =
|
|
529
|
+
leftExpr = context.parens(leftExpr);
|
|
434
530
|
}
|
|
435
531
|
// Check if right expression needs parentheses
|
|
436
532
|
let rightNeedsParens = false;
|
|
437
533
|
if (rexpr && 'A_Expr' in rexpr && rexpr.A_Expr?.kind === 'AEXPR_OP') {
|
|
438
|
-
const rightOp = this.deparseOperatorName(ListUtils.unwrapList(rexpr.A_Expr.name));
|
|
534
|
+
const rightOp = this.deparseOperatorName(ListUtils.unwrapList(rexpr.A_Expr.name), context);
|
|
439
535
|
if (this.needsParentheses(rightOp, operator, 'right')) {
|
|
440
536
|
rightNeedsParens = true;
|
|
441
537
|
}
|
|
@@ -444,42 +540,42 @@ export class Deparser {
|
|
|
444
540
|
rightNeedsParens = true;
|
|
445
541
|
}
|
|
446
542
|
if (rightNeedsParens) {
|
|
447
|
-
rightExpr =
|
|
543
|
+
rightExpr = context.parens(rightExpr);
|
|
448
544
|
}
|
|
449
|
-
return
|
|
545
|
+
return context.format([leftExpr, operator, rightExpr]);
|
|
450
546
|
}
|
|
451
547
|
else if (rexpr) {
|
|
452
|
-
return
|
|
453
|
-
this.deparseOperatorName(name),
|
|
548
|
+
return context.format([
|
|
549
|
+
this.deparseOperatorName(name, context),
|
|
454
550
|
this.visit(rexpr, context)
|
|
455
551
|
]);
|
|
456
552
|
}
|
|
457
553
|
break;
|
|
458
554
|
case 'AEXPR_OP_ANY':
|
|
459
|
-
return
|
|
555
|
+
return context.format([
|
|
460
556
|
this.visit(lexpr, context),
|
|
461
|
-
this.deparseOperatorName(name),
|
|
557
|
+
this.deparseOperatorName(name, context),
|
|
462
558
|
'ANY',
|
|
463
|
-
|
|
559
|
+
context.parens(this.visit(rexpr, context))
|
|
464
560
|
]);
|
|
465
561
|
case 'AEXPR_OP_ALL':
|
|
466
|
-
return
|
|
562
|
+
return context.format([
|
|
467
563
|
this.visit(lexpr, context),
|
|
468
|
-
this.deparseOperatorName(name),
|
|
564
|
+
this.deparseOperatorName(name, context),
|
|
469
565
|
'ALL',
|
|
470
|
-
|
|
566
|
+
context.parens(this.visit(rexpr, context))
|
|
471
567
|
]);
|
|
472
568
|
case 'AEXPR_DISTINCT': {
|
|
473
569
|
let leftExpr = this.visit(lexpr, context);
|
|
474
570
|
let rightExpr = this.visit(rexpr, context);
|
|
475
571
|
// Add parentheses for complex expressions
|
|
476
572
|
if (lexpr && this.isComplexExpression(lexpr)) {
|
|
477
|
-
leftExpr =
|
|
573
|
+
leftExpr = context.parens(leftExpr);
|
|
478
574
|
}
|
|
479
575
|
if (rexpr && this.isComplexExpression(rexpr)) {
|
|
480
|
-
rightExpr =
|
|
576
|
+
rightExpr = context.parens(rightExpr);
|
|
481
577
|
}
|
|
482
|
-
return
|
|
578
|
+
return context.format([
|
|
483
579
|
leftExpr,
|
|
484
580
|
'IS DISTINCT FROM',
|
|
485
581
|
rightExpr
|
|
@@ -490,75 +586,75 @@ export class Deparser {
|
|
|
490
586
|
let rightExpr = this.visit(rexpr, context);
|
|
491
587
|
// Add parentheses for complex expressions
|
|
492
588
|
if (lexpr && this.isComplexExpression(lexpr)) {
|
|
493
|
-
leftExpr =
|
|
589
|
+
leftExpr = context.parens(leftExpr);
|
|
494
590
|
}
|
|
495
591
|
if (rexpr && this.isComplexExpression(rexpr)) {
|
|
496
|
-
rightExpr =
|
|
592
|
+
rightExpr = context.parens(rightExpr);
|
|
497
593
|
}
|
|
498
|
-
return
|
|
594
|
+
return context.format([
|
|
499
595
|
leftExpr,
|
|
500
596
|
'IS NOT DISTINCT FROM',
|
|
501
597
|
rightExpr
|
|
502
598
|
]);
|
|
503
599
|
}
|
|
504
600
|
case 'AEXPR_NULLIF':
|
|
505
|
-
return
|
|
601
|
+
return context.format([
|
|
506
602
|
'NULLIF',
|
|
507
|
-
|
|
603
|
+
context.parens([
|
|
508
604
|
this.visit(lexpr, context),
|
|
509
605
|
this.visit(rexpr, context)
|
|
510
606
|
].join(', '))
|
|
511
607
|
]);
|
|
512
608
|
case 'AEXPR_IN':
|
|
513
|
-
const inOperator = this.deparseOperatorName(name);
|
|
609
|
+
const inOperator = this.deparseOperatorName(name, context);
|
|
514
610
|
if (inOperator === '<>' || inOperator === '!=') {
|
|
515
|
-
return
|
|
611
|
+
return context.format([
|
|
516
612
|
this.visit(lexpr, context),
|
|
517
613
|
'NOT IN',
|
|
518
|
-
|
|
614
|
+
context.parens(this.visit(rexpr, context))
|
|
519
615
|
]);
|
|
520
616
|
}
|
|
521
617
|
else {
|
|
522
|
-
return
|
|
618
|
+
return context.format([
|
|
523
619
|
this.visit(lexpr, context),
|
|
524
620
|
'IN',
|
|
525
|
-
|
|
621
|
+
context.parens(this.visit(rexpr, context))
|
|
526
622
|
]);
|
|
527
623
|
}
|
|
528
624
|
case 'AEXPR_LIKE':
|
|
529
|
-
const likeOp = this.deparseOperatorName(name);
|
|
625
|
+
const likeOp = this.deparseOperatorName(name, context);
|
|
530
626
|
if (likeOp === '!~~') {
|
|
531
|
-
return
|
|
627
|
+
return context.format([
|
|
532
628
|
this.visit(lexpr, context),
|
|
533
629
|
'NOT LIKE',
|
|
534
630
|
this.visit(rexpr, context)
|
|
535
631
|
]);
|
|
536
632
|
}
|
|
537
633
|
else {
|
|
538
|
-
return
|
|
634
|
+
return context.format([
|
|
539
635
|
this.visit(lexpr, context),
|
|
540
636
|
'LIKE',
|
|
541
637
|
this.visit(rexpr, context)
|
|
542
638
|
]);
|
|
543
639
|
}
|
|
544
640
|
case 'AEXPR_ILIKE':
|
|
545
|
-
const ilikeOp = this.deparseOperatorName(name);
|
|
641
|
+
const ilikeOp = this.deparseOperatorName(name, context);
|
|
546
642
|
if (ilikeOp === '!~~*') {
|
|
547
|
-
return
|
|
643
|
+
return context.format([
|
|
548
644
|
this.visit(lexpr, context),
|
|
549
645
|
'NOT ILIKE',
|
|
550
646
|
this.visit(rexpr, context)
|
|
551
647
|
]);
|
|
552
648
|
}
|
|
553
649
|
else {
|
|
554
|
-
return
|
|
650
|
+
return context.format([
|
|
555
651
|
this.visit(lexpr, context),
|
|
556
652
|
'ILIKE',
|
|
557
653
|
this.visit(rexpr, context)
|
|
558
654
|
]);
|
|
559
655
|
}
|
|
560
656
|
case 'AEXPR_SIMILAR':
|
|
561
|
-
const similarOp = this.deparseOperatorName(name);
|
|
657
|
+
const similarOp = this.deparseOperatorName(name, context);
|
|
562
658
|
let rightExpr;
|
|
563
659
|
if (rexpr && 'FuncCall' in rexpr &&
|
|
564
660
|
rexpr.FuncCall?.funcname?.length === 2 &&
|
|
@@ -574,39 +670,39 @@ export class Deparser {
|
|
|
574
670
|
rightExpr = this.visit(rexpr, context);
|
|
575
671
|
}
|
|
576
672
|
if (similarOp === '!~') {
|
|
577
|
-
return
|
|
673
|
+
return context.format([
|
|
578
674
|
this.visit(lexpr, context),
|
|
579
675
|
'NOT SIMILAR TO',
|
|
580
676
|
rightExpr
|
|
581
677
|
]);
|
|
582
678
|
}
|
|
583
679
|
else {
|
|
584
|
-
return
|
|
680
|
+
return context.format([
|
|
585
681
|
this.visit(lexpr, context),
|
|
586
682
|
'SIMILAR TO',
|
|
587
683
|
rightExpr
|
|
588
684
|
]);
|
|
589
685
|
}
|
|
590
686
|
case 'AEXPR_BETWEEN':
|
|
591
|
-
return
|
|
687
|
+
return context.format([
|
|
592
688
|
this.visit(lexpr, context),
|
|
593
689
|
'BETWEEN',
|
|
594
690
|
this.visitBetweenRange(rexpr, context)
|
|
595
691
|
]);
|
|
596
692
|
case 'AEXPR_NOT_BETWEEN':
|
|
597
|
-
return
|
|
693
|
+
return context.format([
|
|
598
694
|
this.visit(lexpr, context),
|
|
599
695
|
'NOT BETWEEN',
|
|
600
696
|
this.visitBetweenRange(rexpr, context)
|
|
601
697
|
]);
|
|
602
698
|
case 'AEXPR_BETWEEN_SYM':
|
|
603
|
-
return
|
|
699
|
+
return context.format([
|
|
604
700
|
this.visit(lexpr, context),
|
|
605
701
|
'BETWEEN SYMMETRIC',
|
|
606
702
|
this.visitBetweenRange(rexpr, context)
|
|
607
703
|
]);
|
|
608
704
|
case 'AEXPR_NOT_BETWEEN_SYM':
|
|
609
|
-
return
|
|
705
|
+
return context.format([
|
|
610
706
|
this.visit(lexpr, context),
|
|
611
707
|
'NOT BETWEEN SYMMETRIC',
|
|
612
708
|
this.visitBetweenRange(rexpr, context)
|
|
@@ -614,7 +710,7 @@ export class Deparser {
|
|
|
614
710
|
}
|
|
615
711
|
throw new Error(`Unhandled A_Expr kind: ${kind}`);
|
|
616
712
|
}
|
|
617
|
-
deparseOperatorName(name) {
|
|
713
|
+
deparseOperatorName(name, context) {
|
|
618
714
|
if (!name || name.length === 0) {
|
|
619
715
|
return '';
|
|
620
716
|
}
|
|
@@ -622,7 +718,7 @@ export class Deparser {
|
|
|
622
718
|
if (n.String) {
|
|
623
719
|
return n.String.sval || n.String.str;
|
|
624
720
|
}
|
|
625
|
-
return this.visit(n,
|
|
721
|
+
return this.visit(n, context);
|
|
626
722
|
});
|
|
627
723
|
if (parts.length > 1) {
|
|
628
724
|
return `OPERATOR(${parts.join('.')})`;
|
|
@@ -685,6 +781,64 @@ export class Deparser {
|
|
|
685
781
|
node.SubLink ||
|
|
686
782
|
node.A_Expr);
|
|
687
783
|
}
|
|
784
|
+
isComplexSelectTarget(node) {
|
|
785
|
+
if (!node)
|
|
786
|
+
return false;
|
|
787
|
+
if (node.ResTarget?.val) {
|
|
788
|
+
return this.isComplexExpression(node.ResTarget.val);
|
|
789
|
+
}
|
|
790
|
+
// Always complex: CASE expressions
|
|
791
|
+
if (node.CaseExpr)
|
|
792
|
+
return true;
|
|
793
|
+
// Always complex: Subqueries and subselects
|
|
794
|
+
if (node.SubLink)
|
|
795
|
+
return true;
|
|
796
|
+
// Always complex: Boolean tests and expressions
|
|
797
|
+
if (node.NullTest || node.BooleanTest || node.BoolExpr)
|
|
798
|
+
return true;
|
|
799
|
+
// COALESCE and similar functions - complex if multiple arguments
|
|
800
|
+
if (node.CoalesceExpr) {
|
|
801
|
+
const args = node.CoalesceExpr.args;
|
|
802
|
+
if (args && Array.isArray(args) && args.length > 1)
|
|
803
|
+
return true;
|
|
804
|
+
}
|
|
805
|
+
// Function calls - complex if multiple args or has clauses
|
|
806
|
+
if (node.FuncCall) {
|
|
807
|
+
const funcCall = node.FuncCall;
|
|
808
|
+
const args = funcCall.args ? (Array.isArray(funcCall.args) ? funcCall.args : [funcCall.args]) : [];
|
|
809
|
+
// Complex if has window clause, filter, order by, etc.
|
|
810
|
+
if (funcCall.over || funcCall.agg_filter || funcCall.agg_order || funcCall.agg_distinct) {
|
|
811
|
+
return true;
|
|
812
|
+
}
|
|
813
|
+
// Complex if multiple arguments
|
|
814
|
+
if (args.length > 1)
|
|
815
|
+
return true;
|
|
816
|
+
if (args.length === 1) {
|
|
817
|
+
return this.isComplexSelectTarget(args[0]);
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
if (node.A_Expr) {
|
|
821
|
+
const expr = node.A_Expr;
|
|
822
|
+
// Check if operands are complex
|
|
823
|
+
if (expr.lexpr && this.isComplexSelectTarget(expr.lexpr))
|
|
824
|
+
return true;
|
|
825
|
+
if (expr.rexpr && this.isComplexSelectTarget(expr.rexpr))
|
|
826
|
+
return true;
|
|
827
|
+
return false;
|
|
828
|
+
}
|
|
829
|
+
if (node.TypeCast) {
|
|
830
|
+
return this.isComplexSelectTarget(node.TypeCast.arg);
|
|
831
|
+
}
|
|
832
|
+
if (node.A_ArrayExpr)
|
|
833
|
+
return true;
|
|
834
|
+
if (node.A_Indirection) {
|
|
835
|
+
return this.isComplexSelectTarget(node.A_Indirection.arg);
|
|
836
|
+
}
|
|
837
|
+
if (node.A_Const || node.ColumnRef || node.ParamRef || node.A_Star) {
|
|
838
|
+
return false;
|
|
839
|
+
}
|
|
840
|
+
return false;
|
|
841
|
+
}
|
|
688
842
|
visitBetweenRange(rexpr, context) {
|
|
689
843
|
if (rexpr && 'List' in rexpr && rexpr.List?.items) {
|
|
690
844
|
const items = rexpr.List.items.map((item) => this.visit(item, context));
|
|
@@ -701,9 +855,16 @@ export class Deparser {
|
|
|
701
855
|
output.push(this.RangeVar(node.relation, context));
|
|
702
856
|
if (node.cols) {
|
|
703
857
|
const cols = ListUtils.unwrapList(node.cols);
|
|
704
|
-
const insertContext =
|
|
858
|
+
const insertContext = context.spawn('InsertStmt', { insertColumns: true });
|
|
705
859
|
const columnNames = cols.map(col => this.visit(col, insertContext));
|
|
706
|
-
|
|
860
|
+
if (context.isPretty()) {
|
|
861
|
+
// Always format columns in multiline parentheses for pretty printing
|
|
862
|
+
const indentedColumns = columnNames.map(col => context.indent(col));
|
|
863
|
+
output.push('(\n' + indentedColumns.join(',\n') + '\n)');
|
|
864
|
+
}
|
|
865
|
+
else {
|
|
866
|
+
output.push(context.parens(columnNames.join(', ')));
|
|
867
|
+
}
|
|
707
868
|
}
|
|
708
869
|
if (node.selectStmt) {
|
|
709
870
|
output.push(this.visit(node.selectStmt, context));
|
|
@@ -724,7 +885,7 @@ export class Deparser {
|
|
|
724
885
|
else if (infer.indexElems) {
|
|
725
886
|
const elems = ListUtils.unwrapList(infer.indexElems);
|
|
726
887
|
const indexElems = elems.map(elem => this.visit(elem, context));
|
|
727
|
-
output.push(
|
|
888
|
+
output.push(context.parens(indexElems.join(', ')));
|
|
728
889
|
}
|
|
729
890
|
// Handle WHERE clause for conflict detection
|
|
730
891
|
if (infer.whereClause) {
|
|
@@ -740,12 +901,12 @@ export class Deparser {
|
|
|
740
901
|
if (firstTarget.ResTarget?.val?.MultiAssignRef && targetList.every(target => target.ResTarget?.val?.MultiAssignRef)) {
|
|
741
902
|
const sortedTargets = targetList.sort((a, b) => a.ResTarget.val.MultiAssignRef.colno - b.ResTarget.val.MultiAssignRef.colno);
|
|
742
903
|
const names = sortedTargets.map(target => target.ResTarget.name);
|
|
743
|
-
output.push(
|
|
904
|
+
output.push(context.parens(names.join(', ')));
|
|
744
905
|
output.push('=');
|
|
745
906
|
output.push(this.visit(firstTarget.ResTarget.val.MultiAssignRef.source, context));
|
|
746
907
|
}
|
|
747
908
|
else {
|
|
748
|
-
const updateContext =
|
|
909
|
+
const updateContext = context.spawn('UpdateStmt', { update: true });
|
|
749
910
|
const targets = targetList.map(target => this.visit(target, updateContext));
|
|
750
911
|
output.push(targets.join(', '));
|
|
751
912
|
}
|
|
@@ -799,12 +960,12 @@ export class Deparser {
|
|
|
799
960
|
}
|
|
800
961
|
}
|
|
801
962
|
const names = relatedTargets.map(t => t.ResTarget.name);
|
|
802
|
-
const multiAssignment = `${
|
|
963
|
+
const multiAssignment = `${context.parens(names.join(', '))} = ${this.visit(multiAssignRef.source, context)}`;
|
|
803
964
|
assignmentParts.push(multiAssignment);
|
|
804
965
|
}
|
|
805
966
|
else {
|
|
806
967
|
// Handle regular single-column assignment
|
|
807
|
-
assignmentParts.push(this.visit(target,
|
|
968
|
+
assignmentParts.push(this.visit(target, context.spawn('UpdateStmt', { update: true })));
|
|
808
969
|
processedTargets.add(i);
|
|
809
970
|
}
|
|
810
971
|
}
|
|
@@ -896,14 +1057,14 @@ export class Deparser {
|
|
|
896
1057
|
}
|
|
897
1058
|
if (node.ctes && node.ctes.length > 0) {
|
|
898
1059
|
const ctes = ListUtils.unwrapList(node.ctes);
|
|
899
|
-
if (
|
|
1060
|
+
if (context.isPretty()) {
|
|
900
1061
|
const cteStrings = ctes.map((cte, index) => {
|
|
901
1062
|
const cteStr = this.visit(cte, context);
|
|
902
|
-
const prefix = index === 0 ?
|
|
1063
|
+
const prefix = index === 0 ? context.newline() : ',' + context.newline();
|
|
903
1064
|
if (this.containsMultilineStringLiteral(cteStr)) {
|
|
904
1065
|
return prefix + cteStr;
|
|
905
1066
|
}
|
|
906
|
-
return prefix +
|
|
1067
|
+
return prefix + context.indent(cteStr);
|
|
907
1068
|
});
|
|
908
1069
|
output.push(cteStrings.join(''));
|
|
909
1070
|
}
|
|
@@ -989,14 +1150,14 @@ export class Deparser {
|
|
|
989
1150
|
if (context.bool) {
|
|
990
1151
|
formatStr = '(%s)';
|
|
991
1152
|
}
|
|
992
|
-
const boolContext =
|
|
1153
|
+
const boolContext = context.spawn('BoolExpr', { bool: true });
|
|
993
1154
|
// explanation of our syntax/fix below:
|
|
994
1155
|
// return formatStr.replace('%s', andArgs); // ❌ Interprets $ as special syntax
|
|
995
1156
|
// return formatStr.replace('%s', () => andArgs); // ✅ Function callback prevents interpretation
|
|
996
1157
|
switch (boolop) {
|
|
997
1158
|
case 'AND_EXPR':
|
|
998
|
-
if (
|
|
999
|
-
const andArgs = args.map(arg => this.visit(arg, boolContext)).join(
|
|
1159
|
+
if (context.isPretty() && args.length > 1) {
|
|
1160
|
+
const andArgs = args.map(arg => this.visit(arg, boolContext)).join(context.newline() + context.indent('AND '));
|
|
1000
1161
|
return formatStr.replace('%s', () => andArgs);
|
|
1001
1162
|
}
|
|
1002
1163
|
else {
|
|
@@ -1004,8 +1165,8 @@ export class Deparser {
|
|
|
1004
1165
|
return formatStr.replace('%s', () => andArgs);
|
|
1005
1166
|
}
|
|
1006
1167
|
case 'OR_EXPR':
|
|
1007
|
-
if (
|
|
1008
|
-
const orArgs = args.map(arg => this.visit(arg, boolContext)).join(
|
|
1168
|
+
if (context.isPretty() && args.length > 1) {
|
|
1169
|
+
const orArgs = args.map(arg => this.visit(arg, boolContext)).join(context.newline() + context.indent('OR '));
|
|
1009
1170
|
return formatStr.replace('%s', () => orArgs);
|
|
1010
1171
|
}
|
|
1011
1172
|
else {
|
|
@@ -1136,9 +1297,9 @@ export class Deparser {
|
|
|
1136
1297
|
const timezone = this.visit(args[0], context);
|
|
1137
1298
|
// Add parentheses around timestamp if it contains arithmetic operations
|
|
1138
1299
|
if (args[1] && 'A_Expr' in args[1] && args[1].A_Expr?.kind === 'AEXPR_OP') {
|
|
1139
|
-
const op = this.deparseOperatorName(ListUtils.unwrapList(args[1].A_Expr.name));
|
|
1300
|
+
const op = this.deparseOperatorName(ListUtils.unwrapList(args[1].A_Expr.name), context);
|
|
1140
1301
|
if (op === '+' || op === '-' || op === '*' || op === '/') {
|
|
1141
|
-
timestamp =
|
|
1302
|
+
timestamp = context.parens(timestamp);
|
|
1142
1303
|
}
|
|
1143
1304
|
}
|
|
1144
1305
|
return `${timestamp} AT TIME ZONE ${timezone}`;
|
|
@@ -1208,14 +1369,14 @@ export class Deparser {
|
|
|
1208
1369
|
windowParts.push(`ORDER BY ${orderStrs.join(', ')}`);
|
|
1209
1370
|
}
|
|
1210
1371
|
// Handle window frame specifications using the dedicated formatWindowFrame method
|
|
1211
|
-
const frameClause = this.formatWindowFrame(node.over);
|
|
1372
|
+
const frameClause = this.formatWindowFrame(node.over, context.spawn('FuncCall'));
|
|
1212
1373
|
if (frameClause) {
|
|
1213
1374
|
windowParts.push(frameClause);
|
|
1214
1375
|
}
|
|
1215
1376
|
if (windowParts.length > 0) {
|
|
1216
|
-
if (
|
|
1217
|
-
const formattedParts = windowParts.map(part =>
|
|
1218
|
-
result += ` OVER (${
|
|
1377
|
+
if (context.isPretty() && windowParts.length > 1) {
|
|
1378
|
+
const formattedParts = windowParts.map(part => context.indent(part));
|
|
1379
|
+
result += ` OVER (${context.newline()}${formattedParts.join(context.newline())}${context.newline()})`;
|
|
1219
1380
|
}
|
|
1220
1381
|
else {
|
|
1221
1382
|
result += ` OVER (${windowParts.join(' ')})`;
|
|
@@ -1495,9 +1656,6 @@ export class Deparser {
|
|
|
1495
1656
|
return output.join(' ');
|
|
1496
1657
|
}
|
|
1497
1658
|
if (catalog === 'pg_catalog') {
|
|
1498
|
-
const builtinTypes = ['int2', 'int4', 'int8', 'float4', 'float8', 'numeric', 'decimal',
|
|
1499
|
-
'varchar', 'char', 'bpchar', 'text', 'bool', 'date', 'time', 'timestamp',
|
|
1500
|
-
'timestamptz', 'interval', 'bytea', 'uuid', 'json', 'jsonb'];
|
|
1501
1659
|
let typeName = `${catalog}.${type}`;
|
|
1502
1660
|
if (type === 'bpchar' && args) {
|
|
1503
1661
|
typeName = 'char';
|
|
@@ -1554,6 +1712,24 @@ export class Deparser {
|
|
|
1554
1712
|
typeName = 'time with time zone';
|
|
1555
1713
|
}
|
|
1556
1714
|
}
|
|
1715
|
+
else if (type === 'timestamp') {
|
|
1716
|
+
if (args) {
|
|
1717
|
+
typeName = `timestamp(${args})`;
|
|
1718
|
+
args = null; // Don't apply args again in mods()
|
|
1719
|
+
}
|
|
1720
|
+
else {
|
|
1721
|
+
typeName = 'timestamp';
|
|
1722
|
+
}
|
|
1723
|
+
}
|
|
1724
|
+
else if (type === 'time') {
|
|
1725
|
+
if (args) {
|
|
1726
|
+
typeName = `time(${args})`;
|
|
1727
|
+
args = null; // Don't apply args again in mods()
|
|
1728
|
+
}
|
|
1729
|
+
else {
|
|
1730
|
+
typeName = 'time';
|
|
1731
|
+
}
|
|
1732
|
+
}
|
|
1557
1733
|
let result = mods(typeName, args);
|
|
1558
1734
|
if (node.arrayBounds && node.arrayBounds.length > 0) {
|
|
1559
1735
|
result += formatArrayBounds(node.arrayBounds);
|
|
@@ -1583,7 +1759,7 @@ export class Deparser {
|
|
|
1583
1759
|
}
|
|
1584
1760
|
return this.quoteIfNeeded(colStr);
|
|
1585
1761
|
});
|
|
1586
|
-
output.push('AS', this.quoteIfNeeded(name) +
|
|
1762
|
+
output.push('AS', this.quoteIfNeeded(name) + context.parens(quotedColnames.join(', ')));
|
|
1587
1763
|
}
|
|
1588
1764
|
else {
|
|
1589
1765
|
output.push('AS', this.quoteIfNeeded(name));
|
|
@@ -1595,7 +1771,7 @@ export class Deparser {
|
|
|
1595
1771
|
// Handle ONLY keyword for inheritance control (but not for type definitions, ALTER TYPE, or CREATE FOREIGN TABLE)
|
|
1596
1772
|
if (node && (!('inh' in node) || node.inh === undefined) &&
|
|
1597
1773
|
!context.parentNodeTypes.includes('CompositeTypeStmt') &&
|
|
1598
|
-
!context.parentNodeTypes.includes('AlterTypeStmt') &&
|
|
1774
|
+
(!context.parentNodeTypes.includes('AlterTypeStmt') && context.objtype !== 'OBJECT_TYPE') &&
|
|
1599
1775
|
!context.parentNodeTypes.includes('CreateForeignTableStmt')) {
|
|
1600
1776
|
output.push('ONLY');
|
|
1601
1777
|
}
|
|
@@ -1792,6 +1968,18 @@ export class Deparser {
|
|
|
1792
1968
|
return `pg_catalog.${typeName}`;
|
|
1793
1969
|
}
|
|
1794
1970
|
}
|
|
1971
|
+
isPgCatalogType(typeName) {
|
|
1972
|
+
const cleanTypeName = typeName.replace(/^pg_catalog\./, '');
|
|
1973
|
+
if (pgCatalogTypes.includes(cleanTypeName)) {
|
|
1974
|
+
return true;
|
|
1975
|
+
}
|
|
1976
|
+
for (const [realType, aliases] of pgCatalogTypeAliases) {
|
|
1977
|
+
if (aliases.includes(cleanTypeName)) {
|
|
1978
|
+
return true;
|
|
1979
|
+
}
|
|
1980
|
+
}
|
|
1981
|
+
return false;
|
|
1982
|
+
}
|
|
1795
1983
|
A_ArrayExpr(node, context) {
|
|
1796
1984
|
const elements = ListUtils.unwrapList(node.elements);
|
|
1797
1985
|
const elementStrs = elements.map(el => this.visit(el, context));
|
|
@@ -1843,26 +2031,26 @@ export class Deparser {
|
|
|
1843
2031
|
output.push(this.visit(node.arg, context));
|
|
1844
2032
|
}
|
|
1845
2033
|
const args = ListUtils.unwrapList(node.args);
|
|
1846
|
-
if (
|
|
2034
|
+
if (context.isPretty() && args.length > 0) {
|
|
1847
2035
|
for (const arg of args) {
|
|
1848
2036
|
const whenClause = this.visit(arg, context);
|
|
1849
2037
|
if (this.containsMultilineStringLiteral(whenClause)) {
|
|
1850
|
-
output.push(
|
|
2038
|
+
output.push(context.newline() + whenClause);
|
|
1851
2039
|
}
|
|
1852
2040
|
else {
|
|
1853
|
-
output.push(
|
|
2041
|
+
output.push(context.newline() + context.indent(whenClause));
|
|
1854
2042
|
}
|
|
1855
2043
|
}
|
|
1856
2044
|
if (node.defresult) {
|
|
1857
2045
|
const elseResult = this.visit(node.defresult, context);
|
|
1858
2046
|
if (this.containsMultilineStringLiteral(elseResult)) {
|
|
1859
|
-
output.push(
|
|
2047
|
+
output.push(context.newline() + 'ELSE ' + elseResult);
|
|
1860
2048
|
}
|
|
1861
2049
|
else {
|
|
1862
|
-
output.push(
|
|
2050
|
+
output.push(context.newline() + context.indent('ELSE ' + elseResult));
|
|
1863
2051
|
}
|
|
1864
2052
|
}
|
|
1865
|
-
output.push(
|
|
2053
|
+
output.push(context.newline() + 'END');
|
|
1866
2054
|
return output.join(' ');
|
|
1867
2055
|
}
|
|
1868
2056
|
else {
|
|
@@ -1885,28 +2073,29 @@ export class Deparser {
|
|
|
1885
2073
|
TypeCast(node, context) {
|
|
1886
2074
|
const arg = this.visit(node.arg, context);
|
|
1887
2075
|
const typeName = this.TypeName(node.typeName, context);
|
|
1888
|
-
// Check if this is a bpchar typecast that should
|
|
1889
|
-
if (typeName === 'bpchar'
|
|
1890
|
-
const names =
|
|
1891
|
-
|
|
1892
|
-
names[0]
|
|
1893
|
-
names[1]
|
|
1894
|
-
|
|
2076
|
+
// Check if this is a bpchar typecast that should preserve original syntax for AST consistency
|
|
2077
|
+
if (typeName === 'bpchar' || typeName === 'pg_catalog.bpchar') {
|
|
2078
|
+
const names = node.typeName?.names;
|
|
2079
|
+
const isQualifiedBpchar = names && names.length === 2 &&
|
|
2080
|
+
names[0]?.String?.sval === 'pg_catalog' &&
|
|
2081
|
+
names[1]?.String?.sval === 'bpchar';
|
|
2082
|
+
if (isQualifiedBpchar) {
|
|
2083
|
+
return `CAST(${arg} AS ${typeName})`;
|
|
1895
2084
|
}
|
|
1896
2085
|
}
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
2086
|
+
if (this.isPgCatalogType(typeName)) {
|
|
2087
|
+
const argType = this.getNodeType(node.arg);
|
|
2088
|
+
const isSimpleArgument = argType === 'A_Const' || argType === 'ColumnRef';
|
|
2089
|
+
const isFunctionCall = argType === 'FuncCall';
|
|
2090
|
+
if (isSimpleArgument || isFunctionCall) {
|
|
2091
|
+
// For simple arguments, avoid :: syntax if they have complex structure
|
|
2092
|
+
if (isSimpleArgument && (arg.includes('(') || arg.startsWith('-'))) {
|
|
2093
|
+
}
|
|
2094
|
+
else {
|
|
2095
|
+
const cleanTypeName = typeName.replace('pg_catalog.', '');
|
|
2096
|
+
return `${arg}::${cleanTypeName}`;
|
|
2097
|
+
}
|
|
2098
|
+
}
|
|
1910
2099
|
}
|
|
1911
2100
|
return `CAST(${arg} AS ${typeName})`;
|
|
1912
2101
|
}
|
|
@@ -1929,7 +2118,7 @@ export class Deparser {
|
|
|
1929
2118
|
}
|
|
1930
2119
|
BooleanTest(node, context) {
|
|
1931
2120
|
const output = [];
|
|
1932
|
-
const boolContext =
|
|
2121
|
+
const boolContext = context.spawn('BooleanTest', { bool: true });
|
|
1933
2122
|
output.push(this.visit(node.arg, boolContext));
|
|
1934
2123
|
switch (node.booltesttype) {
|
|
1935
2124
|
case 'IS_TRUE':
|
|
@@ -2080,24 +2269,31 @@ export class Deparser {
|
|
|
2080
2269
|
const elementStrs = elements.map(el => {
|
|
2081
2270
|
return this.deparse(el, context);
|
|
2082
2271
|
});
|
|
2083
|
-
output.push(
|
|
2272
|
+
output.push(context.parens(elementStrs.join(', ')));
|
|
2084
2273
|
}
|
|
2085
2274
|
}
|
|
2086
2275
|
else if (node.tableElts) {
|
|
2087
2276
|
const elements = ListUtils.unwrapList(node.tableElts);
|
|
2088
2277
|
const elementStrs = elements.map(el => {
|
|
2089
|
-
return this.deparse(el, context);
|
|
2278
|
+
return this.deparse(el, context.spawn('CreateStmt'));
|
|
2090
2279
|
});
|
|
2091
|
-
if (
|
|
2092
|
-
const formattedElements = elementStrs.map(el =>
|
|
2093
|
-
|
|
2280
|
+
if (context.isPretty()) {
|
|
2281
|
+
const formattedElements = elementStrs.map(el => {
|
|
2282
|
+
const trimmedEl = el.trim();
|
|
2283
|
+
// Remove leading newlines from constraint elements to avoid extra blank lines
|
|
2284
|
+
if (trimmedEl.startsWith('\n')) {
|
|
2285
|
+
return context.indent(trimmedEl.substring(1));
|
|
2286
|
+
}
|
|
2287
|
+
return context.indent(trimmedEl);
|
|
2288
|
+
}).join(',' + context.newline());
|
|
2289
|
+
output.push('(' + context.newline() + formattedElements + context.newline() + ')');
|
|
2094
2290
|
}
|
|
2095
2291
|
else {
|
|
2096
|
-
output.push(
|
|
2292
|
+
output.push(context.parens(elementStrs.join(', ')));
|
|
2097
2293
|
}
|
|
2098
2294
|
}
|
|
2099
2295
|
else if (!node.partbound) {
|
|
2100
|
-
output.push(
|
|
2296
|
+
output.push(context.parens(''));
|
|
2101
2297
|
}
|
|
2102
2298
|
if (node.partbound && node.inhRelations && node.inhRelations.length > 0) {
|
|
2103
2299
|
output.push('PARTITION OF');
|
|
@@ -2140,7 +2336,7 @@ export class Deparser {
|
|
|
2140
2336
|
output.push('INHERITS');
|
|
2141
2337
|
const inherits = ListUtils.unwrapList(node.inhRelations);
|
|
2142
2338
|
const inheritStrs = inherits.map(rel => this.visit(rel, context));
|
|
2143
|
-
output.push(
|
|
2339
|
+
output.push(context.parens(inheritStrs.join(', ')));
|
|
2144
2340
|
}
|
|
2145
2341
|
if (node.partspec) {
|
|
2146
2342
|
output.push('PARTITION BY');
|
|
@@ -2178,7 +2374,7 @@ export class Deparser {
|
|
|
2178
2374
|
}
|
|
2179
2375
|
// Handle table options like WITH (fillfactor=10)
|
|
2180
2376
|
if (node.options && node.options.length > 0) {
|
|
2181
|
-
const createStmtContext =
|
|
2377
|
+
const createStmtContext = context.spawn('CreateStmt');
|
|
2182
2378
|
const optionStrs = node.options.map((option) => {
|
|
2183
2379
|
return this.deparse(option, createStmtContext);
|
|
2184
2380
|
});
|
|
@@ -2201,7 +2397,7 @@ export class Deparser {
|
|
|
2201
2397
|
}
|
|
2202
2398
|
if (node.fdwoptions && node.fdwoptions.length > 0) {
|
|
2203
2399
|
output.push('OPTIONS');
|
|
2204
|
-
const columnContext =
|
|
2400
|
+
const columnContext = context.spawn('ColumnDef');
|
|
2205
2401
|
const options = ListUtils.unwrapList(node.fdwoptions).map(opt => this.visit(opt, columnContext));
|
|
2206
2402
|
output.push(`(${options.join(', ')})`);
|
|
2207
2403
|
}
|
|
@@ -2211,7 +2407,7 @@ export class Deparser {
|
|
|
2211
2407
|
if (node.constraints) {
|
|
2212
2408
|
const constraints = ListUtils.unwrapList(node.constraints);
|
|
2213
2409
|
const constraintStrs = constraints.map(constraint => {
|
|
2214
|
-
const columnConstraintContext =
|
|
2410
|
+
const columnConstraintContext = context.spawn('ColumnDef', { isColumnConstraint: true });
|
|
2215
2411
|
return this.visit(constraint, columnConstraintContext);
|
|
2216
2412
|
});
|
|
2217
2413
|
output.push(...constraintStrs);
|
|
@@ -2251,9 +2447,25 @@ export class Deparser {
|
|
|
2251
2447
|
}
|
|
2252
2448
|
break;
|
|
2253
2449
|
case 'CONSTR_CHECK':
|
|
2254
|
-
|
|
2450
|
+
if (context.isPretty() && !context.isColumnConstraint) {
|
|
2451
|
+
output.push('\n' + context.indent('CHECK'));
|
|
2452
|
+
}
|
|
2453
|
+
else {
|
|
2454
|
+
output.push('CHECK');
|
|
2455
|
+
}
|
|
2255
2456
|
if (node.raw_expr) {
|
|
2256
|
-
|
|
2457
|
+
if (context.isPretty()) {
|
|
2458
|
+
const checkExpr = this.visit(node.raw_expr, context);
|
|
2459
|
+
if (checkExpr.includes('\n')) {
|
|
2460
|
+
output.push('(\n' + context.indent(checkExpr) + '\n)');
|
|
2461
|
+
}
|
|
2462
|
+
else {
|
|
2463
|
+
output.push(`(${checkExpr})`);
|
|
2464
|
+
}
|
|
2465
|
+
}
|
|
2466
|
+
else {
|
|
2467
|
+
output.push(context.parens(this.visit(node.raw_expr, context)));
|
|
2468
|
+
}
|
|
2257
2469
|
}
|
|
2258
2470
|
// Handle NOT VALID for check constraints
|
|
2259
2471
|
if (node.skip_validation) {
|
|
@@ -2274,7 +2486,7 @@ export class Deparser {
|
|
|
2274
2486
|
}
|
|
2275
2487
|
output.push('AS');
|
|
2276
2488
|
if (node.raw_expr) {
|
|
2277
|
-
output.push(
|
|
2489
|
+
output.push(context.parens(this.visit(node.raw_expr, context)));
|
|
2278
2490
|
}
|
|
2279
2491
|
output.push('STORED');
|
|
2280
2492
|
break;
|
|
@@ -2292,30 +2504,61 @@ export class Deparser {
|
|
|
2292
2504
|
.map(option => {
|
|
2293
2505
|
if (option.DefElem) {
|
|
2294
2506
|
const defElem = option.DefElem;
|
|
2295
|
-
|
|
2296
|
-
|
|
2507
|
+
if (defElem.defname === 'sequence_name') {
|
|
2508
|
+
if (defElem.arg && defElem.arg.List) {
|
|
2509
|
+
const nameList = ListUtils.unwrapList(defElem.arg)
|
|
2510
|
+
.map(item => this.visit(item, context))
|
|
2511
|
+
.join('.');
|
|
2512
|
+
return `SEQUENCE NAME ${nameList}`;
|
|
2513
|
+
}
|
|
2514
|
+
return 'SEQUENCE NAME';
|
|
2515
|
+
}
|
|
2516
|
+
else if (defElem.defname === 'start') {
|
|
2517
|
+
const argValue = defElem.arg ? this.visit(defElem.arg, context) : '';
|
|
2297
2518
|
return `START WITH ${argValue}`;
|
|
2298
2519
|
}
|
|
2299
2520
|
else if (defElem.defname === 'increment') {
|
|
2521
|
+
const argValue = defElem.arg ? this.visit(defElem.arg, context) : '';
|
|
2300
2522
|
return `INCREMENT BY ${argValue}`;
|
|
2301
2523
|
}
|
|
2302
2524
|
else if (defElem.defname === 'minvalue') {
|
|
2303
|
-
|
|
2525
|
+
if (defElem.arg) {
|
|
2526
|
+
const argValue = this.visit(defElem.arg, context);
|
|
2527
|
+
return `MINVALUE ${argValue}`;
|
|
2528
|
+
}
|
|
2529
|
+
else {
|
|
2530
|
+
return 'NO MINVALUE';
|
|
2531
|
+
}
|
|
2304
2532
|
}
|
|
2305
2533
|
else if (defElem.defname === 'maxvalue') {
|
|
2306
|
-
|
|
2534
|
+
if (defElem.arg) {
|
|
2535
|
+
const argValue = this.visit(defElem.arg, context);
|
|
2536
|
+
return `MAXVALUE ${argValue}`;
|
|
2537
|
+
}
|
|
2538
|
+
else {
|
|
2539
|
+
return 'NO MAXVALUE';
|
|
2540
|
+
}
|
|
2307
2541
|
}
|
|
2308
2542
|
else if (defElem.defname === 'cache') {
|
|
2543
|
+
const argValue = defElem.arg ? this.visit(defElem.arg, context) : '';
|
|
2309
2544
|
return `CACHE ${argValue}`;
|
|
2310
2545
|
}
|
|
2311
2546
|
else if (defElem.defname === 'cycle') {
|
|
2547
|
+
const argValue = defElem.arg ? this.visit(defElem.arg, context) : '';
|
|
2312
2548
|
return argValue === 'true' ? 'CYCLE' : 'NO CYCLE';
|
|
2313
2549
|
}
|
|
2550
|
+
const argValue = defElem.arg ? this.visit(defElem.arg, context) : '';
|
|
2314
2551
|
return `${defElem.defname.toUpperCase()} ${argValue}`;
|
|
2315
2552
|
}
|
|
2316
2553
|
return this.visit(option, context);
|
|
2317
2554
|
});
|
|
2318
|
-
|
|
2555
|
+
if (context.isPretty()) {
|
|
2556
|
+
const indentedOptions = optionStrs.map(option => context.indent(option));
|
|
2557
|
+
output.push('(\n' + indentedOptions.join('\n') + '\n)');
|
|
2558
|
+
}
|
|
2559
|
+
else {
|
|
2560
|
+
output.push(`(${optionStrs.join(' ')})`);
|
|
2561
|
+
}
|
|
2319
2562
|
}
|
|
2320
2563
|
break;
|
|
2321
2564
|
case 'CONSTR_PRIMARY':
|
|
@@ -2332,7 +2575,12 @@ export class Deparser {
|
|
|
2332
2575
|
}
|
|
2333
2576
|
break;
|
|
2334
2577
|
case 'CONSTR_UNIQUE':
|
|
2335
|
-
|
|
2578
|
+
if (context.isPretty() && !context.isColumnConstraint) {
|
|
2579
|
+
output.push('\n' + context.indent('UNIQUE'));
|
|
2580
|
+
}
|
|
2581
|
+
else {
|
|
2582
|
+
output.push('UNIQUE');
|
|
2583
|
+
}
|
|
2336
2584
|
if (node.nulls_not_distinct) {
|
|
2337
2585
|
output.push('NULLS NOT DISTINCT');
|
|
2338
2586
|
}
|
|
@@ -2350,33 +2598,77 @@ export class Deparser {
|
|
|
2350
2598
|
case 'CONSTR_FOREIGN':
|
|
2351
2599
|
// Only add "FOREIGN KEY" for table-level constraints, not column-level constraints
|
|
2352
2600
|
if (!context.isColumnConstraint) {
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2601
|
+
if (context.isPretty()) {
|
|
2602
|
+
output.push('\n' + context.indent('FOREIGN KEY'));
|
|
2603
|
+
if (node.fk_attrs && node.fk_attrs.length > 0) {
|
|
2604
|
+
const fkAttrs = ListUtils.unwrapList(node.fk_attrs)
|
|
2605
|
+
.map(attr => this.visit(attr, context))
|
|
2606
|
+
.join(', ');
|
|
2607
|
+
output.push(`(${fkAttrs})`);
|
|
2608
|
+
}
|
|
2609
|
+
output.push('\n' + context.indent('REFERENCES'));
|
|
2610
|
+
}
|
|
2611
|
+
else {
|
|
2612
|
+
output.push('FOREIGN KEY');
|
|
2613
|
+
if (node.fk_attrs && node.fk_attrs.length > 0) {
|
|
2614
|
+
const fkAttrs = ListUtils.unwrapList(node.fk_attrs)
|
|
2615
|
+
.map(attr => this.visit(attr, context))
|
|
2616
|
+
.join(', ');
|
|
2617
|
+
output.push(`(${fkAttrs})`);
|
|
2618
|
+
}
|
|
2619
|
+
output.push('REFERENCES');
|
|
2359
2620
|
}
|
|
2360
2621
|
}
|
|
2361
|
-
|
|
2622
|
+
else {
|
|
2623
|
+
output.push('REFERENCES');
|
|
2624
|
+
}
|
|
2362
2625
|
if (node.pktable) {
|
|
2363
|
-
|
|
2626
|
+
if (context.isPretty() && !context.isColumnConstraint) {
|
|
2627
|
+
const lastIndex = output.length - 1;
|
|
2628
|
+
if (lastIndex >= 0 && output[lastIndex].includes('REFERENCES')) {
|
|
2629
|
+
output[lastIndex] += ' ' + this.RangeVar(node.pktable, context);
|
|
2630
|
+
}
|
|
2631
|
+
else {
|
|
2632
|
+
output.push(this.RangeVar(node.pktable, context));
|
|
2633
|
+
}
|
|
2634
|
+
}
|
|
2635
|
+
else {
|
|
2636
|
+
output.push(this.RangeVar(node.pktable, context));
|
|
2637
|
+
}
|
|
2364
2638
|
}
|
|
2365
2639
|
if (node.pk_attrs && node.pk_attrs.length > 0) {
|
|
2366
2640
|
const pkAttrs = ListUtils.unwrapList(node.pk_attrs)
|
|
2367
2641
|
.map(attr => this.visit(attr, context))
|
|
2368
2642
|
.join(', ');
|
|
2369
|
-
|
|
2643
|
+
if (context.isPretty() && !context.isColumnConstraint) {
|
|
2644
|
+
const lastIndex = output.length - 1;
|
|
2645
|
+
if (lastIndex >= 0) {
|
|
2646
|
+
output[lastIndex] += ` (${pkAttrs})`;
|
|
2647
|
+
}
|
|
2648
|
+
else {
|
|
2649
|
+
output.push(`(${pkAttrs})`);
|
|
2650
|
+
}
|
|
2651
|
+
}
|
|
2652
|
+
else {
|
|
2653
|
+
output.push(`(${pkAttrs})`);
|
|
2654
|
+
}
|
|
2370
2655
|
}
|
|
2371
2656
|
if (node.fk_matchtype && node.fk_matchtype !== 's') {
|
|
2657
|
+
let matchClause = '';
|
|
2372
2658
|
switch (node.fk_matchtype) {
|
|
2373
2659
|
case 'f':
|
|
2374
|
-
|
|
2660
|
+
matchClause = 'MATCH FULL';
|
|
2375
2661
|
break;
|
|
2376
2662
|
case 'p':
|
|
2377
|
-
|
|
2663
|
+
matchClause = 'MATCH PARTIAL';
|
|
2378
2664
|
break;
|
|
2379
2665
|
}
|
|
2666
|
+
if (context.isPretty() && !context.isColumnConstraint) {
|
|
2667
|
+
output.push('\n' + context.indent(matchClause));
|
|
2668
|
+
}
|
|
2669
|
+
else {
|
|
2670
|
+
output.push(matchClause);
|
|
2671
|
+
}
|
|
2380
2672
|
}
|
|
2381
2673
|
if (node.fk_upd_action && node.fk_upd_action !== 'a') {
|
|
2382
2674
|
let updateClause = 'ON UPDATE ';
|
|
@@ -2394,8 +2686,8 @@ export class Deparser {
|
|
|
2394
2686
|
updateClause += 'SET DEFAULT';
|
|
2395
2687
|
break;
|
|
2396
2688
|
}
|
|
2397
|
-
if (
|
|
2398
|
-
output.push('\n' +
|
|
2689
|
+
if (context.isPretty()) {
|
|
2690
|
+
output.push('\n' + context.indent(updateClause));
|
|
2399
2691
|
}
|
|
2400
2692
|
else {
|
|
2401
2693
|
output.push('ON UPDATE');
|
|
@@ -2418,8 +2710,8 @@ export class Deparser {
|
|
|
2418
2710
|
deleteClause += 'SET DEFAULT';
|
|
2419
2711
|
break;
|
|
2420
2712
|
}
|
|
2421
|
-
if (
|
|
2422
|
-
output.push('\n' +
|
|
2713
|
+
if (context.isPretty()) {
|
|
2714
|
+
output.push('\n' + context.indent(deleteClause));
|
|
2423
2715
|
}
|
|
2424
2716
|
else {
|
|
2425
2717
|
output.push('ON DELETE');
|
|
@@ -2428,7 +2720,12 @@ export class Deparser {
|
|
|
2428
2720
|
}
|
|
2429
2721
|
// Handle NOT VALID for foreign key constraints - only for table constraints, not domain constraints
|
|
2430
2722
|
if (node.skip_validation && !context.isDomainConstraint) {
|
|
2431
|
-
|
|
2723
|
+
if (context.isPretty() && !context.isColumnConstraint) {
|
|
2724
|
+
output.push('\n' + context.indent('NOT VALID'));
|
|
2725
|
+
}
|
|
2726
|
+
else {
|
|
2727
|
+
output.push('NOT VALID');
|
|
2728
|
+
}
|
|
2432
2729
|
}
|
|
2433
2730
|
break;
|
|
2434
2731
|
case 'CONSTR_ATTR_DEFERRABLE':
|
|
@@ -2482,13 +2779,13 @@ export class Deparser {
|
|
|
2482
2779
|
// Handle deferrable constraints for all constraint types that support it
|
|
2483
2780
|
if (node.contype === 'CONSTR_PRIMARY' || node.contype === 'CONSTR_UNIQUE' || node.contype === 'CONSTR_FOREIGN') {
|
|
2484
2781
|
if (node.deferrable) {
|
|
2485
|
-
if (
|
|
2486
|
-
output.push('\n' +
|
|
2782
|
+
if (context.isPretty() && node.contype === 'CONSTR_FOREIGN') {
|
|
2783
|
+
output.push('\n' + context.indent('DEFERRABLE'));
|
|
2487
2784
|
if (node.initdeferred === true) {
|
|
2488
|
-
output.push('\n' +
|
|
2785
|
+
output.push('\n' + context.indent('INITIALLY DEFERRED'));
|
|
2489
2786
|
}
|
|
2490
2787
|
else if (node.initdeferred === false) {
|
|
2491
|
-
output.push('\n' +
|
|
2788
|
+
output.push('\n' + context.indent('INITIALLY IMMEDIATE'));
|
|
2492
2789
|
}
|
|
2493
2790
|
}
|
|
2494
2791
|
else {
|
|
@@ -2502,15 +2799,15 @@ export class Deparser {
|
|
|
2502
2799
|
}
|
|
2503
2800
|
}
|
|
2504
2801
|
else if (node.deferrable === false) {
|
|
2505
|
-
if (
|
|
2506
|
-
output.push('\n' +
|
|
2802
|
+
if (context.isPretty() && node.contype === 'CONSTR_FOREIGN') {
|
|
2803
|
+
output.push('\n' + context.indent('NOT DEFERRABLE'));
|
|
2507
2804
|
}
|
|
2508
2805
|
else {
|
|
2509
2806
|
output.push('NOT DEFERRABLE');
|
|
2510
2807
|
}
|
|
2511
2808
|
}
|
|
2512
2809
|
}
|
|
2513
|
-
if (
|
|
2810
|
+
if (context.isPretty() && node.contype === 'CONSTR_FOREIGN') {
|
|
2514
2811
|
let result = '';
|
|
2515
2812
|
for (let i = 0; i < output.length; i++) {
|
|
2516
2813
|
if (output[i].startsWith('\n')) {
|
|
@@ -2528,12 +2825,12 @@ export class Deparser {
|
|
|
2528
2825
|
return output.join(' ');
|
|
2529
2826
|
}
|
|
2530
2827
|
SubLink(node, context) {
|
|
2531
|
-
const subselect =
|
|
2828
|
+
const subselect = context.parens(this.visit(node.subselect, context));
|
|
2532
2829
|
switch (node.subLinkType) {
|
|
2533
2830
|
case 'ANY_SUBLINK':
|
|
2534
2831
|
if (node.testexpr && node.operName) {
|
|
2535
2832
|
const testExpr = this.visit(node.testexpr, context);
|
|
2536
|
-
const operator = this.deparseOperatorName(node.operName);
|
|
2833
|
+
const operator = this.deparseOperatorName(node.operName, context);
|
|
2537
2834
|
return `${testExpr} ${operator} ANY ${subselect}`;
|
|
2538
2835
|
}
|
|
2539
2836
|
else if (node.testexpr) {
|
|
@@ -2544,7 +2841,7 @@ export class Deparser {
|
|
|
2544
2841
|
case 'ALL_SUBLINK':
|
|
2545
2842
|
if (node.testexpr && node.operName) {
|
|
2546
2843
|
const testExpr = this.visit(node.testexpr, context);
|
|
2547
|
-
const operator = this.deparseOperatorName(node.operName);
|
|
2844
|
+
const operator = this.deparseOperatorName(node.operName, context);
|
|
2548
2845
|
return `${testExpr} ${operator} ALL ${subselect}`;
|
|
2549
2846
|
}
|
|
2550
2847
|
return subselect;
|
|
@@ -2586,7 +2883,7 @@ export class Deparser {
|
|
|
2586
2883
|
}
|
|
2587
2884
|
// Only add frame clause if frameOptions indicates non-default framing
|
|
2588
2885
|
if (node.frameOptions && node.frameOptions !== 1058) {
|
|
2589
|
-
const frameClause = this.formatWindowFrame(node);
|
|
2886
|
+
const frameClause = this.formatWindowFrame(node, context.spawn('WindowDef'));
|
|
2590
2887
|
if (frameClause) {
|
|
2591
2888
|
windowParts.push(frameClause);
|
|
2592
2889
|
}
|
|
@@ -2606,7 +2903,7 @@ export class Deparser {
|
|
|
2606
2903
|
}
|
|
2607
2904
|
return output.join(' ');
|
|
2608
2905
|
}
|
|
2609
|
-
formatWindowFrame(node) {
|
|
2906
|
+
formatWindowFrame(node, context) {
|
|
2610
2907
|
if (!node.frameOptions)
|
|
2611
2908
|
return null;
|
|
2612
2909
|
const frameOptions = node.frameOptions;
|
|
@@ -2615,7 +2912,7 @@ export class Deparser {
|
|
|
2615
2912
|
if (frameOptions & 0x02) { // FRAMEOPTION_RANGE
|
|
2616
2913
|
frameParts.push('RANGE');
|
|
2617
2914
|
}
|
|
2618
|
-
else if (frameOptions & 0x04) { // FRAMEOPTION_ROWS
|
|
2915
|
+
else if (frameOptions & 0x04) { // FRAMEOPTION_ROWS
|
|
2619
2916
|
frameParts.push('ROWS');
|
|
2620
2917
|
}
|
|
2621
2918
|
else if (frameOptions & 0x08) { // FRAMEOPTION_GROUPS
|
|
@@ -2636,8 +2933,8 @@ export class Deparser {
|
|
|
2636
2933
|
}
|
|
2637
2934
|
else if (frameOptions === 18453) {
|
|
2638
2935
|
if (node.startOffset && node.endOffset) {
|
|
2639
|
-
boundsParts.push(`${this.visit(node.startOffset,
|
|
2640
|
-
boundsParts.push(`AND ${this.visit(node.endOffset,
|
|
2936
|
+
boundsParts.push(`${this.visit(node.startOffset, context)} PRECEDING`);
|
|
2937
|
+
boundsParts.push(`AND ${this.visit(node.endOffset, context)} FOLLOWING`);
|
|
2641
2938
|
}
|
|
2642
2939
|
}
|
|
2643
2940
|
else if (frameOptions === 1557) {
|
|
@@ -2647,7 +2944,7 @@ export class Deparser {
|
|
|
2647
2944
|
else if (frameOptions === 16917) {
|
|
2648
2945
|
boundsParts.push('CURRENT ROW');
|
|
2649
2946
|
if (node.endOffset) {
|
|
2650
|
-
boundsParts.push(`AND ${this.visit(node.endOffset,
|
|
2947
|
+
boundsParts.push(`AND ${this.visit(node.endOffset, context)} FOLLOWING`);
|
|
2651
2948
|
}
|
|
2652
2949
|
}
|
|
2653
2950
|
else if (frameOptions === 1058) {
|
|
@@ -2657,13 +2954,13 @@ export class Deparser {
|
|
|
2657
2954
|
// Handle start bound - prioritize explicit offset values over bit flags
|
|
2658
2955
|
if (node.startOffset) {
|
|
2659
2956
|
if (frameOptions & 0x400) { // FRAMEOPTION_START_VALUE_PRECEDING
|
|
2660
|
-
boundsParts.push(`${this.visit(node.startOffset,
|
|
2957
|
+
boundsParts.push(`${this.visit(node.startOffset, context)} PRECEDING`);
|
|
2661
2958
|
}
|
|
2662
2959
|
else if (frameOptions & 0x800) { // FRAMEOPTION_START_VALUE_FOLLOWING
|
|
2663
|
-
boundsParts.push(`${this.visit(node.startOffset,
|
|
2960
|
+
boundsParts.push(`${this.visit(node.startOffset, context)} FOLLOWING`);
|
|
2664
2961
|
}
|
|
2665
2962
|
else {
|
|
2666
|
-
boundsParts.push(`${this.visit(node.startOffset,
|
|
2963
|
+
boundsParts.push(`${this.visit(node.startOffset, context)} PRECEDING`);
|
|
2667
2964
|
}
|
|
2668
2965
|
}
|
|
2669
2966
|
else if (frameOptions & 0x10) { // FRAMEOPTION_START_UNBOUNDED_PRECEDING
|
|
@@ -2676,13 +2973,13 @@ export class Deparser {
|
|
|
2676
2973
|
if (node.endOffset) {
|
|
2677
2974
|
if (boundsParts.length > 0) {
|
|
2678
2975
|
if (frameOptions & 0x1000) { // FRAMEOPTION_END_VALUE_PRECEDING
|
|
2679
|
-
boundsParts.push(`AND ${this.visit(node.endOffset,
|
|
2976
|
+
boundsParts.push(`AND ${this.visit(node.endOffset, context)} PRECEDING`);
|
|
2680
2977
|
}
|
|
2681
2978
|
else if (frameOptions & 0x2000) { // FRAMEOPTION_END_VALUE_FOLLOWING
|
|
2682
|
-
boundsParts.push(`AND ${this.visit(node.endOffset,
|
|
2979
|
+
boundsParts.push(`AND ${this.visit(node.endOffset, context)} FOLLOWING`);
|
|
2683
2980
|
}
|
|
2684
2981
|
else {
|
|
2685
|
-
boundsParts.push(`AND ${this.visit(node.endOffset,
|
|
2982
|
+
boundsParts.push(`AND ${this.visit(node.endOffset, context)} FOLLOWING`);
|
|
2686
2983
|
}
|
|
2687
2984
|
}
|
|
2688
2985
|
}
|
|
@@ -2767,7 +3064,7 @@ export class Deparser {
|
|
|
2767
3064
|
const colnames = ListUtils.unwrapList(node.aliascolnames);
|
|
2768
3065
|
const colnameStrs = colnames.map(col => this.visit(col, context));
|
|
2769
3066
|
// Don't add space before column list parentheses to match original formatting
|
|
2770
|
-
output[output.length - 1] +=
|
|
3067
|
+
output[output.length - 1] += context.parens(colnameStrs.join(', '));
|
|
2771
3068
|
}
|
|
2772
3069
|
output.push('AS');
|
|
2773
3070
|
// Handle materialization clauses
|
|
@@ -2778,7 +3075,7 @@ export class Deparser {
|
|
|
2778
3075
|
output.push('MATERIALIZED');
|
|
2779
3076
|
}
|
|
2780
3077
|
if (node.ctequery) {
|
|
2781
|
-
output.push(
|
|
3078
|
+
output.push(context.parens(this.visit(node.ctequery, context)));
|
|
2782
3079
|
}
|
|
2783
3080
|
return output.join(' ');
|
|
2784
3081
|
}
|
|
@@ -2854,7 +3151,7 @@ export class Deparser {
|
|
|
2854
3151
|
DistinctExpr(node, context) {
|
|
2855
3152
|
const args = ListUtils.unwrapList(node.args);
|
|
2856
3153
|
if (args.length === 2) {
|
|
2857
|
-
const literalContext =
|
|
3154
|
+
const literalContext = context.spawn('DistinctExpr', { isStringLiteral: true });
|
|
2858
3155
|
const left = this.visit(args[0], literalContext);
|
|
2859
3156
|
const right = this.visit(args[1], literalContext);
|
|
2860
3157
|
return `${left} IS DISTINCT FROM ${right}`;
|
|
@@ -2864,7 +3161,7 @@ export class Deparser {
|
|
|
2864
3161
|
NullIfExpr(node, context) {
|
|
2865
3162
|
const args = ListUtils.unwrapList(node.args);
|
|
2866
3163
|
if (args.length === 2) {
|
|
2867
|
-
const literalContext =
|
|
3164
|
+
const literalContext = context.spawn('NullIfExpr', { isStringLiteral: true });
|
|
2868
3165
|
const left = this.visit(args[0], literalContext);
|
|
2869
3166
|
const right = this.visit(args[1], literalContext);
|
|
2870
3167
|
return `NULLIF(${left}, ${right})`;
|
|
@@ -2943,7 +3240,7 @@ export class Deparser {
|
|
|
2943
3240
|
}
|
|
2944
3241
|
RelabelType(node, context) {
|
|
2945
3242
|
if (node.arg) {
|
|
2946
|
-
const literalContext =
|
|
3243
|
+
const literalContext = context.spawn('RelabelType', { isStringLiteral: true });
|
|
2947
3244
|
return this.visit(node.arg, literalContext);
|
|
2948
3245
|
}
|
|
2949
3246
|
return '';
|
|
@@ -2962,7 +3259,7 @@ export class Deparser {
|
|
|
2962
3259
|
}
|
|
2963
3260
|
ConvertRowtypeExpr(node, context) {
|
|
2964
3261
|
if (node.arg) {
|
|
2965
|
-
const literalContext =
|
|
3262
|
+
const literalContext = context.spawn('ConvertRowtypeExpr', { isStringLiteral: true });
|
|
2966
3263
|
return this.visit(node.arg, literalContext);
|
|
2967
3264
|
}
|
|
2968
3265
|
return '';
|
|
@@ -2993,10 +3290,10 @@ export class Deparser {
|
|
|
2993
3290
|
}
|
|
2994
3291
|
if (node.aliases && node.aliases.length > 0) {
|
|
2995
3292
|
const aliasStrs = ListUtils.unwrapList(node.aliases).map(alias => this.visit(alias, context));
|
|
2996
|
-
output.push(
|
|
3293
|
+
output.push(context.parens(aliasStrs.join(', ')));
|
|
2997
3294
|
}
|
|
2998
3295
|
if (node.options && node.options.length > 0) {
|
|
2999
|
-
const viewContext =
|
|
3296
|
+
const viewContext = context.spawn('ViewStmt');
|
|
3000
3297
|
const optionStrs = ListUtils.unwrapList(node.options)
|
|
3001
3298
|
.map(option => this.visit(option, viewContext));
|
|
3002
3299
|
output.push(`WITH (${optionStrs.join(', ')})`);
|
|
@@ -3043,22 +3340,22 @@ export class Deparser {
|
|
|
3043
3340
|
}
|
|
3044
3341
|
if (node.indexParams && node.indexParams.length > 0) {
|
|
3045
3342
|
const paramStrs = ListUtils.unwrapList(node.indexParams).map(param => this.visit(param, context));
|
|
3046
|
-
output.push(
|
|
3343
|
+
output.push(context.parens(paramStrs.join(', ')));
|
|
3047
3344
|
}
|
|
3048
3345
|
if (node.indexIncludingParams && node.indexIncludingParams.length > 0) {
|
|
3049
3346
|
const includeStrs = ListUtils.unwrapList(node.indexIncludingParams).map(param => this.visit(param, context));
|
|
3050
3347
|
output.push('INCLUDE');
|
|
3051
|
-
output.push(
|
|
3348
|
+
output.push(context.parens(includeStrs.join(', ')));
|
|
3052
3349
|
}
|
|
3053
3350
|
if (node.whereClause) {
|
|
3054
3351
|
output.push('WHERE');
|
|
3055
3352
|
output.push(this.visit(node.whereClause, context));
|
|
3056
3353
|
}
|
|
3057
3354
|
if (node.options && node.options.length > 0) {
|
|
3058
|
-
const indexContext =
|
|
3355
|
+
const indexContext = context.spawn('IndexStmt');
|
|
3059
3356
|
const optionStrs = ListUtils.unwrapList(node.options).map(option => this.visit(option, indexContext));
|
|
3060
3357
|
output.push('WITH');
|
|
3061
|
-
output.push(
|
|
3358
|
+
output.push(context.parens(optionStrs.join(', ')));
|
|
3062
3359
|
}
|
|
3063
3360
|
if (node.nulls_not_distinct) {
|
|
3064
3361
|
output.push('NULLS NOT DISTINCT');
|
|
@@ -3075,7 +3372,7 @@ export class Deparser {
|
|
|
3075
3372
|
output.push(QuoteUtils.quote(node.name));
|
|
3076
3373
|
}
|
|
3077
3374
|
else if (node.expr) {
|
|
3078
|
-
output.push(
|
|
3375
|
+
output.push(context.parens(this.visit(node.expr, context)));
|
|
3079
3376
|
}
|
|
3080
3377
|
if (node.collation && node.collation.length > 0) {
|
|
3081
3378
|
const collationStrs = ListUtils.unwrapList(node.collation).map(coll => this.visit(coll, context));
|
|
@@ -3092,7 +3389,7 @@ export class Deparser {
|
|
|
3092
3389
|
const stringData = this.getNodeData(opt.DefElem.arg);
|
|
3093
3390
|
return `${opt.DefElem.defname}='${stringData.sval}'`;
|
|
3094
3391
|
}
|
|
3095
|
-
return this.visit(opt, context);
|
|
3392
|
+
return this.visit(opt, context.spawn('IndexElem'));
|
|
3096
3393
|
});
|
|
3097
3394
|
opclassStr += `(${opclassOpts.join(', ')})`;
|
|
3098
3395
|
}
|
|
@@ -3126,7 +3423,7 @@ export class Deparser {
|
|
|
3126
3423
|
output.push(QuoteUtils.quote(node.name));
|
|
3127
3424
|
}
|
|
3128
3425
|
else if (node.expr) {
|
|
3129
|
-
output.push(
|
|
3426
|
+
output.push(context.parens(this.visit(node.expr, context)));
|
|
3130
3427
|
}
|
|
3131
3428
|
if (node.collation && node.collation.length > 0) {
|
|
3132
3429
|
const collationStrs = ListUtils.unwrapList(node.collation).map(coll => this.visit(coll, context));
|
|
@@ -3274,16 +3571,16 @@ export class Deparser {
|
|
|
3274
3571
|
if (node.rarg && 'JoinExpr' in node.rarg && !node.rarg.JoinExpr.alias) {
|
|
3275
3572
|
rargStr = `(${rargStr})`;
|
|
3276
3573
|
}
|
|
3277
|
-
if (
|
|
3278
|
-
output.push(
|
|
3574
|
+
if (context.isPretty()) {
|
|
3575
|
+
output.push(context.newline() + joinStr + ' ' + rargStr);
|
|
3279
3576
|
}
|
|
3280
3577
|
else {
|
|
3281
3578
|
output.push(joinStr + ' ' + rargStr);
|
|
3282
3579
|
}
|
|
3283
3580
|
}
|
|
3284
3581
|
else {
|
|
3285
|
-
if (
|
|
3286
|
-
output.push(
|
|
3582
|
+
if (context.isPretty()) {
|
|
3583
|
+
output.push(context.newline() + joinStr);
|
|
3287
3584
|
}
|
|
3288
3585
|
else {
|
|
3289
3586
|
output.push(joinStr);
|
|
@@ -3292,7 +3589,7 @@ export class Deparser {
|
|
|
3292
3589
|
if (node.usingClause && node.usingClause.length > 0) {
|
|
3293
3590
|
const usingList = ListUtils.unwrapList(node.usingClause);
|
|
3294
3591
|
const columnNames = usingList.map(col => this.visit(col, context));
|
|
3295
|
-
if (
|
|
3592
|
+
if (context.isPretty()) {
|
|
3296
3593
|
output.push(` USING (${columnNames.join(', ')})`);
|
|
3297
3594
|
}
|
|
3298
3595
|
else {
|
|
@@ -3301,14 +3598,14 @@ export class Deparser {
|
|
|
3301
3598
|
}
|
|
3302
3599
|
else if (node.quals) {
|
|
3303
3600
|
const qualsStr = this.visit(node.quals, context);
|
|
3304
|
-
if (
|
|
3601
|
+
if (context.isPretty()) {
|
|
3305
3602
|
// For complex JOIN conditions, format with proper indentation
|
|
3306
3603
|
if (qualsStr.includes('AND') || qualsStr.includes('OR') || qualsStr.length > 50) {
|
|
3307
3604
|
if (this.containsMultilineStringLiteral(qualsStr)) {
|
|
3308
3605
|
output.push(` ON ${qualsStr}`);
|
|
3309
3606
|
}
|
|
3310
3607
|
else {
|
|
3311
|
-
output.push(` ON${
|
|
3608
|
+
output.push(` ON${context.newline()}${context.indent(qualsStr)}`);
|
|
3312
3609
|
}
|
|
3313
3610
|
}
|
|
3314
3611
|
else {
|
|
@@ -3320,7 +3617,7 @@ export class Deparser {
|
|
|
3320
3617
|
}
|
|
3321
3618
|
}
|
|
3322
3619
|
let result;
|
|
3323
|
-
if (
|
|
3620
|
+
if (context.isPretty()) {
|
|
3324
3621
|
result = output.join('');
|
|
3325
3622
|
}
|
|
3326
3623
|
else {
|
|
@@ -3427,8 +3724,8 @@ export class Deparser {
|
|
|
3427
3724
|
else if (nodeData.sval !== undefined) {
|
|
3428
3725
|
// Handle nested sval structure: { sval: { sval: "value" } }
|
|
3429
3726
|
const svalValue = typeof nodeData.sval === 'object' ? nodeData.sval.sval : nodeData.sval;
|
|
3430
|
-
const stringValue = svalValue.replace(/'/g, '')
|
|
3431
|
-
boolValue = stringValue === 'on' || stringValue === 'true';
|
|
3727
|
+
const stringValue = svalValue.replace(/'/g, '');
|
|
3728
|
+
boolValue = stringValue.toLowerCase() === 'on' || stringValue.toLowerCase() === 'true';
|
|
3432
3729
|
}
|
|
3433
3730
|
}
|
|
3434
3731
|
return boolValue ? 'READ ONLY' : 'READ WRITE';
|
|
@@ -3451,8 +3748,8 @@ export class Deparser {
|
|
|
3451
3748
|
else if (nodeData.sval !== undefined) {
|
|
3452
3749
|
// Handle nested sval structure: { sval: { sval: "value" } }
|
|
3453
3750
|
const svalValue = typeof nodeData.sval === 'object' ? nodeData.sval.sval : nodeData.sval;
|
|
3454
|
-
const stringValue = svalValue.replace(/'/g, '')
|
|
3455
|
-
boolValue = stringValue === 'on' || stringValue === 'true';
|
|
3751
|
+
const stringValue = svalValue.replace(/'/g, '');
|
|
3752
|
+
boolValue = stringValue.toLowerCase() === 'on' || stringValue.toLowerCase() === 'true';
|
|
3456
3753
|
}
|
|
3457
3754
|
}
|
|
3458
3755
|
return boolValue ? 'DEFERRABLE' : 'NOT DEFERRABLE';
|
|
@@ -3519,8 +3816,8 @@ export class Deparser {
|
|
|
3519
3816
|
else if (nodeData.sval !== undefined) {
|
|
3520
3817
|
// Handle nested sval structure: { sval: { sval: "value" } }
|
|
3521
3818
|
const svalValue = typeof nodeData.sval === 'object' ? nodeData.sval.sval : nodeData.sval;
|
|
3522
|
-
const stringValue = svalValue.replace(/'/g, '')
|
|
3523
|
-
boolValue = stringValue === 'on' || stringValue === 'true';
|
|
3819
|
+
const stringValue = svalValue.replace(/'/g, '');
|
|
3820
|
+
boolValue = stringValue.toLowerCase() === 'on' || stringValue.toLowerCase() === 'true';
|
|
3524
3821
|
}
|
|
3525
3822
|
}
|
|
3526
3823
|
transactionOptions.push(boolValue ? 'READ ONLY' : 'READ WRITE');
|
|
@@ -3538,8 +3835,8 @@ export class Deparser {
|
|
|
3538
3835
|
else if (nodeData.sval !== undefined) {
|
|
3539
3836
|
// Handle nested sval structure: { sval: { sval: "value" } }
|
|
3540
3837
|
const svalValue = typeof nodeData.sval === 'object' ? nodeData.sval.sval : nodeData.sval;
|
|
3541
|
-
const stringValue = svalValue.replace(/'/g, '')
|
|
3542
|
-
boolValue = stringValue === 'on' || stringValue === 'true';
|
|
3838
|
+
const stringValue = svalValue.replace(/'/g, '');
|
|
3839
|
+
boolValue = stringValue.toLowerCase() === 'on' || stringValue.toLowerCase() === 'true';
|
|
3543
3840
|
}
|
|
3544
3841
|
}
|
|
3545
3842
|
transactionOptions.push(boolValue ? 'DEFERRABLE' : 'NOT DEFERRABLE');
|
|
@@ -3605,7 +3902,7 @@ export class Deparser {
|
|
|
3605
3902
|
}
|
|
3606
3903
|
switch (node.roletype) {
|
|
3607
3904
|
case 'ROLESPEC_PUBLIC':
|
|
3608
|
-
return '
|
|
3905
|
+
return 'PUBLIC';
|
|
3609
3906
|
case 'ROLESPEC_CURRENT_USER':
|
|
3610
3907
|
return 'CURRENT_USER';
|
|
3611
3908
|
case 'ROLESPEC_SESSION_USER':
|
|
@@ -3613,7 +3910,7 @@ export class Deparser {
|
|
|
3613
3910
|
case 'ROLESPEC_CURRENT_ROLE':
|
|
3614
3911
|
return 'CURRENT_ROLE';
|
|
3615
3912
|
default:
|
|
3616
|
-
return '
|
|
3913
|
+
return 'PUBLIC';
|
|
3617
3914
|
}
|
|
3618
3915
|
}
|
|
3619
3916
|
roletype(node, context) {
|
|
@@ -3923,7 +4220,7 @@ export class Deparser {
|
|
|
3923
4220
|
}).filter((name) => name && name.trim());
|
|
3924
4221
|
return items.join('.');
|
|
3925
4222
|
}
|
|
3926
|
-
const objContext =
|
|
4223
|
+
const objContext = context.spawn('DropStmt', { objtype: node.removeType });
|
|
3927
4224
|
const objName = this.visit(objList, objContext);
|
|
3928
4225
|
return objName;
|
|
3929
4226
|
}).filter((name) => name && name.trim()).join(', ');
|
|
@@ -4023,7 +4320,7 @@ export class Deparser {
|
|
|
4023
4320
|
if (node.options && node.options.length > 0) {
|
|
4024
4321
|
output.push('WITH');
|
|
4025
4322
|
const optionsStr = ListUtils.unwrapList(node.options)
|
|
4026
|
-
.map(opt => this.visit(opt, context))
|
|
4323
|
+
.map(opt => this.visit(opt, context.spawn('CopyStmt')))
|
|
4027
4324
|
.join(', ');
|
|
4028
4325
|
output.push(`(${optionsStr})`);
|
|
4029
4326
|
}
|
|
@@ -4069,18 +4366,28 @@ export class Deparser {
|
|
|
4069
4366
|
if (node.missing_ok) {
|
|
4070
4367
|
output.push('IF EXISTS');
|
|
4071
4368
|
}
|
|
4072
|
-
const alterContext = node.objtype
|
|
4073
|
-
? { ...context, parentNodeTypes: [...context.parentNodeTypes, 'AlterTypeStmt'] }
|
|
4074
|
-
: context;
|
|
4369
|
+
const alterContext = context.spawn('AlterTableStmt', { objtype: node.objtype });
|
|
4075
4370
|
if (node.relation) {
|
|
4076
4371
|
const relationStr = this.RangeVar(node.relation, alterContext);
|
|
4077
4372
|
output.push(relationStr);
|
|
4078
4373
|
}
|
|
4079
4374
|
if (node.cmds && node.cmds.length > 0) {
|
|
4080
|
-
const
|
|
4081
|
-
|
|
4082
|
-
|
|
4083
|
-
|
|
4375
|
+
const commands = ListUtils.unwrapList(node.cmds);
|
|
4376
|
+
if (context.isPretty()) {
|
|
4377
|
+
const commandsStr = commands
|
|
4378
|
+
.map(cmd => {
|
|
4379
|
+
const cmdStr = this.visit(cmd, alterContext);
|
|
4380
|
+
return context.newline() + context.indent(cmdStr);
|
|
4381
|
+
})
|
|
4382
|
+
.join(',');
|
|
4383
|
+
output.push(commandsStr);
|
|
4384
|
+
}
|
|
4385
|
+
else {
|
|
4386
|
+
const commandsStr = commands
|
|
4387
|
+
.map(cmd => this.visit(cmd, alterContext))
|
|
4388
|
+
.join(', ');
|
|
4389
|
+
output.push(commandsStr);
|
|
4390
|
+
}
|
|
4084
4391
|
}
|
|
4085
4392
|
return output.join(' ');
|
|
4086
4393
|
}
|
|
@@ -4089,7 +4396,7 @@ export class Deparser {
|
|
|
4089
4396
|
if (node.subtype) {
|
|
4090
4397
|
switch (node.subtype) {
|
|
4091
4398
|
case 'AT_AddColumn':
|
|
4092
|
-
if (context.
|
|
4399
|
+
if (context.objtype === 'OBJECT_TYPE') {
|
|
4093
4400
|
output.push('ADD ATTRIBUTE');
|
|
4094
4401
|
}
|
|
4095
4402
|
else {
|
|
@@ -4100,35 +4407,99 @@ export class Deparser {
|
|
|
4100
4407
|
}
|
|
4101
4408
|
if (node.def) {
|
|
4102
4409
|
const colDefData = this.getNodeData(node.def);
|
|
4103
|
-
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
|
|
4110
|
-
|
|
4111
|
-
|
|
4112
|
-
|
|
4113
|
-
|
|
4114
|
-
|
|
4115
|
-
|
|
4116
|
-
|
|
4117
|
-
|
|
4118
|
-
|
|
4119
|
-
const
|
|
4120
|
-
|
|
4121
|
-
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
|
|
4410
|
+
if (context.isPretty()) {
|
|
4411
|
+
const parts = [];
|
|
4412
|
+
const indentedParts = [];
|
|
4413
|
+
if (colDefData.colname) {
|
|
4414
|
+
parts.push(QuoteUtils.quote(colDefData.colname));
|
|
4415
|
+
}
|
|
4416
|
+
if (colDefData.typeName) {
|
|
4417
|
+
parts.push(this.TypeName(colDefData.typeName, context));
|
|
4418
|
+
}
|
|
4419
|
+
if (colDefData.is_not_null) {
|
|
4420
|
+
indentedParts.push('NOT NULL');
|
|
4421
|
+
}
|
|
4422
|
+
if (colDefData.collClause) {
|
|
4423
|
+
indentedParts.push(this.CollateClause(colDefData.collClause, context));
|
|
4424
|
+
}
|
|
4425
|
+
if (colDefData.constraints) {
|
|
4426
|
+
const constraints = ListUtils.unwrapList(colDefData.constraints);
|
|
4427
|
+
constraints.forEach(constraint => {
|
|
4428
|
+
const columnConstraintContext = context.spawn('ColumnDef', { isColumnConstraint: true });
|
|
4429
|
+
const constraintStr = this.visit(constraint, columnConstraintContext);
|
|
4430
|
+
if (constraintStr.includes('REFERENCES') && constraintStr.includes('ON DELETE')) {
|
|
4431
|
+
const refMatch = constraintStr.match(/^(.*REFERENCES[^)]*\([^)]*\))\s*(ON\s+DELETE\s+CASCADE.*)$/);
|
|
4432
|
+
if (refMatch) {
|
|
4433
|
+
indentedParts.push(refMatch[1]);
|
|
4434
|
+
indentedParts.push(refMatch[2]);
|
|
4435
|
+
}
|
|
4436
|
+
else {
|
|
4437
|
+
indentedParts.push(constraintStr);
|
|
4438
|
+
}
|
|
4439
|
+
}
|
|
4440
|
+
else if (constraintStr === 'UNIQUE' && colDefData.raw_default) {
|
|
4441
|
+
const defaultStr = 'DEFAULT ' + this.visit(colDefData.raw_default, context);
|
|
4442
|
+
indentedParts.push('UNIQUE ' + defaultStr);
|
|
4443
|
+
}
|
|
4444
|
+
else {
|
|
4445
|
+
indentedParts.push(constraintStr);
|
|
4446
|
+
}
|
|
4447
|
+
});
|
|
4448
|
+
}
|
|
4449
|
+
if (colDefData.raw_default && !colDefData.constraints?.some((c) => {
|
|
4450
|
+
const constraintStr = this.visit(c, context.spawn('ColumnDef', { isColumnConstraint: true }));
|
|
4451
|
+
return constraintStr === 'UNIQUE';
|
|
4452
|
+
})) {
|
|
4453
|
+
const defaultStr = 'DEFAULT ' + this.visit(colDefData.raw_default, context);
|
|
4454
|
+
indentedParts.push(defaultStr);
|
|
4455
|
+
}
|
|
4456
|
+
if (colDefData.fdwoptions && colDefData.fdwoptions.length > 0) {
|
|
4457
|
+
indentedParts.push('OPTIONS');
|
|
4458
|
+
const columnContext = context.spawn('ColumnDef');
|
|
4459
|
+
const options = ListUtils.unwrapList(colDefData.fdwoptions).map(opt => this.visit(opt, columnContext));
|
|
4460
|
+
indentedParts.push(`(${options.join(', ')})`);
|
|
4461
|
+
}
|
|
4462
|
+
let result = parts.join(' ');
|
|
4463
|
+
if (indentedParts.length > 0) {
|
|
4464
|
+
const indentedStr = indentedParts.map(part => context.indent(part)).join(context.newline());
|
|
4465
|
+
result += context.newline() + indentedStr;
|
|
4466
|
+
}
|
|
4467
|
+
output.push(result);
|
|
4127
4468
|
}
|
|
4128
|
-
|
|
4129
|
-
parts
|
|
4469
|
+
else {
|
|
4470
|
+
const parts = [];
|
|
4471
|
+
if (colDefData.colname) {
|
|
4472
|
+
parts.push(QuoteUtils.quote(colDefData.colname));
|
|
4473
|
+
}
|
|
4474
|
+
if (colDefData.typeName) {
|
|
4475
|
+
parts.push(this.TypeName(colDefData.typeName, context));
|
|
4476
|
+
}
|
|
4477
|
+
if (colDefData.collClause) {
|
|
4478
|
+
parts.push(this.CollateClause(colDefData.collClause, context));
|
|
4479
|
+
}
|
|
4480
|
+
if (colDefData.fdwoptions && colDefData.fdwoptions.length > 0) {
|
|
4481
|
+
parts.push('OPTIONS');
|
|
4482
|
+
const columnContext = context.spawn('ColumnDef');
|
|
4483
|
+
const options = ListUtils.unwrapList(colDefData.fdwoptions).map(opt => this.visit(opt, columnContext));
|
|
4484
|
+
parts.push(`(${options.join(', ')})`);
|
|
4485
|
+
}
|
|
4486
|
+
if (colDefData.constraints) {
|
|
4487
|
+
const constraints = ListUtils.unwrapList(colDefData.constraints);
|
|
4488
|
+
const constraintStrs = constraints.map(constraint => {
|
|
4489
|
+
const columnConstraintContext = context.spawn('ColumnDef', { isColumnConstraint: true });
|
|
4490
|
+
return this.visit(constraint, columnConstraintContext);
|
|
4491
|
+
});
|
|
4492
|
+
parts.push(...constraintStrs);
|
|
4493
|
+
}
|
|
4494
|
+
if (colDefData.raw_default) {
|
|
4495
|
+
parts.push('DEFAULT');
|
|
4496
|
+
parts.push(this.visit(colDefData.raw_default, context));
|
|
4497
|
+
}
|
|
4498
|
+
if (colDefData.is_not_null) {
|
|
4499
|
+
parts.push('NOT NULL');
|
|
4500
|
+
}
|
|
4501
|
+
output.push(parts.join(' '));
|
|
4130
4502
|
}
|
|
4131
|
-
output.push(parts.join(' '));
|
|
4132
4503
|
}
|
|
4133
4504
|
if (node.behavior === 'DROP_CASCADE') {
|
|
4134
4505
|
output.push('CASCADE');
|
|
@@ -4136,7 +4507,7 @@ export class Deparser {
|
|
|
4136
4507
|
break;
|
|
4137
4508
|
case 'AT_DropColumn':
|
|
4138
4509
|
if (node.missing_ok) {
|
|
4139
|
-
if (context.
|
|
4510
|
+
if (context.objtype === 'OBJECT_TYPE') {
|
|
4140
4511
|
output.push('DROP ATTRIBUTE IF EXISTS');
|
|
4141
4512
|
}
|
|
4142
4513
|
else {
|
|
@@ -4144,7 +4515,7 @@ export class Deparser {
|
|
|
4144
4515
|
}
|
|
4145
4516
|
}
|
|
4146
4517
|
else {
|
|
4147
|
-
if (context.
|
|
4518
|
+
if (context.objtype === 'OBJECT_TYPE') {
|
|
4148
4519
|
output.push('DROP ATTRIBUTE');
|
|
4149
4520
|
}
|
|
4150
4521
|
else {
|
|
@@ -4162,7 +4533,7 @@ export class Deparser {
|
|
|
4162
4533
|
}
|
|
4163
4534
|
break;
|
|
4164
4535
|
case 'AT_AlterColumnType':
|
|
4165
|
-
if (context.
|
|
4536
|
+
if (context.objtype === 'OBJECT_TYPE') {
|
|
4166
4537
|
output.push('ALTER ATTRIBUTE');
|
|
4167
4538
|
}
|
|
4168
4539
|
else {
|
|
@@ -4226,7 +4597,7 @@ export class Deparser {
|
|
|
4226
4597
|
case 'AT_SetRelOptions':
|
|
4227
4598
|
output.push('SET');
|
|
4228
4599
|
if (node.def) {
|
|
4229
|
-
const alterTableContext =
|
|
4600
|
+
const alterTableContext = context.spawn('AlterTableCmd', { subtype: 'AT_SetRelOptions' });
|
|
4230
4601
|
const options = ListUtils.unwrapList(node.def)
|
|
4231
4602
|
.map(option => this.visit(option, alterTableContext))
|
|
4232
4603
|
.join(', ');
|
|
@@ -4239,7 +4610,7 @@ export class Deparser {
|
|
|
4239
4610
|
case 'AT_ResetRelOptions':
|
|
4240
4611
|
output.push('RESET');
|
|
4241
4612
|
if (node.def) {
|
|
4242
|
-
const alterTableContext =
|
|
4613
|
+
const alterTableContext = context.spawn('AlterTableCmd', { subtype: 'AT_ResetRelOptions' });
|
|
4243
4614
|
const options = ListUtils.unwrapList(node.def)
|
|
4244
4615
|
.map(option => this.visit(option, alterTableContext))
|
|
4245
4616
|
.join(', ');
|
|
@@ -4334,7 +4705,7 @@ export class Deparser {
|
|
|
4334
4705
|
}
|
|
4335
4706
|
output.push('SET');
|
|
4336
4707
|
if (node.def) {
|
|
4337
|
-
const alterTableContext =
|
|
4708
|
+
const alterTableContext = context.spawn('AlterTableCmd', { subtype: 'AT_SetOptions' });
|
|
4338
4709
|
const options = ListUtils.unwrapList(node.def)
|
|
4339
4710
|
.map(option => this.visit(option, alterTableContext))
|
|
4340
4711
|
.join(', ');
|
|
@@ -4351,7 +4722,7 @@ export class Deparser {
|
|
|
4351
4722
|
}
|
|
4352
4723
|
output.push('RESET');
|
|
4353
4724
|
if (node.def) {
|
|
4354
|
-
const alterTableContext =
|
|
4725
|
+
const alterTableContext = context.spawn('AlterTableCmd', { subtype: 'AT_ResetOptions' });
|
|
4355
4726
|
const options = ListUtils.unwrapList(node.def)
|
|
4356
4727
|
.map(option => this.visit(option, alterTableContext))
|
|
4357
4728
|
.join(', ');
|
|
@@ -4592,7 +4963,7 @@ export class Deparser {
|
|
|
4592
4963
|
}
|
|
4593
4964
|
output.push('OPTIONS');
|
|
4594
4965
|
if (node.def) {
|
|
4595
|
-
const alterColumnContext =
|
|
4966
|
+
const alterColumnContext = context.spawn('AlterTableCmd', { alterColumnOptions: true });
|
|
4596
4967
|
const options = ListUtils.unwrapList(node.def)
|
|
4597
4968
|
.map(option => this.visit(option, alterColumnContext))
|
|
4598
4969
|
.join(', ');
|
|
@@ -4632,7 +5003,7 @@ export class Deparser {
|
|
|
4632
5003
|
case 'AT_GenericOptions':
|
|
4633
5004
|
output.push('OPTIONS');
|
|
4634
5005
|
if (node.def) {
|
|
4635
|
-
const alterTableContext =
|
|
5006
|
+
const alterTableContext = context.spawn('AlterTableCmd', { alterTableOptions: true });
|
|
4636
5007
|
const options = ListUtils.unwrapList(node.def)
|
|
4637
5008
|
.map(option => this.visit(option, alterTableContext))
|
|
4638
5009
|
.join(', ');
|
|
@@ -4644,11 +5015,10 @@ export class Deparser {
|
|
|
4644
5015
|
if (node.name) {
|
|
4645
5016
|
output.push(QuoteUtils.quote(node.name));
|
|
4646
5017
|
}
|
|
4647
|
-
output.push('ADD
|
|
5018
|
+
output.push('ADD');
|
|
4648
5019
|
if (node.def) {
|
|
4649
5020
|
output.push(this.visit(node.def, context));
|
|
4650
5021
|
}
|
|
4651
|
-
output.push('AS IDENTITY');
|
|
4652
5022
|
break;
|
|
4653
5023
|
case 'AT_SetIdentity':
|
|
4654
5024
|
output.push('ALTER COLUMN');
|
|
@@ -4736,7 +5106,7 @@ export class Deparser {
|
|
|
4736
5106
|
output.push(this.TypeName(node.returnType, context));
|
|
4737
5107
|
}
|
|
4738
5108
|
if (node.options && node.options.length > 0) {
|
|
4739
|
-
const funcContext =
|
|
5109
|
+
const funcContext = context.spawn('CreateFunctionStmt');
|
|
4740
5110
|
const options = node.options.map((opt) => this.visit(opt, funcContext));
|
|
4741
5111
|
output.push(...options);
|
|
4742
5112
|
}
|
|
@@ -4823,7 +5193,7 @@ export class Deparser {
|
|
|
4823
5193
|
}
|
|
4824
5194
|
output.push('AS', 'ENUM');
|
|
4825
5195
|
if (node.vals && node.vals.length > 0) {
|
|
4826
|
-
const enumContext =
|
|
5196
|
+
const enumContext = context.spawn('CreateEnumStmt', { isEnumValue: true });
|
|
4827
5197
|
const values = ListUtils.unwrapList(node.vals)
|
|
4828
5198
|
.map(val => this.visit(val, enumContext))
|
|
4829
5199
|
.join(', ');
|
|
@@ -4878,9 +5248,8 @@ export class Deparser {
|
|
|
4878
5248
|
output.push(roleName);
|
|
4879
5249
|
}
|
|
4880
5250
|
if (node.options) {
|
|
4881
|
-
const roleContext = { ...context, parentNodeTypes: [...context.parentNodeTypes, 'CreateRoleStmt'] };
|
|
4882
5251
|
const options = ListUtils.unwrapList(node.options)
|
|
4883
|
-
.map(option => this.visit(option,
|
|
5252
|
+
.map(option => this.visit(option, context.spawn('CreateRoleStmt')))
|
|
4884
5253
|
.join(' ');
|
|
4885
5254
|
if (options) {
|
|
4886
5255
|
output.push('WITH');
|
|
@@ -4911,7 +5280,7 @@ export class Deparser {
|
|
|
4911
5280
|
const stringData = this.getNodeData(node.arg);
|
|
4912
5281
|
return `${node.defname}='${stringData.sval}'`;
|
|
4913
5282
|
}
|
|
4914
|
-
return `${node.defname}=${this.visit(node.arg,
|
|
5283
|
+
return `${node.defname}=${this.visit(node.arg, context.spawn('DefElem'))}`;
|
|
4915
5284
|
}
|
|
4916
5285
|
// Handle CREATE OPERATOR boolean flags - MUST be first to preserve case
|
|
4917
5286
|
if (context.parentNodeTypes.includes('DefineStmt') &&
|
|
@@ -4927,13 +5296,13 @@ export class Deparser {
|
|
|
4927
5296
|
if (!node.arg) {
|
|
4928
5297
|
return `NO ${node.defname.toUpperCase()}`;
|
|
4929
5298
|
}
|
|
4930
|
-
const defElemContext =
|
|
5299
|
+
const defElemContext = context.spawn('DefElem');
|
|
4931
5300
|
const argValue = this.visit(node.arg, defElemContext);
|
|
4932
5301
|
return `${node.defname.toUpperCase()} ${argValue}`;
|
|
4933
5302
|
}
|
|
4934
5303
|
// Handle OPTIONS clause - use space format, not equals format
|
|
4935
5304
|
if (node.arg) {
|
|
4936
|
-
const defElemContext =
|
|
5305
|
+
const defElemContext = context.spawn('DefElem');
|
|
4937
5306
|
const argValue = this.visit(node.arg, defElemContext);
|
|
4938
5307
|
if (context.parentNodeTypes.includes('CreateFdwStmt') || context.parentNodeTypes.includes('AlterFdwStmt')) {
|
|
4939
5308
|
const finalValue = typeof argValue === 'string' && !argValue.startsWith("'")
|
|
@@ -4987,7 +5356,7 @@ export class Deparser {
|
|
|
4987
5356
|
if (!node.arg) {
|
|
4988
5357
|
return 'PASSWORD NULL';
|
|
4989
5358
|
}
|
|
4990
|
-
const defElemContext =
|
|
5359
|
+
const defElemContext = context.spawn('DefElem');
|
|
4991
5360
|
const argValue = this.visit(node.arg, defElemContext);
|
|
4992
5361
|
const quotedValue = typeof argValue === 'string' && !argValue.startsWith("'")
|
|
4993
5362
|
? `'${argValue}'`
|
|
@@ -4996,7 +5365,7 @@ export class Deparser {
|
|
|
4996
5365
|
}
|
|
4997
5366
|
}
|
|
4998
5367
|
if (node.arg) {
|
|
4999
|
-
const defElemContext =
|
|
5368
|
+
const defElemContext = context.spawn('DefElem');
|
|
5000
5369
|
const argValue = this.visit(node.arg, defElemContext);
|
|
5001
5370
|
if (context.parentNodeTypes.includes('AlterOperatorStmt')) {
|
|
5002
5371
|
if (node.arg && this.getNodeType(node.arg) === 'TypeName') {
|
|
@@ -5072,7 +5441,7 @@ export class Deparser {
|
|
|
5072
5441
|
if (node.defname === 'sysid') {
|
|
5073
5442
|
return `SYSID ${argValue}`;
|
|
5074
5443
|
}
|
|
5075
|
-
if (argValue === 'true') {
|
|
5444
|
+
if (String(argValue) === 'true') {
|
|
5076
5445
|
// Handle special cases where the positive form has a different name
|
|
5077
5446
|
if (node.defname === 'isreplication') {
|
|
5078
5447
|
return 'REPLICATION';
|
|
@@ -5082,7 +5451,7 @@ export class Deparser {
|
|
|
5082
5451
|
}
|
|
5083
5452
|
return node.defname.toUpperCase();
|
|
5084
5453
|
}
|
|
5085
|
-
else if (argValue === 'false') {
|
|
5454
|
+
else if (String(argValue) === 'false') {
|
|
5086
5455
|
// Handle special cases where the negative form has a different name
|
|
5087
5456
|
if (node.defname === 'canlogin') {
|
|
5088
5457
|
return 'NOLOGIN';
|
|
@@ -5146,7 +5515,7 @@ export class Deparser {
|
|
|
5146
5515
|
}
|
|
5147
5516
|
if (context.parentNodeTypes.includes('DoStmt')) {
|
|
5148
5517
|
if (node.defname === 'as') {
|
|
5149
|
-
const defElemContext =
|
|
5518
|
+
const defElemContext = context.spawn('DefElem');
|
|
5150
5519
|
const argValue = node.arg ? this.visit(node.arg, defElemContext) : '';
|
|
5151
5520
|
if (Array.isArray(argValue)) {
|
|
5152
5521
|
const bodyParts = argValue;
|
|
@@ -5437,7 +5806,7 @@ export class Deparser {
|
|
|
5437
5806
|
}
|
|
5438
5807
|
if (node.options && node.options.length > 0) {
|
|
5439
5808
|
output.push('WITH');
|
|
5440
|
-
const tsContext =
|
|
5809
|
+
const tsContext = context.spawn('CreateTableSpaceStmt');
|
|
5441
5810
|
const options = ListUtils.unwrapList(node.options)
|
|
5442
5811
|
.map(option => this.visit(option, tsContext))
|
|
5443
5812
|
.join(', ');
|
|
@@ -5467,7 +5836,7 @@ export class Deparser {
|
|
|
5467
5836
|
output.push('SET');
|
|
5468
5837
|
}
|
|
5469
5838
|
if (node.options && node.options.length > 0) {
|
|
5470
|
-
const tablespaceContext =
|
|
5839
|
+
const tablespaceContext = context.spawn('AlterTableSpaceOptionsStmt');
|
|
5471
5840
|
const options = ListUtils.unwrapList(node.options)
|
|
5472
5841
|
.map(option => this.visit(option, tablespaceContext))
|
|
5473
5842
|
.join(', ');
|
|
@@ -5484,7 +5853,7 @@ export class Deparser {
|
|
|
5484
5853
|
output.push(this.quoteIfNeeded(node.extname));
|
|
5485
5854
|
}
|
|
5486
5855
|
if (node.options && node.options.length > 0) {
|
|
5487
|
-
const extContext =
|
|
5856
|
+
const extContext = context.spawn('CreateExtensionStmt');
|
|
5488
5857
|
const options = ListUtils.unwrapList(node.options)
|
|
5489
5858
|
.map(option => this.visit(option, extContext))
|
|
5490
5859
|
.join(' ');
|
|
@@ -5498,7 +5867,7 @@ export class Deparser {
|
|
|
5498
5867
|
output.push(this.quoteIfNeeded(node.extname));
|
|
5499
5868
|
}
|
|
5500
5869
|
if (node.options && node.options.length > 0) {
|
|
5501
|
-
const extContext =
|
|
5870
|
+
const extContext = context.spawn('AlterExtensionStmt');
|
|
5502
5871
|
const options = ListUtils.unwrapList(node.options)
|
|
5503
5872
|
.map(option => this.visit(option, extContext))
|
|
5504
5873
|
.join(' ');
|
|
@@ -5512,7 +5881,7 @@ export class Deparser {
|
|
|
5512
5881
|
output.push(node.fdwname);
|
|
5513
5882
|
}
|
|
5514
5883
|
if (node.func_options && node.func_options.length > 0) {
|
|
5515
|
-
const fdwContext =
|
|
5884
|
+
const fdwContext = context.spawn('CreateFdwStmt');
|
|
5516
5885
|
const funcOptions = ListUtils.unwrapList(node.func_options)
|
|
5517
5886
|
.map(option => this.visit(option, fdwContext))
|
|
5518
5887
|
.join(' ');
|
|
@@ -5520,7 +5889,7 @@ export class Deparser {
|
|
|
5520
5889
|
}
|
|
5521
5890
|
if (node.options && node.options.length > 0) {
|
|
5522
5891
|
output.push('OPTIONS');
|
|
5523
|
-
const fdwContext =
|
|
5892
|
+
const fdwContext = context.spawn('CreateFdwStmt');
|
|
5524
5893
|
const options = ListUtils.unwrapList(node.options)
|
|
5525
5894
|
.map(option => this.visit(option, fdwContext))
|
|
5526
5895
|
.join(', ');
|
|
@@ -5622,7 +5991,7 @@ export class Deparser {
|
|
|
5622
5991
|
output.push('ADD');
|
|
5623
5992
|
if (node.def) {
|
|
5624
5993
|
// Pass domain context to avoid adding constraint names for domain constraints
|
|
5625
|
-
const domainContext =
|
|
5994
|
+
const domainContext = context.spawn('CreateDomainStmt', { isDomainConstraint: true });
|
|
5626
5995
|
output.push(this.visit(node.def, domainContext));
|
|
5627
5996
|
}
|
|
5628
5997
|
break;
|
|
@@ -5648,7 +6017,7 @@ export class Deparser {
|
|
|
5648
6017
|
output.push('ADD');
|
|
5649
6018
|
if (node.def) {
|
|
5650
6019
|
// Pass domain context to avoid adding constraint names for domain constraints
|
|
5651
|
-
const domainContext =
|
|
6020
|
+
const domainContext = context.spawn('CreateDomainStmt', { isDomainConstraint: true });
|
|
5652
6021
|
output.push(this.visit(node.def, domainContext));
|
|
5653
6022
|
}
|
|
5654
6023
|
break;
|
|
@@ -6010,7 +6379,7 @@ export class Deparser {
|
|
|
6010
6379
|
output.push(`${operatorName}(${args.join(', ')})`);
|
|
6011
6380
|
}
|
|
6012
6381
|
else {
|
|
6013
|
-
const objContext =
|
|
6382
|
+
const objContext = context.spawn('CommentStmt', { objtype: node.objtype });
|
|
6014
6383
|
output.push(this.visit(node.object, objContext));
|
|
6015
6384
|
}
|
|
6016
6385
|
}
|
|
@@ -6056,13 +6425,13 @@ export class Deparser {
|
|
|
6056
6425
|
const output = [];
|
|
6057
6426
|
const initialParts = ['CREATE', 'POLICY'];
|
|
6058
6427
|
if (node.policy_name) {
|
|
6059
|
-
initialParts.push(
|
|
6428
|
+
initialParts.push(QuoteUtils.quote(node.policy_name));
|
|
6060
6429
|
}
|
|
6061
6430
|
output.push(initialParts.join(' '));
|
|
6062
6431
|
// Add ON clause on new line in pretty mode
|
|
6063
6432
|
if (node.table) {
|
|
6064
|
-
if (
|
|
6065
|
-
output.push(
|
|
6433
|
+
if (context.isPretty()) {
|
|
6434
|
+
output.push(context.newline() + context.indent(`ON ${this.RangeVar(node.table, context)}`));
|
|
6066
6435
|
}
|
|
6067
6436
|
else {
|
|
6068
6437
|
output.push('ON');
|
|
@@ -6071,24 +6440,24 @@ export class Deparser {
|
|
|
6071
6440
|
}
|
|
6072
6441
|
// Handle AS RESTRICTIVE/PERMISSIVE clause
|
|
6073
6442
|
if (node.permissive === undefined) {
|
|
6074
|
-
if (
|
|
6075
|
-
output.push(
|
|
6443
|
+
if (context.isPretty()) {
|
|
6444
|
+
output.push(context.newline() + context.indent('AS RESTRICTIVE'));
|
|
6076
6445
|
}
|
|
6077
6446
|
else {
|
|
6078
6447
|
output.push('AS', 'RESTRICTIVE');
|
|
6079
6448
|
}
|
|
6080
6449
|
}
|
|
6081
6450
|
else if (node.permissive === true) {
|
|
6082
|
-
if (
|
|
6083
|
-
output.push(
|
|
6451
|
+
if (context.isPretty()) {
|
|
6452
|
+
output.push(context.newline() + context.indent('AS PERMISSIVE'));
|
|
6084
6453
|
}
|
|
6085
6454
|
else {
|
|
6086
6455
|
output.push('AS', 'PERMISSIVE');
|
|
6087
6456
|
}
|
|
6088
6457
|
}
|
|
6089
6458
|
if (node.cmd_name) {
|
|
6090
|
-
if (
|
|
6091
|
-
output.push(
|
|
6459
|
+
if (context.isPretty()) {
|
|
6460
|
+
output.push(context.newline() + context.indent(`FOR ${node.cmd_name.toUpperCase()}`));
|
|
6092
6461
|
}
|
|
6093
6462
|
else {
|
|
6094
6463
|
output.push('FOR', node.cmd_name.toUpperCase());
|
|
@@ -6096,8 +6465,8 @@ export class Deparser {
|
|
|
6096
6465
|
}
|
|
6097
6466
|
if (node.roles && node.roles.length > 0) {
|
|
6098
6467
|
const roles = ListUtils.unwrapList(node.roles).map(role => this.visit(role, context));
|
|
6099
|
-
if (
|
|
6100
|
-
output.push(
|
|
6468
|
+
if (context.isPretty()) {
|
|
6469
|
+
output.push(context.newline() + context.indent(`TO ${roles.join(', ')}`));
|
|
6101
6470
|
}
|
|
6102
6471
|
else {
|
|
6103
6472
|
output.push('TO');
|
|
@@ -6105,11 +6474,11 @@ export class Deparser {
|
|
|
6105
6474
|
}
|
|
6106
6475
|
}
|
|
6107
6476
|
if (node.qual) {
|
|
6108
|
-
if (
|
|
6477
|
+
if (context.isPretty()) {
|
|
6109
6478
|
const qualExpr = this.visit(node.qual, context);
|
|
6110
|
-
output.push(
|
|
6111
|
-
output.push(
|
|
6112
|
-
output.push(
|
|
6479
|
+
output.push(context.newline() + context.indent('USING ('));
|
|
6480
|
+
output.push(context.newline() + context.indent(context.indent(qualExpr)));
|
|
6481
|
+
output.push(context.newline() + context.indent(')'));
|
|
6113
6482
|
}
|
|
6114
6483
|
else {
|
|
6115
6484
|
output.push('USING');
|
|
@@ -6117,23 +6486,23 @@ export class Deparser {
|
|
|
6117
6486
|
}
|
|
6118
6487
|
}
|
|
6119
6488
|
if (node.with_check) {
|
|
6120
|
-
if (
|
|
6489
|
+
if (context.isPretty()) {
|
|
6121
6490
|
const checkExpr = this.visit(node.with_check, context);
|
|
6122
|
-
output.push(
|
|
6123
|
-
output.push(
|
|
6124
|
-
output.push(
|
|
6491
|
+
output.push(context.newline() + context.indent('WITH CHECK ('));
|
|
6492
|
+
output.push(context.newline() + context.indent(context.indent(checkExpr)));
|
|
6493
|
+
output.push(context.newline() + context.indent(')'));
|
|
6125
6494
|
}
|
|
6126
6495
|
else {
|
|
6127
6496
|
output.push('WITH CHECK');
|
|
6128
6497
|
output.push(`(${this.visit(node.with_check, context)})`);
|
|
6129
6498
|
}
|
|
6130
6499
|
}
|
|
6131
|
-
return
|
|
6500
|
+
return context.isPretty() ? output.join('') : output.join(' ');
|
|
6132
6501
|
}
|
|
6133
6502
|
AlterPolicyStmt(node, context) {
|
|
6134
6503
|
const output = ['ALTER', 'POLICY'];
|
|
6135
6504
|
if (node.policy_name) {
|
|
6136
|
-
output.push(
|
|
6505
|
+
output.push(QuoteUtils.quote(node.policy_name));
|
|
6137
6506
|
}
|
|
6138
6507
|
if (node.table) {
|
|
6139
6508
|
output.push('ON');
|
|
@@ -6173,7 +6542,7 @@ export class Deparser {
|
|
|
6173
6542
|
}
|
|
6174
6543
|
if (node.options && node.options.length > 0) {
|
|
6175
6544
|
output.push('OPTIONS');
|
|
6176
|
-
const userMappingContext =
|
|
6545
|
+
const userMappingContext = context.spawn('CreateUserMappingStmt');
|
|
6177
6546
|
const options = ListUtils.unwrapList(node.options).map(opt => this.visit(opt, userMappingContext));
|
|
6178
6547
|
output.push(`(${options.join(', ')})`);
|
|
6179
6548
|
}
|
|
@@ -6356,7 +6725,7 @@ export class Deparser {
|
|
|
6356
6725
|
DoStmt(node, context) {
|
|
6357
6726
|
const output = ['DO'];
|
|
6358
6727
|
if (node.args && node.args.length > 0) {
|
|
6359
|
-
const doContext =
|
|
6728
|
+
const doContext = context.spawn('DoStmt');
|
|
6360
6729
|
const args = ListUtils.unwrapList(node.args);
|
|
6361
6730
|
const processedArgs = [];
|
|
6362
6731
|
for (const arg of args) {
|
|
@@ -6661,7 +7030,7 @@ export class Deparser {
|
|
|
6661
7030
|
ObjectWithArgs(node, context) {
|
|
6662
7031
|
let result = '';
|
|
6663
7032
|
if (node.objname && node.objname.length > 0) {
|
|
6664
|
-
const objContext =
|
|
7033
|
+
const objContext = context.spawn('ObjectWithArgs');
|
|
6665
7034
|
const names = ListUtils.unwrapList(node.objname).map(name => this.visit(name, objContext));
|
|
6666
7035
|
result = names.join('.');
|
|
6667
7036
|
}
|
|
@@ -6703,7 +7072,7 @@ export class Deparser {
|
|
|
6703
7072
|
}
|
|
6704
7073
|
output.push('SET');
|
|
6705
7074
|
if (node.options && node.options.length > 0) {
|
|
6706
|
-
const alterOpContext =
|
|
7075
|
+
const alterOpContext = context.spawn('AlterOperatorStmt');
|
|
6707
7076
|
const options = ListUtils.unwrapList(node.options).map(opt => this.visit(opt, alterOpContext));
|
|
6708
7077
|
output.push(`(${options.join(', ')})`);
|
|
6709
7078
|
}
|
|
@@ -6715,13 +7084,13 @@ export class Deparser {
|
|
|
6715
7084
|
output.push(QuoteUtils.quote(node.fdwname));
|
|
6716
7085
|
}
|
|
6717
7086
|
if (node.func_options && node.func_options.length > 0) {
|
|
6718
|
-
const fdwContext =
|
|
7087
|
+
const fdwContext = context.spawn('AlterFdwStmt');
|
|
6719
7088
|
const funcOptions = ListUtils.unwrapList(node.func_options).map(opt => this.visit(opt, fdwContext));
|
|
6720
7089
|
output.push(funcOptions.join(' '));
|
|
6721
7090
|
}
|
|
6722
7091
|
if (node.options && node.options.length > 0) {
|
|
6723
7092
|
output.push('OPTIONS');
|
|
6724
|
-
const fdwContext =
|
|
7093
|
+
const fdwContext = context.spawn('AlterFdwStmt');
|
|
6725
7094
|
const options = ListUtils.unwrapList(node.options).map(opt => this.visit(opt, fdwContext));
|
|
6726
7095
|
output.push(`(${options.join(', ')})`);
|
|
6727
7096
|
}
|
|
@@ -6747,7 +7116,7 @@ export class Deparser {
|
|
|
6747
7116
|
if (node.options && node.options.length > 0) {
|
|
6748
7117
|
output.push('OPTIONS');
|
|
6749
7118
|
output.push('(');
|
|
6750
|
-
const optionsContext =
|
|
7119
|
+
const optionsContext = context.spawn('CreateForeignServerStmt');
|
|
6751
7120
|
const options = ListUtils.unwrapList(node.options).map(opt => this.visit(opt, optionsContext));
|
|
6752
7121
|
output.push(options.join(', '));
|
|
6753
7122
|
output.push(')');
|
|
@@ -6765,7 +7134,7 @@ export class Deparser {
|
|
|
6765
7134
|
if (node.options && node.options.length > 0) {
|
|
6766
7135
|
output.push('OPTIONS');
|
|
6767
7136
|
output.push('(');
|
|
6768
|
-
const optionsContext =
|
|
7137
|
+
const optionsContext = context.spawn('AlterForeignServerStmt');
|
|
6769
7138
|
const options = ListUtils.unwrapList(node.options).map(opt => this.visit(opt, optionsContext));
|
|
6770
7139
|
output.push(options.join(', '));
|
|
6771
7140
|
output.push(')');
|
|
@@ -6786,7 +7155,7 @@ export class Deparser {
|
|
|
6786
7155
|
}
|
|
6787
7156
|
if (node.options && node.options.length > 0) {
|
|
6788
7157
|
output.push('OPTIONS');
|
|
6789
|
-
const userMappingContext =
|
|
7158
|
+
const userMappingContext = context.spawn('AlterUserMappingStmt');
|
|
6790
7159
|
const options = ListUtils.unwrapList(node.options).map(opt => this.visit(opt, userMappingContext));
|
|
6791
7160
|
output.push(`(${options.join(', ')})`);
|
|
6792
7161
|
}
|
|
@@ -6846,7 +7215,7 @@ export class Deparser {
|
|
|
6846
7215
|
output.push(QuoteUtils.quote(node.local_schema));
|
|
6847
7216
|
}
|
|
6848
7217
|
if (node.options && node.options.length > 0) {
|
|
6849
|
-
const importSchemaContext =
|
|
7218
|
+
const importSchemaContext = context.spawn('ImportForeignSchemaStmt');
|
|
6850
7219
|
const options = ListUtils.unwrapList(node.options).map(opt => this.visit(opt, importSchemaContext));
|
|
6851
7220
|
output.push(`OPTIONS (${options.join(', ')})`);
|
|
6852
7221
|
}
|
|
@@ -6881,7 +7250,7 @@ export class Deparser {
|
|
|
6881
7250
|
ExplainStmt(node, context) {
|
|
6882
7251
|
const output = ['EXPLAIN'];
|
|
6883
7252
|
if (node.options && node.options.length > 0) {
|
|
6884
|
-
const explainContext =
|
|
7253
|
+
const explainContext = context.spawn('ExplainStmt');
|
|
6885
7254
|
const options = ListUtils.unwrapList(node.options).map(option => this.visit(option, explainContext));
|
|
6886
7255
|
output.push(`(${options.join(', ')})`);
|
|
6887
7256
|
}
|
|
@@ -7139,9 +7508,7 @@ export class Deparser {
|
|
|
7139
7508
|
output.push(this.RangeVar(node.relation, context));
|
|
7140
7509
|
}
|
|
7141
7510
|
else if (node.relation) {
|
|
7142
|
-
const rangeVarContext = node.relationType
|
|
7143
|
-
? { ...context, parentNodeTypes: [...context.parentNodeTypes, 'AlterTypeStmt'] }
|
|
7144
|
-
: context;
|
|
7511
|
+
const rangeVarContext = context.spawn('RenameStmt', { objtype: node.relationType });
|
|
7145
7512
|
// Add ON keyword for policy operations
|
|
7146
7513
|
if (node.renameType === 'OBJECT_POLICY') {
|
|
7147
7514
|
output.push('ON');
|
|
@@ -7323,7 +7690,7 @@ export class Deparser {
|
|
|
7323
7690
|
}
|
|
7324
7691
|
}
|
|
7325
7692
|
if (node.privileges && node.privileges.length > 0) {
|
|
7326
|
-
const privilegeContext =
|
|
7693
|
+
const privilegeContext = context.spawn('GrantStmt');
|
|
7327
7694
|
const privileges = ListUtils.unwrapList(node.privileges)
|
|
7328
7695
|
.map(priv => this.visit(priv, privilegeContext))
|
|
7329
7696
|
.join(', ');
|
|
@@ -7631,7 +7998,12 @@ export class Deparser {
|
|
|
7631
7998
|
}
|
|
7632
7999
|
if (node.action) {
|
|
7633
8000
|
const actionStr = this.GrantStmt(node.action, context);
|
|
7634
|
-
|
|
8001
|
+
if (context.isPretty()) {
|
|
8002
|
+
return output.join(' ') + context.newline() + context.indent(actionStr);
|
|
8003
|
+
}
|
|
8004
|
+
else {
|
|
8005
|
+
output.push(actionStr);
|
|
8006
|
+
}
|
|
7635
8007
|
}
|
|
7636
8008
|
return output.join(' ');
|
|
7637
8009
|
}
|
|
@@ -7778,84 +8150,158 @@ export class Deparser {
|
|
|
7778
8150
|
if (node.trigname) {
|
|
7779
8151
|
output.push(QuoteUtils.quote(node.trigname));
|
|
7780
8152
|
}
|
|
7781
|
-
|
|
7782
|
-
|
|
7783
|
-
timing
|
|
7784
|
-
|
|
7785
|
-
|
|
7786
|
-
|
|
7787
|
-
|
|
7788
|
-
|
|
7789
|
-
|
|
7790
|
-
|
|
7791
|
-
events
|
|
7792
|
-
|
|
7793
|
-
events
|
|
7794
|
-
|
|
7795
|
-
events
|
|
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
|
-
|
|
7852
|
-
output.push(args);
|
|
7853
|
-
output.push(')');
|
|
8153
|
+
if (context.isPretty()) {
|
|
8154
|
+
const components = [];
|
|
8155
|
+
const timing = [];
|
|
8156
|
+
if (node.timing & 2)
|
|
8157
|
+
timing.push('BEFORE');
|
|
8158
|
+
else if (node.timing & 64)
|
|
8159
|
+
timing.push('INSTEAD OF');
|
|
8160
|
+
else
|
|
8161
|
+
timing.push('AFTER');
|
|
8162
|
+
const events = [];
|
|
8163
|
+
if (node.events & 4)
|
|
8164
|
+
events.push('INSERT');
|
|
8165
|
+
if (node.events & 8)
|
|
8166
|
+
events.push('DELETE');
|
|
8167
|
+
if (node.events & 16) {
|
|
8168
|
+
let updateStr = 'UPDATE';
|
|
8169
|
+
if (node.columns && node.columns.length > 0) {
|
|
8170
|
+
const columnNames = ListUtils.unwrapList(node.columns)
|
|
8171
|
+
.map(col => this.visit(col, context))
|
|
8172
|
+
.join(', ');
|
|
8173
|
+
updateStr += ' OF ' + columnNames;
|
|
8174
|
+
}
|
|
8175
|
+
events.push(updateStr);
|
|
8176
|
+
}
|
|
8177
|
+
if (node.events & 32)
|
|
8178
|
+
events.push('TRUNCATE');
|
|
8179
|
+
components.push(context.indent(timing.join(' ') + ' ' + events.join(' OR ')));
|
|
8180
|
+
if (node.relation) {
|
|
8181
|
+
components.push(context.indent('ON ' + this.RangeVar(node.relation, context)));
|
|
8182
|
+
}
|
|
8183
|
+
if (node.transitionRels && node.transitionRels.length > 0) {
|
|
8184
|
+
const transitionClauses = ListUtils.unwrapList(node.transitionRels)
|
|
8185
|
+
.map(rel => this.visit(rel, context))
|
|
8186
|
+
.join(' ');
|
|
8187
|
+
components.push(context.indent('REFERENCING ' + transitionClauses));
|
|
8188
|
+
}
|
|
8189
|
+
if (node.deferrable) {
|
|
8190
|
+
components.push(context.indent('DEFERRABLE'));
|
|
8191
|
+
}
|
|
8192
|
+
if (node.initdeferred) {
|
|
8193
|
+
components.push(context.indent('INITIALLY DEFERRED'));
|
|
8194
|
+
}
|
|
8195
|
+
if (node.row) {
|
|
8196
|
+
components.push(context.indent('FOR EACH ROW'));
|
|
8197
|
+
}
|
|
8198
|
+
else {
|
|
8199
|
+
components.push(context.indent('FOR EACH STATEMENT'));
|
|
8200
|
+
}
|
|
8201
|
+
if (node.whenClause) {
|
|
8202
|
+
const whenStr = 'WHEN (' + this.visit(node.whenClause, context) + ')';
|
|
8203
|
+
components.push(context.indent(whenStr));
|
|
8204
|
+
}
|
|
8205
|
+
let executeStr = 'EXECUTE';
|
|
8206
|
+
if (node.funcname && node.funcname.length > 0) {
|
|
8207
|
+
const funcName = ListUtils.unwrapList(node.funcname)
|
|
8208
|
+
.map(name => this.visit(name, context))
|
|
8209
|
+
.join('.');
|
|
8210
|
+
executeStr += ' PROCEDURE ' + funcName;
|
|
8211
|
+
}
|
|
8212
|
+
if (node.args && node.args.length > 0) {
|
|
8213
|
+
const argContext = context.spawn('CreateTrigStmt', { isStringLiteral: true });
|
|
8214
|
+
const args = ListUtils.unwrapList(node.args)
|
|
8215
|
+
.map(arg => this.visit(arg, argContext))
|
|
8216
|
+
.join(', ');
|
|
8217
|
+
executeStr += '(' + args + ')';
|
|
8218
|
+
}
|
|
8219
|
+
else {
|
|
8220
|
+
executeStr += '()';
|
|
8221
|
+
}
|
|
8222
|
+
components.push(context.indent(executeStr));
|
|
8223
|
+
return output.join(' ') + context.newline() + components.join(context.newline());
|
|
7854
8224
|
}
|
|
7855
8225
|
else {
|
|
7856
|
-
|
|
8226
|
+
const timing = [];
|
|
8227
|
+
if (node.timing & 2)
|
|
8228
|
+
timing.push('BEFORE');
|
|
8229
|
+
else if (node.timing & 64)
|
|
8230
|
+
timing.push('INSTEAD OF');
|
|
8231
|
+
else
|
|
8232
|
+
timing.push('AFTER');
|
|
8233
|
+
output.push(timing.join(' '));
|
|
8234
|
+
const events = [];
|
|
8235
|
+
if (node.events & 4)
|
|
8236
|
+
events.push('INSERT');
|
|
8237
|
+
if (node.events & 8)
|
|
8238
|
+
events.push('DELETE');
|
|
8239
|
+
if (node.events & 16)
|
|
8240
|
+
events.push('UPDATE');
|
|
8241
|
+
if (node.events & 32)
|
|
8242
|
+
events.push('TRUNCATE');
|
|
8243
|
+
output.push(events.join(' OR '));
|
|
8244
|
+
if (node.columns && node.columns.length > 0) {
|
|
8245
|
+
output.push('OF');
|
|
8246
|
+
const columnNames = ListUtils.unwrapList(node.columns)
|
|
8247
|
+
.map(col => this.visit(col, context))
|
|
8248
|
+
.join(', ');
|
|
8249
|
+
output.push(columnNames);
|
|
8250
|
+
}
|
|
8251
|
+
output.push('ON');
|
|
8252
|
+
if (node.relation) {
|
|
8253
|
+
output.push(this.RangeVar(node.relation, context));
|
|
8254
|
+
}
|
|
8255
|
+
if (node.constrrel) {
|
|
8256
|
+
output.push('FROM');
|
|
8257
|
+
output.push(this.RangeVar(node.constrrel, context));
|
|
8258
|
+
}
|
|
8259
|
+
if (node.deferrable) {
|
|
8260
|
+
output.push('DEFERRABLE');
|
|
8261
|
+
}
|
|
8262
|
+
if (node.initdeferred) {
|
|
8263
|
+
output.push('INITIALLY DEFERRED');
|
|
8264
|
+
}
|
|
8265
|
+
if (node.transitionRels && node.transitionRels.length > 0) {
|
|
8266
|
+
output.push('REFERENCING');
|
|
8267
|
+
const transitionClauses = ListUtils.unwrapList(node.transitionRels)
|
|
8268
|
+
.map(rel => this.visit(rel, context))
|
|
8269
|
+
.join(' ');
|
|
8270
|
+
output.push(transitionClauses);
|
|
8271
|
+
}
|
|
8272
|
+
if (node.row) {
|
|
8273
|
+
output.push('FOR EACH ROW');
|
|
8274
|
+
}
|
|
8275
|
+
else {
|
|
8276
|
+
output.push('FOR EACH STATEMENT');
|
|
8277
|
+
}
|
|
8278
|
+
if (node.whenClause) {
|
|
8279
|
+
output.push('WHEN');
|
|
8280
|
+
output.push('(');
|
|
8281
|
+
output.push(this.visit(node.whenClause, context));
|
|
8282
|
+
output.push(')');
|
|
8283
|
+
}
|
|
8284
|
+
output.push('EXECUTE');
|
|
8285
|
+
if (node.funcname && node.funcname.length > 0) {
|
|
8286
|
+
const funcName = ListUtils.unwrapList(node.funcname)
|
|
8287
|
+
.map(name => this.visit(name, context))
|
|
8288
|
+
.join('.');
|
|
8289
|
+
output.push('FUNCTION', funcName);
|
|
8290
|
+
}
|
|
8291
|
+
if (node.args && node.args.length > 0) {
|
|
8292
|
+
output.push('(');
|
|
8293
|
+
const argContext = context.spawn('CreateTrigStmt', { isStringLiteral: true });
|
|
8294
|
+
const args = ListUtils.unwrapList(node.args)
|
|
8295
|
+
.map(arg => this.visit(arg, argContext))
|
|
8296
|
+
.join(', ');
|
|
8297
|
+
output.push(args);
|
|
8298
|
+
output.push(')');
|
|
8299
|
+
}
|
|
8300
|
+
else {
|
|
8301
|
+
output.push('()');
|
|
8302
|
+
}
|
|
8303
|
+
return output.join(' ');
|
|
7857
8304
|
}
|
|
7858
|
-
return output.join(' ');
|
|
7859
8305
|
}
|
|
7860
8306
|
TriggerTransition(node, context) {
|
|
7861
8307
|
const output = [];
|
|
@@ -7881,7 +8327,7 @@ export class Deparser {
|
|
|
7881
8327
|
}
|
|
7882
8328
|
if (node.whenclause && node.whenclause.length > 0) {
|
|
7883
8329
|
output.push('WHEN');
|
|
7884
|
-
const eventTriggerContext =
|
|
8330
|
+
const eventTriggerContext = context.spawn('CreateEventTrigStmt');
|
|
7885
8331
|
const conditions = ListUtils.unwrapList(node.whenclause)
|
|
7886
8332
|
.map(condition => this.visit(condition, eventTriggerContext))
|
|
7887
8333
|
.join(' AND ');
|
|
@@ -8070,7 +8516,7 @@ export class Deparser {
|
|
|
8070
8516
|
output.push(sequenceName.join('.'));
|
|
8071
8517
|
}
|
|
8072
8518
|
if (node.options && node.options.length > 0) {
|
|
8073
|
-
const seqContext =
|
|
8519
|
+
const seqContext = context.spawn('CreateSeqStmt');
|
|
8074
8520
|
const optionStrs = ListUtils.unwrapList(node.options)
|
|
8075
8521
|
.filter(option => option != null && this.getNodeType(option) !== 'undefined')
|
|
8076
8522
|
.map(option => {
|
|
@@ -8107,7 +8553,7 @@ export class Deparser {
|
|
|
8107
8553
|
output.push(sequenceName.join('.'));
|
|
8108
8554
|
}
|
|
8109
8555
|
if (node.options && node.options.length > 0) {
|
|
8110
|
-
const seqContext =
|
|
8556
|
+
const seqContext = context.spawn('AlterSeqStmt');
|
|
8111
8557
|
const optionStrs = ListUtils.unwrapList(node.options)
|
|
8112
8558
|
.filter(option => option && option !== undefined)
|
|
8113
8559
|
.map(option => {
|
|
@@ -8136,7 +8582,7 @@ export class Deparser {
|
|
|
8136
8582
|
CompositeTypeStmt(node, context) {
|
|
8137
8583
|
const output = ['CREATE', 'TYPE'];
|
|
8138
8584
|
if (node.typevar) {
|
|
8139
|
-
const typeContext =
|
|
8585
|
+
const typeContext = context.spawn('CompositeTypeStmt');
|
|
8140
8586
|
output.push(this.RangeVar(node.typevar, typeContext));
|
|
8141
8587
|
}
|
|
8142
8588
|
output.push('AS');
|
|
@@ -8237,7 +8683,7 @@ export class Deparser {
|
|
|
8237
8683
|
output.push(this.RoleSpec(node.role, context));
|
|
8238
8684
|
}
|
|
8239
8685
|
if (node.options) {
|
|
8240
|
-
const roleContext =
|
|
8686
|
+
const roleContext = context.spawn('AlterRoleStmt');
|
|
8241
8687
|
// Handle GROUP operations specially based on action value
|
|
8242
8688
|
if (isGroupStatement) {
|
|
8243
8689
|
const roleMembersOption = ListUtils.unwrapList(node.options).find(option => option.DefElem && option.DefElem.defname === 'rolemembers');
|
|
@@ -8433,14 +8879,14 @@ export class Deparser {
|
|
|
8433
8879
|
AccessPriv(node, context) {
|
|
8434
8880
|
const output = [];
|
|
8435
8881
|
if (node.priv_name) {
|
|
8436
|
-
output.push(node.priv_name);
|
|
8882
|
+
output.push(node.priv_name.toUpperCase());
|
|
8437
8883
|
}
|
|
8438
8884
|
else {
|
|
8439
8885
|
output.push('ALL');
|
|
8440
8886
|
}
|
|
8441
8887
|
if (node.cols && node.cols.length > 0) {
|
|
8442
8888
|
output.push('(');
|
|
8443
|
-
const colContext =
|
|
8889
|
+
const colContext = context.spawn('AccessPriv');
|
|
8444
8890
|
const columns = ListUtils.unwrapList(node.cols).map(col => this.visit(col, colContext));
|
|
8445
8891
|
output.push(columns.join(', '));
|
|
8446
8892
|
output.push(')');
|
|
@@ -8520,7 +8966,7 @@ export class Deparser {
|
|
|
8520
8966
|
output.push(ListUtils.unwrapList(node.defnames).map(name => this.visit(name, context)).join('.'));
|
|
8521
8967
|
}
|
|
8522
8968
|
if (node.definition && node.definition.length > 0) {
|
|
8523
|
-
const defineStmtContext =
|
|
8969
|
+
const defineStmtContext = context.spawn('DefineStmt');
|
|
8524
8970
|
const definitions = ListUtils.unwrapList(node.definition).map(def => {
|
|
8525
8971
|
return this.visit(def, defineStmtContext);
|
|
8526
8972
|
});
|
|
@@ -9006,7 +9452,7 @@ export class Deparser {
|
|
|
9006
9452
|
const operatorNumber = node.number !== undefined ? node.number : 0;
|
|
9007
9453
|
output.push(operatorNumber.toString());
|
|
9008
9454
|
if (node.name) {
|
|
9009
|
-
const opClassContext =
|
|
9455
|
+
const opClassContext = context.spawn('CreateOpClassItem');
|
|
9010
9456
|
output.push(this.ObjectWithArgs(node.name, opClassContext));
|
|
9011
9457
|
}
|
|
9012
9458
|
}
|
|
@@ -9016,7 +9462,7 @@ export class Deparser {
|
|
|
9016
9462
|
const functionNumber = node.number !== undefined ? node.number : 0;
|
|
9017
9463
|
output.push(functionNumber.toString());
|
|
9018
9464
|
if (node.name) {
|
|
9019
|
-
const opClassContext =
|
|
9465
|
+
const opClassContext = context.spawn('CreateOpClassItem');
|
|
9020
9466
|
output.push(this.ObjectWithArgs(node.name, opClassContext));
|
|
9021
9467
|
}
|
|
9022
9468
|
}
|
|
@@ -9714,7 +10160,7 @@ export class Deparser {
|
|
|
9714
10160
|
output.push(this.ObjectWithArgs(node.func, context));
|
|
9715
10161
|
}
|
|
9716
10162
|
if (node.actions && node.actions.length > 0) {
|
|
9717
|
-
const alterFunctionContext =
|
|
10163
|
+
const alterFunctionContext = context.spawn('AlterFunctionStmt');
|
|
9718
10164
|
const actionStrs = ListUtils.unwrapList(node.actions).map(action => this.visit(action, alterFunctionContext));
|
|
9719
10165
|
output.push(actionStrs.join(' '));
|
|
9720
10166
|
}
|
|
@@ -9958,7 +10404,7 @@ export class Deparser {
|
|
|
9958
10404
|
CreateForeignTableStmt(node, context) {
|
|
9959
10405
|
const output = ['CREATE FOREIGN TABLE'];
|
|
9960
10406
|
if (node.base && node.base.relation) {
|
|
9961
|
-
const relationContext =
|
|
10407
|
+
const relationContext = context.spawn('CreateForeignTableStmt');
|
|
9962
10408
|
// Handle relation node directly as RangeVar since it contains the RangeVar properties
|
|
9963
10409
|
output.push(this.RangeVar(node.base.relation, relationContext));
|
|
9964
10410
|
}
|
|
@@ -9988,7 +10434,7 @@ export class Deparser {
|
|
|
9988
10434
|
output.push(QuoteUtils.quote(node.servername));
|
|
9989
10435
|
}
|
|
9990
10436
|
if (node.options && node.options.length > 0) {
|
|
9991
|
-
const foreignTableContext =
|
|
10437
|
+
const foreignTableContext = context.spawn('CreateForeignTableStmt');
|
|
9992
10438
|
const optionStrs = ListUtils.unwrapList(node.options).map(opt => this.visit(opt, foreignTableContext));
|
|
9993
10439
|
output.push(`OPTIONS (${optionStrs.join(', ')})`);
|
|
9994
10440
|
}
|