pgsql-deparser 16.0.0 → 16.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -16
- package/deparser/deparser.d.ts +10 -3
- package/deparser/deparser.js +1042 -570
- package/deparser/utils/sql-formatter.js +1 -1
- package/deparser/visitors/base.d.ts +49 -2
- package/deparser/visitors/base.js +89 -1
- package/esm/deparser/deparser.js +1042 -570
- package/esm/deparser/utils/sql-formatter.js +1 -1
- package/esm/deparser/visitors/base.js +87 -0
- package/package.json +5 -5
package/esm/deparser/deparser.js
CHANGED
|
@@ -2,9 +2,66 @@
|
|
|
2
2
|
* Auto-generated file with types stripped for better tree-shaking
|
|
3
3
|
* DO NOT EDIT - Generated by strip-deparser-types.ts
|
|
4
4
|
*/
|
|
5
|
+
import { DeparserContext } from './visitors/base';
|
|
5
6
|
import { SqlFormatter } from './utils/sql-formatter';
|
|
6
7
|
import { QuoteUtils } from './utils/quote-utils';
|
|
7
8
|
import { ListUtils } from './utils/list-utils';
|
|
9
|
+
/**
|
|
10
|
+
* List of real PostgreSQL built-in types as they appear in pg_catalog.pg_type.typname.
|
|
11
|
+
* These are stored in lowercase in PostgreSQL system catalogs.
|
|
12
|
+
* Use these for lookups, validations, or introspection logic.
|
|
13
|
+
*/
|
|
14
|
+
const pgCatalogTypes = [
|
|
15
|
+
// Integers
|
|
16
|
+
'int2', // smallint
|
|
17
|
+
'int4', // integer
|
|
18
|
+
'int8', // bigint
|
|
19
|
+
// Floating-point & numeric
|
|
20
|
+
'float4', // real
|
|
21
|
+
'float8', // double precision
|
|
22
|
+
'numeric', // arbitrary precision (aka "decimal")
|
|
23
|
+
// Text & string
|
|
24
|
+
'varchar', // variable-length string
|
|
25
|
+
'char', // internal one-byte type (used in special cases)
|
|
26
|
+
'bpchar', // blank-padded char(n)
|
|
27
|
+
'text', // unlimited string
|
|
28
|
+
'bool', // boolean
|
|
29
|
+
// Dates & times
|
|
30
|
+
'date', // calendar date
|
|
31
|
+
'time', // time without time zone
|
|
32
|
+
'timetz', // time with time zone
|
|
33
|
+
'timestamp', // timestamp without time zone
|
|
34
|
+
'timestamptz', // timestamp with time zone
|
|
35
|
+
'interval', // duration
|
|
36
|
+
// Binary & structured
|
|
37
|
+
'bytea', // binary data
|
|
38
|
+
'uuid', // universally unique identifier
|
|
39
|
+
// JSON & XML
|
|
40
|
+
'json', // textual JSON
|
|
41
|
+
'jsonb', // binary JSON
|
|
42
|
+
'xml', // XML format
|
|
43
|
+
// Money & bitstrings
|
|
44
|
+
'money', // currency value
|
|
45
|
+
'bit', // fixed-length bit string
|
|
46
|
+
'varbit', // variable-length bit string
|
|
47
|
+
// Network types
|
|
48
|
+
'inet', // IPv4 or IPv6 address
|
|
49
|
+
'cidr', // network address
|
|
50
|
+
'macaddr', // MAC address (6 bytes)
|
|
51
|
+
'macaddr8' // MAC address (8 bytes)
|
|
52
|
+
];
|
|
53
|
+
/**
|
|
54
|
+
* Parser-level type aliases accepted by PostgreSQL SQL syntax,
|
|
55
|
+
* but not present in pg_catalog.pg_type. These are resolved to
|
|
56
|
+
* real types during parsing and never appear in introspection.
|
|
57
|
+
*/
|
|
58
|
+
const pgCatalogTypeAliases = [
|
|
59
|
+
['numeric', ['decimal', 'dec']],
|
|
60
|
+
['int4', ['int', 'integer']],
|
|
61
|
+
['float8', ['float']],
|
|
62
|
+
['bpchar', ['character']],
|
|
63
|
+
['varchar', ['character varying']]
|
|
64
|
+
];
|
|
8
65
|
// Type guards for better type safety
|
|
9
66
|
function isParseResult(obj) {
|
|
10
67
|
// A ParseResult is an object that could have stmts (but not required)
|
|
@@ -48,11 +105,9 @@ function isWrappedParseResult(obj) {
|
|
|
48
105
|
* compatibility and wraps them internally for consistent processing.
|
|
49
106
|
*/
|
|
50
107
|
export class Deparser {
|
|
51
|
-
formatter;
|
|
52
108
|
tree;
|
|
53
109
|
options;
|
|
54
110
|
constructor(tree, opts = {}) {
|
|
55
|
-
this.formatter = new SqlFormatter(opts.newline, opts.tab, opts.pretty);
|
|
56
111
|
// Set default options
|
|
57
112
|
this.options = {
|
|
58
113
|
functionDelimiter: '$$',
|
|
@@ -89,15 +144,17 @@ export class Deparser {
|
|
|
89
144
|
return new Deparser(query, opts).deparseQuery();
|
|
90
145
|
}
|
|
91
146
|
deparseQuery() {
|
|
147
|
+
const formatter = new SqlFormatter(this.options.newline, this.options.tab, this.options.pretty);
|
|
148
|
+
const context = new DeparserContext({ formatter, prettyMode: this.options.pretty });
|
|
92
149
|
return this.tree
|
|
93
150
|
.map(node => {
|
|
94
151
|
// All nodes should go through the standard deparse method
|
|
95
152
|
// which will route to the appropriate handler
|
|
96
|
-
const result = this.deparse(node);
|
|
153
|
+
const result = this.deparse(node, context);
|
|
97
154
|
return result || '';
|
|
98
155
|
})
|
|
99
156
|
.filter(result => result !== '')
|
|
100
|
-
.join(
|
|
157
|
+
.join(context.newline() + context.newline());
|
|
101
158
|
}
|
|
102
159
|
/**
|
|
103
160
|
* Get the appropriate function delimiter based on the body content
|
|
@@ -111,10 +168,128 @@ export class Deparser {
|
|
|
111
168
|
}
|
|
112
169
|
return delimiter;
|
|
113
170
|
}
|
|
114
|
-
|
|
171
|
+
/**
|
|
172
|
+
* Maps ObjectType enum values to their corresponding SQL keywords
|
|
173
|
+
* Used by AlterOwnerStmt, AlterObjectSchemaStmt, and other statements that need object type keywords
|
|
174
|
+
*/
|
|
175
|
+
getObjectTypeKeyword(objectType) {
|
|
176
|
+
switch (objectType) {
|
|
177
|
+
case 'OBJECT_TABLE':
|
|
178
|
+
return 'TABLE';
|
|
179
|
+
case 'OBJECT_VIEW':
|
|
180
|
+
return 'VIEW';
|
|
181
|
+
case 'OBJECT_INDEX':
|
|
182
|
+
return 'INDEX';
|
|
183
|
+
case 'OBJECT_SEQUENCE':
|
|
184
|
+
return 'SEQUENCE';
|
|
185
|
+
case 'OBJECT_FUNCTION':
|
|
186
|
+
return 'FUNCTION';
|
|
187
|
+
case 'OBJECT_PROCEDURE':
|
|
188
|
+
return 'PROCEDURE';
|
|
189
|
+
case 'OBJECT_SCHEMA':
|
|
190
|
+
return 'SCHEMA';
|
|
191
|
+
case 'OBJECT_DATABASE':
|
|
192
|
+
return 'DATABASE';
|
|
193
|
+
case 'OBJECT_DOMAIN':
|
|
194
|
+
return 'DOMAIN';
|
|
195
|
+
case 'OBJECT_AGGREGATE':
|
|
196
|
+
return 'AGGREGATE';
|
|
197
|
+
case 'OBJECT_CONVERSION':
|
|
198
|
+
return 'CONVERSION';
|
|
199
|
+
case 'OBJECT_LANGUAGE':
|
|
200
|
+
return 'LANGUAGE';
|
|
201
|
+
case 'OBJECT_OPERATOR':
|
|
202
|
+
return 'OPERATOR';
|
|
203
|
+
case 'OBJECT_OPFAMILY':
|
|
204
|
+
return 'OPERATOR FAMILY';
|
|
205
|
+
case 'OBJECT_OPCLASS':
|
|
206
|
+
return 'OPERATOR CLASS';
|
|
207
|
+
case 'OBJECT_TSDICTIONARY':
|
|
208
|
+
return 'TEXT SEARCH DICTIONARY';
|
|
209
|
+
case 'OBJECT_TSCONFIGURATION':
|
|
210
|
+
return 'TEXT SEARCH CONFIGURATION';
|
|
211
|
+
case 'OBJECT_EVENT_TRIGGER':
|
|
212
|
+
return 'EVENT TRIGGER';
|
|
213
|
+
case 'OBJECT_FDW':
|
|
214
|
+
return 'FOREIGN DATA WRAPPER';
|
|
215
|
+
case 'OBJECT_FOREIGN_SERVER':
|
|
216
|
+
return 'SERVER';
|
|
217
|
+
case 'OBJECT_TYPE':
|
|
218
|
+
return 'TYPE';
|
|
219
|
+
case 'OBJECT_COLLATION':
|
|
220
|
+
return 'COLLATION';
|
|
221
|
+
case 'OBJECT_PUBLICATION':
|
|
222
|
+
return 'PUBLICATION';
|
|
223
|
+
case 'OBJECT_ACCESS_METHOD':
|
|
224
|
+
return 'ACCESS METHOD';
|
|
225
|
+
case 'OBJECT_AMOP':
|
|
226
|
+
return 'OPERATOR CLASS';
|
|
227
|
+
case 'OBJECT_AMPROC':
|
|
228
|
+
return 'OPERATOR CLASS';
|
|
229
|
+
case 'OBJECT_ATTRIBUTE':
|
|
230
|
+
return 'ATTRIBUTE';
|
|
231
|
+
case 'OBJECT_CAST':
|
|
232
|
+
return 'CAST';
|
|
233
|
+
case 'OBJECT_COLUMN':
|
|
234
|
+
return 'COLUMN';
|
|
235
|
+
case 'OBJECT_DEFAULT':
|
|
236
|
+
return 'DEFAULT';
|
|
237
|
+
case 'OBJECT_DEFACL':
|
|
238
|
+
return 'DEFAULT PRIVILEGES';
|
|
239
|
+
case 'OBJECT_DOMCONSTRAINT':
|
|
240
|
+
return 'DOMAIN';
|
|
241
|
+
case 'OBJECT_EXTENSION':
|
|
242
|
+
return 'EXTENSION';
|
|
243
|
+
case 'OBJECT_FOREIGN_TABLE':
|
|
244
|
+
return 'FOREIGN TABLE';
|
|
245
|
+
case 'OBJECT_LARGEOBJECT':
|
|
246
|
+
return 'LARGE OBJECT';
|
|
247
|
+
case 'OBJECT_MATVIEW':
|
|
248
|
+
return 'MATERIALIZED VIEW';
|
|
249
|
+
case 'OBJECT_PARAMETER_ACL':
|
|
250
|
+
return 'PARAMETER';
|
|
251
|
+
case 'OBJECT_POLICY':
|
|
252
|
+
return 'POLICY';
|
|
253
|
+
case 'OBJECT_PUBLICATION_NAMESPACE':
|
|
254
|
+
return 'PUBLICATION';
|
|
255
|
+
case 'OBJECT_PUBLICATION_REL':
|
|
256
|
+
return 'PUBLICATION';
|
|
257
|
+
case 'OBJECT_ROLE':
|
|
258
|
+
return 'ROLE';
|
|
259
|
+
case 'OBJECT_ROUTINE':
|
|
260
|
+
return 'ROUTINE';
|
|
261
|
+
case 'OBJECT_RULE':
|
|
262
|
+
return 'RULE';
|
|
263
|
+
case 'OBJECT_STATISTIC_EXT':
|
|
264
|
+
return 'STATISTICS';
|
|
265
|
+
case 'OBJECT_SUBSCRIPTION':
|
|
266
|
+
return 'SUBSCRIPTION';
|
|
267
|
+
case 'OBJECT_TABCONSTRAINT':
|
|
268
|
+
return 'CONSTRAINT';
|
|
269
|
+
case 'OBJECT_TABLESPACE':
|
|
270
|
+
return 'TABLESPACE';
|
|
271
|
+
case 'OBJECT_TRANSFORM':
|
|
272
|
+
return 'TRANSFORM';
|
|
273
|
+
case 'OBJECT_TRIGGER':
|
|
274
|
+
return 'TRIGGER';
|
|
275
|
+
case 'OBJECT_TSPARSER':
|
|
276
|
+
return 'TEXT SEARCH PARSER';
|
|
277
|
+
case 'OBJECT_TSTEMPLATE':
|
|
278
|
+
return 'TEXT SEARCH TEMPLATE';
|
|
279
|
+
case 'OBJECT_USER_MAPPING':
|
|
280
|
+
return 'USER MAPPING';
|
|
281
|
+
default:
|
|
282
|
+
throw new Error(`Unsupported objectType: ${objectType}`);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
deparse(node, context) {
|
|
115
286
|
if (node == null) {
|
|
116
287
|
return null;
|
|
117
288
|
}
|
|
289
|
+
if (!context) {
|
|
290
|
+
const formatter = new SqlFormatter(this.options.newline, this.options.tab, this.options.pretty);
|
|
291
|
+
context = new DeparserContext({ formatter, prettyMode: this.options.pretty });
|
|
292
|
+
}
|
|
118
293
|
if (typeof node === 'number' || node instanceof Number) {
|
|
119
294
|
return node.toString();
|
|
120
295
|
}
|
|
@@ -126,7 +301,11 @@ export class Deparser {
|
|
|
126
301
|
throw new Error(`Error deparsing ${nodeType}: ${error.message}`);
|
|
127
302
|
}
|
|
128
303
|
}
|
|
129
|
-
visit(node, context
|
|
304
|
+
visit(node, context) {
|
|
305
|
+
if (!context) {
|
|
306
|
+
const formatter = new SqlFormatter(this.options.newline, this.options.tab, this.options.pretty);
|
|
307
|
+
context = new DeparserContext({ formatter, prettyMode: this.options.pretty });
|
|
308
|
+
}
|
|
130
309
|
const nodeType = this.getNodeType(node);
|
|
131
310
|
// Handle empty objects
|
|
132
311
|
if (!nodeType) {
|
|
@@ -135,11 +314,7 @@ export class Deparser {
|
|
|
135
314
|
const nodeData = this.getNodeData(node);
|
|
136
315
|
const methodName = nodeType;
|
|
137
316
|
if (typeof this[methodName] === 'function') {
|
|
138
|
-
const
|
|
139
|
-
...context,
|
|
140
|
-
parentNodeTypes: [...context.parentNodeTypes, nodeType]
|
|
141
|
-
};
|
|
142
|
-
const result = this[methodName](nodeData, childContext);
|
|
317
|
+
const result = this[methodName](nodeData, context);
|
|
143
318
|
return result;
|
|
144
319
|
}
|
|
145
320
|
throw new Error(`Deparser does not handle node type: ${nodeType}`);
|
|
@@ -165,7 +340,7 @@ export class Deparser {
|
|
|
165
340
|
.filter((rawStmt) => rawStmt != null)
|
|
166
341
|
.map((rawStmt) => this.RawStmt(rawStmt, context))
|
|
167
342
|
.filter((result) => result !== '')
|
|
168
|
-
.join(
|
|
343
|
+
.join(context.newline() + context.newline());
|
|
169
344
|
}
|
|
170
345
|
RawStmt(node, context) {
|
|
171
346
|
if (!node.stmt) {
|
|
@@ -185,7 +360,7 @@ export class Deparser {
|
|
|
185
360
|
}
|
|
186
361
|
if (!node.op || node.op === 'SETOP_NONE') {
|
|
187
362
|
if (node.valuesLists == null) {
|
|
188
|
-
if (!
|
|
363
|
+
if (!context.isPretty() || !node.targetList) {
|
|
189
364
|
output.push('SELECT');
|
|
190
365
|
}
|
|
191
366
|
}
|
|
@@ -205,7 +380,7 @@ export class Deparser {
|
|
|
205
380
|
(node.rarg).limitOffset ||
|
|
206
381
|
(node.rarg).withClause);
|
|
207
382
|
if (leftNeedsParens) {
|
|
208
|
-
output.push(
|
|
383
|
+
output.push(context.parens(leftStmt));
|
|
209
384
|
}
|
|
210
385
|
else {
|
|
211
386
|
output.push(leftStmt);
|
|
@@ -227,7 +402,7 @@ export class Deparser {
|
|
|
227
402
|
output.push('ALL');
|
|
228
403
|
}
|
|
229
404
|
if (rightNeedsParens) {
|
|
230
|
-
output.push(
|
|
405
|
+
output.push(context.parens(rightStmt));
|
|
231
406
|
}
|
|
232
407
|
else {
|
|
233
408
|
output.push(rightStmt);
|
|
@@ -239,20 +414,20 @@ export class Deparser {
|
|
|
239
414
|
const distinctClause = ListUtils.unwrapList(node.distinctClause);
|
|
240
415
|
if (distinctClause.length > 0 && Object.keys(distinctClause[0]).length > 0) {
|
|
241
416
|
const clause = distinctClause
|
|
242
|
-
.map(e => this.visit(e,
|
|
417
|
+
.map(e => this.visit(e, context.spawn('SelectStmt', { select: true })))
|
|
243
418
|
.join(', ');
|
|
244
|
-
distinctPart = ' DISTINCT ON ' +
|
|
419
|
+
distinctPart = ' DISTINCT ON ' + context.parens(clause);
|
|
245
420
|
}
|
|
246
421
|
else {
|
|
247
422
|
distinctPart = ' DISTINCT';
|
|
248
423
|
}
|
|
249
|
-
if (!
|
|
424
|
+
if (!context.isPretty()) {
|
|
250
425
|
if (distinctClause.length > 0 && Object.keys(distinctClause[0]).length > 0) {
|
|
251
426
|
output.push('DISTINCT ON');
|
|
252
427
|
const clause = distinctClause
|
|
253
|
-
.map(e => this.visit(e,
|
|
428
|
+
.map(e => this.visit(e, context.spawn('SelectStmt', { select: true })))
|
|
254
429
|
.join(', ');
|
|
255
|
-
output.push(
|
|
430
|
+
output.push(context.parens(clause));
|
|
256
431
|
}
|
|
257
432
|
else {
|
|
258
433
|
output.push('DISTINCT');
|
|
@@ -261,22 +436,41 @@ export class Deparser {
|
|
|
261
436
|
}
|
|
262
437
|
if (node.targetList) {
|
|
263
438
|
const targetList = ListUtils.unwrapList(node.targetList);
|
|
264
|
-
if (
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
const
|
|
268
|
-
if
|
|
269
|
-
|
|
439
|
+
if (context.isPretty()) {
|
|
440
|
+
if (targetList.length === 1) {
|
|
441
|
+
const targetNode = targetList[0];
|
|
442
|
+
const target = this.visit(targetNode, context.spawn('SelectStmt', { select: true }));
|
|
443
|
+
// Check if single target is complex - if so, use multiline format
|
|
444
|
+
if (this.isComplexSelectTarget(targetNode)) {
|
|
445
|
+
output.push('SELECT' + distinctPart);
|
|
446
|
+
if (this.containsMultilineStringLiteral(target)) {
|
|
447
|
+
output.push(target);
|
|
448
|
+
}
|
|
449
|
+
else {
|
|
450
|
+
output.push(context.indent(target));
|
|
451
|
+
}
|
|
270
452
|
}
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
453
|
+
else {
|
|
454
|
+
output.push('SELECT' + distinctPart + ' ' + target);
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
else {
|
|
458
|
+
const targetStrings = targetList
|
|
459
|
+
.map(e => {
|
|
460
|
+
const targetStr = this.visit(e, context.spawn('SelectStmt', { select: true }));
|
|
461
|
+
if (this.containsMultilineStringLiteral(targetStr)) {
|
|
462
|
+
return targetStr;
|
|
463
|
+
}
|
|
464
|
+
return context.indent(targetStr);
|
|
465
|
+
});
|
|
466
|
+
const formattedTargets = targetStrings.join(',' + context.newline());
|
|
467
|
+
output.push('SELECT' + distinctPart);
|
|
468
|
+
output.push(formattedTargets);
|
|
469
|
+
}
|
|
276
470
|
}
|
|
277
471
|
else {
|
|
278
472
|
const targets = targetList
|
|
279
|
-
.map(e => this.visit(e,
|
|
473
|
+
.map(e => this.visit(e, context.spawn('SelectStmt', { select: true })))
|
|
280
474
|
.join(', ');
|
|
281
475
|
output.push(targets);
|
|
282
476
|
}
|
|
@@ -288,22 +482,22 @@ export class Deparser {
|
|
|
288
482
|
if (node.fromClause) {
|
|
289
483
|
const fromList = ListUtils.unwrapList(node.fromClause);
|
|
290
484
|
const fromItems = fromList
|
|
291
|
-
.map(e => this.deparse(e,
|
|
485
|
+
.map(e => this.deparse(e, context.spawn('SelectStmt', { from: true })))
|
|
292
486
|
.join(', ');
|
|
293
487
|
output.push('FROM ' + fromItems.trim());
|
|
294
488
|
}
|
|
295
489
|
if (node.whereClause) {
|
|
296
|
-
if (
|
|
490
|
+
if (context.isPretty()) {
|
|
297
491
|
output.push('WHERE');
|
|
298
492
|
const whereExpr = this.visit(node.whereClause, context);
|
|
299
|
-
const lines = whereExpr.split(
|
|
493
|
+
const lines = whereExpr.split(context.newline());
|
|
300
494
|
const indentedLines = lines.map((line, index) => {
|
|
301
495
|
if (index === 0) {
|
|
302
|
-
return
|
|
496
|
+
return context.indent(line);
|
|
303
497
|
}
|
|
304
498
|
return line;
|
|
305
499
|
});
|
|
306
|
-
output.push(indentedLines.join(
|
|
500
|
+
output.push(indentedLines.join(context.newline()));
|
|
307
501
|
}
|
|
308
502
|
else {
|
|
309
503
|
output.push('WHERE');
|
|
@@ -311,45 +505,61 @@ export class Deparser {
|
|
|
311
505
|
}
|
|
312
506
|
}
|
|
313
507
|
if (node.valuesLists) {
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
const
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
508
|
+
if (context.isPretty()) {
|
|
509
|
+
output.push('VALUES');
|
|
510
|
+
const lists = ListUtils.unwrapList(node.valuesLists).map(list => {
|
|
511
|
+
const values = ListUtils.unwrapList(list).map(val => this.visit(val, context));
|
|
512
|
+
return context.parens(values.join(', '));
|
|
513
|
+
});
|
|
514
|
+
const indentedTuples = lists.map(tuple => {
|
|
515
|
+
if (this.containsMultilineStringLiteral(tuple)) {
|
|
516
|
+
return tuple;
|
|
517
|
+
}
|
|
518
|
+
return context.indent(tuple);
|
|
519
|
+
});
|
|
520
|
+
output.push(indentedTuples.join(',\n'));
|
|
521
|
+
}
|
|
522
|
+
else {
|
|
523
|
+
output.push('VALUES');
|
|
524
|
+
const lists = ListUtils.unwrapList(node.valuesLists).map(list => {
|
|
525
|
+
const values = ListUtils.unwrapList(list).map(val => this.visit(val, context));
|
|
526
|
+
return context.parens(values.join(', '));
|
|
527
|
+
});
|
|
528
|
+
output.push(lists.join(', '));
|
|
529
|
+
}
|
|
320
530
|
}
|
|
321
531
|
if (node.groupClause) {
|
|
322
532
|
const groupList = ListUtils.unwrapList(node.groupClause);
|
|
323
|
-
if (
|
|
533
|
+
if (context.isPretty()) {
|
|
324
534
|
const groupItems = groupList
|
|
325
535
|
.map(e => {
|
|
326
|
-
const groupStr = this.visit(e,
|
|
536
|
+
const groupStr = this.visit(e, context.spawn('SelectStmt', { group: true, indentLevel: context.indentLevel + 1 }));
|
|
327
537
|
if (this.containsMultilineStringLiteral(groupStr)) {
|
|
328
538
|
return groupStr;
|
|
329
539
|
}
|
|
330
|
-
return
|
|
540
|
+
return context.indent(groupStr);
|
|
331
541
|
})
|
|
332
|
-
.join(',' +
|
|
542
|
+
.join(',' + context.newline());
|
|
333
543
|
output.push('GROUP BY');
|
|
334
544
|
output.push(groupItems);
|
|
335
545
|
}
|
|
336
546
|
else {
|
|
337
547
|
output.push('GROUP BY');
|
|
338
548
|
const groupItems = groupList
|
|
339
|
-
.map(e => this.visit(e,
|
|
549
|
+
.map(e => this.visit(e, context.spawn('SelectStmt', { group: true })))
|
|
340
550
|
.join(', ');
|
|
341
551
|
output.push(groupItems);
|
|
342
552
|
}
|
|
343
553
|
}
|
|
344
554
|
if (node.havingClause) {
|
|
345
|
-
if (
|
|
555
|
+
if (context.isPretty()) {
|
|
346
556
|
output.push('HAVING');
|
|
347
557
|
const havingStr = this.visit(node.havingClause, context);
|
|
348
558
|
if (this.containsMultilineStringLiteral(havingStr)) {
|
|
349
559
|
output.push(havingStr);
|
|
350
560
|
}
|
|
351
561
|
else {
|
|
352
|
-
output.push(
|
|
562
|
+
output.push(context.indent(havingStr));
|
|
353
563
|
}
|
|
354
564
|
}
|
|
355
565
|
else {
|
|
@@ -367,23 +577,23 @@ export class Deparser {
|
|
|
367
577
|
}
|
|
368
578
|
if (node.sortClause) {
|
|
369
579
|
const sortList = ListUtils.unwrapList(node.sortClause);
|
|
370
|
-
if (
|
|
580
|
+
if (context.isPretty()) {
|
|
371
581
|
const sortItems = sortList
|
|
372
582
|
.map(e => {
|
|
373
|
-
const sortStr = this.visit(e,
|
|
583
|
+
const sortStr = this.visit(e, context.spawn('SelectStmt', { sort: true, indentLevel: context.indentLevel + 1 }));
|
|
374
584
|
if (this.containsMultilineStringLiteral(sortStr)) {
|
|
375
585
|
return sortStr;
|
|
376
586
|
}
|
|
377
|
-
return
|
|
587
|
+
return context.indent(sortStr);
|
|
378
588
|
})
|
|
379
|
-
.join(',' +
|
|
589
|
+
.join(',' + context.newline());
|
|
380
590
|
output.push('ORDER BY');
|
|
381
591
|
output.push(sortItems);
|
|
382
592
|
}
|
|
383
593
|
else {
|
|
384
594
|
output.push('ORDER BY');
|
|
385
595
|
const sortItems = sortList
|
|
386
|
-
.map(e => this.visit(e,
|
|
596
|
+
.map(e => this.visit(e, context.spawn('SelectStmt', { sort: true })))
|
|
387
597
|
.join(', ');
|
|
388
598
|
output.push(sortItems);
|
|
389
599
|
}
|
|
@@ -401,9 +611,9 @@ export class Deparser {
|
|
|
401
611
|
.join(' ');
|
|
402
612
|
output.push(lockingClauses);
|
|
403
613
|
}
|
|
404
|
-
if (
|
|
614
|
+
if (context.isPretty()) {
|
|
405
615
|
const filteredOutput = output.filter(item => item.trim() !== '');
|
|
406
|
-
return filteredOutput.join(
|
|
616
|
+
return filteredOutput.join(context.newline());
|
|
407
617
|
}
|
|
408
618
|
return output.join(' ');
|
|
409
619
|
}
|
|
@@ -415,13 +625,13 @@ export class Deparser {
|
|
|
415
625
|
switch (kind) {
|
|
416
626
|
case 'AEXPR_OP':
|
|
417
627
|
if (lexpr && rexpr) {
|
|
418
|
-
const operator = this.deparseOperatorName(name);
|
|
628
|
+
const operator = this.deparseOperatorName(name, context);
|
|
419
629
|
let leftExpr = this.visit(lexpr, context);
|
|
420
630
|
let rightExpr = this.visit(rexpr, context);
|
|
421
631
|
// Check if left expression needs parentheses
|
|
422
632
|
let leftNeedsParens = false;
|
|
423
633
|
if (lexpr && 'A_Expr' in lexpr && lexpr.A_Expr?.kind === 'AEXPR_OP') {
|
|
424
|
-
const leftOp = this.deparseOperatorName(ListUtils.unwrapList(lexpr.A_Expr.name));
|
|
634
|
+
const leftOp = this.deparseOperatorName(ListUtils.unwrapList(lexpr.A_Expr.name), context);
|
|
425
635
|
if (this.needsParentheses(leftOp, operator, 'left')) {
|
|
426
636
|
leftNeedsParens = true;
|
|
427
637
|
}
|
|
@@ -430,12 +640,12 @@ export class Deparser {
|
|
|
430
640
|
leftNeedsParens = true;
|
|
431
641
|
}
|
|
432
642
|
if (leftNeedsParens) {
|
|
433
|
-
leftExpr =
|
|
643
|
+
leftExpr = context.parens(leftExpr);
|
|
434
644
|
}
|
|
435
645
|
// Check if right expression needs parentheses
|
|
436
646
|
let rightNeedsParens = false;
|
|
437
647
|
if (rexpr && 'A_Expr' in rexpr && rexpr.A_Expr?.kind === 'AEXPR_OP') {
|
|
438
|
-
const rightOp = this.deparseOperatorName(ListUtils.unwrapList(rexpr.A_Expr.name));
|
|
648
|
+
const rightOp = this.deparseOperatorName(ListUtils.unwrapList(rexpr.A_Expr.name), context);
|
|
439
649
|
if (this.needsParentheses(rightOp, operator, 'right')) {
|
|
440
650
|
rightNeedsParens = true;
|
|
441
651
|
}
|
|
@@ -444,42 +654,42 @@ export class Deparser {
|
|
|
444
654
|
rightNeedsParens = true;
|
|
445
655
|
}
|
|
446
656
|
if (rightNeedsParens) {
|
|
447
|
-
rightExpr =
|
|
657
|
+
rightExpr = context.parens(rightExpr);
|
|
448
658
|
}
|
|
449
|
-
return
|
|
659
|
+
return context.format([leftExpr, operator, rightExpr]);
|
|
450
660
|
}
|
|
451
661
|
else if (rexpr) {
|
|
452
|
-
return
|
|
453
|
-
this.deparseOperatorName(name),
|
|
662
|
+
return context.format([
|
|
663
|
+
this.deparseOperatorName(name, context),
|
|
454
664
|
this.visit(rexpr, context)
|
|
455
665
|
]);
|
|
456
666
|
}
|
|
457
667
|
break;
|
|
458
668
|
case 'AEXPR_OP_ANY':
|
|
459
|
-
return
|
|
669
|
+
return context.format([
|
|
460
670
|
this.visit(lexpr, context),
|
|
461
|
-
this.deparseOperatorName(name),
|
|
671
|
+
this.deparseOperatorName(name, context),
|
|
462
672
|
'ANY',
|
|
463
|
-
|
|
673
|
+
context.parens(this.visit(rexpr, context))
|
|
464
674
|
]);
|
|
465
675
|
case 'AEXPR_OP_ALL':
|
|
466
|
-
return
|
|
676
|
+
return context.format([
|
|
467
677
|
this.visit(lexpr, context),
|
|
468
|
-
this.deparseOperatorName(name),
|
|
678
|
+
this.deparseOperatorName(name, context),
|
|
469
679
|
'ALL',
|
|
470
|
-
|
|
680
|
+
context.parens(this.visit(rexpr, context))
|
|
471
681
|
]);
|
|
472
682
|
case 'AEXPR_DISTINCT': {
|
|
473
683
|
let leftExpr = this.visit(lexpr, context);
|
|
474
684
|
let rightExpr = this.visit(rexpr, context);
|
|
475
685
|
// Add parentheses for complex expressions
|
|
476
686
|
if (lexpr && this.isComplexExpression(lexpr)) {
|
|
477
|
-
leftExpr =
|
|
687
|
+
leftExpr = context.parens(leftExpr);
|
|
478
688
|
}
|
|
479
689
|
if (rexpr && this.isComplexExpression(rexpr)) {
|
|
480
|
-
rightExpr =
|
|
690
|
+
rightExpr = context.parens(rightExpr);
|
|
481
691
|
}
|
|
482
|
-
return
|
|
692
|
+
return context.format([
|
|
483
693
|
leftExpr,
|
|
484
694
|
'IS DISTINCT FROM',
|
|
485
695
|
rightExpr
|
|
@@ -490,75 +700,75 @@ export class Deparser {
|
|
|
490
700
|
let rightExpr = this.visit(rexpr, context);
|
|
491
701
|
// Add parentheses for complex expressions
|
|
492
702
|
if (lexpr && this.isComplexExpression(lexpr)) {
|
|
493
|
-
leftExpr =
|
|
703
|
+
leftExpr = context.parens(leftExpr);
|
|
494
704
|
}
|
|
495
705
|
if (rexpr && this.isComplexExpression(rexpr)) {
|
|
496
|
-
rightExpr =
|
|
706
|
+
rightExpr = context.parens(rightExpr);
|
|
497
707
|
}
|
|
498
|
-
return
|
|
708
|
+
return context.format([
|
|
499
709
|
leftExpr,
|
|
500
710
|
'IS NOT DISTINCT FROM',
|
|
501
711
|
rightExpr
|
|
502
712
|
]);
|
|
503
713
|
}
|
|
504
714
|
case 'AEXPR_NULLIF':
|
|
505
|
-
return
|
|
715
|
+
return context.format([
|
|
506
716
|
'NULLIF',
|
|
507
|
-
|
|
717
|
+
context.parens([
|
|
508
718
|
this.visit(lexpr, context),
|
|
509
719
|
this.visit(rexpr, context)
|
|
510
720
|
].join(', '))
|
|
511
721
|
]);
|
|
512
722
|
case 'AEXPR_IN':
|
|
513
|
-
const inOperator = this.deparseOperatorName(name);
|
|
723
|
+
const inOperator = this.deparseOperatorName(name, context);
|
|
514
724
|
if (inOperator === '<>' || inOperator === '!=') {
|
|
515
|
-
return
|
|
725
|
+
return context.format([
|
|
516
726
|
this.visit(lexpr, context),
|
|
517
727
|
'NOT IN',
|
|
518
|
-
|
|
728
|
+
context.parens(this.visit(rexpr, context))
|
|
519
729
|
]);
|
|
520
730
|
}
|
|
521
731
|
else {
|
|
522
|
-
return
|
|
732
|
+
return context.format([
|
|
523
733
|
this.visit(lexpr, context),
|
|
524
734
|
'IN',
|
|
525
|
-
|
|
735
|
+
context.parens(this.visit(rexpr, context))
|
|
526
736
|
]);
|
|
527
737
|
}
|
|
528
738
|
case 'AEXPR_LIKE':
|
|
529
|
-
const likeOp = this.deparseOperatorName(name);
|
|
739
|
+
const likeOp = this.deparseOperatorName(name, context);
|
|
530
740
|
if (likeOp === '!~~') {
|
|
531
|
-
return
|
|
741
|
+
return context.format([
|
|
532
742
|
this.visit(lexpr, context),
|
|
533
743
|
'NOT LIKE',
|
|
534
744
|
this.visit(rexpr, context)
|
|
535
745
|
]);
|
|
536
746
|
}
|
|
537
747
|
else {
|
|
538
|
-
return
|
|
748
|
+
return context.format([
|
|
539
749
|
this.visit(lexpr, context),
|
|
540
750
|
'LIKE',
|
|
541
751
|
this.visit(rexpr, context)
|
|
542
752
|
]);
|
|
543
753
|
}
|
|
544
754
|
case 'AEXPR_ILIKE':
|
|
545
|
-
const ilikeOp = this.deparseOperatorName(name);
|
|
755
|
+
const ilikeOp = this.deparseOperatorName(name, context);
|
|
546
756
|
if (ilikeOp === '!~~*') {
|
|
547
|
-
return
|
|
757
|
+
return context.format([
|
|
548
758
|
this.visit(lexpr, context),
|
|
549
759
|
'NOT ILIKE',
|
|
550
760
|
this.visit(rexpr, context)
|
|
551
761
|
]);
|
|
552
762
|
}
|
|
553
763
|
else {
|
|
554
|
-
return
|
|
764
|
+
return context.format([
|
|
555
765
|
this.visit(lexpr, context),
|
|
556
766
|
'ILIKE',
|
|
557
767
|
this.visit(rexpr, context)
|
|
558
768
|
]);
|
|
559
769
|
}
|
|
560
770
|
case 'AEXPR_SIMILAR':
|
|
561
|
-
const similarOp = this.deparseOperatorName(name);
|
|
771
|
+
const similarOp = this.deparseOperatorName(name, context);
|
|
562
772
|
let rightExpr;
|
|
563
773
|
if (rexpr && 'FuncCall' in rexpr &&
|
|
564
774
|
rexpr.FuncCall?.funcname?.length === 2 &&
|
|
@@ -574,39 +784,39 @@ export class Deparser {
|
|
|
574
784
|
rightExpr = this.visit(rexpr, context);
|
|
575
785
|
}
|
|
576
786
|
if (similarOp === '!~') {
|
|
577
|
-
return
|
|
787
|
+
return context.format([
|
|
578
788
|
this.visit(lexpr, context),
|
|
579
789
|
'NOT SIMILAR TO',
|
|
580
790
|
rightExpr
|
|
581
791
|
]);
|
|
582
792
|
}
|
|
583
793
|
else {
|
|
584
|
-
return
|
|
794
|
+
return context.format([
|
|
585
795
|
this.visit(lexpr, context),
|
|
586
796
|
'SIMILAR TO',
|
|
587
797
|
rightExpr
|
|
588
798
|
]);
|
|
589
799
|
}
|
|
590
800
|
case 'AEXPR_BETWEEN':
|
|
591
|
-
return
|
|
801
|
+
return context.format([
|
|
592
802
|
this.visit(lexpr, context),
|
|
593
803
|
'BETWEEN',
|
|
594
804
|
this.visitBetweenRange(rexpr, context)
|
|
595
805
|
]);
|
|
596
806
|
case 'AEXPR_NOT_BETWEEN':
|
|
597
|
-
return
|
|
807
|
+
return context.format([
|
|
598
808
|
this.visit(lexpr, context),
|
|
599
809
|
'NOT BETWEEN',
|
|
600
810
|
this.visitBetweenRange(rexpr, context)
|
|
601
811
|
]);
|
|
602
812
|
case 'AEXPR_BETWEEN_SYM':
|
|
603
|
-
return
|
|
813
|
+
return context.format([
|
|
604
814
|
this.visit(lexpr, context),
|
|
605
815
|
'BETWEEN SYMMETRIC',
|
|
606
816
|
this.visitBetweenRange(rexpr, context)
|
|
607
817
|
]);
|
|
608
818
|
case 'AEXPR_NOT_BETWEEN_SYM':
|
|
609
|
-
return
|
|
819
|
+
return context.format([
|
|
610
820
|
this.visit(lexpr, context),
|
|
611
821
|
'NOT BETWEEN SYMMETRIC',
|
|
612
822
|
this.visitBetweenRange(rexpr, context)
|
|
@@ -614,7 +824,7 @@ export class Deparser {
|
|
|
614
824
|
}
|
|
615
825
|
throw new Error(`Unhandled A_Expr kind: ${kind}`);
|
|
616
826
|
}
|
|
617
|
-
deparseOperatorName(name) {
|
|
827
|
+
deparseOperatorName(name, context) {
|
|
618
828
|
if (!name || name.length === 0) {
|
|
619
829
|
return '';
|
|
620
830
|
}
|
|
@@ -622,7 +832,7 @@ export class Deparser {
|
|
|
622
832
|
if (n.String) {
|
|
623
833
|
return n.String.sval || n.String.str;
|
|
624
834
|
}
|
|
625
|
-
return this.visit(n,
|
|
835
|
+
return this.visit(n, context);
|
|
626
836
|
});
|
|
627
837
|
if (parts.length > 1) {
|
|
628
838
|
return `OPERATOR(${parts.join('.')})`;
|
|
@@ -685,6 +895,64 @@ export class Deparser {
|
|
|
685
895
|
node.SubLink ||
|
|
686
896
|
node.A_Expr);
|
|
687
897
|
}
|
|
898
|
+
isComplexSelectTarget(node) {
|
|
899
|
+
if (!node)
|
|
900
|
+
return false;
|
|
901
|
+
if (node.ResTarget?.val) {
|
|
902
|
+
return this.isComplexExpression(node.ResTarget.val);
|
|
903
|
+
}
|
|
904
|
+
// Always complex: CASE expressions
|
|
905
|
+
if (node.CaseExpr)
|
|
906
|
+
return true;
|
|
907
|
+
// Always complex: Subqueries and subselects
|
|
908
|
+
if (node.SubLink)
|
|
909
|
+
return true;
|
|
910
|
+
// Always complex: Boolean tests and expressions
|
|
911
|
+
if (node.NullTest || node.BooleanTest || node.BoolExpr)
|
|
912
|
+
return true;
|
|
913
|
+
// COALESCE and similar functions - complex if multiple arguments
|
|
914
|
+
if (node.CoalesceExpr) {
|
|
915
|
+
const args = node.CoalesceExpr.args;
|
|
916
|
+
if (args && Array.isArray(args) && args.length > 1)
|
|
917
|
+
return true;
|
|
918
|
+
}
|
|
919
|
+
// Function calls - complex if multiple args or has clauses
|
|
920
|
+
if (node.FuncCall) {
|
|
921
|
+
const funcCall = node.FuncCall;
|
|
922
|
+
const args = funcCall.args ? (Array.isArray(funcCall.args) ? funcCall.args : [funcCall.args]) : [];
|
|
923
|
+
// Complex if has window clause, filter, order by, etc.
|
|
924
|
+
if (funcCall.over || funcCall.agg_filter || funcCall.agg_order || funcCall.agg_distinct) {
|
|
925
|
+
return true;
|
|
926
|
+
}
|
|
927
|
+
// Complex if multiple arguments
|
|
928
|
+
if (args.length > 1)
|
|
929
|
+
return true;
|
|
930
|
+
if (args.length === 1) {
|
|
931
|
+
return this.isComplexSelectTarget(args[0]);
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
if (node.A_Expr) {
|
|
935
|
+
const expr = node.A_Expr;
|
|
936
|
+
// Check if operands are complex
|
|
937
|
+
if (expr.lexpr && this.isComplexSelectTarget(expr.lexpr))
|
|
938
|
+
return true;
|
|
939
|
+
if (expr.rexpr && this.isComplexSelectTarget(expr.rexpr))
|
|
940
|
+
return true;
|
|
941
|
+
return false;
|
|
942
|
+
}
|
|
943
|
+
if (node.TypeCast) {
|
|
944
|
+
return this.isComplexSelectTarget(node.TypeCast.arg);
|
|
945
|
+
}
|
|
946
|
+
if (node.A_ArrayExpr)
|
|
947
|
+
return true;
|
|
948
|
+
if (node.A_Indirection) {
|
|
949
|
+
return this.isComplexSelectTarget(node.A_Indirection.arg);
|
|
950
|
+
}
|
|
951
|
+
if (node.A_Const || node.ColumnRef || node.ParamRef || node.A_Star) {
|
|
952
|
+
return false;
|
|
953
|
+
}
|
|
954
|
+
return false;
|
|
955
|
+
}
|
|
688
956
|
visitBetweenRange(rexpr, context) {
|
|
689
957
|
if (rexpr && 'List' in rexpr && rexpr.List?.items) {
|
|
690
958
|
const items = rexpr.List.items.map((item) => this.visit(item, context));
|
|
@@ -701,9 +969,16 @@ export class Deparser {
|
|
|
701
969
|
output.push(this.RangeVar(node.relation, context));
|
|
702
970
|
if (node.cols) {
|
|
703
971
|
const cols = ListUtils.unwrapList(node.cols);
|
|
704
|
-
const insertContext =
|
|
972
|
+
const insertContext = context.spawn('InsertStmt', { insertColumns: true });
|
|
705
973
|
const columnNames = cols.map(col => this.visit(col, insertContext));
|
|
706
|
-
|
|
974
|
+
if (context.isPretty()) {
|
|
975
|
+
// Always format columns in multiline parentheses for pretty printing
|
|
976
|
+
const indentedColumns = columnNames.map(col => context.indent(col));
|
|
977
|
+
output.push('(\n' + indentedColumns.join(',\n') + '\n)');
|
|
978
|
+
}
|
|
979
|
+
else {
|
|
980
|
+
output.push(context.parens(columnNames.join(', ')));
|
|
981
|
+
}
|
|
707
982
|
}
|
|
708
983
|
if (node.selectStmt) {
|
|
709
984
|
output.push(this.visit(node.selectStmt, context));
|
|
@@ -724,7 +999,7 @@ export class Deparser {
|
|
|
724
999
|
else if (infer.indexElems) {
|
|
725
1000
|
const elems = ListUtils.unwrapList(infer.indexElems);
|
|
726
1001
|
const indexElems = elems.map(elem => this.visit(elem, context));
|
|
727
|
-
output.push(
|
|
1002
|
+
output.push(context.parens(indexElems.join(', ')));
|
|
728
1003
|
}
|
|
729
1004
|
// Handle WHERE clause for conflict detection
|
|
730
1005
|
if (infer.whereClause) {
|
|
@@ -740,12 +1015,12 @@ export class Deparser {
|
|
|
740
1015
|
if (firstTarget.ResTarget?.val?.MultiAssignRef && targetList.every(target => target.ResTarget?.val?.MultiAssignRef)) {
|
|
741
1016
|
const sortedTargets = targetList.sort((a, b) => a.ResTarget.val.MultiAssignRef.colno - b.ResTarget.val.MultiAssignRef.colno);
|
|
742
1017
|
const names = sortedTargets.map(target => target.ResTarget.name);
|
|
743
|
-
output.push(
|
|
1018
|
+
output.push(context.parens(names.join(', ')));
|
|
744
1019
|
output.push('=');
|
|
745
1020
|
output.push(this.visit(firstTarget.ResTarget.val.MultiAssignRef.source, context));
|
|
746
1021
|
}
|
|
747
1022
|
else {
|
|
748
|
-
const updateContext =
|
|
1023
|
+
const updateContext = context.spawn('UpdateStmt', { update: true });
|
|
749
1024
|
const targets = targetList.map(target => this.visit(target, updateContext));
|
|
750
1025
|
output.push(targets.join(', '));
|
|
751
1026
|
}
|
|
@@ -799,12 +1074,12 @@ export class Deparser {
|
|
|
799
1074
|
}
|
|
800
1075
|
}
|
|
801
1076
|
const names = relatedTargets.map(t => t.ResTarget.name);
|
|
802
|
-
const multiAssignment = `${
|
|
1077
|
+
const multiAssignment = `${context.parens(names.join(', '))} = ${this.visit(multiAssignRef.source, context)}`;
|
|
803
1078
|
assignmentParts.push(multiAssignment);
|
|
804
1079
|
}
|
|
805
1080
|
else {
|
|
806
1081
|
// Handle regular single-column assignment
|
|
807
|
-
assignmentParts.push(this.visit(target,
|
|
1082
|
+
assignmentParts.push(this.visit(target, context.spawn('UpdateStmt', { update: true })));
|
|
808
1083
|
processedTargets.add(i);
|
|
809
1084
|
}
|
|
810
1085
|
}
|
|
@@ -896,14 +1171,14 @@ export class Deparser {
|
|
|
896
1171
|
}
|
|
897
1172
|
if (node.ctes && node.ctes.length > 0) {
|
|
898
1173
|
const ctes = ListUtils.unwrapList(node.ctes);
|
|
899
|
-
if (
|
|
1174
|
+
if (context.isPretty()) {
|
|
900
1175
|
const cteStrings = ctes.map((cte, index) => {
|
|
901
1176
|
const cteStr = this.visit(cte, context);
|
|
902
|
-
const prefix = index === 0 ?
|
|
1177
|
+
const prefix = index === 0 ? context.newline() : ',' + context.newline();
|
|
903
1178
|
if (this.containsMultilineStringLiteral(cteStr)) {
|
|
904
1179
|
return prefix + cteStr;
|
|
905
1180
|
}
|
|
906
|
-
return prefix +
|
|
1181
|
+
return prefix + context.indent(cteStr);
|
|
907
1182
|
});
|
|
908
1183
|
output.push(cteStrings.join(''));
|
|
909
1184
|
}
|
|
@@ -989,14 +1264,14 @@ export class Deparser {
|
|
|
989
1264
|
if (context.bool) {
|
|
990
1265
|
formatStr = '(%s)';
|
|
991
1266
|
}
|
|
992
|
-
const boolContext =
|
|
1267
|
+
const boolContext = context.spawn('BoolExpr', { bool: true });
|
|
993
1268
|
// explanation of our syntax/fix below:
|
|
994
1269
|
// return formatStr.replace('%s', andArgs); // ❌ Interprets $ as special syntax
|
|
995
1270
|
// return formatStr.replace('%s', () => andArgs); // ✅ Function callback prevents interpretation
|
|
996
1271
|
switch (boolop) {
|
|
997
1272
|
case 'AND_EXPR':
|
|
998
|
-
if (
|
|
999
|
-
const andArgs = args.map(arg => this.visit(arg, boolContext)).join(
|
|
1273
|
+
if (context.isPretty() && args.length > 1) {
|
|
1274
|
+
const andArgs = args.map(arg => this.visit(arg, boolContext)).join(context.newline() + context.indent('AND '));
|
|
1000
1275
|
return formatStr.replace('%s', () => andArgs);
|
|
1001
1276
|
}
|
|
1002
1277
|
else {
|
|
@@ -1004,8 +1279,8 @@ export class Deparser {
|
|
|
1004
1279
|
return formatStr.replace('%s', () => andArgs);
|
|
1005
1280
|
}
|
|
1006
1281
|
case 'OR_EXPR':
|
|
1007
|
-
if (
|
|
1008
|
-
const orArgs = args.map(arg => this.visit(arg, boolContext)).join(
|
|
1282
|
+
if (context.isPretty() && args.length > 1) {
|
|
1283
|
+
const orArgs = args.map(arg => this.visit(arg, boolContext)).join(context.newline() + context.indent('OR '));
|
|
1009
1284
|
return formatStr.replace('%s', () => orArgs);
|
|
1010
1285
|
}
|
|
1011
1286
|
else {
|
|
@@ -1136,9 +1411,9 @@ export class Deparser {
|
|
|
1136
1411
|
const timezone = this.visit(args[0], context);
|
|
1137
1412
|
// Add parentheses around timestamp if it contains arithmetic operations
|
|
1138
1413
|
if (args[1] && 'A_Expr' in args[1] && args[1].A_Expr?.kind === 'AEXPR_OP') {
|
|
1139
|
-
const op = this.deparseOperatorName(ListUtils.unwrapList(args[1].A_Expr.name));
|
|
1414
|
+
const op = this.deparseOperatorName(ListUtils.unwrapList(args[1].A_Expr.name), context);
|
|
1140
1415
|
if (op === '+' || op === '-' || op === '*' || op === '/') {
|
|
1141
|
-
timestamp =
|
|
1416
|
+
timestamp = context.parens(timestamp);
|
|
1142
1417
|
}
|
|
1143
1418
|
}
|
|
1144
1419
|
return `${timestamp} AT TIME ZONE ${timezone}`;
|
|
@@ -1208,14 +1483,14 @@ export class Deparser {
|
|
|
1208
1483
|
windowParts.push(`ORDER BY ${orderStrs.join(', ')}`);
|
|
1209
1484
|
}
|
|
1210
1485
|
// Handle window frame specifications using the dedicated formatWindowFrame method
|
|
1211
|
-
const frameClause = this.formatWindowFrame(node.over);
|
|
1486
|
+
const frameClause = this.formatWindowFrame(node.over, context.spawn('FuncCall'));
|
|
1212
1487
|
if (frameClause) {
|
|
1213
1488
|
windowParts.push(frameClause);
|
|
1214
1489
|
}
|
|
1215
1490
|
if (windowParts.length > 0) {
|
|
1216
|
-
if (
|
|
1217
|
-
const formattedParts = windowParts.map(part =>
|
|
1218
|
-
result += ` OVER (${
|
|
1491
|
+
if (context.isPretty() && windowParts.length > 1) {
|
|
1492
|
+
const formattedParts = windowParts.map(part => context.indent(part));
|
|
1493
|
+
result += ` OVER (${context.newline()}${formattedParts.join(context.newline())}${context.newline()})`;
|
|
1219
1494
|
}
|
|
1220
1495
|
else {
|
|
1221
1496
|
result += ` OVER (${windowParts.join(' ')})`;
|
|
@@ -1495,9 +1770,6 @@ export class Deparser {
|
|
|
1495
1770
|
return output.join(' ');
|
|
1496
1771
|
}
|
|
1497
1772
|
if (catalog === 'pg_catalog') {
|
|
1498
|
-
const builtinTypes = ['int2', 'int4', 'int8', 'float4', 'float8', 'numeric', 'decimal',
|
|
1499
|
-
'varchar', 'char', 'bpchar', 'text', 'bool', 'date', 'time', 'timestamp',
|
|
1500
|
-
'timestamptz', 'interval', 'bytea', 'uuid', 'json', 'jsonb'];
|
|
1501
1773
|
let typeName = `${catalog}.${type}`;
|
|
1502
1774
|
if (type === 'bpchar' && args) {
|
|
1503
1775
|
typeName = 'char';
|
|
@@ -1554,6 +1826,24 @@ export class Deparser {
|
|
|
1554
1826
|
typeName = 'time with time zone';
|
|
1555
1827
|
}
|
|
1556
1828
|
}
|
|
1829
|
+
else if (type === 'timestamp') {
|
|
1830
|
+
if (args) {
|
|
1831
|
+
typeName = `timestamp(${args})`;
|
|
1832
|
+
args = null; // Don't apply args again in mods()
|
|
1833
|
+
}
|
|
1834
|
+
else {
|
|
1835
|
+
typeName = 'timestamp';
|
|
1836
|
+
}
|
|
1837
|
+
}
|
|
1838
|
+
else if (type === 'time') {
|
|
1839
|
+
if (args) {
|
|
1840
|
+
typeName = `time(${args})`;
|
|
1841
|
+
args = null; // Don't apply args again in mods()
|
|
1842
|
+
}
|
|
1843
|
+
else {
|
|
1844
|
+
typeName = 'time';
|
|
1845
|
+
}
|
|
1846
|
+
}
|
|
1557
1847
|
let result = mods(typeName, args);
|
|
1558
1848
|
if (node.arrayBounds && node.arrayBounds.length > 0) {
|
|
1559
1849
|
result += formatArrayBounds(node.arrayBounds);
|
|
@@ -1583,7 +1873,7 @@ export class Deparser {
|
|
|
1583
1873
|
}
|
|
1584
1874
|
return this.quoteIfNeeded(colStr);
|
|
1585
1875
|
});
|
|
1586
|
-
output.push('AS', this.quoteIfNeeded(name) +
|
|
1876
|
+
output.push('AS', this.quoteIfNeeded(name) + context.parens(quotedColnames.join(', ')));
|
|
1587
1877
|
}
|
|
1588
1878
|
else {
|
|
1589
1879
|
output.push('AS', this.quoteIfNeeded(name));
|
|
@@ -1595,7 +1885,7 @@ export class Deparser {
|
|
|
1595
1885
|
// Handle ONLY keyword for inheritance control (but not for type definitions, ALTER TYPE, or CREATE FOREIGN TABLE)
|
|
1596
1886
|
if (node && (!('inh' in node) || node.inh === undefined) &&
|
|
1597
1887
|
!context.parentNodeTypes.includes('CompositeTypeStmt') &&
|
|
1598
|
-
!context.parentNodeTypes.includes('AlterTypeStmt') &&
|
|
1888
|
+
(!context.parentNodeTypes.includes('AlterTypeStmt') && context.objtype !== 'OBJECT_TYPE') &&
|
|
1599
1889
|
!context.parentNodeTypes.includes('CreateForeignTableStmt')) {
|
|
1600
1890
|
output.push('ONLY');
|
|
1601
1891
|
}
|
|
@@ -1792,6 +2082,18 @@ export class Deparser {
|
|
|
1792
2082
|
return `pg_catalog.${typeName}`;
|
|
1793
2083
|
}
|
|
1794
2084
|
}
|
|
2085
|
+
isPgCatalogType(typeName) {
|
|
2086
|
+
const cleanTypeName = typeName.replace(/^pg_catalog\./, '');
|
|
2087
|
+
if (pgCatalogTypes.includes(cleanTypeName)) {
|
|
2088
|
+
return true;
|
|
2089
|
+
}
|
|
2090
|
+
for (const [realType, aliases] of pgCatalogTypeAliases) {
|
|
2091
|
+
if (aliases.includes(cleanTypeName)) {
|
|
2092
|
+
return true;
|
|
2093
|
+
}
|
|
2094
|
+
}
|
|
2095
|
+
return false;
|
|
2096
|
+
}
|
|
1795
2097
|
A_ArrayExpr(node, context) {
|
|
1796
2098
|
const elements = ListUtils.unwrapList(node.elements);
|
|
1797
2099
|
const elementStrs = elements.map(el => this.visit(el, context));
|
|
@@ -1843,26 +2145,26 @@ export class Deparser {
|
|
|
1843
2145
|
output.push(this.visit(node.arg, context));
|
|
1844
2146
|
}
|
|
1845
2147
|
const args = ListUtils.unwrapList(node.args);
|
|
1846
|
-
if (
|
|
2148
|
+
if (context.isPretty() && args.length > 0) {
|
|
1847
2149
|
for (const arg of args) {
|
|
1848
2150
|
const whenClause = this.visit(arg, context);
|
|
1849
2151
|
if (this.containsMultilineStringLiteral(whenClause)) {
|
|
1850
|
-
output.push(
|
|
2152
|
+
output.push(context.newline() + whenClause);
|
|
1851
2153
|
}
|
|
1852
2154
|
else {
|
|
1853
|
-
output.push(
|
|
2155
|
+
output.push(context.newline() + context.indent(whenClause));
|
|
1854
2156
|
}
|
|
1855
2157
|
}
|
|
1856
2158
|
if (node.defresult) {
|
|
1857
2159
|
const elseResult = this.visit(node.defresult, context);
|
|
1858
2160
|
if (this.containsMultilineStringLiteral(elseResult)) {
|
|
1859
|
-
output.push(
|
|
2161
|
+
output.push(context.newline() + 'ELSE ' + elseResult);
|
|
1860
2162
|
}
|
|
1861
2163
|
else {
|
|
1862
|
-
output.push(
|
|
2164
|
+
output.push(context.newline() + context.indent('ELSE ' + elseResult));
|
|
1863
2165
|
}
|
|
1864
2166
|
}
|
|
1865
|
-
output.push(
|
|
2167
|
+
output.push(context.newline() + 'END');
|
|
1866
2168
|
return output.join(' ');
|
|
1867
2169
|
}
|
|
1868
2170
|
else {
|
|
@@ -1885,28 +2187,32 @@ export class Deparser {
|
|
|
1885
2187
|
TypeCast(node, context) {
|
|
1886
2188
|
const arg = this.visit(node.arg, context);
|
|
1887
2189
|
const typeName = this.TypeName(node.typeName, context);
|
|
1888
|
-
// Check if this is a bpchar typecast that should
|
|
1889
|
-
if (typeName === 'bpchar'
|
|
1890
|
-
const names =
|
|
1891
|
-
|
|
1892
|
-
names[0]
|
|
1893
|
-
names[1]
|
|
1894
|
-
|
|
2190
|
+
// Check if this is a bpchar typecast that should preserve original syntax for AST consistency
|
|
2191
|
+
if (typeName === 'bpchar' || typeName === 'pg_catalog.bpchar') {
|
|
2192
|
+
const names = node.typeName?.names;
|
|
2193
|
+
const isQualifiedBpchar = names && names.length === 2 &&
|
|
2194
|
+
names[0]?.String?.sval === 'pg_catalog' &&
|
|
2195
|
+
names[1]?.String?.sval === 'bpchar';
|
|
2196
|
+
if (isQualifiedBpchar) {
|
|
2197
|
+
return `CAST(${arg} AS ${typeName})`;
|
|
1895
2198
|
}
|
|
1896
2199
|
}
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
2200
|
+
if (this.isPgCatalogType(typeName)) {
|
|
2201
|
+
const argType = this.getNodeType(node.arg);
|
|
2202
|
+
const isSimpleArgument = argType === 'A_Const' || argType === 'ColumnRef';
|
|
2203
|
+
const isFunctionCall = argType === 'FuncCall';
|
|
2204
|
+
if (isSimpleArgument || isFunctionCall) {
|
|
2205
|
+
// For simple arguments, avoid :: syntax if they have complex structure
|
|
2206
|
+
const shouldUseCastSyntax = isSimpleArgument && (arg.includes('(') || arg.startsWith('-'));
|
|
2207
|
+
if (!shouldUseCastSyntax) {
|
|
2208
|
+
const cleanTypeName = typeName.replace('pg_catalog.', '');
|
|
2209
|
+
// Wrap FuncCall arguments in parentheses to prevent operator precedence issues
|
|
2210
|
+
if (isFunctionCall) {
|
|
2211
|
+
return `${context.parens(arg)}::${cleanTypeName}`;
|
|
2212
|
+
}
|
|
2213
|
+
return `${arg}::${cleanTypeName}`;
|
|
2214
|
+
}
|
|
2215
|
+
}
|
|
1910
2216
|
}
|
|
1911
2217
|
return `CAST(${arg} AS ${typeName})`;
|
|
1912
2218
|
}
|
|
@@ -1929,7 +2235,7 @@ export class Deparser {
|
|
|
1929
2235
|
}
|
|
1930
2236
|
BooleanTest(node, context) {
|
|
1931
2237
|
const output = [];
|
|
1932
|
-
const boolContext =
|
|
2238
|
+
const boolContext = context.spawn('BooleanTest', { bool: true });
|
|
1933
2239
|
output.push(this.visit(node.arg, boolContext));
|
|
1934
2240
|
switch (node.booltesttype) {
|
|
1935
2241
|
case 'IS_TRUE':
|
|
@@ -2080,24 +2386,31 @@ export class Deparser {
|
|
|
2080
2386
|
const elementStrs = elements.map(el => {
|
|
2081
2387
|
return this.deparse(el, context);
|
|
2082
2388
|
});
|
|
2083
|
-
output.push(
|
|
2389
|
+
output.push(context.parens(elementStrs.join(', ')));
|
|
2084
2390
|
}
|
|
2085
2391
|
}
|
|
2086
2392
|
else if (node.tableElts) {
|
|
2087
2393
|
const elements = ListUtils.unwrapList(node.tableElts);
|
|
2088
2394
|
const elementStrs = elements.map(el => {
|
|
2089
|
-
return this.deparse(el, context);
|
|
2395
|
+
return this.deparse(el, context.spawn('CreateStmt'));
|
|
2090
2396
|
});
|
|
2091
|
-
if (
|
|
2092
|
-
const formattedElements = elementStrs.map(el =>
|
|
2093
|
-
|
|
2397
|
+
if (context.isPretty()) {
|
|
2398
|
+
const formattedElements = elementStrs.map(el => {
|
|
2399
|
+
const trimmedEl = el.trim();
|
|
2400
|
+
// Remove leading newlines from constraint elements to avoid extra blank lines
|
|
2401
|
+
if (trimmedEl.startsWith('\n')) {
|
|
2402
|
+
return context.indent(trimmedEl.substring(1));
|
|
2403
|
+
}
|
|
2404
|
+
return context.indent(trimmedEl);
|
|
2405
|
+
}).join(',' + context.newline());
|
|
2406
|
+
output.push('(' + context.newline() + formattedElements + context.newline() + ')');
|
|
2094
2407
|
}
|
|
2095
2408
|
else {
|
|
2096
|
-
output.push(
|
|
2409
|
+
output.push(context.parens(elementStrs.join(', ')));
|
|
2097
2410
|
}
|
|
2098
2411
|
}
|
|
2099
2412
|
else if (!node.partbound) {
|
|
2100
|
-
output.push(
|
|
2413
|
+
output.push(context.parens(''));
|
|
2101
2414
|
}
|
|
2102
2415
|
if (node.partbound && node.inhRelations && node.inhRelations.length > 0) {
|
|
2103
2416
|
output.push('PARTITION OF');
|
|
@@ -2140,7 +2453,7 @@ export class Deparser {
|
|
|
2140
2453
|
output.push('INHERITS');
|
|
2141
2454
|
const inherits = ListUtils.unwrapList(node.inhRelations);
|
|
2142
2455
|
const inheritStrs = inherits.map(rel => this.visit(rel, context));
|
|
2143
|
-
output.push(
|
|
2456
|
+
output.push(context.parens(inheritStrs.join(', ')));
|
|
2144
2457
|
}
|
|
2145
2458
|
if (node.partspec) {
|
|
2146
2459
|
output.push('PARTITION BY');
|
|
@@ -2178,7 +2491,7 @@ export class Deparser {
|
|
|
2178
2491
|
}
|
|
2179
2492
|
// Handle table options like WITH (fillfactor=10)
|
|
2180
2493
|
if (node.options && node.options.length > 0) {
|
|
2181
|
-
const createStmtContext =
|
|
2494
|
+
const createStmtContext = context.spawn('CreateStmt');
|
|
2182
2495
|
const optionStrs = node.options.map((option) => {
|
|
2183
2496
|
return this.deparse(option, createStmtContext);
|
|
2184
2497
|
});
|
|
@@ -2201,7 +2514,7 @@ export class Deparser {
|
|
|
2201
2514
|
}
|
|
2202
2515
|
if (node.fdwoptions && node.fdwoptions.length > 0) {
|
|
2203
2516
|
output.push('OPTIONS');
|
|
2204
|
-
const columnContext =
|
|
2517
|
+
const columnContext = context.spawn('ColumnDef');
|
|
2205
2518
|
const options = ListUtils.unwrapList(node.fdwoptions).map(opt => this.visit(opt, columnContext));
|
|
2206
2519
|
output.push(`(${options.join(', ')})`);
|
|
2207
2520
|
}
|
|
@@ -2211,7 +2524,7 @@ export class Deparser {
|
|
|
2211
2524
|
if (node.constraints) {
|
|
2212
2525
|
const constraints = ListUtils.unwrapList(node.constraints);
|
|
2213
2526
|
const constraintStrs = constraints.map(constraint => {
|
|
2214
|
-
const columnConstraintContext =
|
|
2527
|
+
const columnConstraintContext = context.spawn('ColumnDef', { isColumnConstraint: true });
|
|
2215
2528
|
return this.visit(constraint, columnConstraintContext);
|
|
2216
2529
|
});
|
|
2217
2530
|
output.push(...constraintStrs);
|
|
@@ -2251,9 +2564,25 @@ export class Deparser {
|
|
|
2251
2564
|
}
|
|
2252
2565
|
break;
|
|
2253
2566
|
case 'CONSTR_CHECK':
|
|
2254
|
-
|
|
2567
|
+
if (context.isPretty() && !context.isColumnConstraint) {
|
|
2568
|
+
output.push('\n' + context.indent('CHECK'));
|
|
2569
|
+
}
|
|
2570
|
+
else {
|
|
2571
|
+
output.push('CHECK');
|
|
2572
|
+
}
|
|
2255
2573
|
if (node.raw_expr) {
|
|
2256
|
-
|
|
2574
|
+
if (context.isPretty()) {
|
|
2575
|
+
const checkExpr = this.visit(node.raw_expr, context);
|
|
2576
|
+
if (checkExpr.includes('\n')) {
|
|
2577
|
+
output.push('(\n' + context.indent(checkExpr) + '\n)');
|
|
2578
|
+
}
|
|
2579
|
+
else {
|
|
2580
|
+
output.push(`(${checkExpr})`);
|
|
2581
|
+
}
|
|
2582
|
+
}
|
|
2583
|
+
else {
|
|
2584
|
+
output.push(context.parens(this.visit(node.raw_expr, context)));
|
|
2585
|
+
}
|
|
2257
2586
|
}
|
|
2258
2587
|
// Handle NOT VALID for check constraints
|
|
2259
2588
|
if (node.skip_validation) {
|
|
@@ -2274,7 +2603,7 @@ export class Deparser {
|
|
|
2274
2603
|
}
|
|
2275
2604
|
output.push('AS');
|
|
2276
2605
|
if (node.raw_expr) {
|
|
2277
|
-
output.push(
|
|
2606
|
+
output.push(context.parens(this.visit(node.raw_expr, context)));
|
|
2278
2607
|
}
|
|
2279
2608
|
output.push('STORED');
|
|
2280
2609
|
break;
|
|
@@ -2292,30 +2621,61 @@ export class Deparser {
|
|
|
2292
2621
|
.map(option => {
|
|
2293
2622
|
if (option.DefElem) {
|
|
2294
2623
|
const defElem = option.DefElem;
|
|
2295
|
-
|
|
2296
|
-
|
|
2624
|
+
if (defElem.defname === 'sequence_name') {
|
|
2625
|
+
if (defElem.arg && defElem.arg.List) {
|
|
2626
|
+
const nameList = ListUtils.unwrapList(defElem.arg)
|
|
2627
|
+
.map(item => this.visit(item, context))
|
|
2628
|
+
.join('.');
|
|
2629
|
+
return `SEQUENCE NAME ${nameList}`;
|
|
2630
|
+
}
|
|
2631
|
+
return 'SEQUENCE NAME';
|
|
2632
|
+
}
|
|
2633
|
+
else if (defElem.defname === 'start') {
|
|
2634
|
+
const argValue = defElem.arg ? this.visit(defElem.arg, context) : '';
|
|
2297
2635
|
return `START WITH ${argValue}`;
|
|
2298
2636
|
}
|
|
2299
2637
|
else if (defElem.defname === 'increment') {
|
|
2638
|
+
const argValue = defElem.arg ? this.visit(defElem.arg, context) : '';
|
|
2300
2639
|
return `INCREMENT BY ${argValue}`;
|
|
2301
2640
|
}
|
|
2302
2641
|
else if (defElem.defname === 'minvalue') {
|
|
2303
|
-
|
|
2642
|
+
if (defElem.arg) {
|
|
2643
|
+
const argValue = this.visit(defElem.arg, context);
|
|
2644
|
+
return `MINVALUE ${argValue}`;
|
|
2645
|
+
}
|
|
2646
|
+
else {
|
|
2647
|
+
return 'NO MINVALUE';
|
|
2648
|
+
}
|
|
2304
2649
|
}
|
|
2305
2650
|
else if (defElem.defname === 'maxvalue') {
|
|
2306
|
-
|
|
2651
|
+
if (defElem.arg) {
|
|
2652
|
+
const argValue = this.visit(defElem.arg, context);
|
|
2653
|
+
return `MAXVALUE ${argValue}`;
|
|
2654
|
+
}
|
|
2655
|
+
else {
|
|
2656
|
+
return 'NO MAXVALUE';
|
|
2657
|
+
}
|
|
2307
2658
|
}
|
|
2308
2659
|
else if (defElem.defname === 'cache') {
|
|
2660
|
+
const argValue = defElem.arg ? this.visit(defElem.arg, context) : '';
|
|
2309
2661
|
return `CACHE ${argValue}`;
|
|
2310
2662
|
}
|
|
2311
2663
|
else if (defElem.defname === 'cycle') {
|
|
2664
|
+
const argValue = defElem.arg ? this.visit(defElem.arg, context) : '';
|
|
2312
2665
|
return argValue === 'true' ? 'CYCLE' : 'NO CYCLE';
|
|
2313
2666
|
}
|
|
2667
|
+
const argValue = defElem.arg ? this.visit(defElem.arg, context) : '';
|
|
2314
2668
|
return `${defElem.defname.toUpperCase()} ${argValue}`;
|
|
2315
2669
|
}
|
|
2316
2670
|
return this.visit(option, context);
|
|
2317
2671
|
});
|
|
2318
|
-
|
|
2672
|
+
if (context.isPretty()) {
|
|
2673
|
+
const indentedOptions = optionStrs.map(option => context.indent(option));
|
|
2674
|
+
output.push('(\n' + indentedOptions.join('\n') + '\n)');
|
|
2675
|
+
}
|
|
2676
|
+
else {
|
|
2677
|
+
output.push(`(${optionStrs.join(' ')})`);
|
|
2678
|
+
}
|
|
2319
2679
|
}
|
|
2320
2680
|
break;
|
|
2321
2681
|
case 'CONSTR_PRIMARY':
|
|
@@ -2332,7 +2692,12 @@ export class Deparser {
|
|
|
2332
2692
|
}
|
|
2333
2693
|
break;
|
|
2334
2694
|
case 'CONSTR_UNIQUE':
|
|
2335
|
-
|
|
2695
|
+
if (context.isPretty() && !context.isColumnConstraint) {
|
|
2696
|
+
output.push('\n' + context.indent('UNIQUE'));
|
|
2697
|
+
}
|
|
2698
|
+
else {
|
|
2699
|
+
output.push('UNIQUE');
|
|
2700
|
+
}
|
|
2336
2701
|
if (node.nulls_not_distinct) {
|
|
2337
2702
|
output.push('NULLS NOT DISTINCT');
|
|
2338
2703
|
}
|
|
@@ -2350,33 +2715,77 @@ export class Deparser {
|
|
|
2350
2715
|
case 'CONSTR_FOREIGN':
|
|
2351
2716
|
// Only add "FOREIGN KEY" for table-level constraints, not column-level constraints
|
|
2352
2717
|
if (!context.isColumnConstraint) {
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2718
|
+
if (context.isPretty()) {
|
|
2719
|
+
output.push('\n' + context.indent('FOREIGN KEY'));
|
|
2720
|
+
if (node.fk_attrs && node.fk_attrs.length > 0) {
|
|
2721
|
+
const fkAttrs = ListUtils.unwrapList(node.fk_attrs)
|
|
2722
|
+
.map(attr => this.visit(attr, context))
|
|
2723
|
+
.join(', ');
|
|
2724
|
+
output.push(`(${fkAttrs})`);
|
|
2725
|
+
}
|
|
2726
|
+
output.push('\n' + context.indent('REFERENCES'));
|
|
2359
2727
|
}
|
|
2728
|
+
else {
|
|
2729
|
+
output.push('FOREIGN KEY');
|
|
2730
|
+
if (node.fk_attrs && node.fk_attrs.length > 0) {
|
|
2731
|
+
const fkAttrs = ListUtils.unwrapList(node.fk_attrs)
|
|
2732
|
+
.map(attr => this.visit(attr, context))
|
|
2733
|
+
.join(', ');
|
|
2734
|
+
output.push(`(${fkAttrs})`);
|
|
2735
|
+
}
|
|
2736
|
+
output.push('REFERENCES');
|
|
2737
|
+
}
|
|
2738
|
+
}
|
|
2739
|
+
else {
|
|
2740
|
+
output.push('REFERENCES');
|
|
2360
2741
|
}
|
|
2361
|
-
output.push('REFERENCES');
|
|
2362
2742
|
if (node.pktable) {
|
|
2363
|
-
|
|
2743
|
+
if (context.isPretty() && !context.isColumnConstraint) {
|
|
2744
|
+
const lastIndex = output.length - 1;
|
|
2745
|
+
if (lastIndex >= 0 && output[lastIndex].includes('REFERENCES')) {
|
|
2746
|
+
output[lastIndex] += ' ' + this.RangeVar(node.pktable, context);
|
|
2747
|
+
}
|
|
2748
|
+
else {
|
|
2749
|
+
output.push(this.RangeVar(node.pktable, context));
|
|
2750
|
+
}
|
|
2751
|
+
}
|
|
2752
|
+
else {
|
|
2753
|
+
output.push(this.RangeVar(node.pktable, context));
|
|
2754
|
+
}
|
|
2364
2755
|
}
|
|
2365
2756
|
if (node.pk_attrs && node.pk_attrs.length > 0) {
|
|
2366
2757
|
const pkAttrs = ListUtils.unwrapList(node.pk_attrs)
|
|
2367
2758
|
.map(attr => this.visit(attr, context))
|
|
2368
2759
|
.join(', ');
|
|
2369
|
-
|
|
2760
|
+
if (context.isPretty() && !context.isColumnConstraint) {
|
|
2761
|
+
const lastIndex = output.length - 1;
|
|
2762
|
+
if (lastIndex >= 0) {
|
|
2763
|
+
output[lastIndex] += ` (${pkAttrs})`;
|
|
2764
|
+
}
|
|
2765
|
+
else {
|
|
2766
|
+
output.push(`(${pkAttrs})`);
|
|
2767
|
+
}
|
|
2768
|
+
}
|
|
2769
|
+
else {
|
|
2770
|
+
output.push(`(${pkAttrs})`);
|
|
2771
|
+
}
|
|
2370
2772
|
}
|
|
2371
2773
|
if (node.fk_matchtype && node.fk_matchtype !== 's') {
|
|
2774
|
+
let matchClause = '';
|
|
2372
2775
|
switch (node.fk_matchtype) {
|
|
2373
2776
|
case 'f':
|
|
2374
|
-
|
|
2777
|
+
matchClause = 'MATCH FULL';
|
|
2375
2778
|
break;
|
|
2376
2779
|
case 'p':
|
|
2377
|
-
|
|
2780
|
+
matchClause = 'MATCH PARTIAL';
|
|
2378
2781
|
break;
|
|
2379
2782
|
}
|
|
2783
|
+
if (context.isPretty() && !context.isColumnConstraint) {
|
|
2784
|
+
output.push('\n' + context.indent(matchClause));
|
|
2785
|
+
}
|
|
2786
|
+
else {
|
|
2787
|
+
output.push(matchClause);
|
|
2788
|
+
}
|
|
2380
2789
|
}
|
|
2381
2790
|
if (node.fk_upd_action && node.fk_upd_action !== 'a') {
|
|
2382
2791
|
let updateClause = 'ON UPDATE ';
|
|
@@ -2394,8 +2803,8 @@ export class Deparser {
|
|
|
2394
2803
|
updateClause += 'SET DEFAULT';
|
|
2395
2804
|
break;
|
|
2396
2805
|
}
|
|
2397
|
-
if (
|
|
2398
|
-
output.push('\n' +
|
|
2806
|
+
if (context.isPretty()) {
|
|
2807
|
+
output.push('\n' + context.indent(updateClause));
|
|
2399
2808
|
}
|
|
2400
2809
|
else {
|
|
2401
2810
|
output.push('ON UPDATE');
|
|
@@ -2418,8 +2827,8 @@ export class Deparser {
|
|
|
2418
2827
|
deleteClause += 'SET DEFAULT';
|
|
2419
2828
|
break;
|
|
2420
2829
|
}
|
|
2421
|
-
if (
|
|
2422
|
-
output.push('\n' +
|
|
2830
|
+
if (context.isPretty()) {
|
|
2831
|
+
output.push('\n' + context.indent(deleteClause));
|
|
2423
2832
|
}
|
|
2424
2833
|
else {
|
|
2425
2834
|
output.push('ON DELETE');
|
|
@@ -2428,7 +2837,12 @@ export class Deparser {
|
|
|
2428
2837
|
}
|
|
2429
2838
|
// Handle NOT VALID for foreign key constraints - only for table constraints, not domain constraints
|
|
2430
2839
|
if (node.skip_validation && !context.isDomainConstraint) {
|
|
2431
|
-
|
|
2840
|
+
if (context.isPretty() && !context.isColumnConstraint) {
|
|
2841
|
+
output.push('\n' + context.indent('NOT VALID'));
|
|
2842
|
+
}
|
|
2843
|
+
else {
|
|
2844
|
+
output.push('NOT VALID');
|
|
2845
|
+
}
|
|
2432
2846
|
}
|
|
2433
2847
|
break;
|
|
2434
2848
|
case 'CONSTR_ATTR_DEFERRABLE':
|
|
@@ -2482,13 +2896,13 @@ export class Deparser {
|
|
|
2482
2896
|
// Handle deferrable constraints for all constraint types that support it
|
|
2483
2897
|
if (node.contype === 'CONSTR_PRIMARY' || node.contype === 'CONSTR_UNIQUE' || node.contype === 'CONSTR_FOREIGN') {
|
|
2484
2898
|
if (node.deferrable) {
|
|
2485
|
-
if (
|
|
2486
|
-
output.push('\n' +
|
|
2899
|
+
if (context.isPretty() && node.contype === 'CONSTR_FOREIGN') {
|
|
2900
|
+
output.push('\n' + context.indent('DEFERRABLE'));
|
|
2487
2901
|
if (node.initdeferred === true) {
|
|
2488
|
-
output.push('\n' +
|
|
2902
|
+
output.push('\n' + context.indent('INITIALLY DEFERRED'));
|
|
2489
2903
|
}
|
|
2490
2904
|
else if (node.initdeferred === false) {
|
|
2491
|
-
output.push('\n' +
|
|
2905
|
+
output.push('\n' + context.indent('INITIALLY IMMEDIATE'));
|
|
2492
2906
|
}
|
|
2493
2907
|
}
|
|
2494
2908
|
else {
|
|
@@ -2502,15 +2916,15 @@ export class Deparser {
|
|
|
2502
2916
|
}
|
|
2503
2917
|
}
|
|
2504
2918
|
else if (node.deferrable === false) {
|
|
2505
|
-
if (
|
|
2506
|
-
output.push('\n' +
|
|
2919
|
+
if (context.isPretty() && node.contype === 'CONSTR_FOREIGN') {
|
|
2920
|
+
output.push('\n' + context.indent('NOT DEFERRABLE'));
|
|
2507
2921
|
}
|
|
2508
2922
|
else {
|
|
2509
2923
|
output.push('NOT DEFERRABLE');
|
|
2510
2924
|
}
|
|
2511
2925
|
}
|
|
2512
2926
|
}
|
|
2513
|
-
if (
|
|
2927
|
+
if (context.isPretty() && node.contype === 'CONSTR_FOREIGN') {
|
|
2514
2928
|
let result = '';
|
|
2515
2929
|
for (let i = 0; i < output.length; i++) {
|
|
2516
2930
|
if (output[i].startsWith('\n')) {
|
|
@@ -2528,12 +2942,12 @@ export class Deparser {
|
|
|
2528
2942
|
return output.join(' ');
|
|
2529
2943
|
}
|
|
2530
2944
|
SubLink(node, context) {
|
|
2531
|
-
const subselect =
|
|
2945
|
+
const subselect = context.parens(this.visit(node.subselect, context));
|
|
2532
2946
|
switch (node.subLinkType) {
|
|
2533
2947
|
case 'ANY_SUBLINK':
|
|
2534
2948
|
if (node.testexpr && node.operName) {
|
|
2535
2949
|
const testExpr = this.visit(node.testexpr, context);
|
|
2536
|
-
const operator = this.deparseOperatorName(node.operName);
|
|
2950
|
+
const operator = this.deparseOperatorName(node.operName, context);
|
|
2537
2951
|
return `${testExpr} ${operator} ANY ${subselect}`;
|
|
2538
2952
|
}
|
|
2539
2953
|
else if (node.testexpr) {
|
|
@@ -2544,7 +2958,7 @@ export class Deparser {
|
|
|
2544
2958
|
case 'ALL_SUBLINK':
|
|
2545
2959
|
if (node.testexpr && node.operName) {
|
|
2546
2960
|
const testExpr = this.visit(node.testexpr, context);
|
|
2547
|
-
const operator = this.deparseOperatorName(node.operName);
|
|
2961
|
+
const operator = this.deparseOperatorName(node.operName, context);
|
|
2548
2962
|
return `${testExpr} ${operator} ALL ${subselect}`;
|
|
2549
2963
|
}
|
|
2550
2964
|
return subselect;
|
|
@@ -2586,7 +3000,7 @@ export class Deparser {
|
|
|
2586
3000
|
}
|
|
2587
3001
|
// Only add frame clause if frameOptions indicates non-default framing
|
|
2588
3002
|
if (node.frameOptions && node.frameOptions !== 1058) {
|
|
2589
|
-
const frameClause = this.formatWindowFrame(node);
|
|
3003
|
+
const frameClause = this.formatWindowFrame(node, context.spawn('WindowDef'));
|
|
2590
3004
|
if (frameClause) {
|
|
2591
3005
|
windowParts.push(frameClause);
|
|
2592
3006
|
}
|
|
@@ -2606,7 +3020,7 @@ export class Deparser {
|
|
|
2606
3020
|
}
|
|
2607
3021
|
return output.join(' ');
|
|
2608
3022
|
}
|
|
2609
|
-
formatWindowFrame(node) {
|
|
3023
|
+
formatWindowFrame(node, context) {
|
|
2610
3024
|
if (!node.frameOptions)
|
|
2611
3025
|
return null;
|
|
2612
3026
|
const frameOptions = node.frameOptions;
|
|
@@ -2615,7 +3029,7 @@ export class Deparser {
|
|
|
2615
3029
|
if (frameOptions & 0x02) { // FRAMEOPTION_RANGE
|
|
2616
3030
|
frameParts.push('RANGE');
|
|
2617
3031
|
}
|
|
2618
|
-
else if (frameOptions & 0x04) { // FRAMEOPTION_ROWS
|
|
3032
|
+
else if (frameOptions & 0x04) { // FRAMEOPTION_ROWS
|
|
2619
3033
|
frameParts.push('ROWS');
|
|
2620
3034
|
}
|
|
2621
3035
|
else if (frameOptions & 0x08) { // FRAMEOPTION_GROUPS
|
|
@@ -2636,8 +3050,8 @@ export class Deparser {
|
|
|
2636
3050
|
}
|
|
2637
3051
|
else if (frameOptions === 18453) {
|
|
2638
3052
|
if (node.startOffset && node.endOffset) {
|
|
2639
|
-
boundsParts.push(`${this.visit(node.startOffset,
|
|
2640
|
-
boundsParts.push(`AND ${this.visit(node.endOffset,
|
|
3053
|
+
boundsParts.push(`${this.visit(node.startOffset, context)} PRECEDING`);
|
|
3054
|
+
boundsParts.push(`AND ${this.visit(node.endOffset, context)} FOLLOWING`);
|
|
2641
3055
|
}
|
|
2642
3056
|
}
|
|
2643
3057
|
else if (frameOptions === 1557) {
|
|
@@ -2647,7 +3061,7 @@ export class Deparser {
|
|
|
2647
3061
|
else if (frameOptions === 16917) {
|
|
2648
3062
|
boundsParts.push('CURRENT ROW');
|
|
2649
3063
|
if (node.endOffset) {
|
|
2650
|
-
boundsParts.push(`AND ${this.visit(node.endOffset,
|
|
3064
|
+
boundsParts.push(`AND ${this.visit(node.endOffset, context)} FOLLOWING`);
|
|
2651
3065
|
}
|
|
2652
3066
|
}
|
|
2653
3067
|
else if (frameOptions === 1058) {
|
|
@@ -2657,13 +3071,13 @@ export class Deparser {
|
|
|
2657
3071
|
// Handle start bound - prioritize explicit offset values over bit flags
|
|
2658
3072
|
if (node.startOffset) {
|
|
2659
3073
|
if (frameOptions & 0x400) { // FRAMEOPTION_START_VALUE_PRECEDING
|
|
2660
|
-
boundsParts.push(`${this.visit(node.startOffset,
|
|
3074
|
+
boundsParts.push(`${this.visit(node.startOffset, context)} PRECEDING`);
|
|
2661
3075
|
}
|
|
2662
3076
|
else if (frameOptions & 0x800) { // FRAMEOPTION_START_VALUE_FOLLOWING
|
|
2663
|
-
boundsParts.push(`${this.visit(node.startOffset,
|
|
3077
|
+
boundsParts.push(`${this.visit(node.startOffset, context)} FOLLOWING`);
|
|
2664
3078
|
}
|
|
2665
3079
|
else {
|
|
2666
|
-
boundsParts.push(`${this.visit(node.startOffset,
|
|
3080
|
+
boundsParts.push(`${this.visit(node.startOffset, context)} PRECEDING`);
|
|
2667
3081
|
}
|
|
2668
3082
|
}
|
|
2669
3083
|
else if (frameOptions & 0x10) { // FRAMEOPTION_START_UNBOUNDED_PRECEDING
|
|
@@ -2676,13 +3090,13 @@ export class Deparser {
|
|
|
2676
3090
|
if (node.endOffset) {
|
|
2677
3091
|
if (boundsParts.length > 0) {
|
|
2678
3092
|
if (frameOptions & 0x1000) { // FRAMEOPTION_END_VALUE_PRECEDING
|
|
2679
|
-
boundsParts.push(`AND ${this.visit(node.endOffset,
|
|
3093
|
+
boundsParts.push(`AND ${this.visit(node.endOffset, context)} PRECEDING`);
|
|
2680
3094
|
}
|
|
2681
3095
|
else if (frameOptions & 0x2000) { // FRAMEOPTION_END_VALUE_FOLLOWING
|
|
2682
|
-
boundsParts.push(`AND ${this.visit(node.endOffset,
|
|
3096
|
+
boundsParts.push(`AND ${this.visit(node.endOffset, context)} FOLLOWING`);
|
|
2683
3097
|
}
|
|
2684
3098
|
else {
|
|
2685
|
-
boundsParts.push(`AND ${this.visit(node.endOffset,
|
|
3099
|
+
boundsParts.push(`AND ${this.visit(node.endOffset, context)} FOLLOWING`);
|
|
2686
3100
|
}
|
|
2687
3101
|
}
|
|
2688
3102
|
}
|
|
@@ -2767,7 +3181,7 @@ export class Deparser {
|
|
|
2767
3181
|
const colnames = ListUtils.unwrapList(node.aliascolnames);
|
|
2768
3182
|
const colnameStrs = colnames.map(col => this.visit(col, context));
|
|
2769
3183
|
// Don't add space before column list parentheses to match original formatting
|
|
2770
|
-
output[output.length - 1] +=
|
|
3184
|
+
output[output.length - 1] += context.parens(colnameStrs.join(', '));
|
|
2771
3185
|
}
|
|
2772
3186
|
output.push('AS');
|
|
2773
3187
|
// Handle materialization clauses
|
|
@@ -2778,7 +3192,7 @@ export class Deparser {
|
|
|
2778
3192
|
output.push('MATERIALIZED');
|
|
2779
3193
|
}
|
|
2780
3194
|
if (node.ctequery) {
|
|
2781
|
-
output.push(
|
|
3195
|
+
output.push(context.parens(this.visit(node.ctequery, context)));
|
|
2782
3196
|
}
|
|
2783
3197
|
return output.join(' ');
|
|
2784
3198
|
}
|
|
@@ -2854,7 +3268,7 @@ export class Deparser {
|
|
|
2854
3268
|
DistinctExpr(node, context) {
|
|
2855
3269
|
const args = ListUtils.unwrapList(node.args);
|
|
2856
3270
|
if (args.length === 2) {
|
|
2857
|
-
const literalContext =
|
|
3271
|
+
const literalContext = context.spawn('DistinctExpr', { isStringLiteral: true });
|
|
2858
3272
|
const left = this.visit(args[0], literalContext);
|
|
2859
3273
|
const right = this.visit(args[1], literalContext);
|
|
2860
3274
|
return `${left} IS DISTINCT FROM ${right}`;
|
|
@@ -2864,7 +3278,7 @@ export class Deparser {
|
|
|
2864
3278
|
NullIfExpr(node, context) {
|
|
2865
3279
|
const args = ListUtils.unwrapList(node.args);
|
|
2866
3280
|
if (args.length === 2) {
|
|
2867
|
-
const literalContext =
|
|
3281
|
+
const literalContext = context.spawn('NullIfExpr', { isStringLiteral: true });
|
|
2868
3282
|
const left = this.visit(args[0], literalContext);
|
|
2869
3283
|
const right = this.visit(args[1], literalContext);
|
|
2870
3284
|
return `NULLIF(${left}, ${right})`;
|
|
@@ -2943,7 +3357,7 @@ export class Deparser {
|
|
|
2943
3357
|
}
|
|
2944
3358
|
RelabelType(node, context) {
|
|
2945
3359
|
if (node.arg) {
|
|
2946
|
-
const literalContext =
|
|
3360
|
+
const literalContext = context.spawn('RelabelType', { isStringLiteral: true });
|
|
2947
3361
|
return this.visit(node.arg, literalContext);
|
|
2948
3362
|
}
|
|
2949
3363
|
return '';
|
|
@@ -2962,7 +3376,7 @@ export class Deparser {
|
|
|
2962
3376
|
}
|
|
2963
3377
|
ConvertRowtypeExpr(node, context) {
|
|
2964
3378
|
if (node.arg) {
|
|
2965
|
-
const literalContext =
|
|
3379
|
+
const literalContext = context.spawn('ConvertRowtypeExpr', { isStringLiteral: true });
|
|
2966
3380
|
return this.visit(node.arg, literalContext);
|
|
2967
3381
|
}
|
|
2968
3382
|
return '';
|
|
@@ -2993,10 +3407,10 @@ export class Deparser {
|
|
|
2993
3407
|
}
|
|
2994
3408
|
if (node.aliases && node.aliases.length > 0) {
|
|
2995
3409
|
const aliasStrs = ListUtils.unwrapList(node.aliases).map(alias => this.visit(alias, context));
|
|
2996
|
-
output.push(
|
|
3410
|
+
output.push(context.parens(aliasStrs.join(', ')));
|
|
2997
3411
|
}
|
|
2998
3412
|
if (node.options && node.options.length > 0) {
|
|
2999
|
-
const viewContext =
|
|
3413
|
+
const viewContext = context.spawn('ViewStmt');
|
|
3000
3414
|
const optionStrs = ListUtils.unwrapList(node.options)
|
|
3001
3415
|
.map(option => this.visit(option, viewContext));
|
|
3002
3416
|
output.push(`WITH (${optionStrs.join(', ')})`);
|
|
@@ -3043,22 +3457,22 @@ export class Deparser {
|
|
|
3043
3457
|
}
|
|
3044
3458
|
if (node.indexParams && node.indexParams.length > 0) {
|
|
3045
3459
|
const paramStrs = ListUtils.unwrapList(node.indexParams).map(param => this.visit(param, context));
|
|
3046
|
-
output.push(
|
|
3460
|
+
output.push(context.parens(paramStrs.join(', ')));
|
|
3047
3461
|
}
|
|
3048
3462
|
if (node.indexIncludingParams && node.indexIncludingParams.length > 0) {
|
|
3049
3463
|
const includeStrs = ListUtils.unwrapList(node.indexIncludingParams).map(param => this.visit(param, context));
|
|
3050
3464
|
output.push('INCLUDE');
|
|
3051
|
-
output.push(
|
|
3465
|
+
output.push(context.parens(includeStrs.join(', ')));
|
|
3052
3466
|
}
|
|
3053
3467
|
if (node.whereClause) {
|
|
3054
3468
|
output.push('WHERE');
|
|
3055
3469
|
output.push(this.visit(node.whereClause, context));
|
|
3056
3470
|
}
|
|
3057
3471
|
if (node.options && node.options.length > 0) {
|
|
3058
|
-
const indexContext =
|
|
3472
|
+
const indexContext = context.spawn('IndexStmt');
|
|
3059
3473
|
const optionStrs = ListUtils.unwrapList(node.options).map(option => this.visit(option, indexContext));
|
|
3060
3474
|
output.push('WITH');
|
|
3061
|
-
output.push(
|
|
3475
|
+
output.push(context.parens(optionStrs.join(', ')));
|
|
3062
3476
|
}
|
|
3063
3477
|
if (node.nulls_not_distinct) {
|
|
3064
3478
|
output.push('NULLS NOT DISTINCT');
|
|
@@ -3075,7 +3489,7 @@ export class Deparser {
|
|
|
3075
3489
|
output.push(QuoteUtils.quote(node.name));
|
|
3076
3490
|
}
|
|
3077
3491
|
else if (node.expr) {
|
|
3078
|
-
output.push(
|
|
3492
|
+
output.push(context.parens(this.visit(node.expr, context)));
|
|
3079
3493
|
}
|
|
3080
3494
|
if (node.collation && node.collation.length > 0) {
|
|
3081
3495
|
const collationStrs = ListUtils.unwrapList(node.collation).map(coll => this.visit(coll, context));
|
|
@@ -3092,7 +3506,7 @@ export class Deparser {
|
|
|
3092
3506
|
const stringData = this.getNodeData(opt.DefElem.arg);
|
|
3093
3507
|
return `${opt.DefElem.defname}='${stringData.sval}'`;
|
|
3094
3508
|
}
|
|
3095
|
-
return this.visit(opt, context);
|
|
3509
|
+
return this.visit(opt, context.spawn('IndexElem'));
|
|
3096
3510
|
});
|
|
3097
3511
|
opclassStr += `(${opclassOpts.join(', ')})`;
|
|
3098
3512
|
}
|
|
@@ -3126,7 +3540,7 @@ export class Deparser {
|
|
|
3126
3540
|
output.push(QuoteUtils.quote(node.name));
|
|
3127
3541
|
}
|
|
3128
3542
|
else if (node.expr) {
|
|
3129
|
-
output.push(
|
|
3543
|
+
output.push(context.parens(this.visit(node.expr, context)));
|
|
3130
3544
|
}
|
|
3131
3545
|
if (node.collation && node.collation.length > 0) {
|
|
3132
3546
|
const collationStrs = ListUtils.unwrapList(node.collation).map(coll => this.visit(coll, context));
|
|
@@ -3274,16 +3688,16 @@ export class Deparser {
|
|
|
3274
3688
|
if (node.rarg && 'JoinExpr' in node.rarg && !node.rarg.JoinExpr.alias) {
|
|
3275
3689
|
rargStr = `(${rargStr})`;
|
|
3276
3690
|
}
|
|
3277
|
-
if (
|
|
3278
|
-
output.push(
|
|
3691
|
+
if (context.isPretty()) {
|
|
3692
|
+
output.push(context.newline() + joinStr + ' ' + rargStr);
|
|
3279
3693
|
}
|
|
3280
3694
|
else {
|
|
3281
3695
|
output.push(joinStr + ' ' + rargStr);
|
|
3282
3696
|
}
|
|
3283
3697
|
}
|
|
3284
3698
|
else {
|
|
3285
|
-
if (
|
|
3286
|
-
output.push(
|
|
3699
|
+
if (context.isPretty()) {
|
|
3700
|
+
output.push(context.newline() + joinStr);
|
|
3287
3701
|
}
|
|
3288
3702
|
else {
|
|
3289
3703
|
output.push(joinStr);
|
|
@@ -3292,7 +3706,7 @@ export class Deparser {
|
|
|
3292
3706
|
if (node.usingClause && node.usingClause.length > 0) {
|
|
3293
3707
|
const usingList = ListUtils.unwrapList(node.usingClause);
|
|
3294
3708
|
const columnNames = usingList.map(col => this.visit(col, context));
|
|
3295
|
-
if (
|
|
3709
|
+
if (context.isPretty()) {
|
|
3296
3710
|
output.push(` USING (${columnNames.join(', ')})`);
|
|
3297
3711
|
}
|
|
3298
3712
|
else {
|
|
@@ -3301,14 +3715,14 @@ export class Deparser {
|
|
|
3301
3715
|
}
|
|
3302
3716
|
else if (node.quals) {
|
|
3303
3717
|
const qualsStr = this.visit(node.quals, context);
|
|
3304
|
-
if (
|
|
3718
|
+
if (context.isPretty()) {
|
|
3305
3719
|
// For complex JOIN conditions, format with proper indentation
|
|
3306
3720
|
if (qualsStr.includes('AND') || qualsStr.includes('OR') || qualsStr.length > 50) {
|
|
3307
3721
|
if (this.containsMultilineStringLiteral(qualsStr)) {
|
|
3308
3722
|
output.push(` ON ${qualsStr}`);
|
|
3309
3723
|
}
|
|
3310
3724
|
else {
|
|
3311
|
-
output.push(` ON${
|
|
3725
|
+
output.push(` ON${context.newline()}${context.indent(qualsStr)}`);
|
|
3312
3726
|
}
|
|
3313
3727
|
}
|
|
3314
3728
|
else {
|
|
@@ -3320,7 +3734,7 @@ export class Deparser {
|
|
|
3320
3734
|
}
|
|
3321
3735
|
}
|
|
3322
3736
|
let result;
|
|
3323
|
-
if (
|
|
3737
|
+
if (context.isPretty()) {
|
|
3324
3738
|
result = output.join('');
|
|
3325
3739
|
}
|
|
3326
3740
|
else {
|
|
@@ -3427,8 +3841,8 @@ export class Deparser {
|
|
|
3427
3841
|
else if (nodeData.sval !== undefined) {
|
|
3428
3842
|
// Handle nested sval structure: { sval: { sval: "value" } }
|
|
3429
3843
|
const svalValue = typeof nodeData.sval === 'object' ? nodeData.sval.sval : nodeData.sval;
|
|
3430
|
-
const stringValue = svalValue.replace(/'/g, '')
|
|
3431
|
-
boolValue = stringValue === 'on' || stringValue === 'true';
|
|
3844
|
+
const stringValue = svalValue.replace(/'/g, '');
|
|
3845
|
+
boolValue = stringValue.toLowerCase() === 'on' || stringValue.toLowerCase() === 'true';
|
|
3432
3846
|
}
|
|
3433
3847
|
}
|
|
3434
3848
|
return boolValue ? 'READ ONLY' : 'READ WRITE';
|
|
@@ -3451,8 +3865,8 @@ export class Deparser {
|
|
|
3451
3865
|
else if (nodeData.sval !== undefined) {
|
|
3452
3866
|
// Handle nested sval structure: { sval: { sval: "value" } }
|
|
3453
3867
|
const svalValue = typeof nodeData.sval === 'object' ? nodeData.sval.sval : nodeData.sval;
|
|
3454
|
-
const stringValue = svalValue.replace(/'/g, '')
|
|
3455
|
-
boolValue = stringValue === 'on' || stringValue === 'true';
|
|
3868
|
+
const stringValue = svalValue.replace(/'/g, '');
|
|
3869
|
+
boolValue = stringValue.toLowerCase() === 'on' || stringValue.toLowerCase() === 'true';
|
|
3456
3870
|
}
|
|
3457
3871
|
}
|
|
3458
3872
|
return boolValue ? 'DEFERRABLE' : 'NOT DEFERRABLE';
|
|
@@ -3519,8 +3933,8 @@ export class Deparser {
|
|
|
3519
3933
|
else if (nodeData.sval !== undefined) {
|
|
3520
3934
|
// Handle nested sval structure: { sval: { sval: "value" } }
|
|
3521
3935
|
const svalValue = typeof nodeData.sval === 'object' ? nodeData.sval.sval : nodeData.sval;
|
|
3522
|
-
const stringValue = svalValue.replace(/'/g, '')
|
|
3523
|
-
boolValue = stringValue === 'on' || stringValue === 'true';
|
|
3936
|
+
const stringValue = svalValue.replace(/'/g, '');
|
|
3937
|
+
boolValue = stringValue.toLowerCase() === 'on' || stringValue.toLowerCase() === 'true';
|
|
3524
3938
|
}
|
|
3525
3939
|
}
|
|
3526
3940
|
transactionOptions.push(boolValue ? 'READ ONLY' : 'READ WRITE');
|
|
@@ -3538,8 +3952,8 @@ export class Deparser {
|
|
|
3538
3952
|
else if (nodeData.sval !== undefined) {
|
|
3539
3953
|
// Handle nested sval structure: { sval: { sval: "value" } }
|
|
3540
3954
|
const svalValue = typeof nodeData.sval === 'object' ? nodeData.sval.sval : nodeData.sval;
|
|
3541
|
-
const stringValue = svalValue.replace(/'/g, '')
|
|
3542
|
-
boolValue = stringValue === 'on' || stringValue === 'true';
|
|
3955
|
+
const stringValue = svalValue.replace(/'/g, '');
|
|
3956
|
+
boolValue = stringValue.toLowerCase() === 'on' || stringValue.toLowerCase() === 'true';
|
|
3543
3957
|
}
|
|
3544
3958
|
}
|
|
3545
3959
|
transactionOptions.push(boolValue ? 'DEFERRABLE' : 'NOT DEFERRABLE');
|
|
@@ -3605,7 +4019,7 @@ export class Deparser {
|
|
|
3605
4019
|
}
|
|
3606
4020
|
switch (node.roletype) {
|
|
3607
4021
|
case 'ROLESPEC_PUBLIC':
|
|
3608
|
-
return '
|
|
4022
|
+
return 'PUBLIC';
|
|
3609
4023
|
case 'ROLESPEC_CURRENT_USER':
|
|
3610
4024
|
return 'CURRENT_USER';
|
|
3611
4025
|
case 'ROLESPEC_SESSION_USER':
|
|
@@ -3613,7 +4027,7 @@ export class Deparser {
|
|
|
3613
4027
|
case 'ROLESPEC_CURRENT_ROLE':
|
|
3614
4028
|
return 'CURRENT_ROLE';
|
|
3615
4029
|
default:
|
|
3616
|
-
return '
|
|
4030
|
+
return 'PUBLIC';
|
|
3617
4031
|
}
|
|
3618
4032
|
}
|
|
3619
4033
|
roletype(node, context) {
|
|
@@ -3923,7 +4337,7 @@ export class Deparser {
|
|
|
3923
4337
|
}).filter((name) => name && name.trim());
|
|
3924
4338
|
return items.join('.');
|
|
3925
4339
|
}
|
|
3926
|
-
const objContext =
|
|
4340
|
+
const objContext = context.spawn('DropStmt', { objtype: node.removeType });
|
|
3927
4341
|
const objName = this.visit(objList, objContext);
|
|
3928
4342
|
return objName;
|
|
3929
4343
|
}).filter((name) => name && name.trim()).join(', ');
|
|
@@ -4023,7 +4437,7 @@ export class Deparser {
|
|
|
4023
4437
|
if (node.options && node.options.length > 0) {
|
|
4024
4438
|
output.push('WITH');
|
|
4025
4439
|
const optionsStr = ListUtils.unwrapList(node.options)
|
|
4026
|
-
.map(opt => this.visit(opt, context))
|
|
4440
|
+
.map(opt => this.visit(opt, context.spawn('CopyStmt')))
|
|
4027
4441
|
.join(', ');
|
|
4028
4442
|
output.push(`(${optionsStr})`);
|
|
4029
4443
|
}
|
|
@@ -4069,18 +4483,28 @@ export class Deparser {
|
|
|
4069
4483
|
if (node.missing_ok) {
|
|
4070
4484
|
output.push('IF EXISTS');
|
|
4071
4485
|
}
|
|
4072
|
-
const alterContext = node.objtype
|
|
4073
|
-
? { ...context, parentNodeTypes: [...context.parentNodeTypes, 'AlterTypeStmt'] }
|
|
4074
|
-
: context;
|
|
4486
|
+
const alterContext = context.spawn('AlterTableStmt', { objtype: node.objtype });
|
|
4075
4487
|
if (node.relation) {
|
|
4076
4488
|
const relationStr = this.RangeVar(node.relation, alterContext);
|
|
4077
4489
|
output.push(relationStr);
|
|
4078
4490
|
}
|
|
4079
4491
|
if (node.cmds && node.cmds.length > 0) {
|
|
4080
|
-
const
|
|
4081
|
-
|
|
4082
|
-
|
|
4083
|
-
|
|
4492
|
+
const commands = ListUtils.unwrapList(node.cmds);
|
|
4493
|
+
if (context.isPretty()) {
|
|
4494
|
+
const commandsStr = commands
|
|
4495
|
+
.map(cmd => {
|
|
4496
|
+
const cmdStr = this.visit(cmd, alterContext);
|
|
4497
|
+
return context.newline() + context.indent(cmdStr);
|
|
4498
|
+
})
|
|
4499
|
+
.join(',');
|
|
4500
|
+
output.push(commandsStr);
|
|
4501
|
+
}
|
|
4502
|
+
else {
|
|
4503
|
+
const commandsStr = commands
|
|
4504
|
+
.map(cmd => this.visit(cmd, alterContext))
|
|
4505
|
+
.join(', ');
|
|
4506
|
+
output.push(commandsStr);
|
|
4507
|
+
}
|
|
4084
4508
|
}
|
|
4085
4509
|
return output.join(' ');
|
|
4086
4510
|
}
|
|
@@ -4089,7 +4513,7 @@ export class Deparser {
|
|
|
4089
4513
|
if (node.subtype) {
|
|
4090
4514
|
switch (node.subtype) {
|
|
4091
4515
|
case 'AT_AddColumn':
|
|
4092
|
-
if (context.
|
|
4516
|
+
if (context.objtype === 'OBJECT_TYPE') {
|
|
4093
4517
|
output.push('ADD ATTRIBUTE');
|
|
4094
4518
|
}
|
|
4095
4519
|
else {
|
|
@@ -4100,35 +4524,99 @@ export class Deparser {
|
|
|
4100
4524
|
}
|
|
4101
4525
|
if (node.def) {
|
|
4102
4526
|
const colDefData = this.getNodeData(node.def);
|
|
4103
|
-
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
|
|
4110
|
-
|
|
4111
|
-
|
|
4112
|
-
|
|
4113
|
-
|
|
4114
|
-
|
|
4115
|
-
|
|
4116
|
-
|
|
4117
|
-
|
|
4118
|
-
|
|
4119
|
-
const
|
|
4120
|
-
|
|
4121
|
-
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
|
|
4527
|
+
if (context.isPretty()) {
|
|
4528
|
+
const parts = [];
|
|
4529
|
+
const indentedParts = [];
|
|
4530
|
+
if (colDefData.colname) {
|
|
4531
|
+
parts.push(QuoteUtils.quote(colDefData.colname));
|
|
4532
|
+
}
|
|
4533
|
+
if (colDefData.typeName) {
|
|
4534
|
+
parts.push(this.TypeName(colDefData.typeName, context));
|
|
4535
|
+
}
|
|
4536
|
+
if (colDefData.is_not_null) {
|
|
4537
|
+
indentedParts.push('NOT NULL');
|
|
4538
|
+
}
|
|
4539
|
+
if (colDefData.collClause) {
|
|
4540
|
+
indentedParts.push(this.CollateClause(colDefData.collClause, context));
|
|
4541
|
+
}
|
|
4542
|
+
if (colDefData.constraints) {
|
|
4543
|
+
const constraints = ListUtils.unwrapList(colDefData.constraints);
|
|
4544
|
+
constraints.forEach(constraint => {
|
|
4545
|
+
const columnConstraintContext = context.spawn('ColumnDef', { isColumnConstraint: true });
|
|
4546
|
+
const constraintStr = this.visit(constraint, columnConstraintContext);
|
|
4547
|
+
if (constraintStr.includes('REFERENCES') && constraintStr.includes('ON DELETE')) {
|
|
4548
|
+
const refMatch = constraintStr.match(/^(.*REFERENCES[^)]*\([^)]*\))\s*(ON\s+DELETE\s+CASCADE.*)$/);
|
|
4549
|
+
if (refMatch) {
|
|
4550
|
+
indentedParts.push(refMatch[1]);
|
|
4551
|
+
indentedParts.push(refMatch[2]);
|
|
4552
|
+
}
|
|
4553
|
+
else {
|
|
4554
|
+
indentedParts.push(constraintStr);
|
|
4555
|
+
}
|
|
4556
|
+
}
|
|
4557
|
+
else if (constraintStr === 'UNIQUE' && colDefData.raw_default) {
|
|
4558
|
+
const defaultStr = 'DEFAULT ' + this.visit(colDefData.raw_default, context);
|
|
4559
|
+
indentedParts.push('UNIQUE ' + defaultStr);
|
|
4560
|
+
}
|
|
4561
|
+
else {
|
|
4562
|
+
indentedParts.push(constraintStr);
|
|
4563
|
+
}
|
|
4564
|
+
});
|
|
4565
|
+
}
|
|
4566
|
+
if (colDefData.raw_default && !colDefData.constraints?.some((c) => {
|
|
4567
|
+
const constraintStr = this.visit(c, context.spawn('ColumnDef', { isColumnConstraint: true }));
|
|
4568
|
+
return constraintStr === 'UNIQUE';
|
|
4569
|
+
})) {
|
|
4570
|
+
const defaultStr = 'DEFAULT ' + this.visit(colDefData.raw_default, context);
|
|
4571
|
+
indentedParts.push(defaultStr);
|
|
4572
|
+
}
|
|
4573
|
+
if (colDefData.fdwoptions && colDefData.fdwoptions.length > 0) {
|
|
4574
|
+
indentedParts.push('OPTIONS');
|
|
4575
|
+
const columnContext = context.spawn('ColumnDef');
|
|
4576
|
+
const options = ListUtils.unwrapList(colDefData.fdwoptions).map(opt => this.visit(opt, columnContext));
|
|
4577
|
+
indentedParts.push(`(${options.join(', ')})`);
|
|
4578
|
+
}
|
|
4579
|
+
let result = parts.join(' ');
|
|
4580
|
+
if (indentedParts.length > 0) {
|
|
4581
|
+
const indentedStr = indentedParts.map(part => context.indent(part)).join(context.newline());
|
|
4582
|
+
result += context.newline() + indentedStr;
|
|
4583
|
+
}
|
|
4584
|
+
output.push(result);
|
|
4127
4585
|
}
|
|
4128
|
-
|
|
4129
|
-
parts
|
|
4586
|
+
else {
|
|
4587
|
+
const parts = [];
|
|
4588
|
+
if (colDefData.colname) {
|
|
4589
|
+
parts.push(QuoteUtils.quote(colDefData.colname));
|
|
4590
|
+
}
|
|
4591
|
+
if (colDefData.typeName) {
|
|
4592
|
+
parts.push(this.TypeName(colDefData.typeName, context));
|
|
4593
|
+
}
|
|
4594
|
+
if (colDefData.collClause) {
|
|
4595
|
+
parts.push(this.CollateClause(colDefData.collClause, context));
|
|
4596
|
+
}
|
|
4597
|
+
if (colDefData.fdwoptions && colDefData.fdwoptions.length > 0) {
|
|
4598
|
+
parts.push('OPTIONS');
|
|
4599
|
+
const columnContext = context.spawn('ColumnDef');
|
|
4600
|
+
const options = ListUtils.unwrapList(colDefData.fdwoptions).map(opt => this.visit(opt, columnContext));
|
|
4601
|
+
parts.push(`(${options.join(', ')})`);
|
|
4602
|
+
}
|
|
4603
|
+
if (colDefData.constraints) {
|
|
4604
|
+
const constraints = ListUtils.unwrapList(colDefData.constraints);
|
|
4605
|
+
const constraintStrs = constraints.map(constraint => {
|
|
4606
|
+
const columnConstraintContext = context.spawn('ColumnDef', { isColumnConstraint: true });
|
|
4607
|
+
return this.visit(constraint, columnConstraintContext);
|
|
4608
|
+
});
|
|
4609
|
+
parts.push(...constraintStrs);
|
|
4610
|
+
}
|
|
4611
|
+
if (colDefData.raw_default) {
|
|
4612
|
+
parts.push('DEFAULT');
|
|
4613
|
+
parts.push(this.visit(colDefData.raw_default, context));
|
|
4614
|
+
}
|
|
4615
|
+
if (colDefData.is_not_null) {
|
|
4616
|
+
parts.push('NOT NULL');
|
|
4617
|
+
}
|
|
4618
|
+
output.push(parts.join(' '));
|
|
4130
4619
|
}
|
|
4131
|
-
output.push(parts.join(' '));
|
|
4132
4620
|
}
|
|
4133
4621
|
if (node.behavior === 'DROP_CASCADE') {
|
|
4134
4622
|
output.push('CASCADE');
|
|
@@ -4136,7 +4624,7 @@ export class Deparser {
|
|
|
4136
4624
|
break;
|
|
4137
4625
|
case 'AT_DropColumn':
|
|
4138
4626
|
if (node.missing_ok) {
|
|
4139
|
-
if (context.
|
|
4627
|
+
if (context.objtype === 'OBJECT_TYPE') {
|
|
4140
4628
|
output.push('DROP ATTRIBUTE IF EXISTS');
|
|
4141
4629
|
}
|
|
4142
4630
|
else {
|
|
@@ -4144,7 +4632,7 @@ export class Deparser {
|
|
|
4144
4632
|
}
|
|
4145
4633
|
}
|
|
4146
4634
|
else {
|
|
4147
|
-
if (context.
|
|
4635
|
+
if (context.objtype === 'OBJECT_TYPE') {
|
|
4148
4636
|
output.push('DROP ATTRIBUTE');
|
|
4149
4637
|
}
|
|
4150
4638
|
else {
|
|
@@ -4162,7 +4650,7 @@ export class Deparser {
|
|
|
4162
4650
|
}
|
|
4163
4651
|
break;
|
|
4164
4652
|
case 'AT_AlterColumnType':
|
|
4165
|
-
if (context.
|
|
4653
|
+
if (context.objtype === 'OBJECT_TYPE') {
|
|
4166
4654
|
output.push('ALTER ATTRIBUTE');
|
|
4167
4655
|
}
|
|
4168
4656
|
else {
|
|
@@ -4226,7 +4714,7 @@ export class Deparser {
|
|
|
4226
4714
|
case 'AT_SetRelOptions':
|
|
4227
4715
|
output.push('SET');
|
|
4228
4716
|
if (node.def) {
|
|
4229
|
-
const alterTableContext =
|
|
4717
|
+
const alterTableContext = context.spawn('AlterTableCmd', { subtype: 'AT_SetRelOptions' });
|
|
4230
4718
|
const options = ListUtils.unwrapList(node.def)
|
|
4231
4719
|
.map(option => this.visit(option, alterTableContext))
|
|
4232
4720
|
.join(', ');
|
|
@@ -4239,7 +4727,7 @@ export class Deparser {
|
|
|
4239
4727
|
case 'AT_ResetRelOptions':
|
|
4240
4728
|
output.push('RESET');
|
|
4241
4729
|
if (node.def) {
|
|
4242
|
-
const alterTableContext =
|
|
4730
|
+
const alterTableContext = context.spawn('AlterTableCmd', { subtype: 'AT_ResetRelOptions' });
|
|
4243
4731
|
const options = ListUtils.unwrapList(node.def)
|
|
4244
4732
|
.map(option => this.visit(option, alterTableContext))
|
|
4245
4733
|
.join(', ');
|
|
@@ -4334,7 +4822,7 @@ export class Deparser {
|
|
|
4334
4822
|
}
|
|
4335
4823
|
output.push('SET');
|
|
4336
4824
|
if (node.def) {
|
|
4337
|
-
const alterTableContext =
|
|
4825
|
+
const alterTableContext = context.spawn('AlterTableCmd', { subtype: 'AT_SetOptions' });
|
|
4338
4826
|
const options = ListUtils.unwrapList(node.def)
|
|
4339
4827
|
.map(option => this.visit(option, alterTableContext))
|
|
4340
4828
|
.join(', ');
|
|
@@ -4351,7 +4839,7 @@ export class Deparser {
|
|
|
4351
4839
|
}
|
|
4352
4840
|
output.push('RESET');
|
|
4353
4841
|
if (node.def) {
|
|
4354
|
-
const alterTableContext =
|
|
4842
|
+
const alterTableContext = context.spawn('AlterTableCmd', { subtype: 'AT_ResetOptions' });
|
|
4355
4843
|
const options = ListUtils.unwrapList(node.def)
|
|
4356
4844
|
.map(option => this.visit(option, alterTableContext))
|
|
4357
4845
|
.join(', ');
|
|
@@ -4592,7 +5080,7 @@ export class Deparser {
|
|
|
4592
5080
|
}
|
|
4593
5081
|
output.push('OPTIONS');
|
|
4594
5082
|
if (node.def) {
|
|
4595
|
-
const alterColumnContext =
|
|
5083
|
+
const alterColumnContext = context.spawn('AlterTableCmd', { alterColumnOptions: true });
|
|
4596
5084
|
const options = ListUtils.unwrapList(node.def)
|
|
4597
5085
|
.map(option => this.visit(option, alterColumnContext))
|
|
4598
5086
|
.join(', ');
|
|
@@ -4632,7 +5120,7 @@ export class Deparser {
|
|
|
4632
5120
|
case 'AT_GenericOptions':
|
|
4633
5121
|
output.push('OPTIONS');
|
|
4634
5122
|
if (node.def) {
|
|
4635
|
-
const alterTableContext =
|
|
5123
|
+
const alterTableContext = context.spawn('AlterTableCmd', { alterTableOptions: true });
|
|
4636
5124
|
const options = ListUtils.unwrapList(node.def)
|
|
4637
5125
|
.map(option => this.visit(option, alterTableContext))
|
|
4638
5126
|
.join(', ');
|
|
@@ -4644,11 +5132,10 @@ export class Deparser {
|
|
|
4644
5132
|
if (node.name) {
|
|
4645
5133
|
output.push(QuoteUtils.quote(node.name));
|
|
4646
5134
|
}
|
|
4647
|
-
output.push('ADD
|
|
5135
|
+
output.push('ADD');
|
|
4648
5136
|
if (node.def) {
|
|
4649
5137
|
output.push(this.visit(node.def, context));
|
|
4650
5138
|
}
|
|
4651
|
-
output.push('AS IDENTITY');
|
|
4652
5139
|
break;
|
|
4653
5140
|
case 'AT_SetIdentity':
|
|
4654
5141
|
output.push('ALTER COLUMN');
|
|
@@ -4736,7 +5223,7 @@ export class Deparser {
|
|
|
4736
5223
|
output.push(this.TypeName(node.returnType, context));
|
|
4737
5224
|
}
|
|
4738
5225
|
if (node.options && node.options.length > 0) {
|
|
4739
|
-
const funcContext =
|
|
5226
|
+
const funcContext = context.spawn('CreateFunctionStmt');
|
|
4740
5227
|
const options = node.options.map((opt) => this.visit(opt, funcContext));
|
|
4741
5228
|
output.push(...options);
|
|
4742
5229
|
}
|
|
@@ -4823,7 +5310,7 @@ export class Deparser {
|
|
|
4823
5310
|
}
|
|
4824
5311
|
output.push('AS', 'ENUM');
|
|
4825
5312
|
if (node.vals && node.vals.length > 0) {
|
|
4826
|
-
const enumContext =
|
|
5313
|
+
const enumContext = context.spawn('CreateEnumStmt', { isEnumValue: true });
|
|
4827
5314
|
const values = ListUtils.unwrapList(node.vals)
|
|
4828
5315
|
.map(val => this.visit(val, enumContext))
|
|
4829
5316
|
.join(', ');
|
|
@@ -4878,9 +5365,8 @@ export class Deparser {
|
|
|
4878
5365
|
output.push(roleName);
|
|
4879
5366
|
}
|
|
4880
5367
|
if (node.options) {
|
|
4881
|
-
const roleContext = { ...context, parentNodeTypes: [...context.parentNodeTypes, 'CreateRoleStmt'] };
|
|
4882
5368
|
const options = ListUtils.unwrapList(node.options)
|
|
4883
|
-
.map(option => this.visit(option,
|
|
5369
|
+
.map(option => this.visit(option, context.spawn('CreateRoleStmt')))
|
|
4884
5370
|
.join(' ');
|
|
4885
5371
|
if (options) {
|
|
4886
5372
|
output.push('WITH');
|
|
@@ -4911,7 +5397,7 @@ export class Deparser {
|
|
|
4911
5397
|
const stringData = this.getNodeData(node.arg);
|
|
4912
5398
|
return `${node.defname}='${stringData.sval}'`;
|
|
4913
5399
|
}
|
|
4914
|
-
return `${node.defname}=${this.visit(node.arg,
|
|
5400
|
+
return `${node.defname}=${this.visit(node.arg, context.spawn('DefElem'))}`;
|
|
4915
5401
|
}
|
|
4916
5402
|
// Handle CREATE OPERATOR boolean flags - MUST be first to preserve case
|
|
4917
5403
|
if (context.parentNodeTypes.includes('DefineStmt') &&
|
|
@@ -4927,13 +5413,13 @@ export class Deparser {
|
|
|
4927
5413
|
if (!node.arg) {
|
|
4928
5414
|
return `NO ${node.defname.toUpperCase()}`;
|
|
4929
5415
|
}
|
|
4930
|
-
const defElemContext =
|
|
5416
|
+
const defElemContext = context.spawn('DefElem');
|
|
4931
5417
|
const argValue = this.visit(node.arg, defElemContext);
|
|
4932
5418
|
return `${node.defname.toUpperCase()} ${argValue}`;
|
|
4933
5419
|
}
|
|
4934
5420
|
// Handle OPTIONS clause - use space format, not equals format
|
|
4935
5421
|
if (node.arg) {
|
|
4936
|
-
const defElemContext =
|
|
5422
|
+
const defElemContext = context.spawn('DefElem');
|
|
4937
5423
|
const argValue = this.visit(node.arg, defElemContext);
|
|
4938
5424
|
if (context.parentNodeTypes.includes('CreateFdwStmt') || context.parentNodeTypes.includes('AlterFdwStmt')) {
|
|
4939
5425
|
const finalValue = typeof argValue === 'string' && !argValue.startsWith("'")
|
|
@@ -4987,7 +5473,7 @@ export class Deparser {
|
|
|
4987
5473
|
if (!node.arg) {
|
|
4988
5474
|
return 'PASSWORD NULL';
|
|
4989
5475
|
}
|
|
4990
|
-
const defElemContext =
|
|
5476
|
+
const defElemContext = context.spawn('DefElem');
|
|
4991
5477
|
const argValue = this.visit(node.arg, defElemContext);
|
|
4992
5478
|
const quotedValue = typeof argValue === 'string' && !argValue.startsWith("'")
|
|
4993
5479
|
? `'${argValue}'`
|
|
@@ -4996,7 +5482,7 @@ export class Deparser {
|
|
|
4996
5482
|
}
|
|
4997
5483
|
}
|
|
4998
5484
|
if (node.arg) {
|
|
4999
|
-
const defElemContext =
|
|
5485
|
+
const defElemContext = context.spawn('DefElem');
|
|
5000
5486
|
const argValue = this.visit(node.arg, defElemContext);
|
|
5001
5487
|
if (context.parentNodeTypes.includes('AlterOperatorStmt')) {
|
|
5002
5488
|
if (node.arg && this.getNodeType(node.arg) === 'TypeName') {
|
|
@@ -5072,7 +5558,7 @@ export class Deparser {
|
|
|
5072
5558
|
if (node.defname === 'sysid') {
|
|
5073
5559
|
return `SYSID ${argValue}`;
|
|
5074
5560
|
}
|
|
5075
|
-
if (argValue === 'true') {
|
|
5561
|
+
if (String(argValue) === 'true') {
|
|
5076
5562
|
// Handle special cases where the positive form has a different name
|
|
5077
5563
|
if (node.defname === 'isreplication') {
|
|
5078
5564
|
return 'REPLICATION';
|
|
@@ -5082,7 +5568,7 @@ export class Deparser {
|
|
|
5082
5568
|
}
|
|
5083
5569
|
return node.defname.toUpperCase();
|
|
5084
5570
|
}
|
|
5085
|
-
else if (argValue === 'false') {
|
|
5571
|
+
else if (String(argValue) === 'false') {
|
|
5086
5572
|
// Handle special cases where the negative form has a different name
|
|
5087
5573
|
if (node.defname === 'canlogin') {
|
|
5088
5574
|
return 'NOLOGIN';
|
|
@@ -5146,7 +5632,7 @@ export class Deparser {
|
|
|
5146
5632
|
}
|
|
5147
5633
|
if (context.parentNodeTypes.includes('DoStmt')) {
|
|
5148
5634
|
if (node.defname === 'as') {
|
|
5149
|
-
const defElemContext =
|
|
5635
|
+
const defElemContext = context.spawn('DefElem');
|
|
5150
5636
|
const argValue = node.arg ? this.visit(node.arg, defElemContext) : '';
|
|
5151
5637
|
if (Array.isArray(argValue)) {
|
|
5152
5638
|
const bodyParts = argValue;
|
|
@@ -5238,11 +5724,15 @@ export class Deparser {
|
|
|
5238
5724
|
if (context.parentNodeTypes.includes('CreateExtensionStmt') || context.parentNodeTypes.includes('AlterExtensionStmt') || context.parentNodeTypes.includes('CreateFdwStmt') || context.parentNodeTypes.includes('AlterFdwStmt')) {
|
|
5239
5725
|
// AlterExtensionStmt specific cases
|
|
5240
5726
|
if (context.parentNodeTypes.includes('AlterExtensionStmt')) {
|
|
5241
|
-
if (node.defname === '
|
|
5242
|
-
|
|
5727
|
+
if (node.defname === 'new_version') {
|
|
5728
|
+
// argValue is unquoted due to DefElem context, so we need to quote it
|
|
5729
|
+
const quotedValue = typeof argValue === 'string' && !argValue.startsWith("'")
|
|
5730
|
+
? `'${argValue}'`
|
|
5731
|
+
: argValue;
|
|
5732
|
+
return `UPDATE TO ${quotedValue}`;
|
|
5243
5733
|
}
|
|
5244
5734
|
if (node.defname === 'schema') {
|
|
5245
|
-
return `SCHEMA ${argValue}`;
|
|
5735
|
+
return `SET SCHEMA ${argValue}`;
|
|
5246
5736
|
}
|
|
5247
5737
|
}
|
|
5248
5738
|
// CreateFdwStmt specific cases
|
|
@@ -5437,7 +5927,7 @@ export class Deparser {
|
|
|
5437
5927
|
}
|
|
5438
5928
|
if (node.options && node.options.length > 0) {
|
|
5439
5929
|
output.push('WITH');
|
|
5440
|
-
const tsContext =
|
|
5930
|
+
const tsContext = context.spawn('CreateTableSpaceStmt');
|
|
5441
5931
|
const options = ListUtils.unwrapList(node.options)
|
|
5442
5932
|
.map(option => this.visit(option, tsContext))
|
|
5443
5933
|
.join(', ');
|
|
@@ -5467,7 +5957,7 @@ export class Deparser {
|
|
|
5467
5957
|
output.push('SET');
|
|
5468
5958
|
}
|
|
5469
5959
|
if (node.options && node.options.length > 0) {
|
|
5470
|
-
const tablespaceContext =
|
|
5960
|
+
const tablespaceContext = context.spawn('AlterTableSpaceOptionsStmt');
|
|
5471
5961
|
const options = ListUtils.unwrapList(node.options)
|
|
5472
5962
|
.map(option => this.visit(option, tablespaceContext))
|
|
5473
5963
|
.join(', ');
|
|
@@ -5484,7 +5974,7 @@ export class Deparser {
|
|
|
5484
5974
|
output.push(this.quoteIfNeeded(node.extname));
|
|
5485
5975
|
}
|
|
5486
5976
|
if (node.options && node.options.length > 0) {
|
|
5487
|
-
const extContext =
|
|
5977
|
+
const extContext = context.spawn('CreateExtensionStmt');
|
|
5488
5978
|
const options = ListUtils.unwrapList(node.options)
|
|
5489
5979
|
.map(option => this.visit(option, extContext))
|
|
5490
5980
|
.join(' ');
|
|
@@ -5498,7 +5988,7 @@ export class Deparser {
|
|
|
5498
5988
|
output.push(this.quoteIfNeeded(node.extname));
|
|
5499
5989
|
}
|
|
5500
5990
|
if (node.options && node.options.length > 0) {
|
|
5501
|
-
const extContext =
|
|
5991
|
+
const extContext = context.spawn('AlterExtensionStmt');
|
|
5502
5992
|
const options = ListUtils.unwrapList(node.options)
|
|
5503
5993
|
.map(option => this.visit(option, extContext))
|
|
5504
5994
|
.join(' ');
|
|
@@ -5506,13 +5996,41 @@ export class Deparser {
|
|
|
5506
5996
|
}
|
|
5507
5997
|
return output.join(' ');
|
|
5508
5998
|
}
|
|
5999
|
+
AlterExtensionContentsStmt(node, context) {
|
|
6000
|
+
const output = ['ALTER', 'EXTENSION'];
|
|
6001
|
+
if (node.extname) {
|
|
6002
|
+
output.push(this.quoteIfNeeded(node.extname));
|
|
6003
|
+
}
|
|
6004
|
+
// Handle action: 1 = ADD, -1 = DROP
|
|
6005
|
+
if (node.action === 1) {
|
|
6006
|
+
output.push('ADD');
|
|
6007
|
+
}
|
|
6008
|
+
else if (node.action === -1) {
|
|
6009
|
+
output.push('DROP');
|
|
6010
|
+
}
|
|
6011
|
+
// Add object type keyword
|
|
6012
|
+
if (node.objtype) {
|
|
6013
|
+
try {
|
|
6014
|
+
output.push(this.getObjectTypeKeyword(node.objtype));
|
|
6015
|
+
}
|
|
6016
|
+
catch {
|
|
6017
|
+
// Fallback to the raw objtype if not supported
|
|
6018
|
+
output.push(node.objtype.toString());
|
|
6019
|
+
}
|
|
6020
|
+
}
|
|
6021
|
+
// Add the object itself
|
|
6022
|
+
if (node.object) {
|
|
6023
|
+
output.push(this.visit(node.object, context));
|
|
6024
|
+
}
|
|
6025
|
+
return output.join(' ');
|
|
6026
|
+
}
|
|
5509
6027
|
CreateFdwStmt(node, context) {
|
|
5510
6028
|
const output = ['CREATE', 'FOREIGN', 'DATA', 'WRAPPER'];
|
|
5511
6029
|
if (node.fdwname) {
|
|
5512
6030
|
output.push(node.fdwname);
|
|
5513
6031
|
}
|
|
5514
6032
|
if (node.func_options && node.func_options.length > 0) {
|
|
5515
|
-
const fdwContext =
|
|
6033
|
+
const fdwContext = context.spawn('CreateFdwStmt');
|
|
5516
6034
|
const funcOptions = ListUtils.unwrapList(node.func_options)
|
|
5517
6035
|
.map(option => this.visit(option, fdwContext))
|
|
5518
6036
|
.join(' ');
|
|
@@ -5520,7 +6038,7 @@ export class Deparser {
|
|
|
5520
6038
|
}
|
|
5521
6039
|
if (node.options && node.options.length > 0) {
|
|
5522
6040
|
output.push('OPTIONS');
|
|
5523
|
-
const fdwContext =
|
|
6041
|
+
const fdwContext = context.spawn('CreateFdwStmt');
|
|
5524
6042
|
const options = ListUtils.unwrapList(node.options)
|
|
5525
6043
|
.map(option => this.visit(option, fdwContext))
|
|
5526
6044
|
.join(', ');
|
|
@@ -5622,7 +6140,7 @@ export class Deparser {
|
|
|
5622
6140
|
output.push('ADD');
|
|
5623
6141
|
if (node.def) {
|
|
5624
6142
|
// Pass domain context to avoid adding constraint names for domain constraints
|
|
5625
|
-
const domainContext =
|
|
6143
|
+
const domainContext = context.spawn('CreateDomainStmt', { isDomainConstraint: true });
|
|
5626
6144
|
output.push(this.visit(node.def, domainContext));
|
|
5627
6145
|
}
|
|
5628
6146
|
break;
|
|
@@ -5648,7 +6166,7 @@ export class Deparser {
|
|
|
5648
6166
|
output.push('ADD');
|
|
5649
6167
|
if (node.def) {
|
|
5650
6168
|
// Pass domain context to avoid adding constraint names for domain constraints
|
|
5651
|
-
const domainContext =
|
|
6169
|
+
const domainContext = context.spawn('CreateDomainStmt', { isDomainConstraint: true });
|
|
5652
6170
|
output.push(this.visit(node.def, domainContext));
|
|
5653
6171
|
}
|
|
5654
6172
|
break;
|
|
@@ -6010,7 +6528,7 @@ export class Deparser {
|
|
|
6010
6528
|
output.push(`${operatorName}(${args.join(', ')})`);
|
|
6011
6529
|
}
|
|
6012
6530
|
else {
|
|
6013
|
-
const objContext =
|
|
6531
|
+
const objContext = context.spawn('CommentStmt', { objtype: node.objtype });
|
|
6014
6532
|
output.push(this.visit(node.object, objContext));
|
|
6015
6533
|
}
|
|
6016
6534
|
}
|
|
@@ -6056,13 +6574,13 @@ export class Deparser {
|
|
|
6056
6574
|
const output = [];
|
|
6057
6575
|
const initialParts = ['CREATE', 'POLICY'];
|
|
6058
6576
|
if (node.policy_name) {
|
|
6059
|
-
initialParts.push(
|
|
6577
|
+
initialParts.push(QuoteUtils.quote(node.policy_name));
|
|
6060
6578
|
}
|
|
6061
6579
|
output.push(initialParts.join(' '));
|
|
6062
6580
|
// Add ON clause on new line in pretty mode
|
|
6063
6581
|
if (node.table) {
|
|
6064
|
-
if (
|
|
6065
|
-
output.push(
|
|
6582
|
+
if (context.isPretty()) {
|
|
6583
|
+
output.push(context.newline() + context.indent(`ON ${this.RangeVar(node.table, context)}`));
|
|
6066
6584
|
}
|
|
6067
6585
|
else {
|
|
6068
6586
|
output.push('ON');
|
|
@@ -6071,24 +6589,24 @@ export class Deparser {
|
|
|
6071
6589
|
}
|
|
6072
6590
|
// Handle AS RESTRICTIVE/PERMISSIVE clause
|
|
6073
6591
|
if (node.permissive === undefined) {
|
|
6074
|
-
if (
|
|
6075
|
-
output.push(
|
|
6592
|
+
if (context.isPretty()) {
|
|
6593
|
+
output.push(context.newline() + context.indent('AS RESTRICTIVE'));
|
|
6076
6594
|
}
|
|
6077
6595
|
else {
|
|
6078
6596
|
output.push('AS', 'RESTRICTIVE');
|
|
6079
6597
|
}
|
|
6080
6598
|
}
|
|
6081
6599
|
else if (node.permissive === true) {
|
|
6082
|
-
if (
|
|
6083
|
-
output.push(
|
|
6600
|
+
if (context.isPretty()) {
|
|
6601
|
+
output.push(context.newline() + context.indent('AS PERMISSIVE'));
|
|
6084
6602
|
}
|
|
6085
6603
|
else {
|
|
6086
6604
|
output.push('AS', 'PERMISSIVE');
|
|
6087
6605
|
}
|
|
6088
6606
|
}
|
|
6089
6607
|
if (node.cmd_name) {
|
|
6090
|
-
if (
|
|
6091
|
-
output.push(
|
|
6608
|
+
if (context.isPretty()) {
|
|
6609
|
+
output.push(context.newline() + context.indent(`FOR ${node.cmd_name.toUpperCase()}`));
|
|
6092
6610
|
}
|
|
6093
6611
|
else {
|
|
6094
6612
|
output.push('FOR', node.cmd_name.toUpperCase());
|
|
@@ -6096,8 +6614,8 @@ export class Deparser {
|
|
|
6096
6614
|
}
|
|
6097
6615
|
if (node.roles && node.roles.length > 0) {
|
|
6098
6616
|
const roles = ListUtils.unwrapList(node.roles).map(role => this.visit(role, context));
|
|
6099
|
-
if (
|
|
6100
|
-
output.push(
|
|
6617
|
+
if (context.isPretty()) {
|
|
6618
|
+
output.push(context.newline() + context.indent(`TO ${roles.join(', ')}`));
|
|
6101
6619
|
}
|
|
6102
6620
|
else {
|
|
6103
6621
|
output.push('TO');
|
|
@@ -6105,11 +6623,11 @@ export class Deparser {
|
|
|
6105
6623
|
}
|
|
6106
6624
|
}
|
|
6107
6625
|
if (node.qual) {
|
|
6108
|
-
if (
|
|
6626
|
+
if (context.isPretty()) {
|
|
6109
6627
|
const qualExpr = this.visit(node.qual, context);
|
|
6110
|
-
output.push(
|
|
6111
|
-
output.push(
|
|
6112
|
-
output.push(
|
|
6628
|
+
output.push(context.newline() + context.indent('USING ('));
|
|
6629
|
+
output.push(context.newline() + context.indent(context.indent(qualExpr)));
|
|
6630
|
+
output.push(context.newline() + context.indent(')'));
|
|
6113
6631
|
}
|
|
6114
6632
|
else {
|
|
6115
6633
|
output.push('USING');
|
|
@@ -6117,23 +6635,23 @@ export class Deparser {
|
|
|
6117
6635
|
}
|
|
6118
6636
|
}
|
|
6119
6637
|
if (node.with_check) {
|
|
6120
|
-
if (
|
|
6638
|
+
if (context.isPretty()) {
|
|
6121
6639
|
const checkExpr = this.visit(node.with_check, context);
|
|
6122
|
-
output.push(
|
|
6123
|
-
output.push(
|
|
6124
|
-
output.push(
|
|
6640
|
+
output.push(context.newline() + context.indent('WITH CHECK ('));
|
|
6641
|
+
output.push(context.newline() + context.indent(context.indent(checkExpr)));
|
|
6642
|
+
output.push(context.newline() + context.indent(')'));
|
|
6125
6643
|
}
|
|
6126
6644
|
else {
|
|
6127
6645
|
output.push('WITH CHECK');
|
|
6128
6646
|
output.push(`(${this.visit(node.with_check, context)})`);
|
|
6129
6647
|
}
|
|
6130
6648
|
}
|
|
6131
|
-
return
|
|
6649
|
+
return context.isPretty() ? output.join('') : output.join(' ');
|
|
6132
6650
|
}
|
|
6133
6651
|
AlterPolicyStmt(node, context) {
|
|
6134
6652
|
const output = ['ALTER', 'POLICY'];
|
|
6135
6653
|
if (node.policy_name) {
|
|
6136
|
-
output.push(
|
|
6654
|
+
output.push(QuoteUtils.quote(node.policy_name));
|
|
6137
6655
|
}
|
|
6138
6656
|
if (node.table) {
|
|
6139
6657
|
output.push('ON');
|
|
@@ -6173,7 +6691,7 @@ export class Deparser {
|
|
|
6173
6691
|
}
|
|
6174
6692
|
if (node.options && node.options.length > 0) {
|
|
6175
6693
|
output.push('OPTIONS');
|
|
6176
|
-
const userMappingContext =
|
|
6694
|
+
const userMappingContext = context.spawn('CreateUserMappingStmt');
|
|
6177
6695
|
const options = ListUtils.unwrapList(node.options).map(opt => this.visit(opt, userMappingContext));
|
|
6178
6696
|
output.push(`(${options.join(', ')})`);
|
|
6179
6697
|
}
|
|
@@ -6356,7 +6874,7 @@ export class Deparser {
|
|
|
6356
6874
|
DoStmt(node, context) {
|
|
6357
6875
|
const output = ['DO'];
|
|
6358
6876
|
if (node.args && node.args.length > 0) {
|
|
6359
|
-
const doContext =
|
|
6877
|
+
const doContext = context.spawn('DoStmt');
|
|
6360
6878
|
const args = ListUtils.unwrapList(node.args);
|
|
6361
6879
|
const processedArgs = [];
|
|
6362
6880
|
for (const arg of args) {
|
|
@@ -6661,7 +7179,7 @@ export class Deparser {
|
|
|
6661
7179
|
ObjectWithArgs(node, context) {
|
|
6662
7180
|
let result = '';
|
|
6663
7181
|
if (node.objname && node.objname.length > 0) {
|
|
6664
|
-
const objContext =
|
|
7182
|
+
const objContext = context.spawn('ObjectWithArgs');
|
|
6665
7183
|
const names = ListUtils.unwrapList(node.objname).map(name => this.visit(name, objContext));
|
|
6666
7184
|
result = names.join('.');
|
|
6667
7185
|
}
|
|
@@ -6703,7 +7221,7 @@ export class Deparser {
|
|
|
6703
7221
|
}
|
|
6704
7222
|
output.push('SET');
|
|
6705
7223
|
if (node.options && node.options.length > 0) {
|
|
6706
|
-
const alterOpContext =
|
|
7224
|
+
const alterOpContext = context.spawn('AlterOperatorStmt');
|
|
6707
7225
|
const options = ListUtils.unwrapList(node.options).map(opt => this.visit(opt, alterOpContext));
|
|
6708
7226
|
output.push(`(${options.join(', ')})`);
|
|
6709
7227
|
}
|
|
@@ -6715,13 +7233,13 @@ export class Deparser {
|
|
|
6715
7233
|
output.push(QuoteUtils.quote(node.fdwname));
|
|
6716
7234
|
}
|
|
6717
7235
|
if (node.func_options && node.func_options.length > 0) {
|
|
6718
|
-
const fdwContext =
|
|
7236
|
+
const fdwContext = context.spawn('AlterFdwStmt');
|
|
6719
7237
|
const funcOptions = ListUtils.unwrapList(node.func_options).map(opt => this.visit(opt, fdwContext));
|
|
6720
7238
|
output.push(funcOptions.join(' '));
|
|
6721
7239
|
}
|
|
6722
7240
|
if (node.options && node.options.length > 0) {
|
|
6723
7241
|
output.push('OPTIONS');
|
|
6724
|
-
const fdwContext =
|
|
7242
|
+
const fdwContext = context.spawn('AlterFdwStmt');
|
|
6725
7243
|
const options = ListUtils.unwrapList(node.options).map(opt => this.visit(opt, fdwContext));
|
|
6726
7244
|
output.push(`(${options.join(', ')})`);
|
|
6727
7245
|
}
|
|
@@ -6747,7 +7265,7 @@ export class Deparser {
|
|
|
6747
7265
|
if (node.options && node.options.length > 0) {
|
|
6748
7266
|
output.push('OPTIONS');
|
|
6749
7267
|
output.push('(');
|
|
6750
|
-
const optionsContext =
|
|
7268
|
+
const optionsContext = context.spawn('CreateForeignServerStmt');
|
|
6751
7269
|
const options = ListUtils.unwrapList(node.options).map(opt => this.visit(opt, optionsContext));
|
|
6752
7270
|
output.push(options.join(', '));
|
|
6753
7271
|
output.push(')');
|
|
@@ -6765,7 +7283,7 @@ export class Deparser {
|
|
|
6765
7283
|
if (node.options && node.options.length > 0) {
|
|
6766
7284
|
output.push('OPTIONS');
|
|
6767
7285
|
output.push('(');
|
|
6768
|
-
const optionsContext =
|
|
7286
|
+
const optionsContext = context.spawn('AlterForeignServerStmt');
|
|
6769
7287
|
const options = ListUtils.unwrapList(node.options).map(opt => this.visit(opt, optionsContext));
|
|
6770
7288
|
output.push(options.join(', '));
|
|
6771
7289
|
output.push(')');
|
|
@@ -6786,7 +7304,7 @@ export class Deparser {
|
|
|
6786
7304
|
}
|
|
6787
7305
|
if (node.options && node.options.length > 0) {
|
|
6788
7306
|
output.push('OPTIONS');
|
|
6789
|
-
const userMappingContext =
|
|
7307
|
+
const userMappingContext = context.spawn('AlterUserMappingStmt');
|
|
6790
7308
|
const options = ListUtils.unwrapList(node.options).map(opt => this.visit(opt, userMappingContext));
|
|
6791
7309
|
output.push(`(${options.join(', ')})`);
|
|
6792
7310
|
}
|
|
@@ -6846,7 +7364,7 @@ export class Deparser {
|
|
|
6846
7364
|
output.push(QuoteUtils.quote(node.local_schema));
|
|
6847
7365
|
}
|
|
6848
7366
|
if (node.options && node.options.length > 0) {
|
|
6849
|
-
const importSchemaContext =
|
|
7367
|
+
const importSchemaContext = context.spawn('ImportForeignSchemaStmt');
|
|
6850
7368
|
const options = ListUtils.unwrapList(node.options).map(opt => this.visit(opt, importSchemaContext));
|
|
6851
7369
|
output.push(`OPTIONS (${options.join(', ')})`);
|
|
6852
7370
|
}
|
|
@@ -6881,7 +7399,7 @@ export class Deparser {
|
|
|
6881
7399
|
ExplainStmt(node, context) {
|
|
6882
7400
|
const output = ['EXPLAIN'];
|
|
6883
7401
|
if (node.options && node.options.length > 0) {
|
|
6884
|
-
const explainContext =
|
|
7402
|
+
const explainContext = context.spawn('ExplainStmt');
|
|
6885
7403
|
const options = ListUtils.unwrapList(node.options).map(option => this.visit(option, explainContext));
|
|
6886
7404
|
output.push(`(${options.join(', ')})`);
|
|
6887
7405
|
}
|
|
@@ -7139,9 +7657,7 @@ export class Deparser {
|
|
|
7139
7657
|
output.push(this.RangeVar(node.relation, context));
|
|
7140
7658
|
}
|
|
7141
7659
|
else if (node.relation) {
|
|
7142
|
-
const rangeVarContext = node.relationType
|
|
7143
|
-
? { ...context, parentNodeTypes: [...context.parentNodeTypes, 'AlterTypeStmt'] }
|
|
7144
|
-
: context;
|
|
7660
|
+
const rangeVarContext = context.spawn('RenameStmt', { objtype: node.relationType });
|
|
7145
7661
|
// Add ON keyword for policy operations
|
|
7146
7662
|
if (node.renameType === 'OBJECT_POLICY') {
|
|
7147
7663
|
output.push('ON');
|
|
@@ -7214,76 +7730,7 @@ export class Deparser {
|
|
|
7214
7730
|
if (!node.objectType) {
|
|
7215
7731
|
throw new Error('AlterOwnerStmt requires objectType');
|
|
7216
7732
|
}
|
|
7217
|
-
|
|
7218
|
-
case 'OBJECT_TABLE':
|
|
7219
|
-
output.push('TABLE');
|
|
7220
|
-
break;
|
|
7221
|
-
case 'OBJECT_VIEW':
|
|
7222
|
-
output.push('VIEW');
|
|
7223
|
-
break;
|
|
7224
|
-
case 'OBJECT_INDEX':
|
|
7225
|
-
output.push('INDEX');
|
|
7226
|
-
break;
|
|
7227
|
-
case 'OBJECT_SEQUENCE':
|
|
7228
|
-
output.push('SEQUENCE');
|
|
7229
|
-
break;
|
|
7230
|
-
case 'OBJECT_FUNCTION':
|
|
7231
|
-
output.push('FUNCTION');
|
|
7232
|
-
break;
|
|
7233
|
-
case 'OBJECT_PROCEDURE':
|
|
7234
|
-
output.push('PROCEDURE');
|
|
7235
|
-
break;
|
|
7236
|
-
case 'OBJECT_SCHEMA':
|
|
7237
|
-
output.push('SCHEMA');
|
|
7238
|
-
break;
|
|
7239
|
-
case 'OBJECT_DATABASE':
|
|
7240
|
-
output.push('DATABASE');
|
|
7241
|
-
break;
|
|
7242
|
-
case 'OBJECT_DOMAIN':
|
|
7243
|
-
output.push('DOMAIN');
|
|
7244
|
-
break;
|
|
7245
|
-
case 'OBJECT_AGGREGATE':
|
|
7246
|
-
output.push('AGGREGATE');
|
|
7247
|
-
break;
|
|
7248
|
-
case 'OBJECT_CONVERSION':
|
|
7249
|
-
output.push('CONVERSION');
|
|
7250
|
-
break;
|
|
7251
|
-
case 'OBJECT_LANGUAGE':
|
|
7252
|
-
output.push('LANGUAGE');
|
|
7253
|
-
break;
|
|
7254
|
-
case 'OBJECT_OPERATOR':
|
|
7255
|
-
output.push('OPERATOR');
|
|
7256
|
-
break;
|
|
7257
|
-
case 'OBJECT_OPFAMILY':
|
|
7258
|
-
output.push('OPERATOR FAMILY');
|
|
7259
|
-
break;
|
|
7260
|
-
case 'OBJECT_OPCLASS':
|
|
7261
|
-
output.push('OPERATOR CLASS');
|
|
7262
|
-
break;
|
|
7263
|
-
case 'OBJECT_TSDICTIONARY':
|
|
7264
|
-
output.push('TEXT SEARCH DICTIONARY');
|
|
7265
|
-
break;
|
|
7266
|
-
case 'OBJECT_TSCONFIGURATION':
|
|
7267
|
-
output.push('TEXT SEARCH CONFIGURATION');
|
|
7268
|
-
break;
|
|
7269
|
-
case 'OBJECT_EVENT_TRIGGER':
|
|
7270
|
-
output.push('EVENT TRIGGER');
|
|
7271
|
-
break;
|
|
7272
|
-
case 'OBJECT_FDW':
|
|
7273
|
-
output.push('FOREIGN DATA WRAPPER');
|
|
7274
|
-
break;
|
|
7275
|
-
case 'OBJECT_FOREIGN_SERVER':
|
|
7276
|
-
output.push('SERVER');
|
|
7277
|
-
break;
|
|
7278
|
-
case 'OBJECT_TYPE':
|
|
7279
|
-
output.push('TYPE');
|
|
7280
|
-
break;
|
|
7281
|
-
case 'OBJECT_COLLATION':
|
|
7282
|
-
output.push('COLLATION');
|
|
7283
|
-
break;
|
|
7284
|
-
default:
|
|
7285
|
-
throw new Error(`Unsupported AlterOwnerStmt objectType: ${node.objectType}`);
|
|
7286
|
-
}
|
|
7733
|
+
output.push(this.getObjectTypeKeyword(node.objectType));
|
|
7287
7734
|
if (node.relation) {
|
|
7288
7735
|
output.push(this.RangeVar(node.relation, context));
|
|
7289
7736
|
}
|
|
@@ -7323,7 +7770,7 @@ export class Deparser {
|
|
|
7323
7770
|
}
|
|
7324
7771
|
}
|
|
7325
7772
|
if (node.privileges && node.privileges.length > 0) {
|
|
7326
|
-
const privilegeContext =
|
|
7773
|
+
const privilegeContext = context.spawn('GrantStmt');
|
|
7327
7774
|
const privileges = ListUtils.unwrapList(node.privileges)
|
|
7328
7775
|
.map(priv => this.visit(priv, privilegeContext))
|
|
7329
7776
|
.join(', ');
|
|
@@ -7631,7 +8078,12 @@ export class Deparser {
|
|
|
7631
8078
|
}
|
|
7632
8079
|
if (node.action) {
|
|
7633
8080
|
const actionStr = this.GrantStmt(node.action, context);
|
|
7634
|
-
|
|
8081
|
+
if (context.isPretty()) {
|
|
8082
|
+
return output.join(' ') + context.newline() + context.indent(actionStr);
|
|
8083
|
+
}
|
|
8084
|
+
else {
|
|
8085
|
+
output.push(actionStr);
|
|
8086
|
+
}
|
|
7635
8087
|
}
|
|
7636
8088
|
return output.join(' ');
|
|
7637
8089
|
}
|
|
@@ -7778,84 +8230,158 @@ export class Deparser {
|
|
|
7778
8230
|
if (node.trigname) {
|
|
7779
8231
|
output.push(QuoteUtils.quote(node.trigname));
|
|
7780
8232
|
}
|
|
7781
|
-
|
|
7782
|
-
|
|
7783
|
-
timing
|
|
7784
|
-
|
|
7785
|
-
|
|
7786
|
-
|
|
7787
|
-
|
|
7788
|
-
|
|
7789
|
-
|
|
7790
|
-
|
|
7791
|
-
events
|
|
7792
|
-
|
|
7793
|
-
events
|
|
7794
|
-
|
|
7795
|
-
events
|
|
7796
|
-
|
|
7797
|
-
|
|
7798
|
-
|
|
7799
|
-
|
|
7800
|
-
|
|
7801
|
-
|
|
7802
|
-
|
|
7803
|
-
.
|
|
7804
|
-
|
|
7805
|
-
|
|
7806
|
-
|
|
7807
|
-
|
|
7808
|
-
|
|
7809
|
-
|
|
7810
|
-
|
|
7811
|
-
|
|
7812
|
-
|
|
7813
|
-
|
|
7814
|
-
|
|
7815
|
-
|
|
7816
|
-
|
|
7817
|
-
|
|
7818
|
-
|
|
7819
|
-
|
|
7820
|
-
|
|
7821
|
-
|
|
7822
|
-
|
|
7823
|
-
|
|
7824
|
-
.
|
|
7825
|
-
|
|
7826
|
-
|
|
7827
|
-
|
|
7828
|
-
|
|
7829
|
-
|
|
7830
|
-
|
|
7831
|
-
|
|
7832
|
-
|
|
7833
|
-
|
|
7834
|
-
|
|
7835
|
-
|
|
7836
|
-
|
|
7837
|
-
|
|
7838
|
-
|
|
7839
|
-
|
|
7840
|
-
|
|
7841
|
-
|
|
7842
|
-
|
|
7843
|
-
|
|
7844
|
-
|
|
7845
|
-
|
|
7846
|
-
|
|
7847
|
-
|
|
7848
|
-
|
|
7849
|
-
|
|
7850
|
-
|
|
7851
|
-
|
|
7852
|
-
output.push(args);
|
|
7853
|
-
output.push(')');
|
|
8233
|
+
if (context.isPretty()) {
|
|
8234
|
+
const components = [];
|
|
8235
|
+
const timing = [];
|
|
8236
|
+
if (node.timing & 2)
|
|
8237
|
+
timing.push('BEFORE');
|
|
8238
|
+
else if (node.timing & 64)
|
|
8239
|
+
timing.push('INSTEAD OF');
|
|
8240
|
+
else
|
|
8241
|
+
timing.push('AFTER');
|
|
8242
|
+
const events = [];
|
|
8243
|
+
if (node.events & 4)
|
|
8244
|
+
events.push('INSERT');
|
|
8245
|
+
if (node.events & 8)
|
|
8246
|
+
events.push('DELETE');
|
|
8247
|
+
if (node.events & 16) {
|
|
8248
|
+
let updateStr = 'UPDATE';
|
|
8249
|
+
if (node.columns && node.columns.length > 0) {
|
|
8250
|
+
const columnNames = ListUtils.unwrapList(node.columns)
|
|
8251
|
+
.map(col => this.visit(col, context))
|
|
8252
|
+
.join(', ');
|
|
8253
|
+
updateStr += ' OF ' + columnNames;
|
|
8254
|
+
}
|
|
8255
|
+
events.push(updateStr);
|
|
8256
|
+
}
|
|
8257
|
+
if (node.events & 32)
|
|
8258
|
+
events.push('TRUNCATE');
|
|
8259
|
+
components.push(context.indent(timing.join(' ') + ' ' + events.join(' OR ')));
|
|
8260
|
+
if (node.relation) {
|
|
8261
|
+
components.push(context.indent('ON ' + this.RangeVar(node.relation, context)));
|
|
8262
|
+
}
|
|
8263
|
+
if (node.transitionRels && node.transitionRels.length > 0) {
|
|
8264
|
+
const transitionClauses = ListUtils.unwrapList(node.transitionRels)
|
|
8265
|
+
.map(rel => this.visit(rel, context))
|
|
8266
|
+
.join(' ');
|
|
8267
|
+
components.push(context.indent('REFERENCING ' + transitionClauses));
|
|
8268
|
+
}
|
|
8269
|
+
if (node.deferrable) {
|
|
8270
|
+
components.push(context.indent('DEFERRABLE'));
|
|
8271
|
+
}
|
|
8272
|
+
if (node.initdeferred) {
|
|
8273
|
+
components.push(context.indent('INITIALLY DEFERRED'));
|
|
8274
|
+
}
|
|
8275
|
+
if (node.row) {
|
|
8276
|
+
components.push(context.indent('FOR EACH ROW'));
|
|
8277
|
+
}
|
|
8278
|
+
else {
|
|
8279
|
+
components.push(context.indent('FOR EACH STATEMENT'));
|
|
8280
|
+
}
|
|
8281
|
+
if (node.whenClause) {
|
|
8282
|
+
const whenStr = 'WHEN (' + this.visit(node.whenClause, context) + ')';
|
|
8283
|
+
components.push(context.indent(whenStr));
|
|
8284
|
+
}
|
|
8285
|
+
let executeStr = 'EXECUTE';
|
|
8286
|
+
if (node.funcname && node.funcname.length > 0) {
|
|
8287
|
+
const funcName = ListUtils.unwrapList(node.funcname)
|
|
8288
|
+
.map(name => this.visit(name, context))
|
|
8289
|
+
.join('.');
|
|
8290
|
+
executeStr += ' PROCEDURE ' + funcName;
|
|
8291
|
+
}
|
|
8292
|
+
if (node.args && node.args.length > 0) {
|
|
8293
|
+
const argContext = context.spawn('CreateTrigStmt', { isStringLiteral: true });
|
|
8294
|
+
const args = ListUtils.unwrapList(node.args)
|
|
8295
|
+
.map(arg => this.visit(arg, argContext))
|
|
8296
|
+
.join(', ');
|
|
8297
|
+
executeStr += '(' + args + ')';
|
|
8298
|
+
}
|
|
8299
|
+
else {
|
|
8300
|
+
executeStr += '()';
|
|
8301
|
+
}
|
|
8302
|
+
components.push(context.indent(executeStr));
|
|
8303
|
+
return output.join(' ') + context.newline() + components.join(context.newline());
|
|
7854
8304
|
}
|
|
7855
8305
|
else {
|
|
7856
|
-
|
|
8306
|
+
const timing = [];
|
|
8307
|
+
if (node.timing & 2)
|
|
8308
|
+
timing.push('BEFORE');
|
|
8309
|
+
else if (node.timing & 64)
|
|
8310
|
+
timing.push('INSTEAD OF');
|
|
8311
|
+
else
|
|
8312
|
+
timing.push('AFTER');
|
|
8313
|
+
output.push(timing.join(' '));
|
|
8314
|
+
const events = [];
|
|
8315
|
+
if (node.events & 4)
|
|
8316
|
+
events.push('INSERT');
|
|
8317
|
+
if (node.events & 8)
|
|
8318
|
+
events.push('DELETE');
|
|
8319
|
+
if (node.events & 16)
|
|
8320
|
+
events.push('UPDATE');
|
|
8321
|
+
if (node.events & 32)
|
|
8322
|
+
events.push('TRUNCATE');
|
|
8323
|
+
output.push(events.join(' OR '));
|
|
8324
|
+
if (node.columns && node.columns.length > 0) {
|
|
8325
|
+
output.push('OF');
|
|
8326
|
+
const columnNames = ListUtils.unwrapList(node.columns)
|
|
8327
|
+
.map(col => this.visit(col, context))
|
|
8328
|
+
.join(', ');
|
|
8329
|
+
output.push(columnNames);
|
|
8330
|
+
}
|
|
8331
|
+
output.push('ON');
|
|
8332
|
+
if (node.relation) {
|
|
8333
|
+
output.push(this.RangeVar(node.relation, context));
|
|
8334
|
+
}
|
|
8335
|
+
if (node.constrrel) {
|
|
8336
|
+
output.push('FROM');
|
|
8337
|
+
output.push(this.RangeVar(node.constrrel, context));
|
|
8338
|
+
}
|
|
8339
|
+
if (node.deferrable) {
|
|
8340
|
+
output.push('DEFERRABLE');
|
|
8341
|
+
}
|
|
8342
|
+
if (node.initdeferred) {
|
|
8343
|
+
output.push('INITIALLY DEFERRED');
|
|
8344
|
+
}
|
|
8345
|
+
if (node.transitionRels && node.transitionRels.length > 0) {
|
|
8346
|
+
output.push('REFERENCING');
|
|
8347
|
+
const transitionClauses = ListUtils.unwrapList(node.transitionRels)
|
|
8348
|
+
.map(rel => this.visit(rel, context))
|
|
8349
|
+
.join(' ');
|
|
8350
|
+
output.push(transitionClauses);
|
|
8351
|
+
}
|
|
8352
|
+
if (node.row) {
|
|
8353
|
+
output.push('FOR EACH ROW');
|
|
8354
|
+
}
|
|
8355
|
+
else {
|
|
8356
|
+
output.push('FOR EACH STATEMENT');
|
|
8357
|
+
}
|
|
8358
|
+
if (node.whenClause) {
|
|
8359
|
+
output.push('WHEN');
|
|
8360
|
+
output.push('(');
|
|
8361
|
+
output.push(this.visit(node.whenClause, context));
|
|
8362
|
+
output.push(')');
|
|
8363
|
+
}
|
|
8364
|
+
output.push('EXECUTE');
|
|
8365
|
+
if (node.funcname && node.funcname.length > 0) {
|
|
8366
|
+
const funcName = ListUtils.unwrapList(node.funcname)
|
|
8367
|
+
.map(name => this.visit(name, context))
|
|
8368
|
+
.join('.');
|
|
8369
|
+
output.push('FUNCTION', funcName);
|
|
8370
|
+
}
|
|
8371
|
+
if (node.args && node.args.length > 0) {
|
|
8372
|
+
output.push('(');
|
|
8373
|
+
const argContext = context.spawn('CreateTrigStmt', { isStringLiteral: true });
|
|
8374
|
+
const args = ListUtils.unwrapList(node.args)
|
|
8375
|
+
.map(arg => this.visit(arg, argContext))
|
|
8376
|
+
.join(', ');
|
|
8377
|
+
output.push(args);
|
|
8378
|
+
output.push(')');
|
|
8379
|
+
}
|
|
8380
|
+
else {
|
|
8381
|
+
output.push('()');
|
|
8382
|
+
}
|
|
8383
|
+
return output.join(' ');
|
|
7857
8384
|
}
|
|
7858
|
-
return output.join(' ');
|
|
7859
8385
|
}
|
|
7860
8386
|
TriggerTransition(node, context) {
|
|
7861
8387
|
const output = [];
|
|
@@ -7881,7 +8407,7 @@ export class Deparser {
|
|
|
7881
8407
|
}
|
|
7882
8408
|
if (node.whenclause && node.whenclause.length > 0) {
|
|
7883
8409
|
output.push('WHEN');
|
|
7884
|
-
const eventTriggerContext =
|
|
8410
|
+
const eventTriggerContext = context.spawn('CreateEventTrigStmt');
|
|
7885
8411
|
const conditions = ListUtils.unwrapList(node.whenclause)
|
|
7886
8412
|
.map(condition => this.visit(condition, eventTriggerContext))
|
|
7887
8413
|
.join(' AND ');
|
|
@@ -8070,7 +8596,7 @@ export class Deparser {
|
|
|
8070
8596
|
output.push(sequenceName.join('.'));
|
|
8071
8597
|
}
|
|
8072
8598
|
if (node.options && node.options.length > 0) {
|
|
8073
|
-
const seqContext =
|
|
8599
|
+
const seqContext = context.spawn('CreateSeqStmt');
|
|
8074
8600
|
const optionStrs = ListUtils.unwrapList(node.options)
|
|
8075
8601
|
.filter(option => option != null && this.getNodeType(option) !== 'undefined')
|
|
8076
8602
|
.map(option => {
|
|
@@ -8107,7 +8633,7 @@ export class Deparser {
|
|
|
8107
8633
|
output.push(sequenceName.join('.'));
|
|
8108
8634
|
}
|
|
8109
8635
|
if (node.options && node.options.length > 0) {
|
|
8110
|
-
const seqContext =
|
|
8636
|
+
const seqContext = context.spawn('AlterSeqStmt');
|
|
8111
8637
|
const optionStrs = ListUtils.unwrapList(node.options)
|
|
8112
8638
|
.filter(option => option && option !== undefined)
|
|
8113
8639
|
.map(option => {
|
|
@@ -8136,7 +8662,7 @@ export class Deparser {
|
|
|
8136
8662
|
CompositeTypeStmt(node, context) {
|
|
8137
8663
|
const output = ['CREATE', 'TYPE'];
|
|
8138
8664
|
if (node.typevar) {
|
|
8139
|
-
const typeContext =
|
|
8665
|
+
const typeContext = context.spawn('CompositeTypeStmt');
|
|
8140
8666
|
output.push(this.RangeVar(node.typevar, typeContext));
|
|
8141
8667
|
}
|
|
8142
8668
|
output.push('AS');
|
|
@@ -8237,7 +8763,7 @@ export class Deparser {
|
|
|
8237
8763
|
output.push(this.RoleSpec(node.role, context));
|
|
8238
8764
|
}
|
|
8239
8765
|
if (node.options) {
|
|
8240
|
-
const roleContext =
|
|
8766
|
+
const roleContext = context.spawn('AlterRoleStmt');
|
|
8241
8767
|
// Handle GROUP operations specially based on action value
|
|
8242
8768
|
if (isGroupStatement) {
|
|
8243
8769
|
const roleMembersOption = ListUtils.unwrapList(node.options).find(option => option.DefElem && option.DefElem.defname === 'rolemembers');
|
|
@@ -8433,14 +8959,14 @@ export class Deparser {
|
|
|
8433
8959
|
AccessPriv(node, context) {
|
|
8434
8960
|
const output = [];
|
|
8435
8961
|
if (node.priv_name) {
|
|
8436
|
-
output.push(node.priv_name);
|
|
8962
|
+
output.push(node.priv_name.toUpperCase());
|
|
8437
8963
|
}
|
|
8438
8964
|
else {
|
|
8439
8965
|
output.push('ALL');
|
|
8440
8966
|
}
|
|
8441
8967
|
if (node.cols && node.cols.length > 0) {
|
|
8442
8968
|
output.push('(');
|
|
8443
|
-
const colContext =
|
|
8969
|
+
const colContext = context.spawn('AccessPriv');
|
|
8444
8970
|
const columns = ListUtils.unwrapList(node.cols).map(col => this.visit(col, colContext));
|
|
8445
8971
|
output.push(columns.join(', '));
|
|
8446
8972
|
output.push(')');
|
|
@@ -8520,7 +9046,7 @@ export class Deparser {
|
|
|
8520
9046
|
output.push(ListUtils.unwrapList(node.defnames).map(name => this.visit(name, context)).join('.'));
|
|
8521
9047
|
}
|
|
8522
9048
|
if (node.definition && node.definition.length > 0) {
|
|
8523
|
-
const defineStmtContext =
|
|
9049
|
+
const defineStmtContext = context.spawn('DefineStmt');
|
|
8524
9050
|
const definitions = ListUtils.unwrapList(node.definition).map(def => {
|
|
8525
9051
|
return this.visit(def, defineStmtContext);
|
|
8526
9052
|
});
|
|
@@ -9006,7 +9532,7 @@ export class Deparser {
|
|
|
9006
9532
|
const operatorNumber = node.number !== undefined ? node.number : 0;
|
|
9007
9533
|
output.push(operatorNumber.toString());
|
|
9008
9534
|
if (node.name) {
|
|
9009
|
-
const opClassContext =
|
|
9535
|
+
const opClassContext = context.spawn('CreateOpClassItem');
|
|
9010
9536
|
output.push(this.ObjectWithArgs(node.name, opClassContext));
|
|
9011
9537
|
}
|
|
9012
9538
|
}
|
|
@@ -9016,7 +9542,7 @@ export class Deparser {
|
|
|
9016
9542
|
const functionNumber = node.number !== undefined ? node.number : 0;
|
|
9017
9543
|
output.push(functionNumber.toString());
|
|
9018
9544
|
if (node.name) {
|
|
9019
|
-
const opClassContext =
|
|
9545
|
+
const opClassContext = context.spawn('CreateOpClassItem');
|
|
9020
9546
|
output.push(this.ObjectWithArgs(node.name, opClassContext));
|
|
9021
9547
|
}
|
|
9022
9548
|
}
|
|
@@ -9714,7 +10240,7 @@ export class Deparser {
|
|
|
9714
10240
|
output.push(this.ObjectWithArgs(node.func, context));
|
|
9715
10241
|
}
|
|
9716
10242
|
if (node.actions && node.actions.length > 0) {
|
|
9717
|
-
const alterFunctionContext =
|
|
10243
|
+
const alterFunctionContext = context.spawn('AlterFunctionStmt');
|
|
9718
10244
|
const actionStrs = ListUtils.unwrapList(node.actions).map(action => this.visit(action, alterFunctionContext));
|
|
9719
10245
|
output.push(actionStrs.join(' '));
|
|
9720
10246
|
}
|
|
@@ -9722,66 +10248,12 @@ export class Deparser {
|
|
|
9722
10248
|
}
|
|
9723
10249
|
AlterObjectSchemaStmt(node, context) {
|
|
9724
10250
|
const output = ['ALTER'];
|
|
9725
|
-
|
|
9726
|
-
|
|
9727
|
-
|
|
9728
|
-
|
|
9729
|
-
|
|
9730
|
-
|
|
9731
|
-
break;
|
|
9732
|
-
case 'OBJECT_FUNCTION':
|
|
9733
|
-
output.push('FUNCTION');
|
|
9734
|
-
break;
|
|
9735
|
-
case 'OBJECT_TYPE':
|
|
9736
|
-
output.push('TYPE');
|
|
9737
|
-
break;
|
|
9738
|
-
case 'OBJECT_DOMAIN':
|
|
9739
|
-
output.push('DOMAIN');
|
|
9740
|
-
break;
|
|
9741
|
-
case 'OBJECT_SEQUENCE':
|
|
9742
|
-
output.push('SEQUENCE');
|
|
9743
|
-
break;
|
|
9744
|
-
case 'OBJECT_OPCLASS':
|
|
9745
|
-
output.push('OPERATOR CLASS');
|
|
9746
|
-
break;
|
|
9747
|
-
case 'OBJECT_OPFAMILY':
|
|
9748
|
-
output.push('OPERATOR FAMILY');
|
|
9749
|
-
break;
|
|
9750
|
-
case 'OBJECT_OPERATOR':
|
|
9751
|
-
output.push('OPERATOR');
|
|
9752
|
-
break;
|
|
9753
|
-
case 'OBJECT_TYPE':
|
|
9754
|
-
output.push('TYPE');
|
|
9755
|
-
break;
|
|
9756
|
-
case 'OBJECT_COLLATION':
|
|
9757
|
-
output.push('COLLATION');
|
|
9758
|
-
break;
|
|
9759
|
-
case 'OBJECT_CONVERSION':
|
|
9760
|
-
output.push('CONVERSION');
|
|
9761
|
-
break;
|
|
9762
|
-
case 'OBJECT_TSPARSER':
|
|
9763
|
-
output.push('TEXT SEARCH PARSER');
|
|
9764
|
-
break;
|
|
9765
|
-
case 'OBJECT_TSCONFIGURATION':
|
|
9766
|
-
output.push('TEXT SEARCH CONFIGURATION');
|
|
9767
|
-
break;
|
|
9768
|
-
case 'OBJECT_TSTEMPLATE':
|
|
9769
|
-
output.push('TEXT SEARCH TEMPLATE');
|
|
9770
|
-
break;
|
|
9771
|
-
case 'OBJECT_TSDICTIONARY':
|
|
9772
|
-
output.push('TEXT SEARCH DICTIONARY');
|
|
9773
|
-
break;
|
|
9774
|
-
case 'OBJECT_AGGREGATE':
|
|
9775
|
-
output.push('AGGREGATE');
|
|
9776
|
-
break;
|
|
9777
|
-
case 'OBJECT_FOREIGN_TABLE':
|
|
9778
|
-
output.push('FOREIGN TABLE');
|
|
9779
|
-
break;
|
|
9780
|
-
case 'OBJECT_MATVIEW':
|
|
9781
|
-
output.push('MATERIALIZED VIEW');
|
|
9782
|
-
break;
|
|
9783
|
-
default:
|
|
9784
|
-
output.push(node.objectType.toString());
|
|
10251
|
+
try {
|
|
10252
|
+
output.push(this.getObjectTypeKeyword(node.objectType));
|
|
10253
|
+
}
|
|
10254
|
+
catch {
|
|
10255
|
+
// Fallback to objectType string if not supported
|
|
10256
|
+
output.push(node.objectType.toString());
|
|
9785
10257
|
}
|
|
9786
10258
|
if (node.missing_ok) {
|
|
9787
10259
|
output.push('IF EXISTS');
|
|
@@ -9958,7 +10430,7 @@ export class Deparser {
|
|
|
9958
10430
|
CreateForeignTableStmt(node, context) {
|
|
9959
10431
|
const output = ['CREATE FOREIGN TABLE'];
|
|
9960
10432
|
if (node.base && node.base.relation) {
|
|
9961
|
-
const relationContext =
|
|
10433
|
+
const relationContext = context.spawn('CreateForeignTableStmt');
|
|
9962
10434
|
// Handle relation node directly as RangeVar since it contains the RangeVar properties
|
|
9963
10435
|
output.push(this.RangeVar(node.base.relation, relationContext));
|
|
9964
10436
|
}
|
|
@@ -9988,7 +10460,7 @@ export class Deparser {
|
|
|
9988
10460
|
output.push(QuoteUtils.quote(node.servername));
|
|
9989
10461
|
}
|
|
9990
10462
|
if (node.options && node.options.length > 0) {
|
|
9991
|
-
const foreignTableContext =
|
|
10463
|
+
const foreignTableContext = context.spawn('CreateForeignTableStmt');
|
|
9992
10464
|
const optionStrs = ListUtils.unwrapList(node.options).map(opt => this.visit(opt, foreignTableContext));
|
|
9993
10465
|
output.push(`OPTIONS (${optionStrs.join(', ')})`);
|
|
9994
10466
|
}
|