pgsql-deparser 17.8.1 → 17.8.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/deparser.d.ts +4 -3
- package/deparser.js +742 -405
- package/esm/deparser.js +742 -405
- package/esm/visitors/base.js +87 -0
- package/package.json +3 -3
- package/visitors/base.d.ts +49 -2
- package/visitors/base.js +89 -1
package/esm/deparser.js
CHANGED
|
@@ -1,6 +1,63 @@
|
|
|
1
|
+
import { DeparserContext } from './visitors/base';
|
|
1
2
|
import { SqlFormatter } from './utils/sql-formatter';
|
|
2
3
|
import { QuoteUtils } from './utils/quote-utils';
|
|
3
4
|
import { ListUtils } from './utils/list-utils';
|
|
5
|
+
/**
|
|
6
|
+
* List of real PostgreSQL built-in types as they appear in pg_catalog.pg_type.typname.
|
|
7
|
+
* These are stored in lowercase in PostgreSQL system catalogs.
|
|
8
|
+
* Use these for lookups, validations, or introspection logic.
|
|
9
|
+
*/
|
|
10
|
+
const pgCatalogTypes = [
|
|
11
|
+
// Integers
|
|
12
|
+
'int2', // smallint
|
|
13
|
+
'int4', // integer
|
|
14
|
+
'int8', // bigint
|
|
15
|
+
// Floating-point & numeric
|
|
16
|
+
'float4', // real
|
|
17
|
+
'float8', // double precision
|
|
18
|
+
'numeric', // arbitrary precision (aka "decimal")
|
|
19
|
+
// Text & string
|
|
20
|
+
'varchar', // variable-length string
|
|
21
|
+
'char', // internal one-byte type (used in special cases)
|
|
22
|
+
'bpchar', // blank-padded char(n)
|
|
23
|
+
'text', // unlimited string
|
|
24
|
+
'bool', // boolean
|
|
25
|
+
// Dates & times
|
|
26
|
+
'date', // calendar date
|
|
27
|
+
'time', // time without time zone
|
|
28
|
+
'timetz', // time with time zone
|
|
29
|
+
'timestamp', // timestamp without time zone
|
|
30
|
+
'timestamptz', // timestamp with time zone
|
|
31
|
+
'interval', // duration
|
|
32
|
+
// Binary & structured
|
|
33
|
+
'bytea', // binary data
|
|
34
|
+
'uuid', // universally unique identifier
|
|
35
|
+
// JSON & XML
|
|
36
|
+
'json', // textual JSON
|
|
37
|
+
'jsonb', // binary JSON
|
|
38
|
+
'xml', // XML format
|
|
39
|
+
// Money & bitstrings
|
|
40
|
+
'money', // currency value
|
|
41
|
+
'bit', // fixed-length bit string
|
|
42
|
+
'varbit', // variable-length bit string
|
|
43
|
+
// Network types
|
|
44
|
+
'inet', // IPv4 or IPv6 address
|
|
45
|
+
'cidr', // network address
|
|
46
|
+
'macaddr', // MAC address (6 bytes)
|
|
47
|
+
'macaddr8' // MAC address (8 bytes)
|
|
48
|
+
];
|
|
49
|
+
/**
|
|
50
|
+
* Parser-level type aliases accepted by PostgreSQL SQL syntax,
|
|
51
|
+
* but not present in pg_catalog.pg_type. These are resolved to
|
|
52
|
+
* real types during parsing and never appear in introspection.
|
|
53
|
+
*/
|
|
54
|
+
const pgCatalogTypeAliases = [
|
|
55
|
+
['numeric', ['decimal', 'dec']],
|
|
56
|
+
['int4', ['int', 'integer']],
|
|
57
|
+
['float8', ['float']],
|
|
58
|
+
['bpchar', ['character']],
|
|
59
|
+
['varchar', ['character varying']]
|
|
60
|
+
];
|
|
4
61
|
// Type guards for better type safety
|
|
5
62
|
function isParseResult(obj) {
|
|
6
63
|
// A ParseResult is an object that could have stmts (but not required)
|
|
@@ -44,11 +101,9 @@ function isWrappedParseResult(obj) {
|
|
|
44
101
|
* compatibility and wraps them internally for consistent processing.
|
|
45
102
|
*/
|
|
46
103
|
export class Deparser {
|
|
47
|
-
formatter;
|
|
48
104
|
tree;
|
|
49
105
|
options;
|
|
50
106
|
constructor(tree, opts = {}) {
|
|
51
|
-
this.formatter = new SqlFormatter(opts.newline, opts.tab, opts.pretty);
|
|
52
107
|
// Set default options
|
|
53
108
|
this.options = {
|
|
54
109
|
functionDelimiter: '$$',
|
|
@@ -85,15 +140,17 @@ export class Deparser {
|
|
|
85
140
|
return new Deparser(query, opts).deparseQuery();
|
|
86
141
|
}
|
|
87
142
|
deparseQuery() {
|
|
143
|
+
const formatter = new SqlFormatter(this.options.newline, this.options.tab, this.options.pretty);
|
|
144
|
+
const context = new DeparserContext({ formatter, prettyMode: this.options.pretty });
|
|
88
145
|
return this.tree
|
|
89
146
|
.map(node => {
|
|
90
147
|
// All nodes should go through the standard deparse method
|
|
91
148
|
// which will route to the appropriate handler
|
|
92
|
-
const result = this.deparse(node);
|
|
149
|
+
const result = this.deparse(node, context);
|
|
93
150
|
return result || '';
|
|
94
151
|
})
|
|
95
152
|
.filter(result => result !== '')
|
|
96
|
-
.join(
|
|
153
|
+
.join(context.newline() + context.newline());
|
|
97
154
|
}
|
|
98
155
|
/**
|
|
99
156
|
* Get the appropriate function delimiter based on the body content
|
|
@@ -107,10 +164,14 @@ export class Deparser {
|
|
|
107
164
|
}
|
|
108
165
|
return delimiter;
|
|
109
166
|
}
|
|
110
|
-
deparse(node, context
|
|
167
|
+
deparse(node, context) {
|
|
111
168
|
if (node == null) {
|
|
112
169
|
return null;
|
|
113
170
|
}
|
|
171
|
+
if (!context) {
|
|
172
|
+
const formatter = new SqlFormatter(this.options.newline, this.options.tab, this.options.pretty);
|
|
173
|
+
context = new DeparserContext({ formatter, prettyMode: this.options.pretty });
|
|
174
|
+
}
|
|
114
175
|
if (typeof node === 'number' || node instanceof Number) {
|
|
115
176
|
return node.toString();
|
|
116
177
|
}
|
|
@@ -122,7 +183,11 @@ export class Deparser {
|
|
|
122
183
|
throw new Error(`Error deparsing ${nodeType}: ${error.message}`);
|
|
123
184
|
}
|
|
124
185
|
}
|
|
125
|
-
visit(node, context
|
|
186
|
+
visit(node, context) {
|
|
187
|
+
if (!context) {
|
|
188
|
+
const formatter = new SqlFormatter(this.options.newline, this.options.tab, this.options.pretty);
|
|
189
|
+
context = new DeparserContext({ formatter, prettyMode: this.options.pretty });
|
|
190
|
+
}
|
|
126
191
|
const nodeType = this.getNodeType(node);
|
|
127
192
|
// Handle empty objects
|
|
128
193
|
if (!nodeType) {
|
|
@@ -131,11 +196,7 @@ export class Deparser {
|
|
|
131
196
|
const nodeData = this.getNodeData(node);
|
|
132
197
|
const methodName = nodeType;
|
|
133
198
|
if (typeof this[methodName] === 'function') {
|
|
134
|
-
const
|
|
135
|
-
...context,
|
|
136
|
-
parentNodeTypes: [...context.parentNodeTypes, nodeType]
|
|
137
|
-
};
|
|
138
|
-
const result = this[methodName](nodeData, childContext);
|
|
199
|
+
const result = this[methodName](nodeData, context);
|
|
139
200
|
return result;
|
|
140
201
|
}
|
|
141
202
|
throw new Error(`Deparser does not handle node type: ${nodeType}`);
|
|
@@ -161,7 +222,7 @@ export class Deparser {
|
|
|
161
222
|
.filter((rawStmt) => rawStmt != null)
|
|
162
223
|
.map((rawStmt) => this.RawStmt(rawStmt, context))
|
|
163
224
|
.filter((result) => result !== '')
|
|
164
|
-
.join(
|
|
225
|
+
.join(context.newline() + context.newline());
|
|
165
226
|
}
|
|
166
227
|
RawStmt(node, context) {
|
|
167
228
|
if (!node.stmt) {
|
|
@@ -181,7 +242,7 @@ export class Deparser {
|
|
|
181
242
|
}
|
|
182
243
|
if (!node.op || node.op === 'SETOP_NONE') {
|
|
183
244
|
if (node.valuesLists == null) {
|
|
184
|
-
if (!
|
|
245
|
+
if (!context.isPretty() || !node.targetList) {
|
|
185
246
|
output.push('SELECT');
|
|
186
247
|
}
|
|
187
248
|
}
|
|
@@ -201,7 +262,7 @@ export class Deparser {
|
|
|
201
262
|
node.rarg.limitOffset ||
|
|
202
263
|
node.rarg.withClause);
|
|
203
264
|
if (leftNeedsParens) {
|
|
204
|
-
output.push(
|
|
265
|
+
output.push(context.parens(leftStmt));
|
|
205
266
|
}
|
|
206
267
|
else {
|
|
207
268
|
output.push(leftStmt);
|
|
@@ -223,7 +284,7 @@ export class Deparser {
|
|
|
223
284
|
output.push('ALL');
|
|
224
285
|
}
|
|
225
286
|
if (rightNeedsParens) {
|
|
226
|
-
output.push(
|
|
287
|
+
output.push(context.parens(rightStmt));
|
|
227
288
|
}
|
|
228
289
|
else {
|
|
229
290
|
output.push(rightStmt);
|
|
@@ -235,20 +296,20 @@ export class Deparser {
|
|
|
235
296
|
const distinctClause = ListUtils.unwrapList(node.distinctClause);
|
|
236
297
|
if (distinctClause.length > 0 && Object.keys(distinctClause[0]).length > 0) {
|
|
237
298
|
const clause = distinctClause
|
|
238
|
-
.map(e => this.visit(e,
|
|
299
|
+
.map(e => this.visit(e, context.spawn('SelectStmt', { select: true })))
|
|
239
300
|
.join(', ');
|
|
240
|
-
distinctPart = ' DISTINCT ON ' +
|
|
301
|
+
distinctPart = ' DISTINCT ON ' + context.parens(clause);
|
|
241
302
|
}
|
|
242
303
|
else {
|
|
243
304
|
distinctPart = ' DISTINCT';
|
|
244
305
|
}
|
|
245
|
-
if (!
|
|
306
|
+
if (!context.isPretty()) {
|
|
246
307
|
if (distinctClause.length > 0 && Object.keys(distinctClause[0]).length > 0) {
|
|
247
308
|
output.push('DISTINCT ON');
|
|
248
309
|
const clause = distinctClause
|
|
249
|
-
.map(e => this.visit(e,
|
|
310
|
+
.map(e => this.visit(e, context.spawn('SelectStmt', { select: true })))
|
|
250
311
|
.join(', ');
|
|
251
|
-
output.push(
|
|
312
|
+
output.push(context.parens(clause));
|
|
252
313
|
}
|
|
253
314
|
else {
|
|
254
315
|
output.push('DISTINCT');
|
|
@@ -257,22 +318,41 @@ export class Deparser {
|
|
|
257
318
|
}
|
|
258
319
|
if (node.targetList) {
|
|
259
320
|
const targetList = ListUtils.unwrapList(node.targetList);
|
|
260
|
-
if (
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
const
|
|
264
|
-
if
|
|
265
|
-
|
|
321
|
+
if (context.isPretty()) {
|
|
322
|
+
if (targetList.length === 1) {
|
|
323
|
+
const targetNode = targetList[0];
|
|
324
|
+
const target = this.visit(targetNode, context.spawn('SelectStmt', { select: true }));
|
|
325
|
+
// Check if single target is complex - if so, use multiline format
|
|
326
|
+
if (this.isComplexSelectTarget(targetNode)) {
|
|
327
|
+
output.push('SELECT' + distinctPart);
|
|
328
|
+
if (this.containsMultilineStringLiteral(target)) {
|
|
329
|
+
output.push(target);
|
|
330
|
+
}
|
|
331
|
+
else {
|
|
332
|
+
output.push(context.indent(target));
|
|
333
|
+
}
|
|
266
334
|
}
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
335
|
+
else {
|
|
336
|
+
output.push('SELECT' + distinctPart + ' ' + target);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
else {
|
|
340
|
+
const targetStrings = targetList
|
|
341
|
+
.map(e => {
|
|
342
|
+
const targetStr = this.visit(e, context.spawn('SelectStmt', { select: true }));
|
|
343
|
+
if (this.containsMultilineStringLiteral(targetStr)) {
|
|
344
|
+
return targetStr;
|
|
345
|
+
}
|
|
346
|
+
return context.indent(targetStr);
|
|
347
|
+
});
|
|
348
|
+
const formattedTargets = targetStrings.join(',' + context.newline());
|
|
349
|
+
output.push('SELECT' + distinctPart);
|
|
350
|
+
output.push(formattedTargets);
|
|
351
|
+
}
|
|
272
352
|
}
|
|
273
353
|
else {
|
|
274
354
|
const targets = targetList
|
|
275
|
-
.map(e => this.visit(e,
|
|
355
|
+
.map(e => this.visit(e, context.spawn('SelectStmt', { select: true })))
|
|
276
356
|
.join(', ');
|
|
277
357
|
output.push(targets);
|
|
278
358
|
}
|
|
@@ -284,22 +364,22 @@ export class Deparser {
|
|
|
284
364
|
if (node.fromClause) {
|
|
285
365
|
const fromList = ListUtils.unwrapList(node.fromClause);
|
|
286
366
|
const fromItems = fromList
|
|
287
|
-
.map(e => this.deparse(e,
|
|
367
|
+
.map(e => this.deparse(e, context.spawn('SelectStmt', { from: true })))
|
|
288
368
|
.join(', ');
|
|
289
369
|
output.push('FROM ' + fromItems.trim());
|
|
290
370
|
}
|
|
291
371
|
if (node.whereClause) {
|
|
292
|
-
if (
|
|
372
|
+
if (context.isPretty()) {
|
|
293
373
|
output.push('WHERE');
|
|
294
374
|
const whereExpr = this.visit(node.whereClause, context);
|
|
295
|
-
const lines = whereExpr.split(
|
|
375
|
+
const lines = whereExpr.split(context.newline());
|
|
296
376
|
const indentedLines = lines.map((line, index) => {
|
|
297
377
|
if (index === 0) {
|
|
298
|
-
return
|
|
378
|
+
return context.indent(line);
|
|
299
379
|
}
|
|
300
380
|
return line;
|
|
301
381
|
});
|
|
302
|
-
output.push(indentedLines.join(
|
|
382
|
+
output.push(indentedLines.join(context.newline()));
|
|
303
383
|
}
|
|
304
384
|
else {
|
|
305
385
|
output.push('WHERE');
|
|
@@ -307,45 +387,61 @@ export class Deparser {
|
|
|
307
387
|
}
|
|
308
388
|
}
|
|
309
389
|
if (node.valuesLists) {
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
const
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
390
|
+
if (context.isPretty()) {
|
|
391
|
+
output.push('VALUES');
|
|
392
|
+
const lists = ListUtils.unwrapList(node.valuesLists).map(list => {
|
|
393
|
+
const values = ListUtils.unwrapList(list).map(val => this.visit(val, context));
|
|
394
|
+
return context.parens(values.join(', '));
|
|
395
|
+
});
|
|
396
|
+
const indentedTuples = lists.map(tuple => {
|
|
397
|
+
if (this.containsMultilineStringLiteral(tuple)) {
|
|
398
|
+
return tuple;
|
|
399
|
+
}
|
|
400
|
+
return context.indent(tuple);
|
|
401
|
+
});
|
|
402
|
+
output.push(indentedTuples.join(',\n'));
|
|
403
|
+
}
|
|
404
|
+
else {
|
|
405
|
+
output.push('VALUES');
|
|
406
|
+
const lists = ListUtils.unwrapList(node.valuesLists).map(list => {
|
|
407
|
+
const values = ListUtils.unwrapList(list).map(val => this.visit(val, context));
|
|
408
|
+
return context.parens(values.join(', '));
|
|
409
|
+
});
|
|
410
|
+
output.push(lists.join(', '));
|
|
411
|
+
}
|
|
316
412
|
}
|
|
317
413
|
if (node.groupClause) {
|
|
318
414
|
const groupList = ListUtils.unwrapList(node.groupClause);
|
|
319
|
-
if (
|
|
415
|
+
if (context.isPretty()) {
|
|
320
416
|
const groupItems = groupList
|
|
321
417
|
.map(e => {
|
|
322
|
-
const groupStr = this.visit(e,
|
|
418
|
+
const groupStr = this.visit(e, context.spawn('SelectStmt', { group: true, indentLevel: context.indentLevel + 1 }));
|
|
323
419
|
if (this.containsMultilineStringLiteral(groupStr)) {
|
|
324
420
|
return groupStr;
|
|
325
421
|
}
|
|
326
|
-
return
|
|
422
|
+
return context.indent(groupStr);
|
|
327
423
|
})
|
|
328
|
-
.join(',' +
|
|
424
|
+
.join(',' + context.newline());
|
|
329
425
|
output.push('GROUP BY');
|
|
330
426
|
output.push(groupItems);
|
|
331
427
|
}
|
|
332
428
|
else {
|
|
333
429
|
output.push('GROUP BY');
|
|
334
430
|
const groupItems = groupList
|
|
335
|
-
.map(e => this.visit(e,
|
|
431
|
+
.map(e => this.visit(e, context.spawn('SelectStmt', { group: true })))
|
|
336
432
|
.join(', ');
|
|
337
433
|
output.push(groupItems);
|
|
338
434
|
}
|
|
339
435
|
}
|
|
340
436
|
if (node.havingClause) {
|
|
341
|
-
if (
|
|
437
|
+
if (context.isPretty()) {
|
|
342
438
|
output.push('HAVING');
|
|
343
439
|
const havingStr = this.visit(node.havingClause, context);
|
|
344
440
|
if (this.containsMultilineStringLiteral(havingStr)) {
|
|
345
441
|
output.push(havingStr);
|
|
346
442
|
}
|
|
347
443
|
else {
|
|
348
|
-
output.push(
|
|
444
|
+
output.push(context.indent(havingStr));
|
|
349
445
|
}
|
|
350
446
|
}
|
|
351
447
|
else {
|
|
@@ -363,23 +459,23 @@ export class Deparser {
|
|
|
363
459
|
}
|
|
364
460
|
if (node.sortClause) {
|
|
365
461
|
const sortList = ListUtils.unwrapList(node.sortClause);
|
|
366
|
-
if (
|
|
462
|
+
if (context.isPretty()) {
|
|
367
463
|
const sortItems = sortList
|
|
368
464
|
.map(e => {
|
|
369
|
-
const sortStr = this.visit(e,
|
|
465
|
+
const sortStr = this.visit(e, context.spawn('SelectStmt', { sort: true, indentLevel: context.indentLevel + 1 }));
|
|
370
466
|
if (this.containsMultilineStringLiteral(sortStr)) {
|
|
371
467
|
return sortStr;
|
|
372
468
|
}
|
|
373
|
-
return
|
|
469
|
+
return context.indent(sortStr);
|
|
374
470
|
})
|
|
375
|
-
.join(',' +
|
|
471
|
+
.join(',' + context.newline());
|
|
376
472
|
output.push('ORDER BY');
|
|
377
473
|
output.push(sortItems);
|
|
378
474
|
}
|
|
379
475
|
else {
|
|
380
476
|
output.push('ORDER BY');
|
|
381
477
|
const sortItems = sortList
|
|
382
|
-
.map(e => this.visit(e,
|
|
478
|
+
.map(e => this.visit(e, context.spawn('SelectStmt', { sort: true })))
|
|
383
479
|
.join(', ');
|
|
384
480
|
output.push(sortItems);
|
|
385
481
|
}
|
|
@@ -397,9 +493,9 @@ export class Deparser {
|
|
|
397
493
|
.join(' ');
|
|
398
494
|
output.push(lockingClauses);
|
|
399
495
|
}
|
|
400
|
-
if (
|
|
496
|
+
if (context.isPretty()) {
|
|
401
497
|
const filteredOutput = output.filter(item => item.trim() !== '');
|
|
402
|
-
return filteredOutput.join(
|
|
498
|
+
return filteredOutput.join(context.newline());
|
|
403
499
|
}
|
|
404
500
|
return output.join(' ');
|
|
405
501
|
}
|
|
@@ -411,13 +507,13 @@ export class Deparser {
|
|
|
411
507
|
switch (kind) {
|
|
412
508
|
case 'AEXPR_OP':
|
|
413
509
|
if (lexpr && rexpr) {
|
|
414
|
-
const operator = this.deparseOperatorName(name);
|
|
510
|
+
const operator = this.deparseOperatorName(name, context);
|
|
415
511
|
let leftExpr = this.visit(lexpr, context);
|
|
416
512
|
let rightExpr = this.visit(rexpr, context);
|
|
417
513
|
// Check if left expression needs parentheses
|
|
418
514
|
let leftNeedsParens = false;
|
|
419
515
|
if (lexpr && 'A_Expr' in lexpr && lexpr.A_Expr?.kind === 'AEXPR_OP') {
|
|
420
|
-
const leftOp = this.deparseOperatorName(ListUtils.unwrapList(lexpr.A_Expr.name));
|
|
516
|
+
const leftOp = this.deparseOperatorName(ListUtils.unwrapList(lexpr.A_Expr.name), context);
|
|
421
517
|
if (this.needsParentheses(leftOp, operator, 'left')) {
|
|
422
518
|
leftNeedsParens = true;
|
|
423
519
|
}
|
|
@@ -426,12 +522,12 @@ export class Deparser {
|
|
|
426
522
|
leftNeedsParens = true;
|
|
427
523
|
}
|
|
428
524
|
if (leftNeedsParens) {
|
|
429
|
-
leftExpr =
|
|
525
|
+
leftExpr = context.parens(leftExpr);
|
|
430
526
|
}
|
|
431
527
|
// Check if right expression needs parentheses
|
|
432
528
|
let rightNeedsParens = false;
|
|
433
529
|
if (rexpr && 'A_Expr' in rexpr && rexpr.A_Expr?.kind === 'AEXPR_OP') {
|
|
434
|
-
const rightOp = this.deparseOperatorName(ListUtils.unwrapList(rexpr.A_Expr.name));
|
|
530
|
+
const rightOp = this.deparseOperatorName(ListUtils.unwrapList(rexpr.A_Expr.name), context);
|
|
435
531
|
if (this.needsParentheses(rightOp, operator, 'right')) {
|
|
436
532
|
rightNeedsParens = true;
|
|
437
533
|
}
|
|
@@ -440,42 +536,42 @@ export class Deparser {
|
|
|
440
536
|
rightNeedsParens = true;
|
|
441
537
|
}
|
|
442
538
|
if (rightNeedsParens) {
|
|
443
|
-
rightExpr =
|
|
539
|
+
rightExpr = context.parens(rightExpr);
|
|
444
540
|
}
|
|
445
|
-
return
|
|
541
|
+
return context.format([leftExpr, operator, rightExpr]);
|
|
446
542
|
}
|
|
447
543
|
else if (rexpr) {
|
|
448
|
-
return
|
|
449
|
-
this.deparseOperatorName(name),
|
|
544
|
+
return context.format([
|
|
545
|
+
this.deparseOperatorName(name, context),
|
|
450
546
|
this.visit(rexpr, context)
|
|
451
547
|
]);
|
|
452
548
|
}
|
|
453
549
|
break;
|
|
454
550
|
case 'AEXPR_OP_ANY':
|
|
455
|
-
return
|
|
551
|
+
return context.format([
|
|
456
552
|
this.visit(lexpr, context),
|
|
457
|
-
this.deparseOperatorName(name),
|
|
553
|
+
this.deparseOperatorName(name, context),
|
|
458
554
|
'ANY',
|
|
459
|
-
|
|
555
|
+
context.parens(this.visit(rexpr, context))
|
|
460
556
|
]);
|
|
461
557
|
case 'AEXPR_OP_ALL':
|
|
462
|
-
return
|
|
558
|
+
return context.format([
|
|
463
559
|
this.visit(lexpr, context),
|
|
464
|
-
this.deparseOperatorName(name),
|
|
560
|
+
this.deparseOperatorName(name, context),
|
|
465
561
|
'ALL',
|
|
466
|
-
|
|
562
|
+
context.parens(this.visit(rexpr, context))
|
|
467
563
|
]);
|
|
468
564
|
case 'AEXPR_DISTINCT': {
|
|
469
565
|
let leftExpr = this.visit(lexpr, context);
|
|
470
566
|
let rightExpr = this.visit(rexpr, context);
|
|
471
567
|
// Add parentheses for complex expressions
|
|
472
568
|
if (lexpr && this.isComplexExpression(lexpr)) {
|
|
473
|
-
leftExpr =
|
|
569
|
+
leftExpr = context.parens(leftExpr);
|
|
474
570
|
}
|
|
475
571
|
if (rexpr && this.isComplexExpression(rexpr)) {
|
|
476
|
-
rightExpr =
|
|
572
|
+
rightExpr = context.parens(rightExpr);
|
|
477
573
|
}
|
|
478
|
-
return
|
|
574
|
+
return context.format([
|
|
479
575
|
leftExpr,
|
|
480
576
|
'IS DISTINCT FROM',
|
|
481
577
|
rightExpr
|
|
@@ -486,75 +582,75 @@ export class Deparser {
|
|
|
486
582
|
let rightExpr = this.visit(rexpr, context);
|
|
487
583
|
// Add parentheses for complex expressions
|
|
488
584
|
if (lexpr && this.isComplexExpression(lexpr)) {
|
|
489
|
-
leftExpr =
|
|
585
|
+
leftExpr = context.parens(leftExpr);
|
|
490
586
|
}
|
|
491
587
|
if (rexpr && this.isComplexExpression(rexpr)) {
|
|
492
|
-
rightExpr =
|
|
588
|
+
rightExpr = context.parens(rightExpr);
|
|
493
589
|
}
|
|
494
|
-
return
|
|
590
|
+
return context.format([
|
|
495
591
|
leftExpr,
|
|
496
592
|
'IS NOT DISTINCT FROM',
|
|
497
593
|
rightExpr
|
|
498
594
|
]);
|
|
499
595
|
}
|
|
500
596
|
case 'AEXPR_NULLIF':
|
|
501
|
-
return
|
|
597
|
+
return context.format([
|
|
502
598
|
'NULLIF',
|
|
503
|
-
|
|
599
|
+
context.parens([
|
|
504
600
|
this.visit(lexpr, context),
|
|
505
601
|
this.visit(rexpr, context)
|
|
506
602
|
].join(', '))
|
|
507
603
|
]);
|
|
508
604
|
case 'AEXPR_IN':
|
|
509
|
-
const inOperator = this.deparseOperatorName(name);
|
|
605
|
+
const inOperator = this.deparseOperatorName(name, context);
|
|
510
606
|
if (inOperator === '<>' || inOperator === '!=') {
|
|
511
|
-
return
|
|
607
|
+
return context.format([
|
|
512
608
|
this.visit(lexpr, context),
|
|
513
609
|
'NOT IN',
|
|
514
|
-
|
|
610
|
+
context.parens(this.visit(rexpr, context))
|
|
515
611
|
]);
|
|
516
612
|
}
|
|
517
613
|
else {
|
|
518
|
-
return
|
|
614
|
+
return context.format([
|
|
519
615
|
this.visit(lexpr, context),
|
|
520
616
|
'IN',
|
|
521
|
-
|
|
617
|
+
context.parens(this.visit(rexpr, context))
|
|
522
618
|
]);
|
|
523
619
|
}
|
|
524
620
|
case 'AEXPR_LIKE':
|
|
525
|
-
const likeOp = this.deparseOperatorName(name);
|
|
621
|
+
const likeOp = this.deparseOperatorName(name, context);
|
|
526
622
|
if (likeOp === '!~~') {
|
|
527
|
-
return
|
|
623
|
+
return context.format([
|
|
528
624
|
this.visit(lexpr, context),
|
|
529
625
|
'NOT LIKE',
|
|
530
626
|
this.visit(rexpr, context)
|
|
531
627
|
]);
|
|
532
628
|
}
|
|
533
629
|
else {
|
|
534
|
-
return
|
|
630
|
+
return context.format([
|
|
535
631
|
this.visit(lexpr, context),
|
|
536
632
|
'LIKE',
|
|
537
633
|
this.visit(rexpr, context)
|
|
538
634
|
]);
|
|
539
635
|
}
|
|
540
636
|
case 'AEXPR_ILIKE':
|
|
541
|
-
const ilikeOp = this.deparseOperatorName(name);
|
|
637
|
+
const ilikeOp = this.deparseOperatorName(name, context);
|
|
542
638
|
if (ilikeOp === '!~~*') {
|
|
543
|
-
return
|
|
639
|
+
return context.format([
|
|
544
640
|
this.visit(lexpr, context),
|
|
545
641
|
'NOT ILIKE',
|
|
546
642
|
this.visit(rexpr, context)
|
|
547
643
|
]);
|
|
548
644
|
}
|
|
549
645
|
else {
|
|
550
|
-
return
|
|
646
|
+
return context.format([
|
|
551
647
|
this.visit(lexpr, context),
|
|
552
648
|
'ILIKE',
|
|
553
649
|
this.visit(rexpr, context)
|
|
554
650
|
]);
|
|
555
651
|
}
|
|
556
652
|
case 'AEXPR_SIMILAR':
|
|
557
|
-
const similarOp = this.deparseOperatorName(name);
|
|
653
|
+
const similarOp = this.deparseOperatorName(name, context);
|
|
558
654
|
let rightExpr;
|
|
559
655
|
if (rexpr && 'FuncCall' in rexpr &&
|
|
560
656
|
rexpr.FuncCall?.funcname?.length === 2 &&
|
|
@@ -570,39 +666,39 @@ export class Deparser {
|
|
|
570
666
|
rightExpr = this.visit(rexpr, context);
|
|
571
667
|
}
|
|
572
668
|
if (similarOp === '!~') {
|
|
573
|
-
return
|
|
669
|
+
return context.format([
|
|
574
670
|
this.visit(lexpr, context),
|
|
575
671
|
'NOT SIMILAR TO',
|
|
576
672
|
rightExpr
|
|
577
673
|
]);
|
|
578
674
|
}
|
|
579
675
|
else {
|
|
580
|
-
return
|
|
676
|
+
return context.format([
|
|
581
677
|
this.visit(lexpr, context),
|
|
582
678
|
'SIMILAR TO',
|
|
583
679
|
rightExpr
|
|
584
680
|
]);
|
|
585
681
|
}
|
|
586
682
|
case 'AEXPR_BETWEEN':
|
|
587
|
-
return
|
|
683
|
+
return context.format([
|
|
588
684
|
this.visit(lexpr, context),
|
|
589
685
|
'BETWEEN',
|
|
590
686
|
this.visitBetweenRange(rexpr, context)
|
|
591
687
|
]);
|
|
592
688
|
case 'AEXPR_NOT_BETWEEN':
|
|
593
|
-
return
|
|
689
|
+
return context.format([
|
|
594
690
|
this.visit(lexpr, context),
|
|
595
691
|
'NOT BETWEEN',
|
|
596
692
|
this.visitBetweenRange(rexpr, context)
|
|
597
693
|
]);
|
|
598
694
|
case 'AEXPR_BETWEEN_SYM':
|
|
599
|
-
return
|
|
695
|
+
return context.format([
|
|
600
696
|
this.visit(lexpr, context),
|
|
601
697
|
'BETWEEN SYMMETRIC',
|
|
602
698
|
this.visitBetweenRange(rexpr, context)
|
|
603
699
|
]);
|
|
604
700
|
case 'AEXPR_NOT_BETWEEN_SYM':
|
|
605
|
-
return
|
|
701
|
+
return context.format([
|
|
606
702
|
this.visit(lexpr, context),
|
|
607
703
|
'NOT BETWEEN SYMMETRIC',
|
|
608
704
|
this.visitBetweenRange(rexpr, context)
|
|
@@ -610,7 +706,7 @@ export class Deparser {
|
|
|
610
706
|
}
|
|
611
707
|
throw new Error(`Unhandled A_Expr kind: ${kind}`);
|
|
612
708
|
}
|
|
613
|
-
deparseOperatorName(name) {
|
|
709
|
+
deparseOperatorName(name, context) {
|
|
614
710
|
if (!name || name.length === 0) {
|
|
615
711
|
return '';
|
|
616
712
|
}
|
|
@@ -618,7 +714,7 @@ export class Deparser {
|
|
|
618
714
|
if (n.String) {
|
|
619
715
|
return n.String.sval || n.String.str;
|
|
620
716
|
}
|
|
621
|
-
return this.visit(n,
|
|
717
|
+
return this.visit(n, context);
|
|
622
718
|
});
|
|
623
719
|
if (parts.length > 1) {
|
|
624
720
|
return `OPERATOR(${parts.join('.')})`;
|
|
@@ -681,6 +777,64 @@ export class Deparser {
|
|
|
681
777
|
node.SubLink ||
|
|
682
778
|
node.A_Expr);
|
|
683
779
|
}
|
|
780
|
+
isComplexSelectTarget(node) {
|
|
781
|
+
if (!node)
|
|
782
|
+
return false;
|
|
783
|
+
if (node.ResTarget?.val) {
|
|
784
|
+
return this.isComplexExpression(node.ResTarget.val);
|
|
785
|
+
}
|
|
786
|
+
// Always complex: CASE expressions
|
|
787
|
+
if (node.CaseExpr)
|
|
788
|
+
return true;
|
|
789
|
+
// Always complex: Subqueries and subselects
|
|
790
|
+
if (node.SubLink)
|
|
791
|
+
return true;
|
|
792
|
+
// Always complex: Boolean tests and expressions
|
|
793
|
+
if (node.NullTest || node.BooleanTest || node.BoolExpr)
|
|
794
|
+
return true;
|
|
795
|
+
// COALESCE and similar functions - complex if multiple arguments
|
|
796
|
+
if (node.CoalesceExpr) {
|
|
797
|
+
const args = node.CoalesceExpr.args;
|
|
798
|
+
if (args && Array.isArray(args) && args.length > 1)
|
|
799
|
+
return true;
|
|
800
|
+
}
|
|
801
|
+
// Function calls - complex if multiple args or has clauses
|
|
802
|
+
if (node.FuncCall) {
|
|
803
|
+
const funcCall = node.FuncCall;
|
|
804
|
+
const args = funcCall.args ? (Array.isArray(funcCall.args) ? funcCall.args : [funcCall.args]) : [];
|
|
805
|
+
// Complex if has window clause, filter, order by, etc.
|
|
806
|
+
if (funcCall.over || funcCall.agg_filter || funcCall.agg_order || funcCall.agg_distinct) {
|
|
807
|
+
return true;
|
|
808
|
+
}
|
|
809
|
+
// Complex if multiple arguments
|
|
810
|
+
if (args.length > 1)
|
|
811
|
+
return true;
|
|
812
|
+
if (args.length === 1) {
|
|
813
|
+
return this.isComplexSelectTarget(args[0]);
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
if (node.A_Expr) {
|
|
817
|
+
const expr = node.A_Expr;
|
|
818
|
+
// Check if operands are complex
|
|
819
|
+
if (expr.lexpr && this.isComplexSelectTarget(expr.lexpr))
|
|
820
|
+
return true;
|
|
821
|
+
if (expr.rexpr && this.isComplexSelectTarget(expr.rexpr))
|
|
822
|
+
return true;
|
|
823
|
+
return false;
|
|
824
|
+
}
|
|
825
|
+
if (node.TypeCast) {
|
|
826
|
+
return this.isComplexSelectTarget(node.TypeCast.arg);
|
|
827
|
+
}
|
|
828
|
+
if (node.A_ArrayExpr)
|
|
829
|
+
return true;
|
|
830
|
+
if (node.A_Indirection) {
|
|
831
|
+
return this.isComplexSelectTarget(node.A_Indirection.arg);
|
|
832
|
+
}
|
|
833
|
+
if (node.A_Const || node.ColumnRef || node.ParamRef || node.A_Star) {
|
|
834
|
+
return false;
|
|
835
|
+
}
|
|
836
|
+
return false;
|
|
837
|
+
}
|
|
684
838
|
visitBetweenRange(rexpr, context) {
|
|
685
839
|
if (rexpr && 'List' in rexpr && rexpr.List?.items) {
|
|
686
840
|
const items = rexpr.List.items.map((item) => this.visit(item, context));
|
|
@@ -697,9 +851,16 @@ export class Deparser {
|
|
|
697
851
|
output.push(this.RangeVar(node.relation, context));
|
|
698
852
|
if (node.cols) {
|
|
699
853
|
const cols = ListUtils.unwrapList(node.cols);
|
|
700
|
-
const insertContext =
|
|
854
|
+
const insertContext = context.spawn('InsertStmt', { insertColumns: true });
|
|
701
855
|
const columnNames = cols.map(col => this.visit(col, insertContext));
|
|
702
|
-
|
|
856
|
+
if (context.isPretty()) {
|
|
857
|
+
// Always format columns in multiline parentheses for pretty printing
|
|
858
|
+
const indentedColumns = columnNames.map(col => context.indent(col));
|
|
859
|
+
output.push('(\n' + indentedColumns.join(',\n') + '\n)');
|
|
860
|
+
}
|
|
861
|
+
else {
|
|
862
|
+
output.push(context.parens(columnNames.join(', ')));
|
|
863
|
+
}
|
|
703
864
|
}
|
|
704
865
|
if (node.selectStmt) {
|
|
705
866
|
output.push(this.visit(node.selectStmt, context));
|
|
@@ -720,7 +881,7 @@ export class Deparser {
|
|
|
720
881
|
else if (infer.indexElems) {
|
|
721
882
|
const elems = ListUtils.unwrapList(infer.indexElems);
|
|
722
883
|
const indexElems = elems.map(elem => this.visit(elem, context));
|
|
723
|
-
output.push(
|
|
884
|
+
output.push(context.parens(indexElems.join(', ')));
|
|
724
885
|
}
|
|
725
886
|
// Handle WHERE clause for conflict detection
|
|
726
887
|
if (infer.whereClause) {
|
|
@@ -736,12 +897,12 @@ export class Deparser {
|
|
|
736
897
|
if (firstTarget.ResTarget?.val?.MultiAssignRef && targetList.every(target => target.ResTarget?.val?.MultiAssignRef)) {
|
|
737
898
|
const sortedTargets = targetList.sort((a, b) => a.ResTarget.val.MultiAssignRef.colno - b.ResTarget.val.MultiAssignRef.colno);
|
|
738
899
|
const names = sortedTargets.map(target => target.ResTarget.name);
|
|
739
|
-
output.push(
|
|
900
|
+
output.push(context.parens(names.join(', ')));
|
|
740
901
|
output.push('=');
|
|
741
902
|
output.push(this.visit(firstTarget.ResTarget.val.MultiAssignRef.source, context));
|
|
742
903
|
}
|
|
743
904
|
else {
|
|
744
|
-
const updateContext =
|
|
905
|
+
const updateContext = context.spawn('UpdateStmt', { update: true });
|
|
745
906
|
const targets = targetList.map(target => this.visit(target, updateContext));
|
|
746
907
|
output.push(targets.join(', '));
|
|
747
908
|
}
|
|
@@ -795,12 +956,12 @@ export class Deparser {
|
|
|
795
956
|
}
|
|
796
957
|
}
|
|
797
958
|
const names = relatedTargets.map(t => t.ResTarget.name);
|
|
798
|
-
const multiAssignment = `${
|
|
959
|
+
const multiAssignment = `${context.parens(names.join(', '))} = ${this.visit(multiAssignRef.source, context)}`;
|
|
799
960
|
assignmentParts.push(multiAssignment);
|
|
800
961
|
}
|
|
801
962
|
else {
|
|
802
963
|
// Handle regular single-column assignment
|
|
803
|
-
assignmentParts.push(this.visit(target,
|
|
964
|
+
assignmentParts.push(this.visit(target, context.spawn('UpdateStmt', { update: true })));
|
|
804
965
|
processedTargets.add(i);
|
|
805
966
|
}
|
|
806
967
|
}
|
|
@@ -892,14 +1053,14 @@ export class Deparser {
|
|
|
892
1053
|
}
|
|
893
1054
|
if (node.ctes && node.ctes.length > 0) {
|
|
894
1055
|
const ctes = ListUtils.unwrapList(node.ctes);
|
|
895
|
-
if (
|
|
1056
|
+
if (context.isPretty()) {
|
|
896
1057
|
const cteStrings = ctes.map((cte, index) => {
|
|
897
1058
|
const cteStr = this.visit(cte, context);
|
|
898
|
-
const prefix = index === 0 ?
|
|
1059
|
+
const prefix = index === 0 ? context.newline() : ',' + context.newline();
|
|
899
1060
|
if (this.containsMultilineStringLiteral(cteStr)) {
|
|
900
1061
|
return prefix + cteStr;
|
|
901
1062
|
}
|
|
902
|
-
return prefix +
|
|
1063
|
+
return prefix + context.indent(cteStr);
|
|
903
1064
|
});
|
|
904
1065
|
output.push(cteStrings.join(''));
|
|
905
1066
|
}
|
|
@@ -985,14 +1146,14 @@ export class Deparser {
|
|
|
985
1146
|
if (context.bool) {
|
|
986
1147
|
formatStr = '(%s)';
|
|
987
1148
|
}
|
|
988
|
-
const boolContext =
|
|
1149
|
+
const boolContext = context.spawn('BoolExpr', { bool: true });
|
|
989
1150
|
// explanation of our syntax/fix below:
|
|
990
1151
|
// return formatStr.replace('%s', andArgs); // ❌ Interprets $ as special syntax
|
|
991
1152
|
// return formatStr.replace('%s', () => andArgs); // ✅ Function callback prevents interpretation
|
|
992
1153
|
switch (boolop) {
|
|
993
1154
|
case 'AND_EXPR':
|
|
994
|
-
if (
|
|
995
|
-
const andArgs = args.map(arg => this.visit(arg, boolContext)).join(
|
|
1155
|
+
if (context.isPretty() && args.length > 1) {
|
|
1156
|
+
const andArgs = args.map(arg => this.visit(arg, boolContext)).join(context.newline() + context.indent('AND '));
|
|
996
1157
|
return formatStr.replace('%s', () => andArgs);
|
|
997
1158
|
}
|
|
998
1159
|
else {
|
|
@@ -1000,8 +1161,8 @@ export class Deparser {
|
|
|
1000
1161
|
return formatStr.replace('%s', () => andArgs);
|
|
1001
1162
|
}
|
|
1002
1163
|
case 'OR_EXPR':
|
|
1003
|
-
if (
|
|
1004
|
-
const orArgs = args.map(arg => this.visit(arg, boolContext)).join(
|
|
1164
|
+
if (context.isPretty() && args.length > 1) {
|
|
1165
|
+
const orArgs = args.map(arg => this.visit(arg, boolContext)).join(context.newline() + context.indent('OR '));
|
|
1005
1166
|
return formatStr.replace('%s', () => orArgs);
|
|
1006
1167
|
}
|
|
1007
1168
|
else {
|
|
@@ -1132,9 +1293,9 @@ export class Deparser {
|
|
|
1132
1293
|
const timezone = this.visit(args[0], context);
|
|
1133
1294
|
// Add parentheses around timestamp if it contains arithmetic operations
|
|
1134
1295
|
if (args[1] && 'A_Expr' in args[1] && args[1].A_Expr?.kind === 'AEXPR_OP') {
|
|
1135
|
-
const op = this.deparseOperatorName(ListUtils.unwrapList(args[1].A_Expr.name));
|
|
1296
|
+
const op = this.deparseOperatorName(ListUtils.unwrapList(args[1].A_Expr.name), context);
|
|
1136
1297
|
if (op === '+' || op === '-' || op === '*' || op === '/') {
|
|
1137
|
-
timestamp =
|
|
1298
|
+
timestamp = context.parens(timestamp);
|
|
1138
1299
|
}
|
|
1139
1300
|
}
|
|
1140
1301
|
return `${timestamp} AT TIME ZONE ${timezone}`;
|
|
@@ -1204,14 +1365,14 @@ export class Deparser {
|
|
|
1204
1365
|
windowParts.push(`ORDER BY ${orderStrs.join(', ')}`);
|
|
1205
1366
|
}
|
|
1206
1367
|
// Handle window frame specifications using the dedicated formatWindowFrame method
|
|
1207
|
-
const frameClause = this.formatWindowFrame(node.over);
|
|
1368
|
+
const frameClause = this.formatWindowFrame(node.over, context.spawn('FuncCall'));
|
|
1208
1369
|
if (frameClause) {
|
|
1209
1370
|
windowParts.push(frameClause);
|
|
1210
1371
|
}
|
|
1211
1372
|
if (windowParts.length > 0) {
|
|
1212
|
-
if (
|
|
1213
|
-
const formattedParts = windowParts.map(part =>
|
|
1214
|
-
result += ` OVER (${
|
|
1373
|
+
if (context.isPretty() && windowParts.length > 1) {
|
|
1374
|
+
const formattedParts = windowParts.map(part => context.indent(part));
|
|
1375
|
+
result += ` OVER (${context.newline()}${formattedParts.join(context.newline())}${context.newline()})`;
|
|
1215
1376
|
}
|
|
1216
1377
|
else {
|
|
1217
1378
|
result += ` OVER (${windowParts.join(' ')})`;
|
|
@@ -1491,9 +1652,6 @@ export class Deparser {
|
|
|
1491
1652
|
return output.join(' ');
|
|
1492
1653
|
}
|
|
1493
1654
|
if (catalog === 'pg_catalog') {
|
|
1494
|
-
const builtinTypes = ['int2', 'int4', 'int8', 'float4', 'float8', 'numeric', 'decimal',
|
|
1495
|
-
'varchar', 'char', 'bpchar', 'text', 'bool', 'date', 'time', 'timestamp',
|
|
1496
|
-
'timestamptz', 'interval', 'bytea', 'uuid', 'json', 'jsonb'];
|
|
1497
1655
|
let typeName = `${catalog}.${type}`;
|
|
1498
1656
|
if (type === 'bpchar' && args) {
|
|
1499
1657
|
typeName = 'char';
|
|
@@ -1579,7 +1737,7 @@ export class Deparser {
|
|
|
1579
1737
|
}
|
|
1580
1738
|
return this.quoteIfNeeded(colStr);
|
|
1581
1739
|
});
|
|
1582
|
-
output.push('AS', this.quoteIfNeeded(name) +
|
|
1740
|
+
output.push('AS', this.quoteIfNeeded(name) + context.parens(quotedColnames.join(', ')));
|
|
1583
1741
|
}
|
|
1584
1742
|
else {
|
|
1585
1743
|
output.push('AS', this.quoteIfNeeded(name));
|
|
@@ -1591,7 +1749,7 @@ export class Deparser {
|
|
|
1591
1749
|
// Handle ONLY keyword for inheritance control (but not for type definitions, ALTER TYPE, or CREATE FOREIGN TABLE)
|
|
1592
1750
|
if (node && (!('inh' in node) || node.inh === undefined) &&
|
|
1593
1751
|
!context.parentNodeTypes.includes('CompositeTypeStmt') &&
|
|
1594
|
-
!context.parentNodeTypes.includes('AlterTypeStmt') &&
|
|
1752
|
+
(!context.parentNodeTypes.includes('AlterTypeStmt') && context.objtype !== 'OBJECT_TYPE') &&
|
|
1595
1753
|
!context.parentNodeTypes.includes('CreateForeignTableStmt')) {
|
|
1596
1754
|
output.push('ONLY');
|
|
1597
1755
|
}
|
|
@@ -1788,6 +1946,18 @@ export class Deparser {
|
|
|
1788
1946
|
return `pg_catalog.${typeName}`;
|
|
1789
1947
|
}
|
|
1790
1948
|
}
|
|
1949
|
+
isPgCatalogType(typeName) {
|
|
1950
|
+
const cleanTypeName = typeName.replace(/^pg_catalog\./, '');
|
|
1951
|
+
if (pgCatalogTypes.includes(cleanTypeName)) {
|
|
1952
|
+
return true;
|
|
1953
|
+
}
|
|
1954
|
+
for (const [realType, aliases] of pgCatalogTypeAliases) {
|
|
1955
|
+
if (aliases.includes(cleanTypeName)) {
|
|
1956
|
+
return true;
|
|
1957
|
+
}
|
|
1958
|
+
}
|
|
1959
|
+
return false;
|
|
1960
|
+
}
|
|
1791
1961
|
A_ArrayExpr(node, context) {
|
|
1792
1962
|
const elements = ListUtils.unwrapList(node.elements);
|
|
1793
1963
|
const elementStrs = elements.map(el => this.visit(el, context));
|
|
@@ -1839,26 +2009,26 @@ export class Deparser {
|
|
|
1839
2009
|
output.push(this.visit(node.arg, context));
|
|
1840
2010
|
}
|
|
1841
2011
|
const args = ListUtils.unwrapList(node.args);
|
|
1842
|
-
if (
|
|
2012
|
+
if (context.isPretty() && args.length > 0) {
|
|
1843
2013
|
for (const arg of args) {
|
|
1844
2014
|
const whenClause = this.visit(arg, context);
|
|
1845
2015
|
if (this.containsMultilineStringLiteral(whenClause)) {
|
|
1846
|
-
output.push(
|
|
2016
|
+
output.push(context.newline() + whenClause);
|
|
1847
2017
|
}
|
|
1848
2018
|
else {
|
|
1849
|
-
output.push(
|
|
2019
|
+
output.push(context.newline() + context.indent(whenClause));
|
|
1850
2020
|
}
|
|
1851
2021
|
}
|
|
1852
2022
|
if (node.defresult) {
|
|
1853
2023
|
const elseResult = this.visit(node.defresult, context);
|
|
1854
2024
|
if (this.containsMultilineStringLiteral(elseResult)) {
|
|
1855
|
-
output.push(
|
|
2025
|
+
output.push(context.newline() + 'ELSE ' + elseResult);
|
|
1856
2026
|
}
|
|
1857
2027
|
else {
|
|
1858
|
-
output.push(
|
|
2028
|
+
output.push(context.newline() + context.indent('ELSE ' + elseResult));
|
|
1859
2029
|
}
|
|
1860
2030
|
}
|
|
1861
|
-
output.push(
|
|
2031
|
+
output.push(context.newline() + 'END');
|
|
1862
2032
|
return output.join(' ');
|
|
1863
2033
|
}
|
|
1864
2034
|
else {
|
|
@@ -1881,28 +2051,29 @@ export class Deparser {
|
|
|
1881
2051
|
TypeCast(node, context) {
|
|
1882
2052
|
const arg = this.visit(node.arg, context);
|
|
1883
2053
|
const typeName = this.TypeName(node.typeName, context);
|
|
1884
|
-
// Check if this is a bpchar typecast that should
|
|
1885
|
-
if (typeName === 'bpchar'
|
|
1886
|
-
const names =
|
|
1887
|
-
|
|
1888
|
-
names[0]
|
|
1889
|
-
names[1]
|
|
1890
|
-
|
|
2054
|
+
// Check if this is a bpchar typecast that should preserve original syntax for AST consistency
|
|
2055
|
+
if (typeName === 'bpchar' || typeName === 'pg_catalog.bpchar') {
|
|
2056
|
+
const names = node.typeName?.names;
|
|
2057
|
+
const isQualifiedBpchar = names && names.length === 2 &&
|
|
2058
|
+
names[0]?.String?.sval === 'pg_catalog' &&
|
|
2059
|
+
names[1]?.String?.sval === 'bpchar';
|
|
2060
|
+
if (isQualifiedBpchar) {
|
|
2061
|
+
return `CAST(${arg} AS ${typeName})`;
|
|
1891
2062
|
}
|
|
1892
2063
|
}
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
2064
|
+
if (this.isPgCatalogType(typeName)) {
|
|
2065
|
+
const argType = this.getNodeType(node.arg);
|
|
2066
|
+
const isSimpleArgument = argType === 'A_Const' || argType === 'ColumnRef';
|
|
2067
|
+
const isFunctionCall = argType === 'FuncCall';
|
|
2068
|
+
if (isSimpleArgument || isFunctionCall) {
|
|
2069
|
+
// For simple arguments, avoid :: syntax if they have complex structure
|
|
2070
|
+
if (isSimpleArgument && (arg.includes('(') || arg.startsWith('-'))) {
|
|
2071
|
+
}
|
|
2072
|
+
else {
|
|
2073
|
+
const cleanTypeName = typeName.replace('pg_catalog.', '');
|
|
2074
|
+
return `${arg}::${cleanTypeName}`;
|
|
2075
|
+
}
|
|
2076
|
+
}
|
|
1906
2077
|
}
|
|
1907
2078
|
return `CAST(${arg} AS ${typeName})`;
|
|
1908
2079
|
}
|
|
@@ -1925,7 +2096,7 @@ export class Deparser {
|
|
|
1925
2096
|
}
|
|
1926
2097
|
BooleanTest(node, context) {
|
|
1927
2098
|
const output = [];
|
|
1928
|
-
const boolContext =
|
|
2099
|
+
const boolContext = context.spawn('BooleanTest', { bool: true });
|
|
1929
2100
|
output.push(this.visit(node.arg, boolContext));
|
|
1930
2101
|
switch (node.booltesttype) {
|
|
1931
2102
|
case 'IS_TRUE':
|
|
@@ -2076,24 +2247,31 @@ export class Deparser {
|
|
|
2076
2247
|
const elementStrs = elements.map(el => {
|
|
2077
2248
|
return this.deparse(el, context);
|
|
2078
2249
|
});
|
|
2079
|
-
output.push(
|
|
2250
|
+
output.push(context.parens(elementStrs.join(', ')));
|
|
2080
2251
|
}
|
|
2081
2252
|
}
|
|
2082
2253
|
else if (node.tableElts) {
|
|
2083
2254
|
const elements = ListUtils.unwrapList(node.tableElts);
|
|
2084
2255
|
const elementStrs = elements.map(el => {
|
|
2085
|
-
return this.deparse(el, context);
|
|
2256
|
+
return this.deparse(el, context.spawn('CreateStmt'));
|
|
2086
2257
|
});
|
|
2087
|
-
if (
|
|
2088
|
-
const formattedElements = elementStrs.map(el =>
|
|
2089
|
-
|
|
2258
|
+
if (context.isPretty()) {
|
|
2259
|
+
const formattedElements = elementStrs.map(el => {
|
|
2260
|
+
const trimmedEl = el.trim();
|
|
2261
|
+
// Remove leading newlines from constraint elements to avoid extra blank lines
|
|
2262
|
+
if (trimmedEl.startsWith('\n')) {
|
|
2263
|
+
return context.indent(trimmedEl.substring(1));
|
|
2264
|
+
}
|
|
2265
|
+
return context.indent(trimmedEl);
|
|
2266
|
+
}).join(',' + context.newline());
|
|
2267
|
+
output.push('(' + context.newline() + formattedElements + context.newline() + ')');
|
|
2090
2268
|
}
|
|
2091
2269
|
else {
|
|
2092
|
-
output.push(
|
|
2270
|
+
output.push(context.parens(elementStrs.join(', ')));
|
|
2093
2271
|
}
|
|
2094
2272
|
}
|
|
2095
2273
|
else if (!node.partbound) {
|
|
2096
|
-
output.push(
|
|
2274
|
+
output.push(context.parens(''));
|
|
2097
2275
|
}
|
|
2098
2276
|
if (node.partbound && node.inhRelations && node.inhRelations.length > 0) {
|
|
2099
2277
|
output.push('PARTITION OF');
|
|
@@ -2136,7 +2314,7 @@ export class Deparser {
|
|
|
2136
2314
|
output.push('INHERITS');
|
|
2137
2315
|
const inherits = ListUtils.unwrapList(node.inhRelations);
|
|
2138
2316
|
const inheritStrs = inherits.map(rel => this.visit(rel, context));
|
|
2139
|
-
output.push(
|
|
2317
|
+
output.push(context.parens(inheritStrs.join(', ')));
|
|
2140
2318
|
}
|
|
2141
2319
|
if (node.partspec) {
|
|
2142
2320
|
output.push('PARTITION BY');
|
|
@@ -2174,7 +2352,7 @@ export class Deparser {
|
|
|
2174
2352
|
}
|
|
2175
2353
|
// Handle table options like WITH (fillfactor=10)
|
|
2176
2354
|
if (node.options && node.options.length > 0) {
|
|
2177
|
-
const createStmtContext =
|
|
2355
|
+
const createStmtContext = context.spawn('CreateStmt');
|
|
2178
2356
|
const optionStrs = node.options.map((option) => {
|
|
2179
2357
|
return this.deparse(option, createStmtContext);
|
|
2180
2358
|
});
|
|
@@ -2197,7 +2375,7 @@ export class Deparser {
|
|
|
2197
2375
|
}
|
|
2198
2376
|
if (node.fdwoptions && node.fdwoptions.length > 0) {
|
|
2199
2377
|
output.push('OPTIONS');
|
|
2200
|
-
const columnContext =
|
|
2378
|
+
const columnContext = context.spawn('ColumnDef');
|
|
2201
2379
|
const options = ListUtils.unwrapList(node.fdwoptions).map(opt => this.visit(opt, columnContext));
|
|
2202
2380
|
output.push(`(${options.join(', ')})`);
|
|
2203
2381
|
}
|
|
@@ -2207,7 +2385,7 @@ export class Deparser {
|
|
|
2207
2385
|
if (node.constraints) {
|
|
2208
2386
|
const constraints = ListUtils.unwrapList(node.constraints);
|
|
2209
2387
|
const constraintStrs = constraints.map(constraint => {
|
|
2210
|
-
const columnConstraintContext =
|
|
2388
|
+
const columnConstraintContext = context.spawn('ColumnDef', { isColumnConstraint: true });
|
|
2211
2389
|
return this.visit(constraint, columnConstraintContext);
|
|
2212
2390
|
});
|
|
2213
2391
|
output.push(...constraintStrs);
|
|
@@ -2247,9 +2425,25 @@ export class Deparser {
|
|
|
2247
2425
|
}
|
|
2248
2426
|
break;
|
|
2249
2427
|
case 'CONSTR_CHECK':
|
|
2250
|
-
|
|
2428
|
+
if (context.isPretty() && !context.isColumnConstraint) {
|
|
2429
|
+
output.push('\n' + context.indent('CHECK'));
|
|
2430
|
+
}
|
|
2431
|
+
else {
|
|
2432
|
+
output.push('CHECK');
|
|
2433
|
+
}
|
|
2251
2434
|
if (node.raw_expr) {
|
|
2252
|
-
|
|
2435
|
+
if (context.isPretty()) {
|
|
2436
|
+
const checkExpr = this.visit(node.raw_expr, context);
|
|
2437
|
+
if (checkExpr.includes('\n')) {
|
|
2438
|
+
output.push('(\n' + context.indent(checkExpr) + '\n)');
|
|
2439
|
+
}
|
|
2440
|
+
else {
|
|
2441
|
+
output.push(`(${checkExpr})`);
|
|
2442
|
+
}
|
|
2443
|
+
}
|
|
2444
|
+
else {
|
|
2445
|
+
output.push(context.parens(this.visit(node.raw_expr, context)));
|
|
2446
|
+
}
|
|
2253
2447
|
}
|
|
2254
2448
|
// Handle NOT VALID for check constraints
|
|
2255
2449
|
if (node.skip_validation) {
|
|
@@ -2270,7 +2464,7 @@ export class Deparser {
|
|
|
2270
2464
|
}
|
|
2271
2465
|
output.push('AS');
|
|
2272
2466
|
if (node.raw_expr) {
|
|
2273
|
-
output.push(
|
|
2467
|
+
output.push(context.parens(this.visit(node.raw_expr, context)));
|
|
2274
2468
|
}
|
|
2275
2469
|
output.push('STORED');
|
|
2276
2470
|
break;
|
|
@@ -2328,7 +2522,12 @@ export class Deparser {
|
|
|
2328
2522
|
}
|
|
2329
2523
|
break;
|
|
2330
2524
|
case 'CONSTR_UNIQUE':
|
|
2331
|
-
|
|
2525
|
+
if (context.isPretty() && !context.isColumnConstraint) {
|
|
2526
|
+
output.push('\n' + context.indent('UNIQUE'));
|
|
2527
|
+
}
|
|
2528
|
+
else {
|
|
2529
|
+
output.push('UNIQUE');
|
|
2530
|
+
}
|
|
2332
2531
|
if (node.nulls_not_distinct) {
|
|
2333
2532
|
output.push('NULLS NOT DISTINCT');
|
|
2334
2533
|
}
|
|
@@ -2346,33 +2545,77 @@ export class Deparser {
|
|
|
2346
2545
|
case 'CONSTR_FOREIGN':
|
|
2347
2546
|
// Only add "FOREIGN KEY" for table-level constraints, not column-level constraints
|
|
2348
2547
|
if (!context.isColumnConstraint) {
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2548
|
+
if (context.isPretty()) {
|
|
2549
|
+
output.push('\n' + context.indent('FOREIGN KEY'));
|
|
2550
|
+
if (node.fk_attrs && node.fk_attrs.length > 0) {
|
|
2551
|
+
const fkAttrs = ListUtils.unwrapList(node.fk_attrs)
|
|
2552
|
+
.map(attr => this.visit(attr, context))
|
|
2553
|
+
.join(', ');
|
|
2554
|
+
output.push(`(${fkAttrs})`);
|
|
2555
|
+
}
|
|
2556
|
+
output.push('\n' + context.indent('REFERENCES'));
|
|
2355
2557
|
}
|
|
2558
|
+
else {
|
|
2559
|
+
output.push('FOREIGN KEY');
|
|
2560
|
+
if (node.fk_attrs && node.fk_attrs.length > 0) {
|
|
2561
|
+
const fkAttrs = ListUtils.unwrapList(node.fk_attrs)
|
|
2562
|
+
.map(attr => this.visit(attr, context))
|
|
2563
|
+
.join(', ');
|
|
2564
|
+
output.push(`(${fkAttrs})`);
|
|
2565
|
+
}
|
|
2566
|
+
output.push('REFERENCES');
|
|
2567
|
+
}
|
|
2568
|
+
}
|
|
2569
|
+
else {
|
|
2570
|
+
output.push('REFERENCES');
|
|
2356
2571
|
}
|
|
2357
|
-
output.push('REFERENCES');
|
|
2358
2572
|
if (node.pktable) {
|
|
2359
|
-
|
|
2573
|
+
if (context.isPretty() && !context.isColumnConstraint) {
|
|
2574
|
+
const lastIndex = output.length - 1;
|
|
2575
|
+
if (lastIndex >= 0 && output[lastIndex].includes('REFERENCES')) {
|
|
2576
|
+
output[lastIndex] += ' ' + this.RangeVar(node.pktable, context);
|
|
2577
|
+
}
|
|
2578
|
+
else {
|
|
2579
|
+
output.push(this.RangeVar(node.pktable, context));
|
|
2580
|
+
}
|
|
2581
|
+
}
|
|
2582
|
+
else {
|
|
2583
|
+
output.push(this.RangeVar(node.pktable, context));
|
|
2584
|
+
}
|
|
2360
2585
|
}
|
|
2361
2586
|
if (node.pk_attrs && node.pk_attrs.length > 0) {
|
|
2362
2587
|
const pkAttrs = ListUtils.unwrapList(node.pk_attrs)
|
|
2363
2588
|
.map(attr => this.visit(attr, context))
|
|
2364
2589
|
.join(', ');
|
|
2365
|
-
|
|
2590
|
+
if (context.isPretty() && !context.isColumnConstraint) {
|
|
2591
|
+
const lastIndex = output.length - 1;
|
|
2592
|
+
if (lastIndex >= 0) {
|
|
2593
|
+
output[lastIndex] += ` (${pkAttrs})`;
|
|
2594
|
+
}
|
|
2595
|
+
else {
|
|
2596
|
+
output.push(`(${pkAttrs})`);
|
|
2597
|
+
}
|
|
2598
|
+
}
|
|
2599
|
+
else {
|
|
2600
|
+
output.push(`(${pkAttrs})`);
|
|
2601
|
+
}
|
|
2366
2602
|
}
|
|
2367
2603
|
if (node.fk_matchtype && node.fk_matchtype !== 's') {
|
|
2604
|
+
let matchClause = '';
|
|
2368
2605
|
switch (node.fk_matchtype) {
|
|
2369
2606
|
case 'f':
|
|
2370
|
-
|
|
2607
|
+
matchClause = 'MATCH FULL';
|
|
2371
2608
|
break;
|
|
2372
2609
|
case 'p':
|
|
2373
|
-
|
|
2610
|
+
matchClause = 'MATCH PARTIAL';
|
|
2374
2611
|
break;
|
|
2375
2612
|
}
|
|
2613
|
+
if (context.isPretty() && !context.isColumnConstraint) {
|
|
2614
|
+
output.push('\n' + context.indent(matchClause));
|
|
2615
|
+
}
|
|
2616
|
+
else {
|
|
2617
|
+
output.push(matchClause);
|
|
2618
|
+
}
|
|
2376
2619
|
}
|
|
2377
2620
|
if (node.fk_upd_action && node.fk_upd_action !== 'a') {
|
|
2378
2621
|
let updateClause = 'ON UPDATE ';
|
|
@@ -2390,8 +2633,8 @@ export class Deparser {
|
|
|
2390
2633
|
updateClause += 'SET DEFAULT';
|
|
2391
2634
|
break;
|
|
2392
2635
|
}
|
|
2393
|
-
if (
|
|
2394
|
-
output.push('\n' +
|
|
2636
|
+
if (context.isPretty()) {
|
|
2637
|
+
output.push('\n' + context.indent(updateClause));
|
|
2395
2638
|
}
|
|
2396
2639
|
else {
|
|
2397
2640
|
output.push('ON UPDATE');
|
|
@@ -2414,8 +2657,8 @@ export class Deparser {
|
|
|
2414
2657
|
deleteClause += 'SET DEFAULT';
|
|
2415
2658
|
break;
|
|
2416
2659
|
}
|
|
2417
|
-
if (
|
|
2418
|
-
output.push('\n' +
|
|
2660
|
+
if (context.isPretty()) {
|
|
2661
|
+
output.push('\n' + context.indent(deleteClause));
|
|
2419
2662
|
}
|
|
2420
2663
|
else {
|
|
2421
2664
|
output.push('ON DELETE');
|
|
@@ -2424,7 +2667,12 @@ export class Deparser {
|
|
|
2424
2667
|
}
|
|
2425
2668
|
// Handle NOT VALID for foreign key constraints - only for table constraints, not domain constraints
|
|
2426
2669
|
if (node.skip_validation && !context.isDomainConstraint) {
|
|
2427
|
-
|
|
2670
|
+
if (context.isPretty() && !context.isColumnConstraint) {
|
|
2671
|
+
output.push('\n' + context.indent('NOT VALID'));
|
|
2672
|
+
}
|
|
2673
|
+
else {
|
|
2674
|
+
output.push('NOT VALID');
|
|
2675
|
+
}
|
|
2428
2676
|
}
|
|
2429
2677
|
break;
|
|
2430
2678
|
case 'CONSTR_ATTR_DEFERRABLE':
|
|
@@ -2478,13 +2726,13 @@ export class Deparser {
|
|
|
2478
2726
|
// Handle deferrable constraints for all constraint types that support it
|
|
2479
2727
|
if (node.contype === 'CONSTR_PRIMARY' || node.contype === 'CONSTR_UNIQUE' || node.contype === 'CONSTR_FOREIGN') {
|
|
2480
2728
|
if (node.deferrable) {
|
|
2481
|
-
if (
|
|
2482
|
-
output.push('\n' +
|
|
2729
|
+
if (context.isPretty() && node.contype === 'CONSTR_FOREIGN') {
|
|
2730
|
+
output.push('\n' + context.indent('DEFERRABLE'));
|
|
2483
2731
|
if (node.initdeferred === true) {
|
|
2484
|
-
output.push('\n' +
|
|
2732
|
+
output.push('\n' + context.indent('INITIALLY DEFERRED'));
|
|
2485
2733
|
}
|
|
2486
2734
|
else if (node.initdeferred === false) {
|
|
2487
|
-
output.push('\n' +
|
|
2735
|
+
output.push('\n' + context.indent('INITIALLY IMMEDIATE'));
|
|
2488
2736
|
}
|
|
2489
2737
|
}
|
|
2490
2738
|
else {
|
|
@@ -2498,15 +2746,15 @@ export class Deparser {
|
|
|
2498
2746
|
}
|
|
2499
2747
|
}
|
|
2500
2748
|
else if (node.deferrable === false) {
|
|
2501
|
-
if (
|
|
2502
|
-
output.push('\n' +
|
|
2749
|
+
if (context.isPretty() && node.contype === 'CONSTR_FOREIGN') {
|
|
2750
|
+
output.push('\n' + context.indent('NOT DEFERRABLE'));
|
|
2503
2751
|
}
|
|
2504
2752
|
else {
|
|
2505
2753
|
output.push('NOT DEFERRABLE');
|
|
2506
2754
|
}
|
|
2507
2755
|
}
|
|
2508
2756
|
}
|
|
2509
|
-
if (
|
|
2757
|
+
if (context.isPretty() && node.contype === 'CONSTR_FOREIGN') {
|
|
2510
2758
|
let result = '';
|
|
2511
2759
|
for (let i = 0; i < output.length; i++) {
|
|
2512
2760
|
if (output[i].startsWith('\n')) {
|
|
@@ -2524,12 +2772,12 @@ export class Deparser {
|
|
|
2524
2772
|
return output.join(' ');
|
|
2525
2773
|
}
|
|
2526
2774
|
SubLink(node, context) {
|
|
2527
|
-
const subselect =
|
|
2775
|
+
const subselect = context.parens(this.visit(node.subselect, context));
|
|
2528
2776
|
switch (node.subLinkType) {
|
|
2529
2777
|
case 'ANY_SUBLINK':
|
|
2530
2778
|
if (node.testexpr && node.operName) {
|
|
2531
2779
|
const testExpr = this.visit(node.testexpr, context);
|
|
2532
|
-
const operator = this.deparseOperatorName(node.operName);
|
|
2780
|
+
const operator = this.deparseOperatorName(node.operName, context);
|
|
2533
2781
|
return `${testExpr} ${operator} ANY ${subselect}`;
|
|
2534
2782
|
}
|
|
2535
2783
|
else if (node.testexpr) {
|
|
@@ -2540,7 +2788,7 @@ export class Deparser {
|
|
|
2540
2788
|
case 'ALL_SUBLINK':
|
|
2541
2789
|
if (node.testexpr && node.operName) {
|
|
2542
2790
|
const testExpr = this.visit(node.testexpr, context);
|
|
2543
|
-
const operator = this.deparseOperatorName(node.operName);
|
|
2791
|
+
const operator = this.deparseOperatorName(node.operName, context);
|
|
2544
2792
|
return `${testExpr} ${operator} ALL ${subselect}`;
|
|
2545
2793
|
}
|
|
2546
2794
|
return subselect;
|
|
@@ -2582,7 +2830,7 @@ export class Deparser {
|
|
|
2582
2830
|
}
|
|
2583
2831
|
// Only add frame clause if frameOptions indicates non-default framing
|
|
2584
2832
|
if (node.frameOptions && node.frameOptions !== 1058) {
|
|
2585
|
-
const frameClause = this.formatWindowFrame(node);
|
|
2833
|
+
const frameClause = this.formatWindowFrame(node, context.spawn('WindowDef'));
|
|
2586
2834
|
if (frameClause) {
|
|
2587
2835
|
windowParts.push(frameClause);
|
|
2588
2836
|
}
|
|
@@ -2602,7 +2850,7 @@ export class Deparser {
|
|
|
2602
2850
|
}
|
|
2603
2851
|
return output.join(' ');
|
|
2604
2852
|
}
|
|
2605
|
-
formatWindowFrame(node) {
|
|
2853
|
+
formatWindowFrame(node, context) {
|
|
2606
2854
|
if (!node.frameOptions)
|
|
2607
2855
|
return null;
|
|
2608
2856
|
const frameOptions = node.frameOptions;
|
|
@@ -2611,7 +2859,7 @@ export class Deparser {
|
|
|
2611
2859
|
if (frameOptions & 0x02) { // FRAMEOPTION_RANGE
|
|
2612
2860
|
frameParts.push('RANGE');
|
|
2613
2861
|
}
|
|
2614
|
-
else if (frameOptions & 0x04) { // FRAMEOPTION_ROWS
|
|
2862
|
+
else if (frameOptions & 0x04) { // FRAMEOPTION_ROWS
|
|
2615
2863
|
frameParts.push('ROWS');
|
|
2616
2864
|
}
|
|
2617
2865
|
else if (frameOptions & 0x08) { // FRAMEOPTION_GROUPS
|
|
@@ -2632,8 +2880,8 @@ export class Deparser {
|
|
|
2632
2880
|
}
|
|
2633
2881
|
else if (frameOptions === 18453) {
|
|
2634
2882
|
if (node.startOffset && node.endOffset) {
|
|
2635
|
-
boundsParts.push(`${this.visit(node.startOffset,
|
|
2636
|
-
boundsParts.push(`AND ${this.visit(node.endOffset,
|
|
2883
|
+
boundsParts.push(`${this.visit(node.startOffset, context)} PRECEDING`);
|
|
2884
|
+
boundsParts.push(`AND ${this.visit(node.endOffset, context)} FOLLOWING`);
|
|
2637
2885
|
}
|
|
2638
2886
|
}
|
|
2639
2887
|
else if (frameOptions === 1557) {
|
|
@@ -2643,7 +2891,7 @@ export class Deparser {
|
|
|
2643
2891
|
else if (frameOptions === 16917) {
|
|
2644
2892
|
boundsParts.push('CURRENT ROW');
|
|
2645
2893
|
if (node.endOffset) {
|
|
2646
|
-
boundsParts.push(`AND ${this.visit(node.endOffset,
|
|
2894
|
+
boundsParts.push(`AND ${this.visit(node.endOffset, context)} FOLLOWING`);
|
|
2647
2895
|
}
|
|
2648
2896
|
}
|
|
2649
2897
|
else if (frameOptions === 1058) {
|
|
@@ -2653,13 +2901,13 @@ export class Deparser {
|
|
|
2653
2901
|
// Handle start bound - prioritize explicit offset values over bit flags
|
|
2654
2902
|
if (node.startOffset) {
|
|
2655
2903
|
if (frameOptions & 0x400) { // FRAMEOPTION_START_VALUE_PRECEDING
|
|
2656
|
-
boundsParts.push(`${this.visit(node.startOffset,
|
|
2904
|
+
boundsParts.push(`${this.visit(node.startOffset, context)} PRECEDING`);
|
|
2657
2905
|
}
|
|
2658
2906
|
else if (frameOptions & 0x800) { // FRAMEOPTION_START_VALUE_FOLLOWING
|
|
2659
|
-
boundsParts.push(`${this.visit(node.startOffset,
|
|
2907
|
+
boundsParts.push(`${this.visit(node.startOffset, context)} FOLLOWING`);
|
|
2660
2908
|
}
|
|
2661
2909
|
else {
|
|
2662
|
-
boundsParts.push(`${this.visit(node.startOffset,
|
|
2910
|
+
boundsParts.push(`${this.visit(node.startOffset, context)} PRECEDING`);
|
|
2663
2911
|
}
|
|
2664
2912
|
}
|
|
2665
2913
|
else if (frameOptions & 0x10) { // FRAMEOPTION_START_UNBOUNDED_PRECEDING
|
|
@@ -2672,13 +2920,13 @@ export class Deparser {
|
|
|
2672
2920
|
if (node.endOffset) {
|
|
2673
2921
|
if (boundsParts.length > 0) {
|
|
2674
2922
|
if (frameOptions & 0x1000) { // FRAMEOPTION_END_VALUE_PRECEDING
|
|
2675
|
-
boundsParts.push(`AND ${this.visit(node.endOffset,
|
|
2923
|
+
boundsParts.push(`AND ${this.visit(node.endOffset, context)} PRECEDING`);
|
|
2676
2924
|
}
|
|
2677
2925
|
else if (frameOptions & 0x2000) { // FRAMEOPTION_END_VALUE_FOLLOWING
|
|
2678
|
-
boundsParts.push(`AND ${this.visit(node.endOffset,
|
|
2926
|
+
boundsParts.push(`AND ${this.visit(node.endOffset, context)} FOLLOWING`);
|
|
2679
2927
|
}
|
|
2680
2928
|
else {
|
|
2681
|
-
boundsParts.push(`AND ${this.visit(node.endOffset,
|
|
2929
|
+
boundsParts.push(`AND ${this.visit(node.endOffset, context)} FOLLOWING`);
|
|
2682
2930
|
}
|
|
2683
2931
|
}
|
|
2684
2932
|
}
|
|
@@ -2763,7 +3011,7 @@ export class Deparser {
|
|
|
2763
3011
|
const colnames = ListUtils.unwrapList(node.aliascolnames);
|
|
2764
3012
|
const colnameStrs = colnames.map(col => this.visit(col, context));
|
|
2765
3013
|
// Don't add space before column list parentheses to match original formatting
|
|
2766
|
-
output[output.length - 1] +=
|
|
3014
|
+
output[output.length - 1] += context.parens(colnameStrs.join(', '));
|
|
2767
3015
|
}
|
|
2768
3016
|
output.push('AS');
|
|
2769
3017
|
// Handle materialization clauses
|
|
@@ -2774,7 +3022,7 @@ export class Deparser {
|
|
|
2774
3022
|
output.push('MATERIALIZED');
|
|
2775
3023
|
}
|
|
2776
3024
|
if (node.ctequery) {
|
|
2777
|
-
output.push(
|
|
3025
|
+
output.push(context.parens(this.visit(node.ctequery, context)));
|
|
2778
3026
|
}
|
|
2779
3027
|
return output.join(' ');
|
|
2780
3028
|
}
|
|
@@ -2850,7 +3098,7 @@ export class Deparser {
|
|
|
2850
3098
|
DistinctExpr(node, context) {
|
|
2851
3099
|
const args = ListUtils.unwrapList(node.args);
|
|
2852
3100
|
if (args.length === 2) {
|
|
2853
|
-
const literalContext =
|
|
3101
|
+
const literalContext = context.spawn('DistinctExpr', { isStringLiteral: true });
|
|
2854
3102
|
const left = this.visit(args[0], literalContext);
|
|
2855
3103
|
const right = this.visit(args[1], literalContext);
|
|
2856
3104
|
return `${left} IS DISTINCT FROM ${right}`;
|
|
@@ -2860,7 +3108,7 @@ export class Deparser {
|
|
|
2860
3108
|
NullIfExpr(node, context) {
|
|
2861
3109
|
const args = ListUtils.unwrapList(node.args);
|
|
2862
3110
|
if (args.length === 2) {
|
|
2863
|
-
const literalContext =
|
|
3111
|
+
const literalContext = context.spawn('NullIfExpr', { isStringLiteral: true });
|
|
2864
3112
|
const left = this.visit(args[0], literalContext);
|
|
2865
3113
|
const right = this.visit(args[1], literalContext);
|
|
2866
3114
|
return `NULLIF(${left}, ${right})`;
|
|
@@ -2939,7 +3187,7 @@ export class Deparser {
|
|
|
2939
3187
|
}
|
|
2940
3188
|
RelabelType(node, context) {
|
|
2941
3189
|
if (node.arg) {
|
|
2942
|
-
const literalContext =
|
|
3190
|
+
const literalContext = context.spawn('RelabelType', { isStringLiteral: true });
|
|
2943
3191
|
return this.visit(node.arg, literalContext);
|
|
2944
3192
|
}
|
|
2945
3193
|
return '';
|
|
@@ -2958,7 +3206,7 @@ export class Deparser {
|
|
|
2958
3206
|
}
|
|
2959
3207
|
ConvertRowtypeExpr(node, context) {
|
|
2960
3208
|
if (node.arg) {
|
|
2961
|
-
const literalContext =
|
|
3209
|
+
const literalContext = context.spawn('ConvertRowtypeExpr', { isStringLiteral: true });
|
|
2962
3210
|
return this.visit(node.arg, literalContext);
|
|
2963
3211
|
}
|
|
2964
3212
|
return '';
|
|
@@ -2989,10 +3237,10 @@ export class Deparser {
|
|
|
2989
3237
|
}
|
|
2990
3238
|
if (node.aliases && node.aliases.length > 0) {
|
|
2991
3239
|
const aliasStrs = ListUtils.unwrapList(node.aliases).map(alias => this.visit(alias, context));
|
|
2992
|
-
output.push(
|
|
3240
|
+
output.push(context.parens(aliasStrs.join(', ')));
|
|
2993
3241
|
}
|
|
2994
3242
|
if (node.options && node.options.length > 0) {
|
|
2995
|
-
const viewContext =
|
|
3243
|
+
const viewContext = context.spawn('ViewStmt');
|
|
2996
3244
|
const optionStrs = ListUtils.unwrapList(node.options)
|
|
2997
3245
|
.map(option => this.visit(option, viewContext));
|
|
2998
3246
|
output.push(`WITH (${optionStrs.join(', ')})`);
|
|
@@ -3039,22 +3287,22 @@ export class Deparser {
|
|
|
3039
3287
|
}
|
|
3040
3288
|
if (node.indexParams && node.indexParams.length > 0) {
|
|
3041
3289
|
const paramStrs = ListUtils.unwrapList(node.indexParams).map(param => this.visit(param, context));
|
|
3042
|
-
output.push(
|
|
3290
|
+
output.push(context.parens(paramStrs.join(', ')));
|
|
3043
3291
|
}
|
|
3044
3292
|
if (node.indexIncludingParams && node.indexIncludingParams.length > 0) {
|
|
3045
3293
|
const includeStrs = ListUtils.unwrapList(node.indexIncludingParams).map(param => this.visit(param, context));
|
|
3046
3294
|
output.push('INCLUDE');
|
|
3047
|
-
output.push(
|
|
3295
|
+
output.push(context.parens(includeStrs.join(', ')));
|
|
3048
3296
|
}
|
|
3049
3297
|
if (node.whereClause) {
|
|
3050
3298
|
output.push('WHERE');
|
|
3051
3299
|
output.push(this.visit(node.whereClause, context));
|
|
3052
3300
|
}
|
|
3053
3301
|
if (node.options && node.options.length > 0) {
|
|
3054
|
-
const indexContext =
|
|
3302
|
+
const indexContext = context.spawn('IndexStmt');
|
|
3055
3303
|
const optionStrs = ListUtils.unwrapList(node.options).map(option => this.visit(option, indexContext));
|
|
3056
3304
|
output.push('WITH');
|
|
3057
|
-
output.push(
|
|
3305
|
+
output.push(context.parens(optionStrs.join(', ')));
|
|
3058
3306
|
}
|
|
3059
3307
|
if (node.nulls_not_distinct) {
|
|
3060
3308
|
output.push('NULLS NOT DISTINCT');
|
|
@@ -3071,7 +3319,7 @@ export class Deparser {
|
|
|
3071
3319
|
output.push(QuoteUtils.quote(node.name));
|
|
3072
3320
|
}
|
|
3073
3321
|
else if (node.expr) {
|
|
3074
|
-
output.push(
|
|
3322
|
+
output.push(context.parens(this.visit(node.expr, context)));
|
|
3075
3323
|
}
|
|
3076
3324
|
if (node.collation && node.collation.length > 0) {
|
|
3077
3325
|
const collationStrs = ListUtils.unwrapList(node.collation).map(coll => this.visit(coll, context));
|
|
@@ -3088,7 +3336,7 @@ export class Deparser {
|
|
|
3088
3336
|
const stringData = this.getNodeData(opt.DefElem.arg);
|
|
3089
3337
|
return `${opt.DefElem.defname}='${stringData.sval}'`;
|
|
3090
3338
|
}
|
|
3091
|
-
return this.visit(opt, context);
|
|
3339
|
+
return this.visit(opt, context.spawn('IndexElem'));
|
|
3092
3340
|
});
|
|
3093
3341
|
opclassStr += `(${opclassOpts.join(', ')})`;
|
|
3094
3342
|
}
|
|
@@ -3122,7 +3370,7 @@ export class Deparser {
|
|
|
3122
3370
|
output.push(QuoteUtils.quote(node.name));
|
|
3123
3371
|
}
|
|
3124
3372
|
else if (node.expr) {
|
|
3125
|
-
output.push(
|
|
3373
|
+
output.push(context.parens(this.visit(node.expr, context)));
|
|
3126
3374
|
}
|
|
3127
3375
|
if (node.collation && node.collation.length > 0) {
|
|
3128
3376
|
const collationStrs = ListUtils.unwrapList(node.collation).map(coll => this.visit(coll, context));
|
|
@@ -3270,16 +3518,16 @@ export class Deparser {
|
|
|
3270
3518
|
if (node.rarg && 'JoinExpr' in node.rarg && !node.rarg.JoinExpr.alias) {
|
|
3271
3519
|
rargStr = `(${rargStr})`;
|
|
3272
3520
|
}
|
|
3273
|
-
if (
|
|
3274
|
-
output.push(
|
|
3521
|
+
if (context.isPretty()) {
|
|
3522
|
+
output.push(context.newline() + joinStr + ' ' + rargStr);
|
|
3275
3523
|
}
|
|
3276
3524
|
else {
|
|
3277
3525
|
output.push(joinStr + ' ' + rargStr);
|
|
3278
3526
|
}
|
|
3279
3527
|
}
|
|
3280
3528
|
else {
|
|
3281
|
-
if (
|
|
3282
|
-
output.push(
|
|
3529
|
+
if (context.isPretty()) {
|
|
3530
|
+
output.push(context.newline() + joinStr);
|
|
3283
3531
|
}
|
|
3284
3532
|
else {
|
|
3285
3533
|
output.push(joinStr);
|
|
@@ -3288,7 +3536,7 @@ export class Deparser {
|
|
|
3288
3536
|
if (node.usingClause && node.usingClause.length > 0) {
|
|
3289
3537
|
const usingList = ListUtils.unwrapList(node.usingClause);
|
|
3290
3538
|
const columnNames = usingList.map(col => this.visit(col, context));
|
|
3291
|
-
if (
|
|
3539
|
+
if (context.isPretty()) {
|
|
3292
3540
|
output.push(` USING (${columnNames.join(', ')})`);
|
|
3293
3541
|
}
|
|
3294
3542
|
else {
|
|
@@ -3297,14 +3545,14 @@ export class Deparser {
|
|
|
3297
3545
|
}
|
|
3298
3546
|
else if (node.quals) {
|
|
3299
3547
|
const qualsStr = this.visit(node.quals, context);
|
|
3300
|
-
if (
|
|
3548
|
+
if (context.isPretty()) {
|
|
3301
3549
|
// For complex JOIN conditions, format with proper indentation
|
|
3302
3550
|
if (qualsStr.includes('AND') || qualsStr.includes('OR') || qualsStr.length > 50) {
|
|
3303
3551
|
if (this.containsMultilineStringLiteral(qualsStr)) {
|
|
3304
3552
|
output.push(` ON ${qualsStr}`);
|
|
3305
3553
|
}
|
|
3306
3554
|
else {
|
|
3307
|
-
output.push(` ON${
|
|
3555
|
+
output.push(` ON${context.newline()}${context.indent(qualsStr)}`);
|
|
3308
3556
|
}
|
|
3309
3557
|
}
|
|
3310
3558
|
else {
|
|
@@ -3316,7 +3564,7 @@ export class Deparser {
|
|
|
3316
3564
|
}
|
|
3317
3565
|
}
|
|
3318
3566
|
let result;
|
|
3319
|
-
if (
|
|
3567
|
+
if (context.isPretty()) {
|
|
3320
3568
|
result = output.join('');
|
|
3321
3569
|
}
|
|
3322
3570
|
else {
|
|
@@ -3423,8 +3671,8 @@ export class Deparser {
|
|
|
3423
3671
|
else if (nodeData.sval !== undefined) {
|
|
3424
3672
|
// Handle nested sval structure: { sval: { sval: "value" } }
|
|
3425
3673
|
const svalValue = typeof nodeData.sval === 'object' ? nodeData.sval.sval : nodeData.sval;
|
|
3426
|
-
const stringValue = svalValue.replace(/'/g, '')
|
|
3427
|
-
boolValue = stringValue === 'on' || stringValue === 'true';
|
|
3674
|
+
const stringValue = svalValue.replace(/'/g, '');
|
|
3675
|
+
boolValue = stringValue.toLowerCase() === 'on' || stringValue.toLowerCase() === 'true';
|
|
3428
3676
|
}
|
|
3429
3677
|
}
|
|
3430
3678
|
return boolValue ? 'READ ONLY' : 'READ WRITE';
|
|
@@ -3447,8 +3695,8 @@ export class Deparser {
|
|
|
3447
3695
|
else if (nodeData.sval !== undefined) {
|
|
3448
3696
|
// Handle nested sval structure: { sval: { sval: "value" } }
|
|
3449
3697
|
const svalValue = typeof nodeData.sval === 'object' ? nodeData.sval.sval : nodeData.sval;
|
|
3450
|
-
const stringValue = svalValue.replace(/'/g, '')
|
|
3451
|
-
boolValue = stringValue === 'on' || stringValue === 'true';
|
|
3698
|
+
const stringValue = svalValue.replace(/'/g, '');
|
|
3699
|
+
boolValue = stringValue.toLowerCase() === 'on' || stringValue.toLowerCase() === 'true';
|
|
3452
3700
|
}
|
|
3453
3701
|
}
|
|
3454
3702
|
return boolValue ? 'DEFERRABLE' : 'NOT DEFERRABLE';
|
|
@@ -3515,8 +3763,8 @@ export class Deparser {
|
|
|
3515
3763
|
else if (nodeData.sval !== undefined) {
|
|
3516
3764
|
// Handle nested sval structure: { sval: { sval: "value" } }
|
|
3517
3765
|
const svalValue = typeof nodeData.sval === 'object' ? nodeData.sval.sval : nodeData.sval;
|
|
3518
|
-
const stringValue = svalValue.replace(/'/g, '')
|
|
3519
|
-
boolValue = stringValue === 'on' || stringValue === 'true';
|
|
3766
|
+
const stringValue = svalValue.replace(/'/g, '');
|
|
3767
|
+
boolValue = stringValue.toLowerCase() === 'on' || stringValue.toLowerCase() === 'true';
|
|
3520
3768
|
}
|
|
3521
3769
|
}
|
|
3522
3770
|
transactionOptions.push(boolValue ? 'READ ONLY' : 'READ WRITE');
|
|
@@ -3534,8 +3782,8 @@ export class Deparser {
|
|
|
3534
3782
|
else if (nodeData.sval !== undefined) {
|
|
3535
3783
|
// Handle nested sval structure: { sval: { sval: "value" } }
|
|
3536
3784
|
const svalValue = typeof nodeData.sval === 'object' ? nodeData.sval.sval : nodeData.sval;
|
|
3537
|
-
const stringValue = svalValue.replace(/'/g, '')
|
|
3538
|
-
boolValue = stringValue === 'on' || stringValue === 'true';
|
|
3785
|
+
const stringValue = svalValue.replace(/'/g, '');
|
|
3786
|
+
boolValue = stringValue.toLowerCase() === 'on' || stringValue.toLowerCase() === 'true';
|
|
3539
3787
|
}
|
|
3540
3788
|
}
|
|
3541
3789
|
transactionOptions.push(boolValue ? 'DEFERRABLE' : 'NOT DEFERRABLE');
|
|
@@ -3601,7 +3849,7 @@ export class Deparser {
|
|
|
3601
3849
|
}
|
|
3602
3850
|
switch (node.roletype) {
|
|
3603
3851
|
case 'ROLESPEC_PUBLIC':
|
|
3604
|
-
return '
|
|
3852
|
+
return 'PUBLIC';
|
|
3605
3853
|
case 'ROLESPEC_CURRENT_USER':
|
|
3606
3854
|
return 'CURRENT_USER';
|
|
3607
3855
|
case 'ROLESPEC_SESSION_USER':
|
|
@@ -3609,7 +3857,7 @@ export class Deparser {
|
|
|
3609
3857
|
case 'ROLESPEC_CURRENT_ROLE':
|
|
3610
3858
|
return 'CURRENT_ROLE';
|
|
3611
3859
|
default:
|
|
3612
|
-
return '
|
|
3860
|
+
return 'PUBLIC';
|
|
3613
3861
|
}
|
|
3614
3862
|
}
|
|
3615
3863
|
roletype(node, context) {
|
|
@@ -3919,7 +4167,7 @@ export class Deparser {
|
|
|
3919
4167
|
}).filter((name) => name && name.trim());
|
|
3920
4168
|
return items.join('.');
|
|
3921
4169
|
}
|
|
3922
|
-
const objContext =
|
|
4170
|
+
const objContext = context.spawn('DropStmt', { objtype: node.removeType });
|
|
3923
4171
|
const objName = this.visit(objList, objContext);
|
|
3924
4172
|
return objName;
|
|
3925
4173
|
}).filter((name) => name && name.trim()).join(', ');
|
|
@@ -4019,7 +4267,7 @@ export class Deparser {
|
|
|
4019
4267
|
if (node.options && node.options.length > 0) {
|
|
4020
4268
|
output.push('WITH');
|
|
4021
4269
|
const optionsStr = ListUtils.unwrapList(node.options)
|
|
4022
|
-
.map(opt => this.visit(opt, context))
|
|
4270
|
+
.map(opt => this.visit(opt, context.spawn('CopyStmt')))
|
|
4023
4271
|
.join(', ');
|
|
4024
4272
|
output.push(`(${optionsStr})`);
|
|
4025
4273
|
}
|
|
@@ -4065,18 +4313,31 @@ export class Deparser {
|
|
|
4065
4313
|
if (node.missing_ok) {
|
|
4066
4314
|
output.push('IF EXISTS');
|
|
4067
4315
|
}
|
|
4068
|
-
const alterContext = node.objtype
|
|
4069
|
-
? { ...context, parentNodeTypes: [...context.parentNodeTypes, 'AlterTypeStmt'] }
|
|
4070
|
-
: context;
|
|
4316
|
+
const alterContext = context.spawn('AlterTableStmt', { objtype: node.objtype });
|
|
4071
4317
|
if (node.relation) {
|
|
4072
4318
|
const relationStr = this.RangeVar(node.relation, alterContext);
|
|
4073
4319
|
output.push(relationStr);
|
|
4074
4320
|
}
|
|
4075
4321
|
if (node.cmds && node.cmds.length > 0) {
|
|
4076
|
-
const
|
|
4077
|
-
|
|
4078
|
-
|
|
4079
|
-
|
|
4322
|
+
const commands = ListUtils.unwrapList(node.cmds);
|
|
4323
|
+
if (context.isPretty()) {
|
|
4324
|
+
const commandsStr = commands
|
|
4325
|
+
.map(cmd => {
|
|
4326
|
+
const cmdStr = this.visit(cmd, alterContext);
|
|
4327
|
+
if (cmdStr.startsWith('ADD CONSTRAINT') || cmdStr.startsWith('ADD ')) {
|
|
4328
|
+
return context.newline() + context.indent(cmdStr);
|
|
4329
|
+
}
|
|
4330
|
+
return cmdStr;
|
|
4331
|
+
})
|
|
4332
|
+
.join(',');
|
|
4333
|
+
output.push(commandsStr);
|
|
4334
|
+
}
|
|
4335
|
+
else {
|
|
4336
|
+
const commandsStr = commands
|
|
4337
|
+
.map(cmd => this.visit(cmd, alterContext))
|
|
4338
|
+
.join(', ');
|
|
4339
|
+
output.push(commandsStr);
|
|
4340
|
+
}
|
|
4080
4341
|
}
|
|
4081
4342
|
return output.join(' ');
|
|
4082
4343
|
}
|
|
@@ -4085,7 +4346,7 @@ export class Deparser {
|
|
|
4085
4346
|
if (node.subtype) {
|
|
4086
4347
|
switch (node.subtype) {
|
|
4087
4348
|
case 'AT_AddColumn':
|
|
4088
|
-
if (context.
|
|
4349
|
+
if (context.objtype === 'OBJECT_TYPE') {
|
|
4089
4350
|
output.push('ADD ATTRIBUTE');
|
|
4090
4351
|
}
|
|
4091
4352
|
else {
|
|
@@ -4105,14 +4366,14 @@ export class Deparser {
|
|
|
4105
4366
|
}
|
|
4106
4367
|
if (colDefData.fdwoptions && colDefData.fdwoptions.length > 0) {
|
|
4107
4368
|
parts.push('OPTIONS');
|
|
4108
|
-
const columnContext =
|
|
4369
|
+
const columnContext = context.spawn('ColumnDef');
|
|
4109
4370
|
const options = ListUtils.unwrapList(colDefData.fdwoptions).map(opt => this.visit(opt, columnContext));
|
|
4110
4371
|
parts.push(`(${options.join(', ')})`);
|
|
4111
4372
|
}
|
|
4112
4373
|
if (colDefData.constraints) {
|
|
4113
4374
|
const constraints = ListUtils.unwrapList(colDefData.constraints);
|
|
4114
4375
|
const constraintStrs = constraints.map(constraint => {
|
|
4115
|
-
const columnConstraintContext =
|
|
4376
|
+
const columnConstraintContext = context.spawn('ColumnDef', { isColumnConstraint: true });
|
|
4116
4377
|
return this.visit(constraint, columnConstraintContext);
|
|
4117
4378
|
});
|
|
4118
4379
|
parts.push(...constraintStrs);
|
|
@@ -4132,7 +4393,7 @@ export class Deparser {
|
|
|
4132
4393
|
break;
|
|
4133
4394
|
case 'AT_DropColumn':
|
|
4134
4395
|
if (node.missing_ok) {
|
|
4135
|
-
if (context.
|
|
4396
|
+
if (context.objtype === 'OBJECT_TYPE') {
|
|
4136
4397
|
output.push('DROP ATTRIBUTE IF EXISTS');
|
|
4137
4398
|
}
|
|
4138
4399
|
else {
|
|
@@ -4140,7 +4401,7 @@ export class Deparser {
|
|
|
4140
4401
|
}
|
|
4141
4402
|
}
|
|
4142
4403
|
else {
|
|
4143
|
-
if (context.
|
|
4404
|
+
if (context.objtype === 'OBJECT_TYPE') {
|
|
4144
4405
|
output.push('DROP ATTRIBUTE');
|
|
4145
4406
|
}
|
|
4146
4407
|
else {
|
|
@@ -4158,7 +4419,7 @@ export class Deparser {
|
|
|
4158
4419
|
}
|
|
4159
4420
|
break;
|
|
4160
4421
|
case 'AT_AlterColumnType':
|
|
4161
|
-
if (context.
|
|
4422
|
+
if (context.objtype === 'OBJECT_TYPE') {
|
|
4162
4423
|
output.push('ALTER ATTRIBUTE');
|
|
4163
4424
|
}
|
|
4164
4425
|
else {
|
|
@@ -4222,7 +4483,7 @@ export class Deparser {
|
|
|
4222
4483
|
case 'AT_SetRelOptions':
|
|
4223
4484
|
output.push('SET');
|
|
4224
4485
|
if (node.def) {
|
|
4225
|
-
const alterTableContext =
|
|
4486
|
+
const alterTableContext = context.spawn('AlterTableCmd', { subtype: 'AT_SetRelOptions' });
|
|
4226
4487
|
const options = ListUtils.unwrapList(node.def)
|
|
4227
4488
|
.map(option => this.visit(option, alterTableContext))
|
|
4228
4489
|
.join(', ');
|
|
@@ -4235,7 +4496,7 @@ export class Deparser {
|
|
|
4235
4496
|
case 'AT_ResetRelOptions':
|
|
4236
4497
|
output.push('RESET');
|
|
4237
4498
|
if (node.def) {
|
|
4238
|
-
const alterTableContext =
|
|
4499
|
+
const alterTableContext = context.spawn('AlterTableCmd', { subtype: 'AT_ResetRelOptions' });
|
|
4239
4500
|
const options = ListUtils.unwrapList(node.def)
|
|
4240
4501
|
.map(option => this.visit(option, alterTableContext))
|
|
4241
4502
|
.join(', ');
|
|
@@ -4330,7 +4591,7 @@ export class Deparser {
|
|
|
4330
4591
|
}
|
|
4331
4592
|
output.push('SET');
|
|
4332
4593
|
if (node.def) {
|
|
4333
|
-
const alterTableContext =
|
|
4594
|
+
const alterTableContext = context.spawn('AlterTableCmd', { subtype: 'AT_SetOptions' });
|
|
4334
4595
|
const options = ListUtils.unwrapList(node.def)
|
|
4335
4596
|
.map(option => this.visit(option, alterTableContext))
|
|
4336
4597
|
.join(', ');
|
|
@@ -4347,7 +4608,7 @@ export class Deparser {
|
|
|
4347
4608
|
}
|
|
4348
4609
|
output.push('RESET');
|
|
4349
4610
|
if (node.def) {
|
|
4350
|
-
const alterTableContext =
|
|
4611
|
+
const alterTableContext = context.spawn('AlterTableCmd', { subtype: 'AT_ResetOptions' });
|
|
4351
4612
|
const options = ListUtils.unwrapList(node.def)
|
|
4352
4613
|
.map(option => this.visit(option, alterTableContext))
|
|
4353
4614
|
.join(', ');
|
|
@@ -4588,7 +4849,7 @@ export class Deparser {
|
|
|
4588
4849
|
}
|
|
4589
4850
|
output.push('OPTIONS');
|
|
4590
4851
|
if (node.def) {
|
|
4591
|
-
const alterColumnContext =
|
|
4852
|
+
const alterColumnContext = context.spawn('AlterTableCmd', { alterColumnOptions: true });
|
|
4592
4853
|
const options = ListUtils.unwrapList(node.def)
|
|
4593
4854
|
.map(option => this.visit(option, alterColumnContext))
|
|
4594
4855
|
.join(', ');
|
|
@@ -4628,7 +4889,7 @@ export class Deparser {
|
|
|
4628
4889
|
case 'AT_GenericOptions':
|
|
4629
4890
|
output.push('OPTIONS');
|
|
4630
4891
|
if (node.def) {
|
|
4631
|
-
const alterTableContext =
|
|
4892
|
+
const alterTableContext = context.spawn('AlterTableCmd', { alterTableOptions: true });
|
|
4632
4893
|
const options = ListUtils.unwrapList(node.def)
|
|
4633
4894
|
.map(option => this.visit(option, alterTableContext))
|
|
4634
4895
|
.join(', ');
|
|
@@ -4732,7 +4993,7 @@ export class Deparser {
|
|
|
4732
4993
|
output.push(this.TypeName(node.returnType, context));
|
|
4733
4994
|
}
|
|
4734
4995
|
if (node.options && node.options.length > 0) {
|
|
4735
|
-
const funcContext =
|
|
4996
|
+
const funcContext = context.spawn('CreateFunctionStmt');
|
|
4736
4997
|
const options = node.options.map((opt) => this.visit(opt, funcContext));
|
|
4737
4998
|
output.push(...options);
|
|
4738
4999
|
}
|
|
@@ -4819,7 +5080,7 @@ export class Deparser {
|
|
|
4819
5080
|
}
|
|
4820
5081
|
output.push('AS', 'ENUM');
|
|
4821
5082
|
if (node.vals && node.vals.length > 0) {
|
|
4822
|
-
const enumContext =
|
|
5083
|
+
const enumContext = context.spawn('CreateEnumStmt', { isEnumValue: true });
|
|
4823
5084
|
const values = ListUtils.unwrapList(node.vals)
|
|
4824
5085
|
.map(val => this.visit(val, enumContext))
|
|
4825
5086
|
.join(', ');
|
|
@@ -4874,9 +5135,8 @@ export class Deparser {
|
|
|
4874
5135
|
output.push(roleName);
|
|
4875
5136
|
}
|
|
4876
5137
|
if (node.options) {
|
|
4877
|
-
const roleContext = { ...context, parentNodeTypes: [...context.parentNodeTypes, 'CreateRoleStmt'] };
|
|
4878
5138
|
const options = ListUtils.unwrapList(node.options)
|
|
4879
|
-
.map(option => this.visit(option,
|
|
5139
|
+
.map(option => this.visit(option, context.spawn('CreateRoleStmt')))
|
|
4880
5140
|
.join(' ');
|
|
4881
5141
|
if (options) {
|
|
4882
5142
|
output.push('WITH');
|
|
@@ -4907,7 +5167,7 @@ export class Deparser {
|
|
|
4907
5167
|
const stringData = this.getNodeData(node.arg);
|
|
4908
5168
|
return `${node.defname}='${stringData.sval}'`;
|
|
4909
5169
|
}
|
|
4910
|
-
return `${node.defname}=${this.visit(node.arg,
|
|
5170
|
+
return `${node.defname}=${this.visit(node.arg, context.spawn('DefElem'))}`;
|
|
4911
5171
|
}
|
|
4912
5172
|
// Handle CREATE OPERATOR boolean flags - MUST be first to preserve case
|
|
4913
5173
|
if (context.parentNodeTypes.includes('DefineStmt') &&
|
|
@@ -4923,13 +5183,13 @@ export class Deparser {
|
|
|
4923
5183
|
if (!node.arg) {
|
|
4924
5184
|
return `NO ${node.defname.toUpperCase()}`;
|
|
4925
5185
|
}
|
|
4926
|
-
const defElemContext =
|
|
5186
|
+
const defElemContext = context.spawn('DefElem');
|
|
4927
5187
|
const argValue = this.visit(node.arg, defElemContext);
|
|
4928
5188
|
return `${node.defname.toUpperCase()} ${argValue}`;
|
|
4929
5189
|
}
|
|
4930
5190
|
// Handle OPTIONS clause - use space format, not equals format
|
|
4931
5191
|
if (node.arg) {
|
|
4932
|
-
const defElemContext =
|
|
5192
|
+
const defElemContext = context.spawn('DefElem');
|
|
4933
5193
|
const argValue = this.visit(node.arg, defElemContext);
|
|
4934
5194
|
if (context.parentNodeTypes.includes('CreateFdwStmt') || context.parentNodeTypes.includes('AlterFdwStmt')) {
|
|
4935
5195
|
const finalValue = typeof argValue === 'string' && !argValue.startsWith("'")
|
|
@@ -4983,7 +5243,7 @@ export class Deparser {
|
|
|
4983
5243
|
if (!node.arg) {
|
|
4984
5244
|
return 'PASSWORD NULL';
|
|
4985
5245
|
}
|
|
4986
|
-
const defElemContext =
|
|
5246
|
+
const defElemContext = context.spawn('DefElem');
|
|
4987
5247
|
const argValue = this.visit(node.arg, defElemContext);
|
|
4988
5248
|
const quotedValue = typeof argValue === 'string' && !argValue.startsWith("'")
|
|
4989
5249
|
? `'${argValue}'`
|
|
@@ -4992,7 +5252,7 @@ export class Deparser {
|
|
|
4992
5252
|
}
|
|
4993
5253
|
}
|
|
4994
5254
|
if (node.arg) {
|
|
4995
|
-
const defElemContext =
|
|
5255
|
+
const defElemContext = context.spawn('DefElem');
|
|
4996
5256
|
const argValue = this.visit(node.arg, defElemContext);
|
|
4997
5257
|
if (context.parentNodeTypes.includes('AlterOperatorStmt')) {
|
|
4998
5258
|
if (node.arg && this.getNodeType(node.arg) === 'TypeName') {
|
|
@@ -5068,7 +5328,7 @@ export class Deparser {
|
|
|
5068
5328
|
if (node.defname === 'sysid') {
|
|
5069
5329
|
return `SYSID ${argValue}`;
|
|
5070
5330
|
}
|
|
5071
|
-
if (argValue === 'true') {
|
|
5331
|
+
if (String(argValue) === 'true') {
|
|
5072
5332
|
// Handle special cases where the positive form has a different name
|
|
5073
5333
|
if (node.defname === 'isreplication') {
|
|
5074
5334
|
return 'REPLICATION';
|
|
@@ -5078,7 +5338,7 @@ export class Deparser {
|
|
|
5078
5338
|
}
|
|
5079
5339
|
return node.defname.toUpperCase();
|
|
5080
5340
|
}
|
|
5081
|
-
else if (argValue === 'false') {
|
|
5341
|
+
else if (String(argValue) === 'false') {
|
|
5082
5342
|
// Handle special cases where the negative form has a different name
|
|
5083
5343
|
if (node.defname === 'canlogin') {
|
|
5084
5344
|
return 'NOLOGIN';
|
|
@@ -5142,7 +5402,7 @@ export class Deparser {
|
|
|
5142
5402
|
}
|
|
5143
5403
|
if (context.parentNodeTypes.includes('DoStmt')) {
|
|
5144
5404
|
if (node.defname === 'as') {
|
|
5145
|
-
const defElemContext =
|
|
5405
|
+
const defElemContext = context.spawn('DefElem');
|
|
5146
5406
|
const argValue = node.arg ? this.visit(node.arg, defElemContext) : '';
|
|
5147
5407
|
if (Array.isArray(argValue)) {
|
|
5148
5408
|
const bodyParts = argValue;
|
|
@@ -5433,7 +5693,7 @@ export class Deparser {
|
|
|
5433
5693
|
}
|
|
5434
5694
|
if (node.options && node.options.length > 0) {
|
|
5435
5695
|
output.push('WITH');
|
|
5436
|
-
const tsContext =
|
|
5696
|
+
const tsContext = context.spawn('CreateTableSpaceStmt');
|
|
5437
5697
|
const options = ListUtils.unwrapList(node.options)
|
|
5438
5698
|
.map(option => this.visit(option, tsContext))
|
|
5439
5699
|
.join(', ');
|
|
@@ -5463,7 +5723,7 @@ export class Deparser {
|
|
|
5463
5723
|
output.push('SET');
|
|
5464
5724
|
}
|
|
5465
5725
|
if (node.options && node.options.length > 0) {
|
|
5466
|
-
const tablespaceContext =
|
|
5726
|
+
const tablespaceContext = context.spawn('AlterTableSpaceOptionsStmt');
|
|
5467
5727
|
const options = ListUtils.unwrapList(node.options)
|
|
5468
5728
|
.map(option => this.visit(option, tablespaceContext))
|
|
5469
5729
|
.join(', ');
|
|
@@ -5480,7 +5740,7 @@ export class Deparser {
|
|
|
5480
5740
|
output.push(this.quoteIfNeeded(node.extname));
|
|
5481
5741
|
}
|
|
5482
5742
|
if (node.options && node.options.length > 0) {
|
|
5483
|
-
const extContext =
|
|
5743
|
+
const extContext = context.spawn('CreateExtensionStmt');
|
|
5484
5744
|
const options = ListUtils.unwrapList(node.options)
|
|
5485
5745
|
.map(option => this.visit(option, extContext))
|
|
5486
5746
|
.join(' ');
|
|
@@ -5494,7 +5754,7 @@ export class Deparser {
|
|
|
5494
5754
|
output.push(this.quoteIfNeeded(node.extname));
|
|
5495
5755
|
}
|
|
5496
5756
|
if (node.options && node.options.length > 0) {
|
|
5497
|
-
const extContext =
|
|
5757
|
+
const extContext = context.spawn('AlterExtensionStmt');
|
|
5498
5758
|
const options = ListUtils.unwrapList(node.options)
|
|
5499
5759
|
.map(option => this.visit(option, extContext))
|
|
5500
5760
|
.join(' ');
|
|
@@ -5508,7 +5768,7 @@ export class Deparser {
|
|
|
5508
5768
|
output.push(node.fdwname);
|
|
5509
5769
|
}
|
|
5510
5770
|
if (node.func_options && node.func_options.length > 0) {
|
|
5511
|
-
const fdwContext =
|
|
5771
|
+
const fdwContext = context.spawn('CreateFdwStmt');
|
|
5512
5772
|
const funcOptions = ListUtils.unwrapList(node.func_options)
|
|
5513
5773
|
.map(option => this.visit(option, fdwContext))
|
|
5514
5774
|
.join(' ');
|
|
@@ -5516,7 +5776,7 @@ export class Deparser {
|
|
|
5516
5776
|
}
|
|
5517
5777
|
if (node.options && node.options.length > 0) {
|
|
5518
5778
|
output.push('OPTIONS');
|
|
5519
|
-
const fdwContext =
|
|
5779
|
+
const fdwContext = context.spawn('CreateFdwStmt');
|
|
5520
5780
|
const options = ListUtils.unwrapList(node.options)
|
|
5521
5781
|
.map(option => this.visit(option, fdwContext))
|
|
5522
5782
|
.join(', ');
|
|
@@ -5618,7 +5878,7 @@ export class Deparser {
|
|
|
5618
5878
|
output.push('ADD');
|
|
5619
5879
|
if (node.def) {
|
|
5620
5880
|
// Pass domain context to avoid adding constraint names for domain constraints
|
|
5621
|
-
const domainContext =
|
|
5881
|
+
const domainContext = context.spawn('CreateDomainStmt', { isDomainConstraint: true });
|
|
5622
5882
|
output.push(this.visit(node.def, domainContext));
|
|
5623
5883
|
}
|
|
5624
5884
|
break;
|
|
@@ -5644,7 +5904,7 @@ export class Deparser {
|
|
|
5644
5904
|
output.push('ADD');
|
|
5645
5905
|
if (node.def) {
|
|
5646
5906
|
// Pass domain context to avoid adding constraint names for domain constraints
|
|
5647
|
-
const domainContext =
|
|
5907
|
+
const domainContext = context.spawn('CreateDomainStmt', { isDomainConstraint: true });
|
|
5648
5908
|
output.push(this.visit(node.def, domainContext));
|
|
5649
5909
|
}
|
|
5650
5910
|
break;
|
|
@@ -6006,7 +6266,7 @@ export class Deparser {
|
|
|
6006
6266
|
output.push(`${operatorName}(${args.join(', ')})`);
|
|
6007
6267
|
}
|
|
6008
6268
|
else {
|
|
6009
|
-
const objContext =
|
|
6269
|
+
const objContext = context.spawn('CommentStmt', { objtype: node.objtype });
|
|
6010
6270
|
output.push(this.visit(node.object, objContext));
|
|
6011
6271
|
}
|
|
6012
6272
|
}
|
|
@@ -6052,13 +6312,13 @@ export class Deparser {
|
|
|
6052
6312
|
const output = [];
|
|
6053
6313
|
const initialParts = ['CREATE', 'POLICY'];
|
|
6054
6314
|
if (node.policy_name) {
|
|
6055
|
-
initialParts.push(
|
|
6315
|
+
initialParts.push(QuoteUtils.quote(node.policy_name));
|
|
6056
6316
|
}
|
|
6057
6317
|
output.push(initialParts.join(' '));
|
|
6058
6318
|
// Add ON clause on new line in pretty mode
|
|
6059
6319
|
if (node.table) {
|
|
6060
|
-
if (
|
|
6061
|
-
output.push(
|
|
6320
|
+
if (context.isPretty()) {
|
|
6321
|
+
output.push(context.newline() + context.indent(`ON ${this.RangeVar(node.table, context)}`));
|
|
6062
6322
|
}
|
|
6063
6323
|
else {
|
|
6064
6324
|
output.push('ON');
|
|
@@ -6067,24 +6327,24 @@ export class Deparser {
|
|
|
6067
6327
|
}
|
|
6068
6328
|
// Handle AS RESTRICTIVE/PERMISSIVE clause
|
|
6069
6329
|
if (node.permissive === undefined) {
|
|
6070
|
-
if (
|
|
6071
|
-
output.push(
|
|
6330
|
+
if (context.isPretty()) {
|
|
6331
|
+
output.push(context.newline() + context.indent('AS RESTRICTIVE'));
|
|
6072
6332
|
}
|
|
6073
6333
|
else {
|
|
6074
6334
|
output.push('AS', 'RESTRICTIVE');
|
|
6075
6335
|
}
|
|
6076
6336
|
}
|
|
6077
6337
|
else if (node.permissive === true) {
|
|
6078
|
-
if (
|
|
6079
|
-
output.push(
|
|
6338
|
+
if (context.isPretty()) {
|
|
6339
|
+
output.push(context.newline() + context.indent('AS PERMISSIVE'));
|
|
6080
6340
|
}
|
|
6081
6341
|
else {
|
|
6082
6342
|
output.push('AS', 'PERMISSIVE');
|
|
6083
6343
|
}
|
|
6084
6344
|
}
|
|
6085
6345
|
if (node.cmd_name) {
|
|
6086
|
-
if (
|
|
6087
|
-
output.push(
|
|
6346
|
+
if (context.isPretty()) {
|
|
6347
|
+
output.push(context.newline() + context.indent(`FOR ${node.cmd_name.toUpperCase()}`));
|
|
6088
6348
|
}
|
|
6089
6349
|
else {
|
|
6090
6350
|
output.push('FOR', node.cmd_name.toUpperCase());
|
|
@@ -6092,8 +6352,8 @@ export class Deparser {
|
|
|
6092
6352
|
}
|
|
6093
6353
|
if (node.roles && node.roles.length > 0) {
|
|
6094
6354
|
const roles = ListUtils.unwrapList(node.roles).map(role => this.visit(role, context));
|
|
6095
|
-
if (
|
|
6096
|
-
output.push(
|
|
6355
|
+
if (context.isPretty()) {
|
|
6356
|
+
output.push(context.newline() + context.indent(`TO ${roles.join(', ')}`));
|
|
6097
6357
|
}
|
|
6098
6358
|
else {
|
|
6099
6359
|
output.push('TO');
|
|
@@ -6101,11 +6361,11 @@ export class Deparser {
|
|
|
6101
6361
|
}
|
|
6102
6362
|
}
|
|
6103
6363
|
if (node.qual) {
|
|
6104
|
-
if (
|
|
6364
|
+
if (context.isPretty()) {
|
|
6105
6365
|
const qualExpr = this.visit(node.qual, context);
|
|
6106
|
-
output.push(
|
|
6107
|
-
output.push(
|
|
6108
|
-
output.push(
|
|
6366
|
+
output.push(context.newline() + context.indent('USING ('));
|
|
6367
|
+
output.push(context.newline() + context.indent(context.indent(qualExpr)));
|
|
6368
|
+
output.push(context.newline() + context.indent(')'));
|
|
6109
6369
|
}
|
|
6110
6370
|
else {
|
|
6111
6371
|
output.push('USING');
|
|
@@ -6113,23 +6373,23 @@ export class Deparser {
|
|
|
6113
6373
|
}
|
|
6114
6374
|
}
|
|
6115
6375
|
if (node.with_check) {
|
|
6116
|
-
if (
|
|
6376
|
+
if (context.isPretty()) {
|
|
6117
6377
|
const checkExpr = this.visit(node.with_check, context);
|
|
6118
|
-
output.push(
|
|
6119
|
-
output.push(
|
|
6120
|
-
output.push(
|
|
6378
|
+
output.push(context.newline() + context.indent('WITH CHECK ('));
|
|
6379
|
+
output.push(context.newline() + context.indent(context.indent(checkExpr)));
|
|
6380
|
+
output.push(context.newline() + context.indent(')'));
|
|
6121
6381
|
}
|
|
6122
6382
|
else {
|
|
6123
6383
|
output.push('WITH CHECK');
|
|
6124
6384
|
output.push(`(${this.visit(node.with_check, context)})`);
|
|
6125
6385
|
}
|
|
6126
6386
|
}
|
|
6127
|
-
return
|
|
6387
|
+
return context.isPretty() ? output.join('') : output.join(' ');
|
|
6128
6388
|
}
|
|
6129
6389
|
AlterPolicyStmt(node, context) {
|
|
6130
6390
|
const output = ['ALTER', 'POLICY'];
|
|
6131
6391
|
if (node.policy_name) {
|
|
6132
|
-
output.push(
|
|
6392
|
+
output.push(QuoteUtils.quote(node.policy_name));
|
|
6133
6393
|
}
|
|
6134
6394
|
if (node.table) {
|
|
6135
6395
|
output.push('ON');
|
|
@@ -6169,7 +6429,7 @@ export class Deparser {
|
|
|
6169
6429
|
}
|
|
6170
6430
|
if (node.options && node.options.length > 0) {
|
|
6171
6431
|
output.push('OPTIONS');
|
|
6172
|
-
const userMappingContext =
|
|
6432
|
+
const userMappingContext = context.spawn('CreateUserMappingStmt');
|
|
6173
6433
|
const options = ListUtils.unwrapList(node.options).map(opt => this.visit(opt, userMappingContext));
|
|
6174
6434
|
output.push(`(${options.join(', ')})`);
|
|
6175
6435
|
}
|
|
@@ -6352,7 +6612,7 @@ export class Deparser {
|
|
|
6352
6612
|
DoStmt(node, context) {
|
|
6353
6613
|
const output = ['DO'];
|
|
6354
6614
|
if (node.args && node.args.length > 0) {
|
|
6355
|
-
const doContext =
|
|
6615
|
+
const doContext = context.spawn('DoStmt');
|
|
6356
6616
|
const args = ListUtils.unwrapList(node.args);
|
|
6357
6617
|
const processedArgs = [];
|
|
6358
6618
|
for (const arg of args) {
|
|
@@ -6657,7 +6917,7 @@ export class Deparser {
|
|
|
6657
6917
|
ObjectWithArgs(node, context) {
|
|
6658
6918
|
let result = '';
|
|
6659
6919
|
if (node.objname && node.objname.length > 0) {
|
|
6660
|
-
const objContext =
|
|
6920
|
+
const objContext = context.spawn('ObjectWithArgs');
|
|
6661
6921
|
const names = ListUtils.unwrapList(node.objname).map(name => this.visit(name, objContext));
|
|
6662
6922
|
result = names.join('.');
|
|
6663
6923
|
}
|
|
@@ -6699,7 +6959,7 @@ export class Deparser {
|
|
|
6699
6959
|
}
|
|
6700
6960
|
output.push('SET');
|
|
6701
6961
|
if (node.options && node.options.length > 0) {
|
|
6702
|
-
const alterOpContext =
|
|
6962
|
+
const alterOpContext = context.spawn('AlterOperatorStmt');
|
|
6703
6963
|
const options = ListUtils.unwrapList(node.options).map(opt => this.visit(opt, alterOpContext));
|
|
6704
6964
|
output.push(`(${options.join(', ')})`);
|
|
6705
6965
|
}
|
|
@@ -6711,13 +6971,13 @@ export class Deparser {
|
|
|
6711
6971
|
output.push(QuoteUtils.quote(node.fdwname));
|
|
6712
6972
|
}
|
|
6713
6973
|
if (node.func_options && node.func_options.length > 0) {
|
|
6714
|
-
const fdwContext =
|
|
6974
|
+
const fdwContext = context.spawn('AlterFdwStmt');
|
|
6715
6975
|
const funcOptions = ListUtils.unwrapList(node.func_options).map(opt => this.visit(opt, fdwContext));
|
|
6716
6976
|
output.push(funcOptions.join(' '));
|
|
6717
6977
|
}
|
|
6718
6978
|
if (node.options && node.options.length > 0) {
|
|
6719
6979
|
output.push('OPTIONS');
|
|
6720
|
-
const fdwContext =
|
|
6980
|
+
const fdwContext = context.spawn('AlterFdwStmt');
|
|
6721
6981
|
const options = ListUtils.unwrapList(node.options).map(opt => this.visit(opt, fdwContext));
|
|
6722
6982
|
output.push(`(${options.join(', ')})`);
|
|
6723
6983
|
}
|
|
@@ -6743,7 +7003,7 @@ export class Deparser {
|
|
|
6743
7003
|
if (node.options && node.options.length > 0) {
|
|
6744
7004
|
output.push('OPTIONS');
|
|
6745
7005
|
output.push('(');
|
|
6746
|
-
const optionsContext =
|
|
7006
|
+
const optionsContext = context.spawn('CreateForeignServerStmt');
|
|
6747
7007
|
const options = ListUtils.unwrapList(node.options).map(opt => this.visit(opt, optionsContext));
|
|
6748
7008
|
output.push(options.join(', '));
|
|
6749
7009
|
output.push(')');
|
|
@@ -6761,7 +7021,7 @@ export class Deparser {
|
|
|
6761
7021
|
if (node.options && node.options.length > 0) {
|
|
6762
7022
|
output.push('OPTIONS');
|
|
6763
7023
|
output.push('(');
|
|
6764
|
-
const optionsContext =
|
|
7024
|
+
const optionsContext = context.spawn('AlterForeignServerStmt');
|
|
6765
7025
|
const options = ListUtils.unwrapList(node.options).map(opt => this.visit(opt, optionsContext));
|
|
6766
7026
|
output.push(options.join(', '));
|
|
6767
7027
|
output.push(')');
|
|
@@ -6782,7 +7042,7 @@ export class Deparser {
|
|
|
6782
7042
|
}
|
|
6783
7043
|
if (node.options && node.options.length > 0) {
|
|
6784
7044
|
output.push('OPTIONS');
|
|
6785
|
-
const userMappingContext =
|
|
7045
|
+
const userMappingContext = context.spawn('AlterUserMappingStmt');
|
|
6786
7046
|
const options = ListUtils.unwrapList(node.options).map(opt => this.visit(opt, userMappingContext));
|
|
6787
7047
|
output.push(`(${options.join(', ')})`);
|
|
6788
7048
|
}
|
|
@@ -6842,7 +7102,7 @@ export class Deparser {
|
|
|
6842
7102
|
output.push(QuoteUtils.quote(node.local_schema));
|
|
6843
7103
|
}
|
|
6844
7104
|
if (node.options && node.options.length > 0) {
|
|
6845
|
-
const importSchemaContext =
|
|
7105
|
+
const importSchemaContext = context.spawn('ImportForeignSchemaStmt');
|
|
6846
7106
|
const options = ListUtils.unwrapList(node.options).map(opt => this.visit(opt, importSchemaContext));
|
|
6847
7107
|
output.push(`OPTIONS (${options.join(', ')})`);
|
|
6848
7108
|
}
|
|
@@ -6877,7 +7137,7 @@ export class Deparser {
|
|
|
6877
7137
|
ExplainStmt(node, context) {
|
|
6878
7138
|
const output = ['EXPLAIN'];
|
|
6879
7139
|
if (node.options && node.options.length > 0) {
|
|
6880
|
-
const explainContext =
|
|
7140
|
+
const explainContext = context.spawn('ExplainStmt');
|
|
6881
7141
|
const options = ListUtils.unwrapList(node.options).map(option => this.visit(option, explainContext));
|
|
6882
7142
|
output.push(`(${options.join(', ')})`);
|
|
6883
7143
|
}
|
|
@@ -7135,9 +7395,7 @@ export class Deparser {
|
|
|
7135
7395
|
output.push(this.RangeVar(node.relation, context));
|
|
7136
7396
|
}
|
|
7137
7397
|
else if (node.relation) {
|
|
7138
|
-
const rangeVarContext = node.relationType
|
|
7139
|
-
? { ...context, parentNodeTypes: [...context.parentNodeTypes, 'AlterTypeStmt'] }
|
|
7140
|
-
: context;
|
|
7398
|
+
const rangeVarContext = context.spawn('RenameStmt', { objtype: node.relationType });
|
|
7141
7399
|
// Add ON keyword for policy operations
|
|
7142
7400
|
if (node.renameType === 'OBJECT_POLICY') {
|
|
7143
7401
|
output.push('ON');
|
|
@@ -7319,7 +7577,7 @@ export class Deparser {
|
|
|
7319
7577
|
}
|
|
7320
7578
|
}
|
|
7321
7579
|
if (node.privileges && node.privileges.length > 0) {
|
|
7322
|
-
const privilegeContext =
|
|
7580
|
+
const privilegeContext = context.spawn('GrantStmt');
|
|
7323
7581
|
const privileges = ListUtils.unwrapList(node.privileges)
|
|
7324
7582
|
.map(priv => this.visit(priv, privilegeContext))
|
|
7325
7583
|
.join(', ');
|
|
@@ -7627,7 +7885,12 @@ export class Deparser {
|
|
|
7627
7885
|
}
|
|
7628
7886
|
if (node.action) {
|
|
7629
7887
|
const actionStr = this.GrantStmt(node.action, context);
|
|
7630
|
-
|
|
7888
|
+
if (context.isPretty()) {
|
|
7889
|
+
return output.join(' ') + context.newline() + context.indent(actionStr);
|
|
7890
|
+
}
|
|
7891
|
+
else {
|
|
7892
|
+
output.push(actionStr);
|
|
7893
|
+
}
|
|
7631
7894
|
}
|
|
7632
7895
|
return output.join(' ');
|
|
7633
7896
|
}
|
|
@@ -7774,84 +8037,158 @@ export class Deparser {
|
|
|
7774
8037
|
if (node.trigname) {
|
|
7775
8038
|
output.push(QuoteUtils.quote(node.trigname));
|
|
7776
8039
|
}
|
|
7777
|
-
|
|
7778
|
-
|
|
7779
|
-
timing
|
|
7780
|
-
|
|
7781
|
-
|
|
7782
|
-
|
|
7783
|
-
|
|
7784
|
-
|
|
7785
|
-
|
|
7786
|
-
|
|
7787
|
-
events
|
|
7788
|
-
|
|
7789
|
-
events
|
|
7790
|
-
|
|
7791
|
-
events
|
|
7792
|
-
|
|
7793
|
-
|
|
7794
|
-
|
|
7795
|
-
|
|
7796
|
-
|
|
7797
|
-
|
|
7798
|
-
|
|
7799
|
-
.
|
|
7800
|
-
|
|
7801
|
-
|
|
7802
|
-
|
|
7803
|
-
|
|
7804
|
-
|
|
7805
|
-
|
|
7806
|
-
|
|
7807
|
-
|
|
7808
|
-
|
|
7809
|
-
|
|
7810
|
-
|
|
7811
|
-
|
|
7812
|
-
|
|
7813
|
-
|
|
7814
|
-
|
|
7815
|
-
|
|
7816
|
-
|
|
7817
|
-
|
|
7818
|
-
|
|
7819
|
-
|
|
7820
|
-
.
|
|
7821
|
-
|
|
7822
|
-
|
|
7823
|
-
|
|
7824
|
-
|
|
7825
|
-
|
|
7826
|
-
|
|
7827
|
-
|
|
7828
|
-
|
|
7829
|
-
|
|
7830
|
-
|
|
7831
|
-
|
|
7832
|
-
|
|
7833
|
-
|
|
7834
|
-
|
|
7835
|
-
|
|
7836
|
-
|
|
7837
|
-
|
|
7838
|
-
|
|
7839
|
-
|
|
7840
|
-
|
|
7841
|
-
|
|
7842
|
-
|
|
7843
|
-
|
|
7844
|
-
|
|
7845
|
-
|
|
7846
|
-
|
|
7847
|
-
|
|
7848
|
-
output.push(args);
|
|
7849
|
-
output.push(')');
|
|
8040
|
+
if (context.isPretty()) {
|
|
8041
|
+
const components = [];
|
|
8042
|
+
const timing = [];
|
|
8043
|
+
if (node.timing & 2)
|
|
8044
|
+
timing.push('BEFORE');
|
|
8045
|
+
else if (node.timing & 64)
|
|
8046
|
+
timing.push('INSTEAD OF');
|
|
8047
|
+
else
|
|
8048
|
+
timing.push('AFTER');
|
|
8049
|
+
const events = [];
|
|
8050
|
+
if (node.events & 4)
|
|
8051
|
+
events.push('INSERT');
|
|
8052
|
+
if (node.events & 8)
|
|
8053
|
+
events.push('DELETE');
|
|
8054
|
+
if (node.events & 16) {
|
|
8055
|
+
let updateStr = 'UPDATE';
|
|
8056
|
+
if (node.columns && node.columns.length > 0) {
|
|
8057
|
+
const columnNames = ListUtils.unwrapList(node.columns)
|
|
8058
|
+
.map(col => this.visit(col, context))
|
|
8059
|
+
.join(', ');
|
|
8060
|
+
updateStr += ' OF ' + columnNames;
|
|
8061
|
+
}
|
|
8062
|
+
events.push(updateStr);
|
|
8063
|
+
}
|
|
8064
|
+
if (node.events & 32)
|
|
8065
|
+
events.push('TRUNCATE');
|
|
8066
|
+
components.push(context.indent(timing.join(' ') + ' ' + events.join(' OR ')));
|
|
8067
|
+
if (node.relation) {
|
|
8068
|
+
components.push(context.indent('ON ' + this.RangeVar(node.relation, context)));
|
|
8069
|
+
}
|
|
8070
|
+
if (node.transitionRels && node.transitionRels.length > 0) {
|
|
8071
|
+
const transitionClauses = ListUtils.unwrapList(node.transitionRels)
|
|
8072
|
+
.map(rel => this.visit(rel, context))
|
|
8073
|
+
.join(' ');
|
|
8074
|
+
components.push(context.indent('REFERENCING ' + transitionClauses));
|
|
8075
|
+
}
|
|
8076
|
+
if (node.deferrable) {
|
|
8077
|
+
components.push(context.indent('DEFERRABLE'));
|
|
8078
|
+
}
|
|
8079
|
+
if (node.initdeferred) {
|
|
8080
|
+
components.push(context.indent('INITIALLY DEFERRED'));
|
|
8081
|
+
}
|
|
8082
|
+
if (node.row) {
|
|
8083
|
+
components.push(context.indent('FOR EACH ROW'));
|
|
8084
|
+
}
|
|
8085
|
+
else {
|
|
8086
|
+
components.push(context.indent('FOR EACH STATEMENT'));
|
|
8087
|
+
}
|
|
8088
|
+
if (node.whenClause) {
|
|
8089
|
+
const whenStr = 'WHEN (' + this.visit(node.whenClause, context) + ')';
|
|
8090
|
+
components.push(context.indent(whenStr));
|
|
8091
|
+
}
|
|
8092
|
+
let executeStr = 'EXECUTE';
|
|
8093
|
+
if (node.funcname && node.funcname.length > 0) {
|
|
8094
|
+
const funcName = ListUtils.unwrapList(node.funcname)
|
|
8095
|
+
.map(name => this.visit(name, context))
|
|
8096
|
+
.join('.');
|
|
8097
|
+
executeStr += ' PROCEDURE ' + funcName;
|
|
8098
|
+
}
|
|
8099
|
+
if (node.args && node.args.length > 0) {
|
|
8100
|
+
const argContext = context.spawn('CreateTrigStmt', { isStringLiteral: true });
|
|
8101
|
+
const args = ListUtils.unwrapList(node.args)
|
|
8102
|
+
.map(arg => this.visit(arg, argContext))
|
|
8103
|
+
.join(', ');
|
|
8104
|
+
executeStr += '(' + args + ')';
|
|
8105
|
+
}
|
|
8106
|
+
else {
|
|
8107
|
+
executeStr += '()';
|
|
8108
|
+
}
|
|
8109
|
+
components.push(context.indent(executeStr));
|
|
8110
|
+
return output.join(' ') + context.newline() + components.join(context.newline());
|
|
7850
8111
|
}
|
|
7851
8112
|
else {
|
|
7852
|
-
|
|
8113
|
+
const timing = [];
|
|
8114
|
+
if (node.timing & 2)
|
|
8115
|
+
timing.push('BEFORE');
|
|
8116
|
+
else if (node.timing & 64)
|
|
8117
|
+
timing.push('INSTEAD OF');
|
|
8118
|
+
else
|
|
8119
|
+
timing.push('AFTER');
|
|
8120
|
+
output.push(timing.join(' '));
|
|
8121
|
+
const events = [];
|
|
8122
|
+
if (node.events & 4)
|
|
8123
|
+
events.push('INSERT');
|
|
8124
|
+
if (node.events & 8)
|
|
8125
|
+
events.push('DELETE');
|
|
8126
|
+
if (node.events & 16)
|
|
8127
|
+
events.push('UPDATE');
|
|
8128
|
+
if (node.events & 32)
|
|
8129
|
+
events.push('TRUNCATE');
|
|
8130
|
+
output.push(events.join(' OR '));
|
|
8131
|
+
if (node.columns && node.columns.length > 0) {
|
|
8132
|
+
output.push('OF');
|
|
8133
|
+
const columnNames = ListUtils.unwrapList(node.columns)
|
|
8134
|
+
.map(col => this.visit(col, context))
|
|
8135
|
+
.join(', ');
|
|
8136
|
+
output.push(columnNames);
|
|
8137
|
+
}
|
|
8138
|
+
output.push('ON');
|
|
8139
|
+
if (node.relation) {
|
|
8140
|
+
output.push(this.RangeVar(node.relation, context));
|
|
8141
|
+
}
|
|
8142
|
+
if (node.constrrel) {
|
|
8143
|
+
output.push('FROM');
|
|
8144
|
+
output.push(this.RangeVar(node.constrrel, context));
|
|
8145
|
+
}
|
|
8146
|
+
if (node.deferrable) {
|
|
8147
|
+
output.push('DEFERRABLE');
|
|
8148
|
+
}
|
|
8149
|
+
if (node.initdeferred) {
|
|
8150
|
+
output.push('INITIALLY DEFERRED');
|
|
8151
|
+
}
|
|
8152
|
+
if (node.transitionRels && node.transitionRels.length > 0) {
|
|
8153
|
+
output.push('REFERENCING');
|
|
8154
|
+
const transitionClauses = ListUtils.unwrapList(node.transitionRels)
|
|
8155
|
+
.map(rel => this.visit(rel, context))
|
|
8156
|
+
.join(' ');
|
|
8157
|
+
output.push(transitionClauses);
|
|
8158
|
+
}
|
|
8159
|
+
if (node.row) {
|
|
8160
|
+
output.push('FOR EACH ROW');
|
|
8161
|
+
}
|
|
8162
|
+
else {
|
|
8163
|
+
output.push('FOR EACH STATEMENT');
|
|
8164
|
+
}
|
|
8165
|
+
if (node.whenClause) {
|
|
8166
|
+
output.push('WHEN');
|
|
8167
|
+
output.push('(');
|
|
8168
|
+
output.push(this.visit(node.whenClause, context));
|
|
8169
|
+
output.push(')');
|
|
8170
|
+
}
|
|
8171
|
+
output.push('EXECUTE');
|
|
8172
|
+
if (node.funcname && node.funcname.length > 0) {
|
|
8173
|
+
const funcName = ListUtils.unwrapList(node.funcname)
|
|
8174
|
+
.map(name => this.visit(name, context))
|
|
8175
|
+
.join('.');
|
|
8176
|
+
output.push('FUNCTION', funcName);
|
|
8177
|
+
}
|
|
8178
|
+
if (node.args && node.args.length > 0) {
|
|
8179
|
+
output.push('(');
|
|
8180
|
+
const argContext = context.spawn('CreateTrigStmt', { isStringLiteral: true });
|
|
8181
|
+
const args = ListUtils.unwrapList(node.args)
|
|
8182
|
+
.map(arg => this.visit(arg, argContext))
|
|
8183
|
+
.join(', ');
|
|
8184
|
+
output.push(args);
|
|
8185
|
+
output.push(')');
|
|
8186
|
+
}
|
|
8187
|
+
else {
|
|
8188
|
+
output.push('()');
|
|
8189
|
+
}
|
|
8190
|
+
return output.join(' ');
|
|
7853
8191
|
}
|
|
7854
|
-
return output.join(' ');
|
|
7855
8192
|
}
|
|
7856
8193
|
TriggerTransition(node, context) {
|
|
7857
8194
|
const output = [];
|
|
@@ -7877,7 +8214,7 @@ export class Deparser {
|
|
|
7877
8214
|
}
|
|
7878
8215
|
if (node.whenclause && node.whenclause.length > 0) {
|
|
7879
8216
|
output.push('WHEN');
|
|
7880
|
-
const eventTriggerContext =
|
|
8217
|
+
const eventTriggerContext = context.spawn('CreateEventTrigStmt');
|
|
7881
8218
|
const conditions = ListUtils.unwrapList(node.whenclause)
|
|
7882
8219
|
.map(condition => this.visit(condition, eventTriggerContext))
|
|
7883
8220
|
.join(' AND ');
|
|
@@ -8066,7 +8403,7 @@ export class Deparser {
|
|
|
8066
8403
|
output.push(sequenceName.join('.'));
|
|
8067
8404
|
}
|
|
8068
8405
|
if (node.options && node.options.length > 0) {
|
|
8069
|
-
const seqContext =
|
|
8406
|
+
const seqContext = context.spawn('CreateSeqStmt');
|
|
8070
8407
|
const optionStrs = ListUtils.unwrapList(node.options)
|
|
8071
8408
|
.filter(option => option != null && this.getNodeType(option) !== 'undefined')
|
|
8072
8409
|
.map(option => {
|
|
@@ -8103,7 +8440,7 @@ export class Deparser {
|
|
|
8103
8440
|
output.push(sequenceName.join('.'));
|
|
8104
8441
|
}
|
|
8105
8442
|
if (node.options && node.options.length > 0) {
|
|
8106
|
-
const seqContext =
|
|
8443
|
+
const seqContext = context.spawn('AlterSeqStmt');
|
|
8107
8444
|
const optionStrs = ListUtils.unwrapList(node.options)
|
|
8108
8445
|
.filter(option => option && option !== undefined)
|
|
8109
8446
|
.map(option => {
|
|
@@ -8132,7 +8469,7 @@ export class Deparser {
|
|
|
8132
8469
|
CompositeTypeStmt(node, context) {
|
|
8133
8470
|
const output = ['CREATE', 'TYPE'];
|
|
8134
8471
|
if (node.typevar) {
|
|
8135
|
-
const typeContext =
|
|
8472
|
+
const typeContext = context.spawn('CompositeTypeStmt');
|
|
8136
8473
|
output.push(this.RangeVar(node.typevar, typeContext));
|
|
8137
8474
|
}
|
|
8138
8475
|
output.push('AS');
|
|
@@ -8233,7 +8570,7 @@ export class Deparser {
|
|
|
8233
8570
|
output.push(this.RoleSpec(node.role, context));
|
|
8234
8571
|
}
|
|
8235
8572
|
if (node.options) {
|
|
8236
|
-
const roleContext =
|
|
8573
|
+
const roleContext = context.spawn('AlterRoleStmt');
|
|
8237
8574
|
// Handle GROUP operations specially based on action value
|
|
8238
8575
|
if (isGroupStatement) {
|
|
8239
8576
|
const roleMembersOption = ListUtils.unwrapList(node.options).find(option => option.DefElem && option.DefElem.defname === 'rolemembers');
|
|
@@ -8429,14 +8766,14 @@ export class Deparser {
|
|
|
8429
8766
|
AccessPriv(node, context) {
|
|
8430
8767
|
const output = [];
|
|
8431
8768
|
if (node.priv_name) {
|
|
8432
|
-
output.push(node.priv_name);
|
|
8769
|
+
output.push(node.priv_name.toUpperCase());
|
|
8433
8770
|
}
|
|
8434
8771
|
else {
|
|
8435
8772
|
output.push('ALL');
|
|
8436
8773
|
}
|
|
8437
8774
|
if (node.cols && node.cols.length > 0) {
|
|
8438
8775
|
output.push('(');
|
|
8439
|
-
const colContext =
|
|
8776
|
+
const colContext = context.spawn('AccessPriv');
|
|
8440
8777
|
const columns = ListUtils.unwrapList(node.cols).map(col => this.visit(col, colContext));
|
|
8441
8778
|
output.push(columns.join(', '));
|
|
8442
8779
|
output.push(')');
|
|
@@ -8516,7 +8853,7 @@ export class Deparser {
|
|
|
8516
8853
|
output.push(ListUtils.unwrapList(node.defnames).map(name => this.visit(name, context)).join('.'));
|
|
8517
8854
|
}
|
|
8518
8855
|
if (node.definition && node.definition.length > 0) {
|
|
8519
|
-
const defineStmtContext =
|
|
8856
|
+
const defineStmtContext = context.spawn('DefineStmt');
|
|
8520
8857
|
const definitions = ListUtils.unwrapList(node.definition).map(def => {
|
|
8521
8858
|
return this.visit(def, defineStmtContext);
|
|
8522
8859
|
});
|
|
@@ -9002,7 +9339,7 @@ export class Deparser {
|
|
|
9002
9339
|
const operatorNumber = node.number !== undefined ? node.number : 0;
|
|
9003
9340
|
output.push(operatorNumber.toString());
|
|
9004
9341
|
if (node.name) {
|
|
9005
|
-
const opClassContext =
|
|
9342
|
+
const opClassContext = context.spawn('CreateOpClassItem');
|
|
9006
9343
|
output.push(this.ObjectWithArgs(node.name, opClassContext));
|
|
9007
9344
|
}
|
|
9008
9345
|
}
|
|
@@ -9012,7 +9349,7 @@ export class Deparser {
|
|
|
9012
9349
|
const functionNumber = node.number !== undefined ? node.number : 0;
|
|
9013
9350
|
output.push(functionNumber.toString());
|
|
9014
9351
|
if (node.name) {
|
|
9015
|
-
const opClassContext =
|
|
9352
|
+
const opClassContext = context.spawn('CreateOpClassItem');
|
|
9016
9353
|
output.push(this.ObjectWithArgs(node.name, opClassContext));
|
|
9017
9354
|
}
|
|
9018
9355
|
}
|
|
@@ -9710,7 +10047,7 @@ export class Deparser {
|
|
|
9710
10047
|
output.push(this.ObjectWithArgs(node.func, context));
|
|
9711
10048
|
}
|
|
9712
10049
|
if (node.actions && node.actions.length > 0) {
|
|
9713
|
-
const alterFunctionContext =
|
|
10050
|
+
const alterFunctionContext = context.spawn('AlterFunctionStmt');
|
|
9714
10051
|
const actionStrs = ListUtils.unwrapList(node.actions).map(action => this.visit(action, alterFunctionContext));
|
|
9715
10052
|
output.push(actionStrs.join(' '));
|
|
9716
10053
|
}
|
|
@@ -9954,7 +10291,7 @@ export class Deparser {
|
|
|
9954
10291
|
CreateForeignTableStmt(node, context) {
|
|
9955
10292
|
const output = ['CREATE FOREIGN TABLE'];
|
|
9956
10293
|
if (node.base && node.base.relation) {
|
|
9957
|
-
const relationContext =
|
|
10294
|
+
const relationContext = context.spawn('CreateForeignTableStmt');
|
|
9958
10295
|
// Handle relation node directly as RangeVar since it contains the RangeVar properties
|
|
9959
10296
|
output.push(this.RangeVar(node.base.relation, relationContext));
|
|
9960
10297
|
}
|
|
@@ -9984,7 +10321,7 @@ export class Deparser {
|
|
|
9984
10321
|
output.push(QuoteUtils.quote(node.servername));
|
|
9985
10322
|
}
|
|
9986
10323
|
if (node.options && node.options.length > 0) {
|
|
9987
|
-
const foreignTableContext =
|
|
10324
|
+
const foreignTableContext = context.spawn('CreateForeignTableStmt');
|
|
9988
10325
|
const optionStrs = ListUtils.unwrapList(node.options).map(opt => this.visit(opt, foreignTableContext));
|
|
9989
10326
|
output.push(`OPTIONS (${optionStrs.join(', ')})`);
|
|
9990
10327
|
}
|