pgsql-deparser 16.1.1 → 16.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,10 +5,29 @@
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
7
  exports.Deparser = void 0;
8
- const base_1 = require("./visitors/base");
9
- const sql_formatter_1 = require("./utils/sql-formatter");
10
- const quote_utils_1 = require("./utils/quote-utils");
8
+ const quotes_1 = require("@pgsql/quotes");
11
9
  const list_utils_1 = require("./utils/list-utils");
10
+ const sql_formatter_1 = require("./utils/sql-formatter");
11
+ const base_1 = require("./visitors/base");
12
+ // WindowDef.frameOptions bit flags (src/include/nodes/parsenodes.h)
13
+ const FRAMEOPTION_NONDEFAULT = 0x00001;
14
+ const FRAMEOPTION_RANGE = 0x00002;
15
+ const FRAMEOPTION_ROWS = 0x00004;
16
+ const FRAMEOPTION_GROUPS = 0x00008;
17
+ const FRAMEOPTION_BETWEEN = 0x00010;
18
+ const FRAMEOPTION_START_UNBOUNDED_PRECEDING = 0x00020;
19
+ const FRAMEOPTION_END_UNBOUNDED_PRECEDING = 0x00040;
20
+ const FRAMEOPTION_START_UNBOUNDED_FOLLOWING = 0x00080;
21
+ const FRAMEOPTION_END_UNBOUNDED_FOLLOWING = 0x00100;
22
+ const FRAMEOPTION_START_CURRENT_ROW = 0x00200;
23
+ const FRAMEOPTION_END_CURRENT_ROW = 0x00400;
24
+ const FRAMEOPTION_START_OFFSET_PRECEDING = 0x00800;
25
+ const FRAMEOPTION_END_OFFSET_PRECEDING = 0x01000;
26
+ const FRAMEOPTION_START_OFFSET_FOLLOWING = 0x02000;
27
+ const FRAMEOPTION_END_OFFSET_FOLLOWING = 0x04000;
28
+ const FRAMEOPTION_EXCLUDE_CURRENT_ROW = 0x08000;
29
+ const FRAMEOPTION_EXCLUDE_GROUP = 0x10000;
30
+ const FRAMEOPTION_EXCLUDE_TIES = 0x20000;
12
31
  /**
13
32
  * List of real PostgreSQL built-in types as they appear in pg_catalog.pg_type.typname.
14
33
  * These are stored in lowercase in PostgreSQL system catalogs.
@@ -107,6 +126,36 @@ function isWrappedParseResult(obj) {
107
126
  * The deparser automatically detects bare ParseResult objects for backward
108
127
  * compatibility and wraps them internally for consistent processing.
109
128
  */
129
+ function formatBitString(bsval) {
130
+ const quote = (value) => value.replace(/'/g, "''");
131
+ if (/^x[0-9A-Fa-f]*$/.test(bsval)) {
132
+ return `x'${bsval.substring(1)}'`;
133
+ }
134
+ if (bsval.startsWith('b')) {
135
+ return `b'${quote(bsval.substring(1))}'`;
136
+ }
137
+ return `b'${quote(bsval)}'`;
138
+ }
139
+ // A dollar-quoted body ends at the first occurrence of its tag, including one
140
+ // formed by the body's trailing characters plus the closing tag (`...$` + `$$`).
141
+ function dollarTagConflicts(body, tag) {
142
+ return (body + tag).indexOf(tag) < body.length;
143
+ }
144
+ const NUMERIC_LITERAL = /^[+-]?(?:0[xX](?:_?[0-9A-Fa-f])+|0[oO](?:_?[0-7])+|0[bB](?:_?[01])+|(?:\d(?:_?\d)*(?:\.(?:\d(?:_?\d)*)?)?|\.\d(?:_?\d)*)(?:[eE][+-]?\d(?:_?\d)*)?)$/;
145
+ function formatInteger(ival) {
146
+ const value = String(ival);
147
+ if (!/^[+-]?\d+$/.test(value)) {
148
+ throw new Error(`Invalid integer literal: ${value}`);
149
+ }
150
+ return value;
151
+ }
152
+ function formatNumeric(fval) {
153
+ const value = String(fval);
154
+ if (!NUMERIC_LITERAL.test(value)) {
155
+ throw new Error(`Invalid numeric literal: ${value}`);
156
+ }
157
+ return value;
158
+ }
110
159
  class Deparser {
111
160
  tree;
112
161
  options;
@@ -166,10 +215,19 @@ class Deparser {
166
215
  */
167
216
  getFunctionDelimiter(body) {
168
217
  const delimiter = this.options.functionDelimiter || '$$';
169
- if (body.includes(delimiter)) {
170
- return this.options.functionDelimiterFallback || '$EOFCODE$';
218
+ if (!dollarTagConflicts(body, delimiter)) {
219
+ return delimiter;
171
220
  }
172
- return delimiter;
221
+ const fallback = this.options.functionDelimiterFallback || '$EOFCODE$';
222
+ if (!dollarTagConflicts(body, fallback)) {
223
+ return fallback;
224
+ }
225
+ const base = fallback.slice(0, -1);
226
+ let counter = 1;
227
+ while (dollarTagConflicts(body, `${base}${counter}$`)) {
228
+ counter++;
229
+ }
230
+ return `${base}${counter}$`;
173
231
  }
174
232
  /**
175
233
  * Maps ObjectType enum values to their corresponding SQL keywords
@@ -446,12 +504,7 @@ class Deparser {
446
504
  // Check if single target is complex - if so, use multiline format
447
505
  if (this.isComplexSelectTarget(targetNode)) {
448
506
  output.push('SELECT' + distinctPart);
449
- if (this.containsMultilineStringLiteral(target)) {
450
- output.push(target);
451
- }
452
- else {
453
- output.push(context.indent(target));
454
- }
507
+ output.push(context.indent(target));
455
508
  }
456
509
  else {
457
510
  output.push('SELECT' + distinctPart + ' ' + target);
@@ -461,9 +514,6 @@ class Deparser {
461
514
  const targetStrings = targetList
462
515
  .map(e => {
463
516
  const targetStr = this.visit(e, context.spawn('SelectStmt', { select: true }));
464
- if (this.containsMultilineStringLiteral(targetStr)) {
465
- return targetStr;
466
- }
467
517
  return context.indent(targetStr);
468
518
  });
469
519
  const formattedTargets = targetStrings.join(',' + context.newline());
@@ -515,9 +565,6 @@ class Deparser {
515
565
  return context.parens(values.join(', '));
516
566
  });
517
567
  const indentedTuples = lists.map(tuple => {
518
- if (this.containsMultilineStringLiteral(tuple)) {
519
- return tuple;
520
- }
521
568
  return context.indent(tuple);
522
569
  });
523
570
  output.push(indentedTuples.join(',\n'));
@@ -537,9 +584,6 @@ class Deparser {
537
584
  const groupItems = groupList
538
585
  .map(e => {
539
586
  const groupStr = this.visit(e, context.spawn('SelectStmt', { group: true, indentLevel: context.indentLevel + 1 }));
540
- if (this.containsMultilineStringLiteral(groupStr)) {
541
- return groupStr;
542
- }
543
587
  return context.indent(groupStr);
544
588
  })
545
589
  .join(',' + context.newline());
@@ -558,12 +602,7 @@ class Deparser {
558
602
  if (context.isPretty()) {
559
603
  output.push('HAVING');
560
604
  const havingStr = this.visit(node.havingClause, context);
561
- if (this.containsMultilineStringLiteral(havingStr)) {
562
- output.push(havingStr);
563
- }
564
- else {
565
- output.push(context.indent(havingStr));
566
- }
605
+ output.push(context.indent(havingStr));
567
606
  }
568
607
  else {
569
608
  output.push('HAVING');
@@ -584,9 +623,6 @@ class Deparser {
584
623
  const sortItems = sortList
585
624
  .map(e => {
586
625
  const sortStr = this.visit(e, context.spawn('SelectStmt', { sort: true, indentLevel: context.indentLevel + 1 }));
587
- if (this.containsMultilineStringLiteral(sortStr)) {
588
- return sortStr;
589
- }
590
626
  return context.indent(sortStr);
591
627
  })
592
628
  .join(',' + context.newline());
@@ -662,10 +698,15 @@ class Deparser {
662
698
  return context.format([leftExpr, operator, rightExpr]);
663
699
  }
664
700
  else if (rexpr) {
665
- return context.format([
666
- this.deparseOperatorName(name, context),
667
- this.visit(rexpr, context)
668
- ]);
701
+ // Unary operator (e.g., unary minus: - expr)
702
+ const operator = this.deparseOperatorName(name, context);
703
+ let rightExpr = this.visit(rexpr, context);
704
+ // Wrap in parentheses if rexpr is a binary A_Expr to preserve semantics
705
+ // e.g., -(a - b) must stay -(a - b), not become -a - b
706
+ if (rexpr && 'A_Expr' in rexpr && rexpr.A_Expr?.kind === 'AEXPR_OP' && rexpr.A_Expr?.lexpr) {
707
+ rightExpr = context.parens(rightExpr);
708
+ }
709
+ return context.format([operator, rightExpr]);
669
710
  }
670
711
  break;
671
712
  case 'AEXPR_OP_ANY':
@@ -845,15 +886,15 @@ class Deparser {
845
886
  getOperatorPrecedence(operator) {
846
887
  const precedence = {
847
888
  '||': 1, // string concatenation
848
- 'OR': 2, // logical OR
849
- 'AND': 3, // logical AND
850
- 'NOT': 4, // logical NOT
851
- 'IS': 5, // IS NULL, IS NOT NULL, etc.
852
- 'IN': 5, // IN, NOT IN
853
- 'BETWEEN': 5, // BETWEEN, NOT BETWEEN
854
- 'LIKE': 5, // LIKE, ILIKE, SIMILAR TO
855
- 'ILIKE': 5,
856
- 'SIMILAR': 5,
889
+ OR: 2, // logical OR
890
+ AND: 3, // logical AND
891
+ NOT: 4, // logical NOT
892
+ IS: 5, // IS NULL, IS NOT NULL, etc.
893
+ IN: 5, // IN, NOT IN
894
+ BETWEEN: 5, // BETWEEN, NOT BETWEEN
895
+ LIKE: 5, // LIKE, ILIKE, SIMILAR TO
896
+ ILIKE: 5,
897
+ SIMILAR: 5,
857
898
  '<': 6, // comparison operators
858
899
  '<=': 6,
859
900
  '>': 6,
@@ -983,6 +1024,12 @@ class Deparser {
983
1024
  output.push(context.parens(columnNames.join(', ')));
984
1025
  }
985
1026
  }
1027
+ if (node.override === 'OVERRIDING_USER_VALUE') {
1028
+ output.push('OVERRIDING USER VALUE');
1029
+ }
1030
+ else if (node.override === 'OVERRIDING_SYSTEM_VALUE') {
1031
+ output.push('OVERRIDING SYSTEM VALUE');
1032
+ }
986
1033
  if (node.selectStmt) {
987
1034
  output.push(this.visit(node.selectStmt, context));
988
1035
  }
@@ -1025,7 +1072,14 @@ class Deparser {
1025
1072
  else {
1026
1073
  const updateContext = context.spawn('UpdateStmt', { update: true });
1027
1074
  const targets = targetList.map(target => this.visit(target, updateContext));
1028
- output.push(targets.join(', '));
1075
+ if (context.isPretty()) {
1076
+ // Put each assignment on its own line for pretty printing
1077
+ const indentedTargets = targets.map(target => context.indent(target));
1078
+ output[output.length - 1] += '\n' + indentedTargets.join(',\n');
1079
+ }
1080
+ else {
1081
+ output.push(targets.join(', '));
1082
+ }
1029
1083
  }
1030
1084
  }
1031
1085
  if (node.onConflictClause.whereClause) {
@@ -1037,11 +1091,8 @@ class Deparser {
1037
1091
  output.push('DO NOTHING');
1038
1092
  }
1039
1093
  }
1040
- if (node.returningList) {
1041
- output.push('RETURNING');
1042
- const returningList = list_utils_1.ListUtils.unwrapList(node.returningList);
1043
- const returns = returningList.map(ret => this.visit(ret, context));
1044
- output.push(returns.join(', '));
1094
+ if (node.returningClause) {
1095
+ output.push(this.ReturningClause(node.returningClause, context));
1045
1096
  }
1046
1097
  return output.join(' ');
1047
1098
  }
@@ -1055,38 +1106,8 @@ class Deparser {
1055
1106
  output.push(this.RangeVar(node.relation, context));
1056
1107
  }
1057
1108
  output.push('SET');
1058
- const targetList = list_utils_1.ListUtils.unwrapList(node.targetList);
1059
- if (targetList && targetList.length) {
1060
- const firstTarget = targetList[0];
1061
- const processedTargets = new Set();
1062
- const assignmentParts = [];
1063
- for (let i = 0; i < targetList.length; i++) {
1064
- if (processedTargets.has(i))
1065
- continue;
1066
- const target = targetList[i];
1067
- const multiAssignRef = target.ResTarget?.val?.MultiAssignRef;
1068
- if (multiAssignRef) {
1069
- const relatedTargets = [];
1070
- for (let j = i; j < targetList.length; j++) {
1071
- const otherTarget = targetList[j];
1072
- const otherMultiAssignRef = otherTarget.ResTarget?.val?.MultiAssignRef;
1073
- if (otherMultiAssignRef &&
1074
- JSON.stringify(otherMultiAssignRef.source) === JSON.stringify(multiAssignRef.source)) {
1075
- relatedTargets.push(otherTarget);
1076
- processedTargets.add(j);
1077
- }
1078
- }
1079
- const names = relatedTargets.map(t => t.ResTarget.name);
1080
- const multiAssignment = `${context.parens(names.join(', '))} = ${this.visit(multiAssignRef.source, context)}`;
1081
- assignmentParts.push(multiAssignment);
1082
- }
1083
- else {
1084
- // Handle regular single-column assignment
1085
- assignmentParts.push(this.visit(target, context.spawn('UpdateStmt', { update: true })));
1086
- processedTargets.add(i);
1087
- }
1088
- }
1089
- output.push(assignmentParts.join(','));
1109
+ if (node.targetList && node.targetList.length > 0) {
1110
+ output.push(this.formatUpdateAssignments(node.targetList, context));
1090
1111
  }
1091
1112
  if (node.fromClause) {
1092
1113
  output.push('FROM');
@@ -1098,12 +1119,41 @@ class Deparser {
1098
1119
  output.push('WHERE');
1099
1120
  output.push(this.visit(node.whereClause, context));
1100
1121
  }
1101
- if (node.returningList) {
1102
- output.push('RETURNING');
1103
- output.push(this.deparseReturningList(node.returningList, context));
1122
+ if (node.returningClause) {
1123
+ output.push(this.ReturningClause(node.returningClause, context));
1104
1124
  }
1105
1125
  return output.join(' ');
1106
1126
  }
1127
+ formatUpdateAssignments(targets, context) {
1128
+ const targetList = list_utils_1.ListUtils.unwrapList(targets);
1129
+ const processedTargets = new Set();
1130
+ const assignmentParts = [];
1131
+ for (let i = 0; i < targetList.length; i++) {
1132
+ if (processedTargets.has(i))
1133
+ continue;
1134
+ const target = targetList[i];
1135
+ const multiAssignRef = target.ResTarget?.val?.MultiAssignRef;
1136
+ if (multiAssignRef) {
1137
+ const relatedTargets = [];
1138
+ for (let j = i; j < targetList.length; j++) {
1139
+ const otherTarget = targetList[j];
1140
+ const otherMultiAssignRef = otherTarget.ResTarget?.val?.MultiAssignRef;
1141
+ if (otherMultiAssignRef &&
1142
+ JSON.stringify(otherMultiAssignRef.source) === JSON.stringify(multiAssignRef.source)) {
1143
+ relatedTargets.push(otherTarget);
1144
+ processedTargets.add(j);
1145
+ }
1146
+ }
1147
+ const names = relatedTargets.map(t => quotes_1.QuoteUtils.quoteIdentifier(t.ResTarget.name));
1148
+ assignmentParts.push(`${context.parens(names.join(', '))} = ${this.visit(multiAssignRef.source, context)}`);
1149
+ }
1150
+ else {
1151
+ assignmentParts.push(this.visit(target, context.spawn('UpdateStmt', { update: true })));
1152
+ processedTargets.add(i);
1153
+ }
1154
+ }
1155
+ return assignmentParts.join(', ');
1156
+ }
1107
1157
  DeleteStmt(node, context) {
1108
1158
  try {
1109
1159
  const output = [];
@@ -1151,13 +1201,12 @@ class Deparser {
1151
1201
  throw new Error(`Error deparsing DeleteStmt: ${error instanceof Error ? error.message : String(error)}`);
1152
1202
  }
1153
1203
  }
1154
- if (node.returningList) {
1155
- output.push('RETURNING');
1204
+ if (node.returningClause) {
1156
1205
  try {
1157
- output.push(this.deparseReturningList(node.returningList, context));
1206
+ output.push(this.ReturningClause(node.returningClause, context));
1158
1207
  }
1159
1208
  catch (error) {
1160
- console.warn(`Error processing returningList in DeleteStmt: ${error instanceof Error ? error.message : String(error)}`);
1209
+ console.warn(`Error processing returningClause in DeleteStmt: ${error instanceof Error ? error.message : String(error)}`);
1161
1210
  throw new Error(`Error deparsing DeleteStmt: ${error instanceof Error ? error.message : String(error)}`);
1162
1211
  }
1163
1212
  }
@@ -1178,9 +1227,6 @@ class Deparser {
1178
1227
  const cteStrings = ctes.map((cte, index) => {
1179
1228
  const cteStr = this.visit(cte, context);
1180
1229
  const prefix = index === 0 ? context.newline() : ',' + context.newline();
1181
- if (this.containsMultilineStringLiteral(cteStr)) {
1182
- return prefix + cteStr;
1183
- }
1184
1230
  return prefix + context.indent(cteStr);
1185
1231
  });
1186
1232
  output.push(cteStrings.join(''));
@@ -1195,12 +1241,12 @@ class Deparser {
1195
1241
  ResTarget(node, context) {
1196
1242
  const output = [];
1197
1243
  if (context.update && node.name) {
1198
- output.push(quote_utils_1.QuoteUtils.quote(node.name));
1244
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.name));
1199
1245
  // Handle indirection (array indexing, field access, etc.)
1200
1246
  if (node.indirection && node.indirection.length > 0) {
1201
1247
  const indirectionStrs = list_utils_1.ListUtils.unwrapList(node.indirection).map(item => {
1202
1248
  if (item.String) {
1203
- return `.${quote_utils_1.QuoteUtils.quote(item.String.sval || item.String.str)}`;
1249
+ return `.${quotes_1.QuoteUtils.quoteIdentifierAfterDot(item.String.sval || item.String.str)}`;
1204
1250
  }
1205
1251
  return this.visit(item, context);
1206
1252
  });
@@ -1212,12 +1258,12 @@ class Deparser {
1212
1258
  }
1213
1259
  }
1214
1260
  else if (context.insertColumns && node.name) {
1215
- output.push(quote_utils_1.QuoteUtils.quote(node.name));
1261
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.name));
1216
1262
  // Handle indirection for INSERT column lists (e.g., q.c1.r)
1217
1263
  if (node.indirection && node.indirection.length > 0) {
1218
1264
  const indirectionStrs = list_utils_1.ListUtils.unwrapList(node.indirection).map(item => {
1219
1265
  if (item.String) {
1220
- return `.${quote_utils_1.QuoteUtils.quote(item.String.sval || item.String.str)}`;
1266
+ return `.${quotes_1.QuoteUtils.quoteIdentifierAfterDot(item.String.sval || item.String.str)}`;
1221
1267
  }
1222
1268
  return this.visit(item, context);
1223
1269
  });
@@ -1230,11 +1276,53 @@ class Deparser {
1230
1276
  }
1231
1277
  if (node.name) {
1232
1278
  output.push('AS');
1233
- output.push(quote_utils_1.QuoteUtils.quote(node.name));
1279
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.name));
1234
1280
  }
1235
1281
  }
1236
1282
  return output.join(' ');
1237
1283
  }
1284
+ ATAlterConstraint(node, context) {
1285
+ const output = ['ALTER CONSTRAINT'];
1286
+ if (node.conname) {
1287
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.conname));
1288
+ }
1289
+ if (node.alterEnforceability) {
1290
+ output.push(node.is_enforced ? 'ENFORCED' : 'NOT ENFORCED');
1291
+ }
1292
+ if (node.alterDeferrability) {
1293
+ output.push(node.deferrable ? 'DEFERRABLE' : 'NOT DEFERRABLE');
1294
+ if (node.initdeferred) {
1295
+ output.push('INITIALLY DEFERRED');
1296
+ }
1297
+ }
1298
+ if (node.alterInheritability) {
1299
+ output.push(node.noinherit ? 'NO INHERIT' : 'INHERIT');
1300
+ }
1301
+ return output.join(' ');
1302
+ }
1303
+ deparseKeyAttrs(attrs, withPeriod, context) {
1304
+ const items = list_utils_1.ListUtils.unwrapList(attrs).map(attr => this.visit(attr, context));
1305
+ if (withPeriod && items.length > 0) {
1306
+ items[items.length - 1] = `PERIOD ${items[items.length - 1]}`;
1307
+ }
1308
+ return items.join(', ');
1309
+ }
1310
+ ReturningClause(node, context) {
1311
+ const output = ['RETURNING'];
1312
+ if (node.options && node.options.length > 0) {
1313
+ const options = list_utils_1.ListUtils.unwrapList(node.options)
1314
+ .map(option => this.visit(option, context));
1315
+ output.push(`WITH (${options.join(', ')})`);
1316
+ }
1317
+ if (node.exprs && node.exprs.length > 0) {
1318
+ output.push(this.deparseReturningList(node.exprs, context));
1319
+ }
1320
+ return output.join(' ');
1321
+ }
1322
+ ReturningOption(node, context) {
1323
+ const keyword = node.option === 'RETURNING_OPTION_NEW' ? 'NEW' : 'OLD';
1324
+ return `${keyword} AS ${quotes_1.QuoteUtils.quoteIdentifier(node.value)}`;
1325
+ }
1238
1326
  deparseReturningList(list, context) {
1239
1327
  return list_utils_1.ListUtils.unwrapList(list)
1240
1328
  .filter(item => item != null && this.getNodeType(item) !== 'undefined')
@@ -1244,7 +1332,7 @@ class Deparser {
1244
1332
  if (this.getNodeType(item) === 'ResTarget') {
1245
1333
  const resTarget = this.getNodeData(item);
1246
1334
  const val = resTarget.val ? this.visit(resTarget.val, context) : '';
1247
- const alias = resTarget.name ? ` AS ${quote_utils_1.QuoteUtils.quote(resTarget.name)}` : '';
1335
+ const alias = resTarget.name ? ` AS ${quotes_1.QuoteUtils.quoteIdentifier(resTarget.name)}` : '';
1248
1336
  return val + alias;
1249
1337
  }
1250
1338
  else {
@@ -1299,7 +1387,8 @@ class Deparser {
1299
1387
  FuncCall(node, context) {
1300
1388
  const funcname = list_utils_1.ListUtils.unwrapList(node.funcname);
1301
1389
  const args = list_utils_1.ListUtils.unwrapList(node.args);
1302
- const name = funcname.map(n => this.visit(n, context)).join('.');
1390
+ const funcnameParts = funcname.map((n) => n.String?.sval || n.String?.str || '').filter((s) => s);
1391
+ const name = quotes_1.QuoteUtils.quoteDottedName(funcnameParts);
1303
1392
  // Handle special SQL syntax functions like XMLEXISTS and EXTRACT
1304
1393
  if (node.funcformat === 'COERCE_SQL_SYNTAX' && name === 'pg_catalog.xmlexists' && args.length >= 2) {
1305
1394
  const xpath = this.visit(args[0], context);
@@ -1308,8 +1397,15 @@ class Deparser {
1308
1397
  }
1309
1398
  // Handle EXTRACT function with SQL syntax
1310
1399
  if (node.funcformat === 'COERCE_SQL_SYNTAX' && name === 'pg_catalog.extract' && args.length >= 2) {
1311
- const field = this.visit(args[0], context);
1400
+ let field = this.visit(args[0], context);
1312
1401
  const source = this.visit(args[1], context);
1402
+ // EXTRACT requires an unquoted uppercase keyword (EPOCH, YEAR, etc.)
1403
+ // but A_Const sval deparsing wraps it in single quotes — strip and uppercase
1404
+ // only when it is spelled the way the bare-keyword form parses back
1405
+ if (/^'(?:year|month|day|hour|minute|second)'$/.test(field)
1406
+ || (/^'[a-z_][a-z0-9_]*'$/.test(field) && (0, quotes_1.keywordKindOf)(field.slice(1, -1)) === 'NO_KEYWORD')) {
1407
+ field = field.slice(1, -1).toUpperCase();
1408
+ }
1313
1409
  return `EXTRACT(${field} FROM ${source})`;
1314
1410
  }
1315
1411
  // Handle TRIM function with SQL syntax (TRIM TRAILING/LEADING/BOTH)
@@ -1469,43 +1565,41 @@ class Deparser {
1469
1565
  result += ` FILTER (WHERE ${this.visit(node.agg_filter, context)})`;
1470
1566
  }
1471
1567
  if (node.over) {
1472
- // Handle named window references first
1473
- if (node.over.name) {
1474
- result += ` OVER ${node.over.name}`;
1475
- }
1476
- else {
1477
- const windowParts = [];
1478
- if (node.over.partitionClause) {
1479
- const partitions = list_utils_1.ListUtils.unwrapList(node.over.partitionClause);
1480
- const partitionStrs = partitions.map(p => this.visit(p, context));
1481
- windowParts.push(`PARTITION BY ${partitionStrs.join(', ')}`);
1482
- }
1483
- if (node.over.orderClause) {
1484
- const orders = list_utils_1.ListUtils.unwrapList(node.over.orderClause);
1485
- const orderStrs = orders.map(o => this.visit(o, context));
1486
- windowParts.push(`ORDER BY ${orderStrs.join(', ')}`);
1487
- }
1488
- // Handle window frame specifications using the dedicated formatWindowFrame method
1489
- const frameClause = this.formatWindowFrame(node.over, context.spawn('FuncCall'));
1490
- if (frameClause) {
1491
- windowParts.push(frameClause);
1492
- }
1493
- if (windowParts.length > 0) {
1494
- if (context.isPretty() && windowParts.length > 1) {
1495
- const formattedParts = windowParts.map(part => context.indent(part));
1496
- result += ` OVER (${context.newline()}${formattedParts.join(context.newline())}${context.newline()})`;
1497
- }
1498
- else {
1499
- result += ` OVER (${windowParts.join(' ')})`;
1500
- }
1501
- }
1502
- else {
1503
- result += ` OVER ()`;
1504
- }
1505
- }
1568
+ result += this.formatOverClause(node.over, context);
1506
1569
  }
1507
1570
  return result;
1508
1571
  }
1572
+ formatOverClause(over, context) {
1573
+ if (over.name) {
1574
+ return ` OVER ${over.name}`;
1575
+ }
1576
+ const windowParts = [];
1577
+ if (over.refname) {
1578
+ windowParts.push(over.refname);
1579
+ }
1580
+ if (over.partitionClause) {
1581
+ const partitions = list_utils_1.ListUtils.unwrapList(over.partitionClause);
1582
+ const partitionStrs = partitions.map(p => this.visit(p, context));
1583
+ windowParts.push(`PARTITION BY ${partitionStrs.join(', ')}`);
1584
+ }
1585
+ if (over.orderClause) {
1586
+ const orders = list_utils_1.ListUtils.unwrapList(over.orderClause);
1587
+ const orderStrs = orders.map(o => this.visit(o, context));
1588
+ windowParts.push(`ORDER BY ${orderStrs.join(', ')}`);
1589
+ }
1590
+ const frameClause = this.formatWindowFrame(over, context.spawn('FuncCall'));
1591
+ if (frameClause) {
1592
+ windowParts.push(frameClause);
1593
+ }
1594
+ if (windowParts.length === 0) {
1595
+ return ' OVER ()';
1596
+ }
1597
+ if (context.isPretty() && windowParts.length > 1) {
1598
+ const formattedParts = windowParts.map(part => context.indent(part));
1599
+ return ` OVER (${context.newline()}${formattedParts.join(context.newline())}${context.newline()})`;
1600
+ }
1601
+ return ` OVER (${windowParts.join(' ')})`;
1602
+ }
1509
1603
  FuncExpr(node, context) {
1510
1604
  const funcName = `func_${node.funcid}`;
1511
1605
  const args = node.args ? list_utils_1.ListUtils.unwrapList(node.args).map(arg => this.visit(arg, context)).join(', ') : '';
@@ -1516,61 +1610,61 @@ class Deparser {
1516
1610
  if (nodeAny.ival !== undefined) {
1517
1611
  if (typeof nodeAny.ival === 'object' && nodeAny.ival !== null) {
1518
1612
  if (nodeAny.ival.ival !== undefined) {
1519
- return nodeAny.ival.ival.toString();
1613
+ return formatInteger(nodeAny.ival.ival);
1520
1614
  }
1521
1615
  else if (Object.keys(nodeAny.ival).length === 0) {
1522
1616
  return '0';
1523
1617
  }
1524
1618
  else {
1525
- return nodeAny.ival.toString();
1619
+ return formatInteger(nodeAny.ival);
1526
1620
  }
1527
1621
  }
1528
1622
  else if (nodeAny.ival === null) {
1529
1623
  return 'NULL';
1530
1624
  }
1531
1625
  else {
1532
- return nodeAny.ival.toString();
1626
+ return formatInteger(nodeAny.ival);
1533
1627
  }
1534
1628
  }
1535
1629
  else if (nodeAny.fval !== undefined) {
1536
1630
  if (typeof nodeAny.fval === 'object' && nodeAny.fval !== null) {
1537
1631
  if (nodeAny.fval.fval !== undefined) {
1538
- return nodeAny.fval.fval.toString();
1632
+ return formatNumeric(nodeAny.fval.fval);
1539
1633
  }
1540
1634
  else if (Object.keys(nodeAny.fval).length === 0) {
1541
1635
  return '0.0';
1542
1636
  }
1543
1637
  else {
1544
- return nodeAny.fval.toString();
1638
+ return formatNumeric(nodeAny.fval);
1545
1639
  }
1546
1640
  }
1547
1641
  else if (nodeAny.fval === null) {
1548
1642
  return 'NULL';
1549
1643
  }
1550
1644
  else {
1551
- return nodeAny.fval.toString();
1645
+ return formatNumeric(nodeAny.fval);
1552
1646
  }
1553
1647
  }
1554
1648
  else if (nodeAny.sval !== undefined) {
1555
1649
  if (typeof nodeAny.sval === 'object' && nodeAny.sval !== null) {
1556
1650
  if (nodeAny.sval.sval !== undefined) {
1557
- return quote_utils_1.QuoteUtils.formatEString(nodeAny.sval.sval);
1651
+ return quotes_1.QuoteUtils.formatEString(nodeAny.sval.sval);
1558
1652
  }
1559
1653
  else if (nodeAny.sval.String && nodeAny.sval.String.sval !== undefined) {
1560
- return quote_utils_1.QuoteUtils.formatEString(nodeAny.sval.String.sval);
1654
+ return quotes_1.QuoteUtils.formatEString(nodeAny.sval.String.sval);
1561
1655
  }
1562
1656
  else if (Object.keys(nodeAny.sval).length === 0) {
1563
1657
  return "''";
1564
1658
  }
1565
1659
  else {
1566
- return quote_utils_1.QuoteUtils.formatEString(nodeAny.sval.toString());
1660
+ return quotes_1.QuoteUtils.formatEString(nodeAny.sval.toString());
1567
1661
  }
1568
1662
  }
1569
1663
  else if (nodeAny.sval === null) {
1570
1664
  return 'NULL';
1571
1665
  }
1572
1666
  else {
1573
- return quote_utils_1.QuoteUtils.formatEString(nodeAny.sval);
1667
+ return quotes_1.QuoteUtils.formatEString(nodeAny.sval);
1574
1668
  }
1575
1669
  }
1576
1670
  else if (nodeAny.boolval !== undefined) {
@@ -1595,15 +1689,7 @@ class Deparser {
1595
1689
  else if (nodeAny.bsval !== undefined) {
1596
1690
  if (typeof nodeAny.bsval === 'object' && nodeAny.bsval !== null) {
1597
1691
  if (nodeAny.bsval.bsval !== undefined) {
1598
- const bsval = nodeAny.bsval.bsval;
1599
- // Check if this is a hexadecimal bit string (starts with x and contains only hex digits)
1600
- if (bsval.startsWith('x') && /^x[0-9A-Fa-f]+$/.test(bsval)) {
1601
- return `x'${bsval.substring(1)}'`;
1602
- }
1603
- if (bsval.startsWith('b')) {
1604
- return `b'${bsval.substring(1)}'`;
1605
- }
1606
- return `b'${bsval}'`;
1692
+ return formatBitString(nodeAny.bsval.bsval);
1607
1693
  }
1608
1694
  else if (Object.keys(nodeAny.bsval).length === 0) {
1609
1695
  return "''";
@@ -1616,32 +1702,24 @@ class Deparser {
1616
1702
  return 'NULL';
1617
1703
  }
1618
1704
  else {
1619
- const bsval = nodeAny.bsval;
1620
- // Check if this is a hexadecimal bit string (starts with x and contains only hex digits)
1621
- if (bsval.startsWith('x') && /^x[0-9A-Fa-f]+$/.test(bsval)) {
1622
- return `x'${bsval.substring(1)}'`;
1623
- }
1624
- if (bsval.startsWith('b')) {
1625
- return `b'${bsval.substring(1)}'`;
1626
- }
1627
- return `b'${bsval}'`;
1705
+ return formatBitString(nodeAny.bsval);
1628
1706
  }
1629
1707
  }
1630
1708
  if (nodeAny.val) {
1631
1709
  if (nodeAny.val.Integer?.ival !== undefined) {
1632
- return nodeAny.val.Integer.ival.toString();
1710
+ return formatInteger(nodeAny.val.Integer.ival);
1633
1711
  }
1634
1712
  else if (nodeAny.val.Float?.fval !== undefined) {
1635
- return nodeAny.val.Float.fval.toString();
1713
+ return formatNumeric(nodeAny.val.Float.fval);
1636
1714
  }
1637
1715
  else if (nodeAny.val.String?.sval !== undefined) {
1638
- return quote_utils_1.QuoteUtils.escape(nodeAny.val.String.sval);
1716
+ return quotes_1.QuoteUtils.escape(nodeAny.val.String.sval);
1639
1717
  }
1640
1718
  else if (nodeAny.val.Boolean?.boolval !== undefined) {
1641
1719
  return nodeAny.val.Boolean.boolval ? 'true' : 'false';
1642
1720
  }
1643
1721
  else if (nodeAny.val.BitString?.bsval !== undefined) {
1644
- return nodeAny.val.BitString.bsval;
1722
+ return formatBitString(nodeAny.val.BitString.bsval);
1645
1723
  }
1646
1724
  }
1647
1725
  if (nodeAny.isnull === true) {
@@ -1653,21 +1731,21 @@ class Deparser {
1653
1731
  }
1654
1732
  if (nodeAny.Integer !== undefined) {
1655
1733
  if (typeof nodeAny.Integer === 'object' && nodeAny.Integer.ival !== undefined) {
1656
- return nodeAny.Integer.ival.toString();
1734
+ return formatInteger(nodeAny.Integer.ival);
1657
1735
  }
1658
- return nodeAny.Integer.toString();
1736
+ return formatInteger(nodeAny.Integer);
1659
1737
  }
1660
1738
  if (nodeAny.Float !== undefined) {
1661
1739
  if (typeof nodeAny.Float === 'object' && nodeAny.Float.fval !== undefined) {
1662
- return nodeAny.Float.fval.toString();
1740
+ return formatNumeric(nodeAny.Float.fval);
1663
1741
  }
1664
- return nodeAny.Float.toString();
1742
+ return formatNumeric(nodeAny.Float);
1665
1743
  }
1666
1744
  if (nodeAny.String !== undefined) {
1667
1745
  if (typeof nodeAny.String === 'object' && nodeAny.String.sval !== undefined) {
1668
- return quote_utils_1.QuoteUtils.escape(nodeAny.String.sval);
1746
+ return quotes_1.QuoteUtils.escape(nodeAny.String.sval);
1669
1747
  }
1670
- return quote_utils_1.QuoteUtils.escape(nodeAny.String);
1748
+ return quotes_1.QuoteUtils.escape(nodeAny.String);
1671
1749
  }
1672
1750
  if (Object.keys(nodeAny).length === 0) {
1673
1751
  return 'NULL';
@@ -1681,7 +1759,7 @@ class Deparser {
1681
1759
  const fields = list_utils_1.ListUtils.unwrapList(node.fields);
1682
1760
  return fields.map(field => {
1683
1761
  if (field.String) {
1684
- return quote_utils_1.QuoteUtils.quote(field.String.sval || field.String.str);
1762
+ return quotes_1.QuoteUtils.quoteIdentifier(field.String.sval || field.String.str);
1685
1763
  }
1686
1764
  else if (field.A_Star) {
1687
1765
  return '*';
@@ -1758,8 +1836,7 @@ class Deparser {
1758
1836
  }
1759
1837
  return output.join(' ');
1760
1838
  }
1761
- const quotedTypeName = quote_utils_1.QuoteUtils.quote(typeName);
1762
- let result = mods(quotedTypeName, args);
1839
+ let result = mods(quotes_1.QuoteUtils.quoteIdentifierTypeName(typeName), args);
1763
1840
  if (node.arrayBounds && node.arrayBounds.length > 0) {
1764
1841
  result += formatArrayBounds(node.arrayBounds);
1765
1842
  }
@@ -1855,8 +1932,9 @@ class Deparser {
1855
1932
  return output.join(' ');
1856
1933
  }
1857
1934
  }
1858
- const quotedNames = names.map((name) => quote_utils_1.QuoteUtils.quote(name));
1859
- let result = mods(quotedNames.join('.'), args);
1935
+ // Use type-name quoting for non-pg_catalog types
1936
+ // This allows keywords like 'json', 'int', 'boolean' to remain unquoted in type positions
1937
+ let result = mods(quotes_1.QuoteUtils.quoteTypeDottedName(names), args);
1860
1938
  if (node.arrayBounds && node.arrayBounds.length > 0) {
1861
1939
  result += formatArrayBounds(node.arrayBounds);
1862
1940
  }
@@ -1894,17 +1972,17 @@ class Deparser {
1894
1972
  }
1895
1973
  let tableName = '';
1896
1974
  if (node.catalogname) {
1897
- tableName = quote_utils_1.QuoteUtils.quote(node.catalogname);
1975
+ tableName = quotes_1.QuoteUtils.quoteIdentifier(node.catalogname);
1898
1976
  if (node.schemaname) {
1899
- tableName += '.' + quote_utils_1.QuoteUtils.quote(node.schemaname);
1977
+ tableName += '.' + quotes_1.QuoteUtils.quoteIdentifierAfterDot(node.schemaname);
1900
1978
  }
1901
- tableName += '.' + quote_utils_1.QuoteUtils.quote(node.relname);
1979
+ tableName += '.' + quotes_1.QuoteUtils.quoteIdentifierAfterDot(node.relname);
1902
1980
  }
1903
1981
  else if (node.schemaname) {
1904
- tableName = quote_utils_1.QuoteUtils.quote(node.schemaname) + '.' + quote_utils_1.QuoteUtils.quote(node.relname);
1982
+ tableName = quotes_1.QuoteUtils.quoteQualifiedIdentifier(node.schemaname, node.relname);
1905
1983
  }
1906
1984
  else {
1907
- tableName = quote_utils_1.QuoteUtils.quote(node.relname);
1985
+ tableName = quotes_1.QuoteUtils.quoteIdentifier(node.relname);
1908
1986
  }
1909
1987
  output.push(tableName);
1910
1988
  if (node.alias) {
@@ -2058,7 +2136,7 @@ class Deparser {
2058
2136
  if (size != null) {
2059
2137
  return 'char';
2060
2138
  }
2061
- return 'pg_catalog.bpchar';
2139
+ return 'bpchar';
2062
2140
  case 'varchar':
2063
2141
  return 'varchar';
2064
2142
  case 'numeric':
@@ -2072,7 +2150,7 @@ class Deparser {
2072
2150
  case 'int8':
2073
2151
  return 'bigint';
2074
2152
  case 'real':
2075
- return 'pg_catalog.float4';
2153
+ return 'float4';
2076
2154
  case 'time':
2077
2155
  return 'time';
2078
2156
  case 'timestamp':
@@ -2082,7 +2160,7 @@ class Deparser {
2082
2160
  case 'bit':
2083
2161
  return 'bit';
2084
2162
  default:
2085
- return `pg_catalog.${typeName}`;
2163
+ return typeName;
2086
2164
  }
2087
2165
  }
2088
2166
  isPgCatalogType(typeName) {
@@ -2123,14 +2201,16 @@ class Deparser {
2123
2201
  A_Indirection(node, context) {
2124
2202
  let argStr = this.visit(node.arg, context);
2125
2203
  const argType = this.getNodeType(node.arg);
2126
- if (argType === 'TypeCast' || argType === 'SubLink' || argType === 'A_Expr' || argType === 'FuncCall' || argType === 'A_Indirection' || argType === 'ColumnRef' || argType === 'RowExpr') {
2204
+ // Grammar: only a parameter takes indirection bare; every other target is
2205
+ // `'(' a_expr ')' opt_indirection` (a plain column subscript is the same node).
2206
+ if (argType !== 'ParamRef') {
2127
2207
  argStr = `(${argStr})`;
2128
2208
  }
2129
2209
  const output = [argStr];
2130
2210
  const indirection = list_utils_1.ListUtils.unwrapList(node.indirection);
2131
2211
  for (const subnode of indirection) {
2132
2212
  if (subnode.String || subnode.A_Star) {
2133
- const value = subnode.A_Star ? '*' : quote_utils_1.QuoteUtils.quote(subnode.String.sval || subnode.String.str);
2213
+ const value = subnode.A_Star ? '*' : quotes_1.QuoteUtils.quoteIdentifier(subnode.String.sval || subnode.String.str);
2134
2214
  output.push(`.${value}`);
2135
2215
  }
2136
2216
  else {
@@ -2151,21 +2231,11 @@ class Deparser {
2151
2231
  if (context.isPretty() && args.length > 0) {
2152
2232
  for (const arg of args) {
2153
2233
  const whenClause = this.visit(arg, context);
2154
- if (this.containsMultilineStringLiteral(whenClause)) {
2155
- output.push(context.newline() + whenClause);
2156
- }
2157
- else {
2158
- output.push(context.newline() + context.indent(whenClause));
2159
- }
2234
+ output.push(context.newline() + context.indent(whenClause));
2160
2235
  }
2161
2236
  if (node.defresult) {
2162
2237
  const elseResult = this.visit(node.defresult, context);
2163
- if (this.containsMultilineStringLiteral(elseResult)) {
2164
- output.push(context.newline() + 'ELSE ' + elseResult);
2165
- }
2166
- else {
2167
- output.push(context.newline() + context.indent('ELSE ' + elseResult));
2168
- }
2238
+ output.push(context.newline() + context.indent('ELSE ' + elseResult));
2169
2239
  }
2170
2240
  output.push(context.newline() + 'END');
2171
2241
  return output.join(' ');
@@ -2275,51 +2345,27 @@ class Deparser {
2275
2345
  }
2276
2346
  return output.join(' ');
2277
2347
  }
2278
- static RESERVED_WORDS = new Set([
2279
- 'all', 'analyse', 'analyze', 'and', 'any', 'array', 'as', 'asc', 'asymmetric', 'both',
2280
- 'case', 'cast', 'check', 'collate', 'column', 'constraint', 'create', 'current_catalog',
2281
- 'current_date', 'current_role', 'current_time', 'current_timestamp', 'current_user',
2282
- 'default', 'deferrable', 'desc', 'distinct', 'do', 'else', 'end', 'except', 'false',
2283
- 'fetch', 'for', 'foreign', 'from', 'grant', 'group', 'having', 'in', 'initially',
2284
- 'intersect', 'into', 'lateral', 'leading', 'limit', 'localtime', 'localtimestamp',
2285
- 'not', 'null', 'offset', 'on', 'only', 'or', 'order', 'placing', 'primary',
2286
- 'references', 'returning', 'select', 'session_user', 'some', 'symmetric', 'table',
2287
- 'then', 'to', 'trailing', 'true', 'union', 'unique', 'user', 'using', 'variadic',
2288
- 'when', 'where', 'window', 'with'
2289
- ]);
2290
- static needsQuotes(value) {
2291
- if (!value)
2292
- return false;
2293
- const needsQuotesRegex = /[a-z]+[\W\w]*[A-Z]+|[A-Z]+[\W\w]*[a-z]+|\W/;
2294
- const isAllUppercase = /^[A-Z]+$/.test(value);
2295
- return needsQuotesRegex.test(value) ||
2296
- Deparser.RESERVED_WORDS.has(value.toLowerCase()) ||
2297
- isAllUppercase;
2298
- }
2299
2348
  quoteIfNeeded(value) {
2300
- if (Deparser.needsQuotes(value)) {
2301
- return `"${value}"`;
2302
- }
2303
- return value;
2349
+ return quotes_1.QuoteUtils.quoteIdentifier(value);
2304
2350
  }
2305
2351
  preserveOperatorDefElemCase(defName) {
2306
2352
  const caseMap = {
2307
- 'leftarg': 'Leftarg',
2308
- 'rightarg': 'Rightarg',
2309
- 'procedure': 'Procedure',
2310
- 'function': 'Function',
2311
- 'commutator': 'Commutator',
2312
- 'negator': 'Negator',
2313
- 'restrict': 'Restrict',
2314
- 'join': 'Join',
2315
- 'hashes': 'Hashes',
2316
- 'merges': 'Merges'
2353
+ leftarg: 'Leftarg',
2354
+ rightarg: 'Rightarg',
2355
+ procedure: 'Procedure',
2356
+ function: 'Function',
2357
+ commutator: 'Commutator',
2358
+ negator: 'Negator',
2359
+ restrict: 'Restrict',
2360
+ join: 'Join',
2361
+ hashes: 'Hashes',
2362
+ merges: 'Merges'
2317
2363
  };
2318
2364
  return caseMap[defName.toLowerCase()] || defName;
2319
2365
  }
2320
2366
  String(node, context) {
2321
2367
  if (context.isStringLiteral || context.isEnumValue) {
2322
- return quote_utils_1.QuoteUtils.formatEString(node.sval || '');
2368
+ return quotes_1.QuoteUtils.formatEString(node.sval || '');
2323
2369
  }
2324
2370
  const value = node.sval || '';
2325
2371
  if (context.parentNodeTypes.includes('DefElem') ||
@@ -2333,27 +2379,19 @@ class Deparser {
2333
2379
  return value; // Don't quote pure operator symbols like "=" or "-"
2334
2380
  }
2335
2381
  }
2336
- return Deparser.needsQuotes(value) ? `"${value}"` : value;
2382
+ return quotes_1.QuoteUtils.quoteIdentifier(value);
2337
2383
  }
2338
2384
  Integer(node, context) {
2339
- return node.ival?.toString() || '0';
2385
+ return node.ival === undefined || node.ival === null ? '0' : formatInteger(node.ival);
2340
2386
  }
2341
2387
  Float(node, context) {
2342
- return node.fval || '0.0';
2388
+ return node.fval ? formatNumeric(node.fval) : '0.0';
2343
2389
  }
2344
2390
  Boolean(node, context) {
2345
2391
  return node.boolval ? 'true' : 'false';
2346
2392
  }
2347
2393
  BitString(node, context) {
2348
- // Check if this is a hexadecimal bit string (starts with x)
2349
- if (node.bsval.startsWith('x')) {
2350
- return `x'${node.bsval.substring(1)}'`;
2351
- }
2352
- if (node.bsval.startsWith('b')) {
2353
- return `b'${node.bsval.substring(1)}'`;
2354
- }
2355
- // Fallback for raw values without prefix
2356
- return `b'${node.bsval}'`;
2394
+ return formatBitString(node.bsval);
2357
2395
  }
2358
2396
  Null(node, context) {
2359
2397
  return 'NULL';
@@ -2392,7 +2430,7 @@ class Deparser {
2392
2430
  output.push(context.parens(elementStrs.join(', ')));
2393
2431
  }
2394
2432
  }
2395
- else if (node.tableElts) {
2433
+ else if (node.tableElts && !node.partbound) {
2396
2434
  const elements = list_utils_1.ListUtils.unwrapList(node.tableElts);
2397
2435
  const elementStrs = elements.map(el => {
2398
2436
  return this.deparse(el, context.spawn('CreateStmt'));
@@ -2420,7 +2458,16 @@ class Deparser {
2420
2458
  const inherits = list_utils_1.ListUtils.unwrapList(node.inhRelations);
2421
2459
  const inheritStrs = inherits.map(rel => this.visit(rel, context));
2422
2460
  output.push(inheritStrs[0]);
2423
- if (node.partbound.strategy === 'l' && node.partbound.listdatums) {
2461
+ if (node.tableElts) {
2462
+ const elementStrs = list_utils_1.ListUtils.unwrapList(node.tableElts).map(el => {
2463
+ return this.deparse(el, context.spawn('CreateStmt'));
2464
+ });
2465
+ output.push(context.parens(elementStrs.join(', ')));
2466
+ }
2467
+ if (node.partbound.is_default) {
2468
+ output.push('DEFAULT');
2469
+ }
2470
+ else if (node.partbound.strategy === 'l' && node.partbound.listdatums) {
2424
2471
  output.push('FOR VALUES IN');
2425
2472
  const listValues = list_utils_1.ListUtils.unwrapList(node.partbound.listdatums)
2426
2473
  .map(datum => this.visit(datum, context))
@@ -2443,13 +2490,9 @@ class Deparser {
2443
2490
  output.push(`(${upperValues})`);
2444
2491
  }
2445
2492
  }
2446
- else if (node.partbound.strategy === 'h' && node.partbound.modulus !== undefined) {
2493
+ else if (node.partbound.strategy === 'h') {
2447
2494
  output.push('FOR VALUES WITH');
2448
- const remainder = node.partbound.remainder !== undefined ? node.partbound.remainder : 0;
2449
- output.push(`(MODULUS ${node.partbound.modulus}, REMAINDER ${remainder})`);
2450
- }
2451
- else if (node.partbound.is_default) {
2452
- output.push('DEFAULT');
2495
+ output.push(`(MODULUS ${node.partbound.modulus ?? 0}, REMAINDER ${node.partbound.remainder ?? 0})`);
2453
2496
  }
2454
2497
  }
2455
2498
  else if (node.inhRelations) {
@@ -2510,11 +2553,17 @@ class Deparser {
2510
2553
  ColumnDef(node, context) {
2511
2554
  const output = [];
2512
2555
  if (node.colname) {
2513
- output.push(quote_utils_1.QuoteUtils.quote(node.colname));
2556
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.colname));
2514
2557
  }
2515
2558
  if (node.typeName) {
2516
2559
  output.push(this.TypeName(node.typeName, context));
2517
2560
  }
2561
+ if (node.storage_name) {
2562
+ output.push('STORAGE', node.storage_name.toUpperCase());
2563
+ }
2564
+ if (node.compression) {
2565
+ output.push('COMPRESSION', quotes_1.QuoteUtils.quoteIdentifier(node.compression));
2566
+ }
2518
2567
  if (node.fdwoptions && node.fdwoptions.length > 0) {
2519
2568
  output.push('OPTIONS');
2520
2569
  const columnContext = context.spawn('ColumnDef');
@@ -2549,9 +2598,9 @@ class Deparser {
2549
2598
  Constraint(node, context) {
2550
2599
  const output = [];
2551
2600
  // Handle constraint name if present
2552
- if (node.conname && (node.contype === 'CONSTR_CHECK' || node.contype === 'CONSTR_UNIQUE' || node.contype === 'CONSTR_PRIMARY' || node.contype === 'CONSTR_FOREIGN')) {
2601
+ if (node.conname && (node.contype === 'CONSTR_CHECK' || node.contype === 'CONSTR_UNIQUE' || node.contype === 'CONSTR_PRIMARY' || node.contype === 'CONSTR_FOREIGN' || node.contype === 'CONSTR_NOTNULL' || node.contype === 'CONSTR_EXCLUSION')) {
2553
2602
  output.push('CONSTRAINT');
2554
- output.push(quote_utils_1.QuoteUtils.quote(node.conname));
2603
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.conname));
2555
2604
  }
2556
2605
  switch (node.contype) {
2557
2606
  case 'CONSTR_NULL':
@@ -2559,11 +2608,24 @@ class Deparser {
2559
2608
  break;
2560
2609
  case 'CONSTR_NOTNULL':
2561
2610
  output.push('NOT NULL');
2611
+ if (node.keys && node.keys.length > 0 && !context.isColumnConstraint) {
2612
+ const keyList = list_utils_1.ListUtils.unwrapList(node.keys)
2613
+ .map(key => this.visit(key, context))
2614
+ .join(', ');
2615
+ output.push(keyList);
2616
+ }
2617
+ if (node.is_no_inherit) {
2618
+ output.push('NO INHERIT');
2619
+ }
2620
+ if (node.skip_validation) {
2621
+ output.push('NOT VALID');
2622
+ }
2562
2623
  break;
2563
2624
  case 'CONSTR_DEFAULT':
2564
2625
  output.push('DEFAULT');
2565
2626
  if (node.raw_expr) {
2566
- output.push(this.visit(node.raw_expr, context));
2627
+ const defaultExpr = this.visit(node.raw_expr, context);
2628
+ output.push(this.needsBExprParens(node.raw_expr) ? `(${defaultExpr})` : defaultExpr);
2567
2629
  }
2568
2630
  break;
2569
2631
  case 'CONSTR_CHECK':
@@ -2587,8 +2649,13 @@ class Deparser {
2587
2649
  output.push(context.parens(this.visit(node.raw_expr, context)));
2588
2650
  }
2589
2651
  }
2590
- // Handle NOT VALID for check constraints
2591
- if (node.skip_validation) {
2652
+ // PG18: constraints are enforced unless explicitly NOT ENFORCED
2653
+ // (libpg-query omits false booleans, so undefined means not enforced)
2654
+ if (node.is_enforced !== true && !context.isDomainConstraint) {
2655
+ output.push('NOT ENFORCED');
2656
+ }
2657
+ else if (node.skip_validation) {
2658
+ // NOT ENFORCED implies NOT VALID, so only emit NOT VALID when enforced
2592
2659
  output.push('NOT VALID');
2593
2660
  }
2594
2661
  // Handle NO INHERIT for check constraints - only for table constraints, not domain constraints
@@ -2608,7 +2675,7 @@ class Deparser {
2608
2675
  if (node.raw_expr) {
2609
2676
  output.push(context.parens(this.visit(node.raw_expr, context)));
2610
2677
  }
2611
- output.push('STORED');
2678
+ output.push(node.generated_kind === 'v' ? 'VIRTUAL' : 'STORED');
2612
2679
  break;
2613
2680
  case 'CONSTR_IDENTITY':
2614
2681
  output.push('GENERATED');
@@ -2684,10 +2751,12 @@ class Deparser {
2684
2751
  case 'CONSTR_PRIMARY':
2685
2752
  output.push('PRIMARY KEY');
2686
2753
  if (node.keys && node.keys.length > 0) {
2687
- const keyList = list_utils_1.ListUtils.unwrapList(node.keys)
2688
- .map(key => this.visit(key, context))
2689
- .join(', ');
2690
- output.push(`(${keyList})`);
2754
+ const keyItems = list_utils_1.ListUtils.unwrapList(node.keys)
2755
+ .map(key => this.visit(key, context));
2756
+ if (node.without_overlaps) {
2757
+ keyItems[keyItems.length - 1] += ' WITHOUT OVERLAPS';
2758
+ }
2759
+ output.push(`(${keyItems.join(', ')})`);
2691
2760
  }
2692
2761
  if (node.indexname) {
2693
2762
  output.push('USING INDEX');
@@ -2705,10 +2774,12 @@ class Deparser {
2705
2774
  output.push('NULLS NOT DISTINCT');
2706
2775
  }
2707
2776
  if (node.keys && node.keys.length > 0) {
2708
- const keyList = list_utils_1.ListUtils.unwrapList(node.keys)
2709
- .map(key => this.visit(key, context))
2710
- .join(', ');
2711
- output.push(`(${keyList})`);
2777
+ const keyItems = list_utils_1.ListUtils.unwrapList(node.keys)
2778
+ .map(key => this.visit(key, context));
2779
+ if (node.without_overlaps) {
2780
+ keyItems[keyItems.length - 1] += ' WITHOUT OVERLAPS';
2781
+ }
2782
+ output.push(`(${keyItems.join(', ')})`);
2712
2783
  }
2713
2784
  if (node.indexname) {
2714
2785
  output.push('USING INDEX');
@@ -2721,20 +2792,14 @@ class Deparser {
2721
2792
  if (context.isPretty()) {
2722
2793
  output.push('\n' + context.indent('FOREIGN KEY'));
2723
2794
  if (node.fk_attrs && node.fk_attrs.length > 0) {
2724
- const fkAttrs = list_utils_1.ListUtils.unwrapList(node.fk_attrs)
2725
- .map(attr => this.visit(attr, context))
2726
- .join(', ');
2727
- output.push(`(${fkAttrs})`);
2795
+ output.push(`(${this.deparseKeyAttrs(node.fk_attrs, node.fk_with_period, context)})`);
2728
2796
  }
2729
2797
  output.push('\n' + context.indent('REFERENCES'));
2730
2798
  }
2731
2799
  else {
2732
2800
  output.push('FOREIGN KEY');
2733
2801
  if (node.fk_attrs && node.fk_attrs.length > 0) {
2734
- const fkAttrs = list_utils_1.ListUtils.unwrapList(node.fk_attrs)
2735
- .map(attr => this.visit(attr, context))
2736
- .join(', ');
2737
- output.push(`(${fkAttrs})`);
2802
+ output.push(`(${this.deparseKeyAttrs(node.fk_attrs, node.fk_with_period, context)})`);
2738
2803
  }
2739
2804
  output.push('REFERENCES');
2740
2805
  }
@@ -2757,9 +2822,7 @@ class Deparser {
2757
2822
  }
2758
2823
  }
2759
2824
  if (node.pk_attrs && node.pk_attrs.length > 0) {
2760
- const pkAttrs = list_utils_1.ListUtils.unwrapList(node.pk_attrs)
2761
- .map(attr => this.visit(attr, context))
2762
- .join(', ');
2825
+ const pkAttrs = this.deparseKeyAttrs(node.pk_attrs, node.pk_with_period, context);
2763
2826
  if (context.isPretty() && !context.isColumnConstraint) {
2764
2827
  const lastIndex = output.length - 1;
2765
2828
  if (lastIndex >= 0) {
@@ -2830,6 +2893,15 @@ class Deparser {
2830
2893
  deleteClause += 'SET DEFAULT';
2831
2894
  break;
2832
2895
  }
2896
+ if ((node.fk_del_action === 'n' || node.fk_del_action === 'd') && node.fk_del_set_cols && node.fk_del_set_cols.length > 0) {
2897
+ const setColumns = list_utils_1.ListUtils.unwrapList(node.fk_del_set_cols)
2898
+ .map(column => {
2899
+ const stringNode = column.String;
2900
+ return quotes_1.QuoteUtils.quoteIdentifier(stringNode.sval || stringNode.str || '');
2901
+ })
2902
+ .join(', ');
2903
+ deleteClause += ` (${setColumns})`;
2904
+ }
2833
2905
  if (context.isPretty()) {
2834
2906
  output.push('\n' + context.indent(deleteClause));
2835
2907
  }
@@ -2838,8 +2910,18 @@ class Deparser {
2838
2910
  output.push(deleteClause.replace('ON DELETE ', ''));
2839
2911
  }
2840
2912
  }
2841
- // Handle NOT VALID for foreign key constraints - only for table constraints, not domain constraints
2842
- if (node.skip_validation && !context.isDomainConstraint) {
2913
+ // PG18: constraints are enforced unless explicitly NOT ENFORCED
2914
+ // (libpg-query omits false booleans, so undefined means not enforced)
2915
+ if (node.is_enforced !== true && !context.isDomainConstraint) {
2916
+ if (context.isPretty() && !context.isColumnConstraint) {
2917
+ output.push('\n' + context.indent('NOT ENFORCED'));
2918
+ }
2919
+ else {
2920
+ output.push('NOT ENFORCED');
2921
+ }
2922
+ }
2923
+ else if (node.skip_validation && !context.isDomainConstraint) {
2924
+ // NOT ENFORCED implies NOT VALID, so only emit NOT VALID when enforced
2843
2925
  if (context.isPretty() && !context.isColumnConstraint) {
2844
2926
  output.push('\n' + context.indent('NOT VALID'));
2845
2927
  }
@@ -2860,6 +2942,12 @@ class Deparser {
2860
2942
  case 'CONSTR_ATTR_IMMEDIATE':
2861
2943
  output.push('INITIALLY IMMEDIATE');
2862
2944
  break;
2945
+ case 'CONSTR_ATTR_ENFORCED':
2946
+ output.push('ENFORCED');
2947
+ break;
2948
+ case 'CONSTR_ATTR_NOT_ENFORCED':
2949
+ output.push('NOT ENFORCED');
2950
+ break;
2863
2951
  case 'CONSTR_EXCLUSION':
2864
2952
  output.push('EXCLUDE');
2865
2953
  if (node.access_method) {
@@ -2894,10 +2982,14 @@ class Deparser {
2894
2982
  });
2895
2983
  output.push(`(${exclusionElements.join(', ')})`);
2896
2984
  }
2985
+ if (node.where_clause) {
2986
+ output.push('WHERE');
2987
+ output.push(context.parens(this.visit(node.where_clause, context)));
2988
+ }
2897
2989
  break;
2898
2990
  }
2899
2991
  // Handle deferrable constraints for all constraint types that support it
2900
- if (node.contype === 'CONSTR_PRIMARY' || node.contype === 'CONSTR_UNIQUE' || node.contype === 'CONSTR_FOREIGN') {
2992
+ if (node.contype === 'CONSTR_PRIMARY' || node.contype === 'CONSTR_UNIQUE' || node.contype === 'CONSTR_FOREIGN' || node.contype === 'CONSTR_EXCLUSION') {
2901
2993
  if (node.deferrable) {
2902
2994
  if (context.isPretty() && node.contype === 'CONSTR_FOREIGN') {
2903
2995
  output.push('\n' + context.indent('DEFERRABLE'));
@@ -2926,6 +3018,9 @@ class Deparser {
2926
3018
  output.push('NOT DEFERRABLE');
2927
3019
  }
2928
3020
  }
3021
+ else if (node.initdeferred) {
3022
+ output.push('INITIALLY DEFERRED');
3023
+ }
2929
3024
  }
2930
3025
  if (context.isPretty() && node.contype === 'CONSTR_FOREIGN') {
2931
3026
  let result = '';
@@ -2991,6 +3086,9 @@ class Deparser {
2991
3086
  output.push(node.name);
2992
3087
  }
2993
3088
  const windowParts = [];
3089
+ if (node.refname) {
3090
+ windowParts.push(node.refname);
3091
+ }
2994
3092
  if (node.partitionClause) {
2995
3093
  const partitions = list_utils_1.ListUtils.unwrapList(node.partitionClause);
2996
3094
  const partitionStrs = partitions.map(p => this.visit(p, context));
@@ -3001,12 +3099,9 @@ class Deparser {
3001
3099
  const orderStrs = orders.map(o => this.visit(o, context));
3002
3100
  windowParts.push(`ORDER BY ${orderStrs.join(', ')}`);
3003
3101
  }
3004
- // Only add frame clause if frameOptions indicates non-default framing
3005
- if (node.frameOptions && node.frameOptions !== 1058) {
3006
- const frameClause = this.formatWindowFrame(node, context.spawn('WindowDef'));
3007
- if (frameClause) {
3008
- windowParts.push(frameClause);
3009
- }
3102
+ const frameClause = this.formatWindowFrame(node, context.spawn('WindowDef'));
3103
+ if (frameClause) {
3104
+ windowParts.push(frameClause);
3010
3105
  }
3011
3106
  if (windowParts.length > 0) {
3012
3107
  if (node.name) {
@@ -3023,103 +3118,97 @@ class Deparser {
3023
3118
  }
3024
3119
  return output.join(' ');
3025
3120
  }
3121
+ formatIdentityColumnOptions(def, context) {
3122
+ const seqContext = context.spawn('AlterSeqStmt');
3123
+ return list_utils_1.ListUtils.unwrapList(def).map(item => {
3124
+ const el = item.DefElem;
3125
+ if (!el)
3126
+ return this.visit(item, context);
3127
+ if (el.defname === 'generated') {
3128
+ const ival = el.arg?.Integer?.ival ?? 0;
3129
+ return ival === 97 ? 'SET GENERATED ALWAYS' : 'SET GENERATED BY DEFAULT';
3130
+ }
3131
+ if (el.defname === 'restart') {
3132
+ return el.arg ? `RESTART WITH ${this.visit(el.arg, context)}` : 'RESTART';
3133
+ }
3134
+ return `SET ${this.visit(item, seqContext)}`;
3135
+ }).join(' ');
3136
+ }
3137
+ // b_expr (used by DEFAULT) excludes IN/LIKE/BETWEEN and boolean operators.
3138
+ needsBExprParens(node) {
3139
+ const nodeType = this.getNodeType(node);
3140
+ if (nodeType === 'BoolExpr')
3141
+ return true;
3142
+ if (nodeType === 'A_Expr') {
3143
+ const kind = this.getNodeData(node).kind;
3144
+ return kind !== 'AEXPR_OP' && kind !== 'AEXPR_DISTINCT' && kind !== 'AEXPR_NOT_DISTINCT';
3145
+ }
3146
+ return false;
3147
+ }
3026
3148
  formatWindowFrame(node, context) {
3027
- if (!node.frameOptions)
3149
+ if (!node.frameOptions || !(node.frameOptions & FRAMEOPTION_NONDEFAULT))
3028
3150
  return null;
3029
3151
  const frameOptions = node.frameOptions;
3030
3152
  const frameParts = [];
3031
- if (frameOptions & 0x01) { // FRAMEOPTION_NONDEFAULT
3032
- if (frameOptions & 0x02) { // FRAMEOPTION_RANGE
3033
- frameParts.push('RANGE');
3034
- }
3035
- else if (frameOptions & 0x04) { // FRAMEOPTION_ROWS
3036
- frameParts.push('ROWS');
3037
- }
3038
- else if (frameOptions & 0x08) { // FRAMEOPTION_GROUPS
3039
- frameParts.push('GROUPS');
3040
- }
3153
+ if (frameOptions & FRAMEOPTION_RANGE) {
3154
+ frameParts.push('RANGE');
3155
+ }
3156
+ else if (frameOptions & FRAMEOPTION_ROWS) {
3157
+ frameParts.push('ROWS');
3158
+ }
3159
+ else if (frameOptions & FRAMEOPTION_GROUPS) {
3160
+ frameParts.push('GROUPS');
3041
3161
  }
3042
3162
  if (frameParts.length === 0)
3043
3163
  return null;
3044
- const boundsParts = [];
3045
- // Handle specific frameOptions values that have known mappings
3046
- if (frameOptions === 789) {
3047
- boundsParts.push('CURRENT ROW');
3048
- boundsParts.push('AND UNBOUNDED FOLLOWING');
3164
+ let start = null;
3165
+ if (frameOptions & FRAMEOPTION_START_UNBOUNDED_PRECEDING) {
3166
+ start = 'UNBOUNDED PRECEDING';
3049
3167
  }
3050
- else if (frameOptions === 1077) {
3051
- boundsParts.push('UNBOUNDED PRECEDING');
3052
- boundsParts.push('AND CURRENT ROW');
3168
+ else if (frameOptions & FRAMEOPTION_START_UNBOUNDED_FOLLOWING) {
3169
+ start = 'UNBOUNDED FOLLOWING';
3053
3170
  }
3054
- else if (frameOptions === 18453) {
3055
- if (node.startOffset && node.endOffset) {
3056
- boundsParts.push(`${this.visit(node.startOffset, context)} PRECEDING`);
3057
- boundsParts.push(`AND ${this.visit(node.endOffset, context)} FOLLOWING`);
3058
- }
3171
+ else if (frameOptions & FRAMEOPTION_START_CURRENT_ROW) {
3172
+ start = 'CURRENT ROW';
3059
3173
  }
3060
- else if (frameOptions === 1557) {
3061
- boundsParts.push('CURRENT ROW');
3062
- boundsParts.push('AND CURRENT ROW');
3174
+ else if (frameOptions & FRAMEOPTION_START_OFFSET_PRECEDING && node.startOffset) {
3175
+ start = `${this.visit(node.startOffset, context)} PRECEDING`;
3063
3176
  }
3064
- else if (frameOptions === 16917) {
3065
- boundsParts.push('CURRENT ROW');
3066
- if (node.endOffset) {
3067
- boundsParts.push(`AND ${this.visit(node.endOffset, context)} FOLLOWING`);
3068
- }
3177
+ else if (frameOptions & FRAMEOPTION_START_OFFSET_FOLLOWING && node.startOffset) {
3178
+ start = `${this.visit(node.startOffset, context)} FOLLOWING`;
3069
3179
  }
3070
- else if (frameOptions === 1058) {
3071
- return null;
3180
+ let end = null;
3181
+ if (frameOptions & FRAMEOPTION_END_UNBOUNDED_PRECEDING) {
3182
+ end = 'UNBOUNDED PRECEDING';
3072
3183
  }
3073
- else {
3074
- // Handle start bound - prioritize explicit offset values over bit flags
3075
- if (node.startOffset) {
3076
- if (frameOptions & 0x400) { // FRAMEOPTION_START_VALUE_PRECEDING
3077
- boundsParts.push(`${this.visit(node.startOffset, context)} PRECEDING`);
3078
- }
3079
- else if (frameOptions & 0x800) { // FRAMEOPTION_START_VALUE_FOLLOWING
3080
- boundsParts.push(`${this.visit(node.startOffset, context)} FOLLOWING`);
3081
- }
3082
- else {
3083
- boundsParts.push(`${this.visit(node.startOffset, context)} PRECEDING`);
3084
- }
3085
- }
3086
- else if (frameOptions & 0x10) { // FRAMEOPTION_START_UNBOUNDED_PRECEDING
3087
- boundsParts.push('UNBOUNDED PRECEDING');
3088
- }
3089
- else if (frameOptions & 0x20) { // FRAMEOPTION_START_CURRENT_ROW
3090
- boundsParts.push('CURRENT ROW');
3091
- }
3092
- // Handle end bound - prioritize explicit offset values over bit flags
3093
- if (node.endOffset) {
3094
- if (boundsParts.length > 0) {
3095
- if (frameOptions & 0x1000) { // FRAMEOPTION_END_VALUE_PRECEDING
3096
- boundsParts.push(`AND ${this.visit(node.endOffset, context)} PRECEDING`);
3097
- }
3098
- else if (frameOptions & 0x2000) { // FRAMEOPTION_END_VALUE_FOLLOWING
3099
- boundsParts.push(`AND ${this.visit(node.endOffset, context)} FOLLOWING`);
3100
- }
3101
- else {
3102
- boundsParts.push(`AND ${this.visit(node.endOffset, context)} FOLLOWING`);
3103
- }
3104
- }
3105
- }
3106
- else if (frameOptions & 0x80) { // FRAMEOPTION_END_UNBOUNDED_FOLLOWING
3107
- if (boundsParts.length > 0) {
3108
- boundsParts.push('AND UNBOUNDED FOLLOWING');
3109
- }
3110
- }
3111
- else if (frameOptions & 0x100) { // FRAMEOPTION_END_CURRENT_ROW
3112
- if (boundsParts.length > 0) {
3113
- boundsParts.push('AND CURRENT ROW');
3114
- }
3184
+ else if (frameOptions & FRAMEOPTION_END_UNBOUNDED_FOLLOWING) {
3185
+ end = 'UNBOUNDED FOLLOWING';
3186
+ }
3187
+ else if (frameOptions & FRAMEOPTION_END_CURRENT_ROW) {
3188
+ end = 'CURRENT ROW';
3189
+ }
3190
+ else if (frameOptions & FRAMEOPTION_END_OFFSET_PRECEDING && node.endOffset) {
3191
+ end = `${this.visit(node.endOffset, context)} PRECEDING`;
3192
+ }
3193
+ else if (frameOptions & FRAMEOPTION_END_OFFSET_FOLLOWING && node.endOffset) {
3194
+ end = `${this.visit(node.endOffset, context)} FOLLOWING`;
3195
+ }
3196
+ if (start) {
3197
+ if (frameOptions & FRAMEOPTION_BETWEEN) {
3198
+ frameParts.push(`BETWEEN ${start} AND ${end ?? 'CURRENT ROW'}`);
3115
3199
  }
3116
- else if (boundsParts.length > 0) {
3117
- boundsParts.push('AND CURRENT ROW');
3200
+ else {
3201
+ frameParts.push(start);
3118
3202
  }
3119
3203
  }
3120
- if (boundsParts.length > 0) {
3121
- frameParts.push('BETWEEN');
3122
- frameParts.push(boundsParts.join(' '));
3204
+ if (frameOptions & FRAMEOPTION_EXCLUDE_CURRENT_ROW) {
3205
+ frameParts.push('EXCLUDE CURRENT ROW');
3206
+ }
3207
+ else if (frameOptions & FRAMEOPTION_EXCLUDE_GROUP) {
3208
+ frameParts.push('EXCLUDE GROUP');
3209
+ }
3210
+ else if (frameOptions & FRAMEOPTION_EXCLUDE_TIES) {
3211
+ frameParts.push('EXCLUDE TIES');
3123
3212
  }
3124
3213
  return frameParts.join(' ');
3125
3214
  }
@@ -3197,8 +3286,35 @@ class Deparser {
3197
3286
  if (node.ctequery) {
3198
3287
  output.push(context.parens(this.visit(node.ctequery, context)));
3199
3288
  }
3289
+ if (node.search_clause) {
3290
+ const sc = node.search_clause;
3291
+ const cols = list_utils_1.ListUtils.unwrapList(sc.search_col_list).map(c => this.visit(c, context));
3292
+ output.push('SEARCH', sc.search_breadth_first ? 'BREADTH' : 'DEPTH', 'FIRST BY');
3293
+ output.push(cols.join(', '));
3294
+ output.push('SET', quotes_1.QuoteUtils.quoteIdentifier(sc.search_seq_column));
3295
+ }
3296
+ if (node.cycle_clause) {
3297
+ const cc = node.cycle_clause;
3298
+ const cols = list_utils_1.ListUtils.unwrapList(cc.cycle_col_list).map(c => this.visit(c, context));
3299
+ output.push('CYCLE', cols.join(', '));
3300
+ output.push('SET', quotes_1.QuoteUtils.quoteIdentifier(cc.cycle_mark_column));
3301
+ if (cc.cycle_mark_value && cc.cycle_mark_default) {
3302
+ output.push('TO', this.formatAexprConst(cc.cycle_mark_value, context));
3303
+ output.push('DEFAULT', this.formatAexprConst(cc.cycle_mark_default, context));
3304
+ }
3305
+ output.push('USING', quotes_1.QuoteUtils.quoteIdentifier(cc.cycle_path_column));
3306
+ }
3200
3307
  return output.join(' ');
3201
3308
  }
3309
+ // Renders a constant in the restricted AexprConst grammar (e.g. `point '(1,1)'`
3310
+ // rather than `CAST('(1,1)' AS point)`).
3311
+ formatAexprConst(node, context) {
3312
+ const cast = node.TypeCast;
3313
+ if (cast?.arg?.A_Const?.sval && cast.typeName) {
3314
+ return `${this.TypeName(cast.typeName, context)} ${this.visit(cast.arg, context)}`;
3315
+ }
3316
+ return this.visit(node, context);
3317
+ }
3202
3318
  ParamRef(node, context) {
3203
3319
  return `$${node.number}`;
3204
3320
  }
@@ -3448,7 +3564,7 @@ class Deparser {
3448
3564
  output.push('IF NOT EXISTS');
3449
3565
  }
3450
3566
  if (node.idxname) {
3451
- output.push(quote_utils_1.QuoteUtils.quote(node.idxname));
3567
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.idxname));
3452
3568
  }
3453
3569
  output.push('ON');
3454
3570
  if (node.relation) {
@@ -3467,9 +3583,8 @@ class Deparser {
3467
3583
  output.push('INCLUDE');
3468
3584
  output.push(context.parens(includeStrs.join(', ')));
3469
3585
  }
3470
- if (node.whereClause) {
3471
- output.push('WHERE');
3472
- output.push(this.visit(node.whereClause, context));
3586
+ if (node.nulls_not_distinct) {
3587
+ output.push('NULLS NOT DISTINCT');
3473
3588
  }
3474
3589
  if (node.options && node.options.length > 0) {
3475
3590
  const indexContext = context.spawn('IndexStmt');
@@ -3477,19 +3592,20 @@ class Deparser {
3477
3592
  output.push('WITH');
3478
3593
  output.push(context.parens(optionStrs.join(', ')));
3479
3594
  }
3480
- if (node.nulls_not_distinct) {
3481
- output.push('NULLS NOT DISTINCT');
3482
- }
3483
3595
  if (node.tableSpace) {
3484
3596
  output.push('TABLESPACE');
3485
- output.push(quote_utils_1.QuoteUtils.quote(node.tableSpace));
3597
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.tableSpace));
3598
+ }
3599
+ if (node.whereClause) {
3600
+ output.push('WHERE');
3601
+ output.push(this.visit(node.whereClause, context));
3486
3602
  }
3487
3603
  return output.join(' ');
3488
3604
  }
3489
3605
  IndexElem(node, context) {
3490
3606
  const output = [];
3491
3607
  if (node.name) {
3492
- output.push(quote_utils_1.QuoteUtils.quote(node.name));
3608
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.name));
3493
3609
  }
3494
3610
  else if (node.expr) {
3495
3611
  output.push(context.parens(this.visit(node.expr, context)));
@@ -3507,7 +3623,7 @@ class Deparser {
3507
3623
  const opclassOpts = list_utils_1.ListUtils.unwrapList(node.opclassopts).map(opt => {
3508
3624
  if (opt.DefElem && opt.DefElem.arg && this.getNodeType(opt.DefElem.arg) === 'String') {
3509
3625
  const stringData = this.getNodeData(opt.DefElem.arg);
3510
- return `${opt.DefElem.defname}='${stringData.sval}'`;
3626
+ return `${quotes_1.QuoteUtils.quoteIdentifierAfterDot(opt.DefElem.defname)}=${quotes_1.QuoteUtils.escape(stringData.sval)}`;
3511
3627
  }
3512
3628
  return this.visit(opt, context.spawn('IndexElem'));
3513
3629
  });
@@ -3540,7 +3656,7 @@ class Deparser {
3540
3656
  PartitionElem(node, context) {
3541
3657
  const output = [];
3542
3658
  if (node.name) {
3543
- output.push(quote_utils_1.QuoteUtils.quote(node.name));
3659
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.name));
3544
3660
  }
3545
3661
  else if (node.expr) {
3546
3662
  output.push(context.parens(this.visit(node.expr, context)));
@@ -3558,12 +3674,12 @@ class Deparser {
3558
3674
  }
3559
3675
  PartitionCmd(node, context) {
3560
3676
  const output = [];
3677
+ if (node.name) {
3678
+ output.push(this.RangeVar(node.name, context));
3679
+ }
3561
3680
  if (node.concurrent) {
3562
3681
  output.push('CONCURRENTLY');
3563
3682
  }
3564
- if (node.name) {
3565
- output.push(this.visit(node.name, context));
3566
- }
3567
3683
  if (node.bound) {
3568
3684
  if (node.bound.strategy === 'l' && node.bound.listdatums) {
3569
3685
  output.push('FOR VALUES IN');
@@ -3588,9 +3704,9 @@ class Deparser {
3588
3704
  output.push(`(${upperValues})`);
3589
3705
  }
3590
3706
  }
3591
- else if (node.bound.strategy === 'h' && node.bound.modulus !== undefined && node.bound.remainder !== undefined) {
3707
+ else if (node.bound.strategy === 'h') {
3592
3708
  output.push('FOR VALUES WITH');
3593
- output.push(`(modulus ${node.bound.modulus}, remainder ${node.bound.remainder})`);
3709
+ output.push(`(MODULUS ${node.bound.modulus ?? 0}, REMAINDER ${node.bound.remainder ?? 0})`);
3594
3710
  }
3595
3711
  else if (node.bound.is_default) {
3596
3712
  output.push('DEFAULT');
@@ -3721,12 +3837,7 @@ class Deparser {
3721
3837
  if (context.isPretty()) {
3722
3838
  // For complex JOIN conditions, format with proper indentation
3723
3839
  if (qualsStr.includes('AND') || qualsStr.includes('OR') || qualsStr.length > 50) {
3724
- if (this.containsMultilineStringLiteral(qualsStr)) {
3725
- output.push(` ON ${qualsStr}`);
3726
- }
3727
- else {
3728
- output.push(` ON${context.newline()}${context.indent(qualsStr)}`);
3729
- }
3840
+ output.push(` ON${context.newline()}${context.indent(qualsStr)}`);
3730
3841
  }
3731
3842
  else {
3732
3843
  output.push(` ON ${qualsStr}`);
@@ -3790,37 +3901,37 @@ class Deparser {
3790
3901
  case 'TRANS_STMT_SAVEPOINT':
3791
3902
  output.push('SAVEPOINT');
3792
3903
  if (node.savepoint_name) {
3793
- output.push(quote_utils_1.QuoteUtils.quote(node.savepoint_name));
3904
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.savepoint_name));
3794
3905
  }
3795
3906
  break;
3796
3907
  case 'TRANS_STMT_RELEASE':
3797
3908
  output.push('RELEASE SAVEPOINT');
3798
3909
  if (node.savepoint_name) {
3799
- output.push(quote_utils_1.QuoteUtils.quote(node.savepoint_name));
3910
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.savepoint_name));
3800
3911
  }
3801
3912
  break;
3802
3913
  case 'TRANS_STMT_ROLLBACK_TO':
3803
3914
  output.push('ROLLBACK TO');
3804
3915
  if (node.savepoint_name) {
3805
- output.push(quote_utils_1.QuoteUtils.quote(node.savepoint_name));
3916
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.savepoint_name));
3806
3917
  }
3807
3918
  break;
3808
3919
  case 'TRANS_STMT_PREPARE':
3809
3920
  output.push('PREPARE TRANSACTION');
3810
3921
  if (node.gid) {
3811
- output.push(`'${node.gid}'`);
3922
+ output.push(quotes_1.QuoteUtils.escape(node.gid));
3812
3923
  }
3813
3924
  break;
3814
3925
  case 'TRANS_STMT_COMMIT_PREPARED':
3815
3926
  output.push('COMMIT PREPARED');
3816
3927
  if (node.gid) {
3817
- output.push(`'${node.gid}'`);
3928
+ output.push(quotes_1.QuoteUtils.escape(node.gid));
3818
3929
  }
3819
3930
  break;
3820
3931
  case 'TRANS_STMT_ROLLBACK_PREPARED':
3821
3932
  output.push('ROLLBACK PREPARED');
3822
3933
  if (node.gid) {
3823
- output.push(`'${node.gid}'`);
3934
+ output.push(quotes_1.QuoteUtils.escape(node.gid));
3824
3935
  }
3825
3936
  break;
3826
3937
  default:
@@ -3887,28 +3998,39 @@ class Deparser {
3887
3998
  switch (node.kind) {
3888
3999
  case 'VAR_SET_VALUE':
3889
4000
  const localPrefix = node.is_local ? 'LOCAL ' : '';
4001
+ if (node.jumble_args && node.name === 'xmloption' && node.args) {
4002
+ const xmlValue = this.getNodeData(list_utils_1.ListUtils.unwrapList(node.args)[0]);
4003
+ const xmlOption = (typeof xmlValue.sval === 'object' ? xmlValue.sval.sval : xmlValue.sval) || '';
4004
+ return `SET ${localPrefix}XML OPTION ${xmlOption.toUpperCase()}`;
4005
+ }
3890
4006
  const args = node.args ? list_utils_1.ListUtils.unwrapList(node.args).map(arg => {
3891
4007
  const nodeData = this.getNodeData(arg);
3892
4008
  if (nodeData.sval !== undefined) {
3893
4009
  const svalValue = typeof nodeData.sval === 'object' ? nodeData.sval.sval : nodeData.sval;
3894
- if (svalValue === '' || svalValue.includes(' ') || svalValue.includes('-') || /[A-Z]/.test(svalValue) || /^\d/.test(svalValue) || svalValue.includes('.') || svalValue.includes('$') || svalValue.toLowerCase() === 'all' || /^[+-]\d/.test(svalValue)) {
3895
- return `'${svalValue}'`;
4010
+ if (!/^[a-z_][a-z0-9_]*$/.test(svalValue) || svalValue.includes(' ') || svalValue.includes('-') || /[A-Z]/.test(svalValue) || /^\d/.test(svalValue) || svalValue.includes('.') || svalValue.includes('$') || svalValue.toLowerCase() === 'all' || /^[+-]\d/.test(svalValue)) {
4011
+ return quotes_1.QuoteUtils.escape(svalValue);
3896
4012
  }
3897
4013
  return svalValue;
3898
4014
  }
3899
4015
  return this.visit(arg, context);
3900
4016
  }).join(', ') : '';
4017
+ if (node.jumble_args && node.name === 'timezone') {
4018
+ return `SET ${localPrefix}TIME ZONE ${args}`;
4019
+ }
3901
4020
  // Handle args - always include TO clause if args exist (even if empty string)
3902
- const paramName = node.name && (node.name.includes('.') || node.name.includes('-') || /[A-Z]/.test(node.name)) ? `"${node.name}"` : node.name;
4021
+ const paramName = quotes_1.QuoteUtils.quoteIdentifier(node.name);
3903
4022
  if (!node.args || node.args.length === 0) {
3904
4023
  return `SET ${localPrefix}${paramName}`;
3905
4024
  }
3906
4025
  return `SET ${localPrefix}${paramName} TO ${args}`;
3907
4026
  case 'VAR_SET_DEFAULT':
3908
- const defaultParamName = node.name && (node.name.includes('.') || node.name.includes('-') || /[A-Z]/.test(node.name)) ? `"${node.name}"` : node.name;
4027
+ if (node.jumble_args && node.name === 'timezone') {
4028
+ return `SET ${node.is_local ? 'LOCAL ' : ''}TIME ZONE DEFAULT`;
4029
+ }
4030
+ const defaultParamName = quotes_1.QuoteUtils.quoteIdentifier(node.name);
3909
4031
  return `SET ${defaultParamName} TO DEFAULT`;
3910
4032
  case 'VAR_SET_CURRENT':
3911
- const currentParamName = node.name && (node.name.includes('.') || node.name.includes('-') || /[A-Z]/.test(node.name)) ? `"${node.name}"` : node.name;
4033
+ const currentParamName = quotes_1.QuoteUtils.quoteIdentifier(node.name);
3912
4034
  return `SET ${currentParamName} FROM CURRENT`;
3913
4035
  case 'VAR_SET_MULTI':
3914
4036
  if (node.name === 'TRANSACTION' || node.name === 'SESSION CHARACTERISTICS') {
@@ -3982,7 +4104,7 @@ class Deparser {
3982
4104
  return `SET ${assignments}`;
3983
4105
  }
3984
4106
  case 'VAR_RESET':
3985
- const resetParamName = node.name && (node.name.includes('.') || node.name.includes('-') || /[A-Z]/.test(node.name)) ? `"${node.name}"` : node.name;
4107
+ const resetParamName = quotes_1.QuoteUtils.quoteIdentifier(node.name);
3986
4108
  return `RESET ${resetParamName}`;
3987
4109
  case 'VAR_RESET_ALL':
3988
4110
  return 'RESET ALL';
@@ -4002,7 +4124,7 @@ class Deparser {
4002
4124
  output.push('IF NOT EXISTS');
4003
4125
  }
4004
4126
  if (node.schemaname) {
4005
- output.push(node.schemaname);
4127
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.schemaname));
4006
4128
  }
4007
4129
  if (node.authrole) {
4008
4130
  output.push('AUTHORIZATION');
@@ -4209,7 +4331,7 @@ class Deparser {
4209
4331
  if (objList && objList.List && objList.List.items) {
4210
4332
  const items = objList.List.items.map((item) => {
4211
4333
  if (item.String && item.String.sval) {
4212
- return item.String.sval;
4334
+ return quotes_1.QuoteUtils.quoteIdentifier(item.String.sval);
4213
4335
  }
4214
4336
  return this.visit(item, context);
4215
4337
  });
@@ -4251,7 +4373,7 @@ class Deparser {
4251
4373
  if (objList && objList.List && objList.List.items) {
4252
4374
  const items = objList.List.items.map((item) => {
4253
4375
  if (item.String && item.String.sval) {
4254
- return quote_utils_1.QuoteUtils.quote(item.String.sval);
4376
+ return quotes_1.QuoteUtils.quoteIdentifier(item.String.sval);
4255
4377
  }
4256
4378
  return this.visit(item, context);
4257
4379
  }).filter((name) => name && name.trim());
@@ -4285,13 +4407,13 @@ class Deparser {
4285
4407
  if (items.length === 2) {
4286
4408
  const accessMethod = items[0];
4287
4409
  const objectName = items[1];
4288
- return `${quote_utils_1.QuoteUtils.quote(objectName)} USING ${accessMethod}`;
4410
+ return `${quotes_1.QuoteUtils.quoteIdentifier(objectName)} USING ${accessMethod}`;
4289
4411
  }
4290
4412
  else if (items.length === 3) {
4291
4413
  const accessMethod = items[0];
4292
4414
  const schemaName = items[1];
4293
4415
  const objectName = items[2];
4294
- return `${quote_utils_1.QuoteUtils.quote(schemaName)}.${quote_utils_1.QuoteUtils.quote(objectName)} USING ${accessMethod}`;
4416
+ return `${quotes_1.QuoteUtils.quoteQualifiedIdentifier(schemaName, objectName)} USING ${accessMethod}`;
4295
4417
  }
4296
4418
  return items.join('.');
4297
4419
  }
@@ -4334,7 +4456,7 @@ class Deparser {
4334
4456
  if (objList && objList.List && objList.List.items) {
4335
4457
  const items = objList.List.items.map((item) => {
4336
4458
  if (item.String && item.String.sval) {
4337
- return quote_utils_1.QuoteUtils.quote(item.String.sval);
4459
+ return quotes_1.QuoteUtils.quoteIdentifier(item.String.sval);
4338
4460
  }
4339
4461
  return this.visit(item, context);
4340
4462
  }).filter((name) => name && name.trim());
@@ -4382,7 +4504,7 @@ class Deparser {
4382
4504
  PLAssignStmt(node, context) {
4383
4505
  const output = [];
4384
4506
  if (node.name) {
4385
- let nameWithIndirection = quote_utils_1.QuoteUtils.quote(node.name);
4507
+ let nameWithIndirection = quotes_1.QuoteUtils.quoteIdentifier(node.name);
4386
4508
  if (node.indirection && node.indirection.length > 0) {
4387
4509
  const indirectionStr = node.indirection
4388
4510
  .map((ind) => this.visit(ind, context))
@@ -4432,10 +4554,10 @@ class Deparser {
4432
4554
  output.push('PROGRAM');
4433
4555
  }
4434
4556
  if (node.filename) {
4435
- output.push(`'${node.filename}'`);
4557
+ output.push(quotes_1.QuoteUtils.escape(node.filename));
4436
4558
  }
4437
4559
  else {
4438
- output.push('STDIN');
4560
+ output.push(node.is_from ? 'STDIN' : 'STDOUT');
4439
4561
  }
4440
4562
  if (node.options && node.options.length > 0) {
4441
4563
  output.push('WITH');
@@ -4531,7 +4653,7 @@ class Deparser {
4531
4653
  const parts = [];
4532
4654
  const indentedParts = [];
4533
4655
  if (colDefData.colname) {
4534
- parts.push(quote_utils_1.QuoteUtils.quote(colDefData.colname));
4656
+ parts.push(quotes_1.QuoteUtils.quoteIdentifier(colDefData.colname));
4535
4657
  }
4536
4658
  if (colDefData.typeName) {
4537
4659
  parts.push(this.TypeName(colDefData.typeName, context));
@@ -4589,7 +4711,7 @@ class Deparser {
4589
4711
  else {
4590
4712
  const parts = [];
4591
4713
  if (colDefData.colname) {
4592
- parts.push(quote_utils_1.QuoteUtils.quote(colDefData.colname));
4714
+ parts.push(quotes_1.QuoteUtils.quoteIdentifier(colDefData.colname));
4593
4715
  }
4594
4716
  if (colDefData.typeName) {
4595
4717
  parts.push(this.TypeName(colDefData.typeName, context));
@@ -4643,7 +4765,7 @@ class Deparser {
4643
4765
  }
4644
4766
  }
4645
4767
  if (node.name) {
4646
- output.push(quote_utils_1.QuoteUtils.quote(node.name));
4768
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.name));
4647
4769
  }
4648
4770
  if (node.behavior === 'DROP_CASCADE') {
4649
4771
  output.push('CASCADE');
@@ -4660,13 +4782,16 @@ class Deparser {
4660
4782
  output.push('ALTER COLUMN');
4661
4783
  }
4662
4784
  if (node.name) {
4663
- output.push(quote_utils_1.QuoteUtils.quote(node.name));
4785
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.name));
4664
4786
  }
4665
4787
  output.push('TYPE');
4666
4788
  if (node.def) {
4667
4789
  const nodeData = this.getNodeData(node.def);
4668
4790
  if (nodeData && nodeData.typeName) {
4669
4791
  output.push(this.TypeName(nodeData.typeName, context));
4792
+ if (nodeData.collClause) {
4793
+ output.push(this.CollateClause(nodeData.collClause, context));
4794
+ }
4670
4795
  // Handle USING clause (stored in raw_default for ALTER COLUMN TYPE)
4671
4796
  if (nodeData.raw_default) {
4672
4797
  output.push('USING');
@@ -4687,7 +4812,7 @@ class Deparser {
4687
4812
  case 'AT_SetTableSpace':
4688
4813
  output.push('SET TABLESPACE');
4689
4814
  if (node.name) {
4690
- output.push(quote_utils_1.QuoteUtils.quote(node.name));
4815
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.name));
4691
4816
  }
4692
4817
  break;
4693
4818
  case 'AT_AddConstraint':
@@ -4705,7 +4830,7 @@ class Deparser {
4705
4830
  output.push('DROP CONSTRAINT');
4706
4831
  }
4707
4832
  if (node.name) {
4708
- output.push(quote_utils_1.QuoteUtils.quote(node.name));
4833
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.name));
4709
4834
  }
4710
4835
  if (node.behavior === 'DROP_CASCADE') {
4711
4836
  output.push('CASCADE');
@@ -4743,7 +4868,7 @@ class Deparser {
4743
4868
  case 'AT_ColumnDefault':
4744
4869
  output.push('ALTER COLUMN');
4745
4870
  if (node.name) {
4746
- output.push(quote_utils_1.QuoteUtils.quote(node.name));
4871
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.name));
4747
4872
  }
4748
4873
  if (node.def) {
4749
4874
  output.push('SET DEFAULT');
@@ -4756,7 +4881,7 @@ class Deparser {
4756
4881
  case 'AT_SetStorage':
4757
4882
  output.push('ALTER COLUMN');
4758
4883
  if (node.name) {
4759
- output.push(quote_utils_1.QuoteUtils.quote(node.name));
4884
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.name));
4760
4885
  }
4761
4886
  output.push('SET STORAGE');
4762
4887
  if (node.def) {
@@ -4767,7 +4892,7 @@ class Deparser {
4767
4892
  case 'AT_ClusterOn':
4768
4893
  output.push('CLUSTER ON');
4769
4894
  if (node.name) {
4770
- output.push(quote_utils_1.QuoteUtils.quote(node.name));
4895
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.name));
4771
4896
  }
4772
4897
  break;
4773
4898
  case 'AT_DropCluster':
@@ -4794,21 +4919,21 @@ class Deparser {
4794
4919
  case 'AT_SetNotNull':
4795
4920
  output.push('ALTER COLUMN');
4796
4921
  if (node.name) {
4797
- output.push(quote_utils_1.QuoteUtils.quote(node.name));
4922
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.name));
4798
4923
  }
4799
4924
  output.push('SET NOT NULL');
4800
4925
  break;
4801
4926
  case 'AT_DropNotNull':
4802
4927
  output.push('ALTER COLUMN');
4803
4928
  if (node.name) {
4804
- output.push(quote_utils_1.QuoteUtils.quote(node.name));
4929
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.name));
4805
4930
  }
4806
4931
  output.push('DROP NOT NULL');
4807
4932
  break;
4808
4933
  case 'AT_SetStatistics':
4809
4934
  output.push('ALTER COLUMN');
4810
4935
  if (node.name) {
4811
- output.push(quote_utils_1.QuoteUtils.quote(node.name));
4936
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.name));
4812
4937
  }
4813
4938
  else if (node.num !== undefined && node.num !== null) {
4814
4939
  output.push(node.num.toString());
@@ -4821,7 +4946,7 @@ class Deparser {
4821
4946
  case 'AT_SetOptions':
4822
4947
  output.push('ALTER COLUMN');
4823
4948
  if (node.name) {
4824
- output.push(quote_utils_1.QuoteUtils.quote(node.name));
4949
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.name));
4825
4950
  }
4826
4951
  output.push('SET');
4827
4952
  if (node.def) {
@@ -4838,7 +4963,7 @@ class Deparser {
4838
4963
  case 'AT_ResetOptions':
4839
4964
  output.push('ALTER COLUMN');
4840
4965
  if (node.name) {
4841
- output.push(quote_utils_1.QuoteUtils.quote(node.name));
4966
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.name));
4842
4967
  }
4843
4968
  output.push('RESET');
4844
4969
  if (node.def) {
@@ -4855,7 +4980,7 @@ class Deparser {
4855
4980
  case 'AT_SetCompression':
4856
4981
  output.push('ALTER COLUMN');
4857
4982
  if (node.name) {
4858
- output.push(quote_utils_1.QuoteUtils.quote(node.name));
4983
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.name));
4859
4984
  }
4860
4985
  output.push('SET COMPRESSION');
4861
4986
  if (node.def) {
@@ -4865,31 +4990,31 @@ class Deparser {
4865
4990
  case 'AT_ValidateConstraint':
4866
4991
  output.push('VALIDATE CONSTRAINT');
4867
4992
  if (node.name) {
4868
- output.push(quote_utils_1.QuoteUtils.quote(node.name));
4993
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.name));
4869
4994
  }
4870
4995
  break;
4871
4996
  case 'AT_EnableTrig':
4872
4997
  output.push('ENABLE TRIGGER');
4873
4998
  if (node.name) {
4874
- output.push(quote_utils_1.QuoteUtils.quote(node.name));
4999
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.name));
4875
5000
  }
4876
5001
  break;
4877
5002
  case 'AT_EnableAlwaysTrig':
4878
5003
  output.push('ENABLE ALWAYS TRIGGER');
4879
5004
  if (node.name) {
4880
- output.push(quote_utils_1.QuoteUtils.quote(node.name));
5005
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.name));
4881
5006
  }
4882
5007
  break;
4883
5008
  case 'AT_EnableReplicaTrig':
4884
5009
  output.push('ENABLE REPLICA TRIGGER');
4885
5010
  if (node.name) {
4886
- output.push(quote_utils_1.QuoteUtils.quote(node.name));
5011
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.name));
4887
5012
  }
4888
5013
  break;
4889
5014
  case 'AT_DisableTrig':
4890
5015
  output.push('DISABLE TRIGGER');
4891
5016
  if (node.name) {
4892
- output.push(quote_utils_1.QuoteUtils.quote(node.name));
5017
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.name));
4893
5018
  }
4894
5019
  break;
4895
5020
  case 'AT_EnableTrigAll':
@@ -4907,31 +5032,31 @@ class Deparser {
4907
5032
  case 'AT_EnableRule':
4908
5033
  output.push('ENABLE RULE');
4909
5034
  if (node.name) {
4910
- output.push(quote_utils_1.QuoteUtils.quote(node.name));
5035
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.name));
4911
5036
  }
4912
5037
  break;
4913
5038
  case 'AT_EnableAlwaysRule':
4914
5039
  output.push('ENABLE ALWAYS RULE');
4915
5040
  if (node.name) {
4916
- output.push(quote_utils_1.QuoteUtils.quote(node.name));
5041
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.name));
4917
5042
  }
4918
5043
  break;
4919
5044
  case 'AT_EnableReplicaRule':
4920
5045
  output.push('ENABLE REPLICA RULE');
4921
5046
  if (node.name) {
4922
- output.push(quote_utils_1.QuoteUtils.quote(node.name));
5047
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.name));
4923
5048
  }
4924
5049
  break;
4925
5050
  case 'AT_DisableRule':
4926
5051
  output.push('DISABLE RULE');
4927
5052
  if (node.name) {
4928
- output.push(quote_utils_1.QuoteUtils.quote(node.name));
5053
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.name));
4929
5054
  }
4930
5055
  break;
4931
5056
  case 'AT_SetAccessMethod':
4932
5057
  output.push('SET ACCESS METHOD');
4933
5058
  if (node.name) {
4934
- output.push(quote_utils_1.QuoteUtils.quote(node.name));
5059
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.name));
4935
5060
  }
4936
5061
  else {
4937
5062
  // Handle DEFAULT access method case
@@ -4985,7 +5110,7 @@ class Deparser {
4985
5110
  case 'AT_CookedColumnDefault':
4986
5111
  output.push('ALTER COLUMN');
4987
5112
  if (node.name) {
4988
- output.push(quote_utils_1.QuoteUtils.quote(node.name));
5113
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.name));
4989
5114
  }
4990
5115
  if (node.def) {
4991
5116
  output.push('SET DEFAULT');
@@ -4998,26 +5123,23 @@ class Deparser {
4998
5123
  case 'AT_SetExpression':
4999
5124
  output.push('ALTER COLUMN');
5000
5125
  if (node.name) {
5001
- output.push(quote_utils_1.QuoteUtils.quote(node.name));
5126
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.name));
5002
5127
  }
5003
5128
  output.push('SET EXPRESSION');
5004
5129
  if (node.def) {
5005
- output.push(this.visit(node.def, context));
5130
+ output.push('AS');
5131
+ output.push(context.parens(this.visit(node.def, context)));
5006
5132
  }
5007
5133
  break;
5008
5134
  case 'AT_DropExpression':
5009
5135
  output.push('ALTER COLUMN');
5010
5136
  if (node.name) {
5011
- output.push(quote_utils_1.QuoteUtils.quote(node.name));
5137
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.name));
5012
5138
  }
5013
5139
  output.push('DROP EXPRESSION');
5014
- break;
5015
- case 'AT_CheckNotNull':
5016
- output.push('ALTER COLUMN');
5017
- if (node.name) {
5018
- output.push(quote_utils_1.QuoteUtils.quote(node.name));
5140
+ if (node.missing_ok) {
5141
+ output.push('IF EXISTS');
5019
5142
  }
5020
- output.push('SET NOT NULL');
5021
5143
  break;
5022
5144
  case 'AT_AddIndex':
5023
5145
  output.push('ADD');
@@ -5044,23 +5166,28 @@ class Deparser {
5044
5166
  }
5045
5167
  break;
5046
5168
  case 'AT_AlterConstraint':
5047
- output.push('ALTER CONSTRAINT');
5048
- if (node.def && this.getNodeType(node.def) === 'Constraint') {
5049
- const constraintData = this.getNodeData(node.def);
5050
- if (constraintData.conname) {
5051
- output.push(quote_utils_1.QuoteUtils.quote(constraintData.conname));
5052
- if (constraintData.deferrable !== undefined) {
5053
- output.push(constraintData.deferrable ? 'DEFERRABLE' : 'NOT DEFERRABLE');
5054
- }
5055
- if (constraintData.initdeferred !== undefined) {
5056
- output.push(constraintData.initdeferred ? 'INITIALLY DEFERRED' : 'INITIALLY IMMEDIATE');
5169
+ if (node.def && this.getNodeType(node.def) === 'ATAlterConstraint') {
5170
+ output.push(this.ATAlterConstraint(this.getNodeData(node.def), context));
5171
+ }
5172
+ else {
5173
+ output.push('ALTER CONSTRAINT');
5174
+ if (node.def && this.getNodeType(node.def) === 'Constraint') {
5175
+ const constraintData = this.getNodeData(node.def);
5176
+ if (constraintData.conname) {
5177
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(constraintData.conname));
5178
+ if (constraintData.deferrable !== undefined) {
5179
+ output.push(constraintData.deferrable ? 'DEFERRABLE' : 'NOT DEFERRABLE');
5180
+ }
5181
+ if (constraintData.initdeferred !== undefined) {
5182
+ output.push(constraintData.initdeferred ? 'INITIALLY DEFERRED' : 'INITIALLY IMMEDIATE');
5183
+ }
5057
5184
  }
5058
5185
  }
5059
- }
5060
- else if (node.name) {
5061
- output.push(quote_utils_1.QuoteUtils.quote(node.name));
5062
- if (node.def) {
5063
- output.push(this.visit(node.def, context));
5186
+ else if (node.name) {
5187
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.name));
5188
+ if (node.def) {
5189
+ output.push(this.visit(node.def, context));
5190
+ }
5064
5191
  }
5065
5192
  }
5066
5193
  break;
@@ -5079,7 +5206,7 @@ class Deparser {
5079
5206
  case 'AT_AlterColumnGenericOptions':
5080
5207
  output.push('ALTER COLUMN');
5081
5208
  if (node.name) {
5082
- output.push(quote_utils_1.QuoteUtils.quote(node.name));
5209
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.name));
5083
5210
  }
5084
5211
  output.push('OPTIONS');
5085
5212
  if (node.def) {
@@ -5133,7 +5260,7 @@ class Deparser {
5133
5260
  case 'AT_AddIdentity':
5134
5261
  output.push('ALTER COLUMN');
5135
5262
  if (node.name) {
5136
- output.push(quote_utils_1.QuoteUtils.quote(node.name));
5263
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.name));
5137
5264
  }
5138
5265
  output.push('ADD');
5139
5266
  if (node.def) {
@@ -5143,24 +5270,20 @@ class Deparser {
5143
5270
  case 'AT_SetIdentity':
5144
5271
  output.push('ALTER COLUMN');
5145
5272
  if (node.name) {
5146
- output.push(quote_utils_1.QuoteUtils.quote(node.name));
5273
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.name));
5147
5274
  }
5148
- output.push('SET');
5149
5275
  if (node.def) {
5150
- output.push(this.visit(node.def, context));
5276
+ output.push(this.formatIdentityColumnOptions(node.def, context));
5151
5277
  }
5152
5278
  break;
5153
5279
  case 'AT_DropIdentity':
5154
5280
  output.push('ALTER COLUMN');
5155
5281
  if (node.name) {
5156
- output.push(quote_utils_1.QuoteUtils.quote(node.name));
5282
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.name));
5157
5283
  }
5158
5284
  output.push('DROP IDENTITY');
5159
- if (node.behavior === 'DROP_CASCADE') {
5160
- output.push('CASCADE');
5161
- }
5162
- else if (node.behavior === 'DROP_RESTRICT') {
5163
- output.push('RESTRICT');
5285
+ if (node.missing_ok) {
5286
+ output.push('IF EXISTS');
5164
5287
  }
5165
5288
  break;
5166
5289
  case 'AT_ReAddStatistics':
@@ -5187,7 +5310,8 @@ class Deparser {
5187
5310
  output.push('FUNCTION');
5188
5311
  }
5189
5312
  if (node.funcname && node.funcname.length > 0) {
5190
- const funcName = node.funcname.map((name) => this.visit(name, context)).join('.');
5313
+ const funcnameParts = node.funcname.map((name) => name.String?.sval || name.String?.str || '').filter((s) => s);
5314
+ const funcName = quotes_1.QuoteUtils.quoteDottedName(funcnameParts);
5191
5315
  if (node.parameters && node.parameters.length > 0) {
5192
5316
  const params = node.parameters
5193
5317
  .filter((param) => {
@@ -5196,7 +5320,13 @@ class Deparser {
5196
5320
  })
5197
5321
  .map((param) => this.visit(param, context));
5198
5322
  if (params.length > 0) {
5199
- output.push(funcName + '(' + params.join(', ') + ')');
5323
+ if (context.isPretty()) {
5324
+ const formattedParams = params.map(p => context.indent(p)).join(',' + context.newline());
5325
+ output.push(funcName + '(' + context.newline() + formattedParams + context.newline() + ')');
5326
+ }
5327
+ else {
5328
+ output.push(funcName + '(' + params.join(', ') + ')');
5329
+ }
5200
5330
  }
5201
5331
  else {
5202
5332
  output.push(funcName + '()');
@@ -5211,15 +5341,21 @@ class Deparser {
5211
5341
  return paramData.mode === 'FUNC_PARAM_TABLE';
5212
5342
  });
5213
5343
  if (hasTableParams) {
5214
- output.push('RETURNS TABLE (');
5215
5344
  const tableParams = node.parameters
5216
5345
  .filter((param) => {
5217
5346
  const paramData = this.getNodeData(param);
5218
5347
  return paramData.mode === 'FUNC_PARAM_TABLE';
5219
5348
  })
5220
5349
  .map((param) => this.visit(param, context));
5221
- output.push(tableParams.join(', '));
5222
- output.push(')');
5350
+ if (context.isPretty()) {
5351
+ const formattedTableParams = tableParams.map(p => context.indent(p)).join(',' + context.newline());
5352
+ output.push('RETURNS TABLE (' + context.newline() + formattedTableParams + context.newline() + ')');
5353
+ }
5354
+ else {
5355
+ output.push('RETURNS TABLE (');
5356
+ output.push(tableParams.join(', '));
5357
+ output.push(')');
5358
+ }
5223
5359
  }
5224
5360
  else if (node.returnType) {
5225
5361
  output.push('RETURNS');
@@ -5241,6 +5377,7 @@ class Deparser {
5241
5377
  if (bodyType === 'List') {
5242
5378
  const statements = list_utils_1.ListUtils.unwrapList(node.sql_body);
5243
5379
  if (statements.length === 0 || (statements.length === 1 && Object.keys(statements[0]).length === 0)) {
5380
+ // empty body: nothing to emit
5244
5381
  }
5245
5382
  else {
5246
5383
  // Handle nested List structure in BEGIN ATOMIC blocks
@@ -5292,7 +5429,7 @@ class Deparser {
5292
5429
  }
5293
5430
  }
5294
5431
  if (node.name) {
5295
- output.push(quote_utils_1.QuoteUtils.quote(node.name));
5432
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.name));
5296
5433
  }
5297
5434
  if (node.argType) {
5298
5435
  output.push(this.TypeName(node.argType, context));
@@ -5364,7 +5501,7 @@ class Deparser {
5364
5501
  output.push('ROLE');
5365
5502
  }
5366
5503
  if (node.role) {
5367
- const roleName = Deparser.needsQuotes(node.role) ? `"${node.role}"` : node.role;
5504
+ const roleName = quotes_1.QuoteUtils.quoteIdentifier(node.role);
5368
5505
  output.push(roleName);
5369
5506
  }
5370
5507
  if (node.options) {
@@ -5388,25 +5525,28 @@ class Deparser {
5388
5525
  if (node.arg && this.getNodeType(node.arg) === 'List') {
5389
5526
  const listData = this.getNodeData(node.arg);
5390
5527
  const listItems = list_utils_1.ListUtils.unwrapList(listData.items);
5528
+ const preservedName = this.preserveOperatorDefElemCase(node.defname);
5391
5529
  if (listItems.length === 1 && listItems[0].String) {
5392
- const preservedName = this.preserveOperatorDefElemCase(node.defname);
5393
5530
  return `${preservedName} = ${listItems[0].String.sval}`;
5394
5531
  }
5532
+ if (listItems.length > 1 && listItems.every((item) => item.String)) {
5533
+ return `${preservedName} = OPERATOR(${this.qualifiedOperatorName(listItems)})`;
5534
+ }
5395
5535
  }
5396
5536
  }
5397
5537
  // Handle IndexElem opclassopts - MUST be first to preserve string types
5398
5538
  if (context.parentNodeTypes.includes('IndexElem')) {
5399
5539
  if (node.arg && this.getNodeType(node.arg) === 'String') {
5400
5540
  const stringData = this.getNodeData(node.arg);
5401
- return `${node.defname}='${stringData.sval}'`;
5541
+ return `${quotes_1.QuoteUtils.quoteIdentifierAfterDot(node.defname)}=${quotes_1.QuoteUtils.escape(stringData.sval)}`;
5402
5542
  }
5403
- return `${node.defname}=${this.visit(node.arg, context.spawn('DefElem'))}`;
5543
+ return `${quotes_1.QuoteUtils.quoteIdentifierAfterDot(node.defname)}=${this.formatOptionValue(node.arg, this.visit(node.arg, context.spawn('DefElem')))}`;
5404
5544
  }
5405
5545
  // Handle CREATE OPERATOR boolean flags - MUST be first to preserve case
5406
5546
  if (context.parentNodeTypes.includes('DefineStmt') &&
5407
5547
  ['hashes', 'merges'].includes(node.defname.toLowerCase()) && !node.arg) {
5408
5548
  if (node.defname !== node.defname.toLowerCase() && node.defname !== node.defname.toUpperCase()) {
5409
- return `"${node.defname}"`;
5549
+ return quotes_1.QuoteUtils.quoteIdentifier(node.defname);
5410
5550
  }
5411
5551
  return node.defname.charAt(0).toUpperCase() + node.defname.slice(1).toLowerCase();
5412
5552
  }
@@ -5425,12 +5565,8 @@ class Deparser {
5425
5565
  const defElemContext = context.spawn('DefElem');
5426
5566
  const argValue = this.visit(node.arg, defElemContext);
5427
5567
  if (context.parentNodeTypes.includes('CreateFdwStmt') || context.parentNodeTypes.includes('AlterFdwStmt')) {
5428
- const finalValue = typeof argValue === 'string' && !argValue.startsWith("'")
5429
- ? `'${argValue}'`
5430
- : argValue;
5431
- const quotedDefname = node.defname.includes(' ') || node.defname.includes('-') || Deparser.needsQuotes(node.defname)
5432
- ? `"${node.defname}"`
5433
- : node.defname;
5568
+ const finalValue = this.quoteDefElemArg(node.arg, argValue);
5569
+ const quotedDefname = quotes_1.QuoteUtils.quoteIdentifier(node.defname);
5434
5570
  if (node.defaction === 'DEFELEM_ADD') {
5435
5571
  return `ADD ${quotedDefname} ${finalValue}`;
5436
5572
  }
@@ -5442,9 +5578,7 @@ class Deparser {
5442
5578
  }
5443
5579
  return `${quotedDefname} ${finalValue}`;
5444
5580
  }
5445
- const quotedValue = typeof argValue === 'string' && !argValue.startsWith("'")
5446
- ? `'${argValue}'`
5447
- : argValue;
5581
+ const quotedValue = this.quoteDefElemArg(node.arg, argValue);
5448
5582
  if (node.defaction === 'DEFELEM_ADD') {
5449
5583
  return `ADD ${node.defname} ${quotedValue}`;
5450
5584
  }
@@ -5454,9 +5588,7 @@ class Deparser {
5454
5588
  else if (node.defaction === 'DEFELEM_SET') {
5455
5589
  return `SET ${node.defname} ${quotedValue}`;
5456
5590
  }
5457
- const quotedDefname = node.defname.includes(' ') || node.defname.includes('-')
5458
- ? `"${node.defname}"`
5459
- : node.defname;
5591
+ const quotedDefname = quotes_1.QuoteUtils.quoteIdentifier(node.defname);
5460
5592
  return `${quotedDefname} ${quotedValue}`;
5461
5593
  }
5462
5594
  else if (node.defaction === 'DEFELEM_DROP') {
@@ -5478,9 +5610,7 @@ class Deparser {
5478
5610
  }
5479
5611
  const defElemContext = context.spawn('DefElem');
5480
5612
  const argValue = this.visit(node.arg, defElemContext);
5481
- const quotedValue = typeof argValue === 'string' && !argValue.startsWith("'")
5482
- ? `'${argValue}'`
5483
- : argValue;
5613
+ const quotedValue = this.quoteDefElemArg(node.arg, argValue);
5484
5614
  return `PASSWORD ${quotedValue}`;
5485
5615
  }
5486
5616
  }
@@ -5503,22 +5633,23 @@ class Deparser {
5503
5633
  if (listItems.length === 1 && listItems[0].String) {
5504
5634
  return `${node.defname} = ${listItems[0].String.sval}`;
5505
5635
  }
5636
+ if (listItems.length > 1 && listItems.every((item) => item.String)) {
5637
+ return `${node.defname} = OPERATOR(${this.qualifiedOperatorName(listItems)})`;
5638
+ }
5506
5639
  }
5507
5640
  }
5508
5641
  if (context.parentNodeTypes.includes('CreatedbStmt') || context.parentNodeTypes.includes('DropdbStmt')) {
5509
5642
  const quotedValue = typeof argValue === 'string'
5510
- ? quote_utils_1.QuoteUtils.escape(argValue)
5643
+ ? quotes_1.QuoteUtils.escape(argValue)
5511
5644
  : argValue;
5512
5645
  return `${node.defname} = ${quotedValue}`;
5513
5646
  }
5514
5647
  // CreateForeignServerStmt and AlterForeignServerStmt use space format like CreateFdwStmt
5515
5648
  if (context.parentNodeTypes.includes('CreateForeignServerStmt') || context.parentNodeTypes.includes('AlterForeignServerStmt')) {
5516
5649
  const quotedValue = typeof argValue === 'string'
5517
- ? quote_utils_1.QuoteUtils.escape(argValue)
5650
+ ? quotes_1.QuoteUtils.escape(argValue)
5518
5651
  : argValue;
5519
- const quotedDefname = node.defname.includes(' ') || node.defname.includes('-')
5520
- ? `"${node.defname}"`
5521
- : node.defname;
5652
+ const quotedDefname = quotes_1.QuoteUtils.quoteIdentifier(node.defname);
5522
5653
  return `${quotedDefname} ${quotedValue}`;
5523
5654
  }
5524
5655
  if (context.parentNodeTypes.includes('CreateRoleStmt') || context.parentNodeTypes.includes('AlterRoleStmt')) {
@@ -5547,9 +5678,7 @@ class Deparser {
5547
5678
  }
5548
5679
  }
5549
5680
  if (node.defname === 'validUntil') {
5550
- const quotedValue = typeof argValue === 'string' && !argValue.startsWith("'")
5551
- ? `'${argValue}'`
5552
- : argValue;
5681
+ const quotedValue = this.quoteDefElemArg(node.arg, argValue);
5553
5682
  return `VALID UNTIL ${quotedValue}`;
5554
5683
  }
5555
5684
  if (node.defname === 'adminmembers') {
@@ -5588,15 +5717,15 @@ class Deparser {
5588
5717
  if (node.arg && this.getNodeType(node.arg) === 'List') {
5589
5718
  const listData = this.getNodeData(node.arg);
5590
5719
  const listItems = list_utils_1.ListUtils.unwrapList(listData.items);
5720
+ if (listItems.length === 1 && listItems[0].String?.sval === 'none') {
5721
+ return 'OWNED BY NONE';
5722
+ }
5591
5723
  const parts = listItems.map(item => {
5592
5724
  const itemData = this.getNodeData(item);
5593
5725
  if (this.getNodeType(item) === 'String') {
5594
5726
  // Check if this identifier needs quotes to preserve case
5595
5727
  const value = itemData.sval;
5596
- if (Deparser.needsQuotes(value)) {
5597
- return `"${value}"`;
5598
- }
5599
- return value;
5728
+ return quotes_1.QuoteUtils.quoteIdentifier(value);
5600
5729
  }
5601
5730
  return this.visit(item, context);
5602
5731
  });
@@ -5729,10 +5858,8 @@ class Deparser {
5729
5858
  if (context.parentNodeTypes.includes('AlterExtensionStmt')) {
5730
5859
  if (node.defname === 'new_version') {
5731
5860
  // argValue is unquoted due to DefElem context, so we need to quote it
5732
- const quotedValue = typeof argValue === 'string' && !argValue.startsWith("'")
5733
- ? `'${argValue}'`
5734
- : argValue;
5735
- return `UPDATE TO ${quotedValue}`;
5861
+ const quotedValue = this.quoteDefElemArg(node.arg, argValue);
5862
+ return `TO ${quotedValue}`;
5736
5863
  }
5737
5864
  if (node.defname === 'schema') {
5738
5865
  return `SET SCHEMA ${argValue}`;
@@ -5744,7 +5871,7 @@ class Deparser {
5744
5871
  return `${node.defname.toUpperCase()} ${argValue}`;
5745
5872
  }
5746
5873
  const quotedValue = typeof argValue === 'string'
5747
- ? quote_utils_1.QuoteUtils.escape(argValue)
5874
+ ? quotes_1.QuoteUtils.escape(argValue)
5748
5875
  : argValue;
5749
5876
  return `${node.defname} ${quotedValue}`;
5750
5877
  }
@@ -5752,28 +5879,37 @@ class Deparser {
5752
5879
  if (node.defname === 'cascade') {
5753
5880
  return argValue === 'true' ? 'CASCADE' : '';
5754
5881
  }
5882
+ if (node.defname === 'new_version') {
5883
+ return `VERSION ${this.quoteDefElemArg(node.arg, argValue)}`;
5884
+ }
5885
+ if (node.defname === 'schema' && node.arg && this.getNodeType(node.arg) === 'String') {
5886
+ return `SCHEMA ${quotes_1.QuoteUtils.quoteIdentifier(this.getNodeData(node.arg).sval)}`;
5887
+ }
5755
5888
  return `${node.defname.toUpperCase()} ${argValue}`;
5756
5889
  }
5757
5890
  // Handle IndexStmt WITH clause options - no quotes, compact formatting
5758
5891
  if (context.parentNodeTypes.includes('IndexStmt')) {
5759
- return `${node.defname}=${argValue}`;
5892
+ return `${quotes_1.QuoteUtils.quoteIdentifierAfterDot(node.defname)}=${this.formatOptionValue(node.arg, argValue)}`;
5760
5893
  }
5761
5894
  // Handle IndexElem opclassopts - preserve string values as strings
5762
5895
  if (context.parentNodeTypes.includes('IndexElem')) {
5763
5896
  if (node.arg && this.getNodeType(node.arg) === 'String') {
5764
5897
  const stringData = this.getNodeData(node.arg);
5765
- return `${node.defname}='${stringData.sval}'`;
5898
+ return `${quotes_1.QuoteUtils.quoteIdentifierAfterDot(node.defname)}=${quotes_1.QuoteUtils.escape(stringData.sval)}`;
5766
5899
  }
5767
- return `${node.defname}=${argValue}`;
5900
+ return `${quotes_1.QuoteUtils.quoteIdentifierAfterDot(node.defname)}=${this.formatOptionValue(node.arg, argValue)}`;
5768
5901
  }
5769
5902
  // Handle CreateStmt table options - no quotes, compact formatting
5770
5903
  if (context.parentNodeTypes.includes('CreateStmt')) {
5904
+ const relOptName = node.defnamespace
5905
+ ? `${quotes_1.QuoteUtils.quoteIdentifier(node.defnamespace)}.${quotes_1.QuoteUtils.quoteIdentifier(node.defname)}`
5906
+ : quotes_1.QuoteUtils.quoteIdentifier(node.defname);
5771
5907
  // For numeric values, use the raw value without quotes
5772
5908
  if (node.arg && this.getNodeType(node.arg) === 'Integer') {
5773
5909
  const integerData = this.getNodeData(node.arg);
5774
- return `${node.defname}=${integerData.ival}`;
5910
+ return `${relOptName}=${formatInteger(integerData.ival)}`;
5775
5911
  }
5776
- return `${node.defname}=${argValue}`;
5912
+ return `${relOptName}=${this.formatOptionValue(node.arg, argValue)}`;
5777
5913
  }
5778
5914
  // Handle CreateEventTrigStmt WHEN clause - use IN syntax for List arguments
5779
5915
  if (context.parentNodeTypes.includes('CreateEventTrigStmt')) {
@@ -5783,7 +5919,7 @@ class Deparser {
5783
5919
  const values = listItems.map(item => {
5784
5920
  if (this.getNodeType(item) === 'String') {
5785
5921
  const stringData = this.getNodeData(item);
5786
- return `'${stringData.sval || ''}'`;
5922
+ return quotes_1.QuoteUtils.escape(stringData.sval || '');
5787
5923
  }
5788
5924
  return this.visit(item, context);
5789
5925
  });
@@ -5798,7 +5934,7 @@ class Deparser {
5798
5934
  if (node.arg && this.getNodeType(node.arg) === 'TypeName') {
5799
5935
  return `${optionName} = ${argValue}`;
5800
5936
  }
5801
- return `${optionName} = ${argValue}`;
5937
+ return `${optionName} = ${this.formatOptionValue(node.arg, argValue)}`;
5802
5938
  }
5803
5939
  // Handle ViewStmt WITH options - don't quote numeric values
5804
5940
  if (context.parentNodeTypes.includes('ViewStmt')) {
@@ -5806,21 +5942,33 @@ class Deparser {
5806
5942
  return `${node.defname}=${argValue}`;
5807
5943
  }
5808
5944
  const quotedValue = typeof argValue === 'string'
5809
- ? quote_utils_1.QuoteUtils.escape(argValue)
5945
+ ? quotes_1.QuoteUtils.escape(argValue)
5810
5946
  : argValue;
5811
5947
  return `${node.defname} = ${quotedValue}`;
5812
5948
  }
5813
5949
  // Handle CopyStmt WITH clause options - uppercase format without quotes
5814
5950
  if (context.parentNodeTypes.includes('CopyStmt')) {
5815
- if (node.defname === 'format' && node.arg && this.getNodeType(node.arg) === 'String') {
5816
- const stringData = this.getNodeData(node.arg);
5817
- return `FORMAT ${stringData.sval.toUpperCase()}`;
5951
+ const optName = node.defname.toUpperCase();
5952
+ if (!node.arg) {
5953
+ return optName;
5818
5954
  }
5819
- // Handle other COPY options with uppercase defname
5820
- if (node.arg) {
5821
- return `${node.defname.toUpperCase()} ${argValue}`;
5955
+ const copyArgType = this.getNodeType(node.arg);
5956
+ if (copyArgType === 'Boolean' && this.getNodeData(node.arg).boolval !== false) {
5957
+ return optName;
5822
5958
  }
5823
- return node.defname.toUpperCase();
5959
+ if (copyArgType === 'List') {
5960
+ const items = list_utils_1.ListUtils.unwrapList(this.getNodeData(node.arg).items)
5961
+ .map(item => this.visit(item, context));
5962
+ return `${optName} (${items.join(', ')})`;
5963
+ }
5964
+ if (copyArgType === 'String') {
5965
+ const sval = this.getNodeData(node.arg).sval;
5966
+ if (node.defname === 'format') {
5967
+ return `${optName} ${sval}`;
5968
+ }
5969
+ return `${optName} ${quotes_1.QuoteUtils.escape(sval)}`;
5970
+ }
5971
+ return `${optName} ${argValue}`;
5824
5972
  }
5825
5973
  // Handle CREATE OPERATOR and CREATE TYPE context
5826
5974
  if (context.parentNodeTypes.includes('DefineStmt')) {
@@ -5844,13 +5992,13 @@ class Deparser {
5844
5992
  // Handle boolean flags (no arguments) - preserve quoted case
5845
5993
  if (['hashes', 'merges'].includes(node.defname.toLowerCase())) {
5846
5994
  if (node.defname !== node.defname.toLowerCase() && node.defname !== node.defname.toUpperCase()) {
5847
- return `"${node.defname}"`;
5995
+ return quotes_1.QuoteUtils.quoteIdentifier(node.defname);
5848
5996
  }
5849
5997
  return preservedName.toUpperCase();
5850
5998
  }
5851
5999
  // Handle CREATE AGGREGATE quoted identifiers - preserve quotes when needed
5852
- if (Deparser.needsQuotes(node.defname)) {
5853
- const quotedDefname = `"${node.defname}"`;
6000
+ const quotedDefname = quotes_1.QuoteUtils.quoteIdentifier(node.defname);
6001
+ if (quotedDefname !== node.defname) {
5854
6002
  if (node.arg) {
5855
6003
  if (this.getNodeType(node.arg) === 'String') {
5856
6004
  const stringData = this.getNodeData(node.arg);
@@ -5859,7 +6007,7 @@ class Deparser {
5859
6007
  return `${quotedDefname} = ${stringData.sval}`;
5860
6008
  }
5861
6009
  // Regular string literals get single quotes
5862
- return `${quotedDefname} = '${stringData.sval}'`;
6010
+ return `${quotedDefname} = ${quotes_1.QuoteUtils.escape(stringData.sval)}`;
5863
6011
  }
5864
6012
  return `${quotedDefname} = ${argValue}`;
5865
6013
  }
@@ -5880,7 +6028,7 @@ class Deparser {
5880
6028
  return `${node.defname} = ${stringData.sval}`;
5881
6029
  }
5882
6030
  // Regular string literals get single quotes
5883
- return `${node.defname} = '${stringData.sval}'`;
6031
+ return `${node.defname} = ${quotes_1.QuoteUtils.escape(stringData.sval)}`;
5884
6032
  }
5885
6033
  if (node.arg && this.getNodeType(node.arg) === 'Boolean') {
5886
6034
  const boolData = this.getNodeData(node.arg);
@@ -5901,8 +6049,12 @@ class Deparser {
5901
6049
  return `${node.defname} = ${argValue}`;
5902
6050
  }
5903
6051
  }
6052
+ const argType = this.getNodeType(node.arg);
6053
+ if (argType === 'TypeName' || argType === 'Integer' || argType === 'Float' || argType === 'Boolean') {
6054
+ return `${node.defname} = ${argValue}`;
6055
+ }
5904
6056
  const quotedValue = typeof argValue === 'string'
5905
- ? quote_utils_1.QuoteUtils.escape(argValue)
6057
+ ? quotes_1.QuoteUtils.escape(argValue)
5906
6058
  : argValue;
5907
6059
  return `${node.defname} = ${quotedValue}`;
5908
6060
  }
@@ -5910,7 +6062,7 @@ class Deparser {
5910
6062
  if (context.parentNodeTypes.includes('DefineStmt') && !node.arg) {
5911
6063
  // Check if the original defname appears to be quoted (mixed case that's not all upper/lower)
5912
6064
  if (node.defname !== node.defname.toLowerCase() && node.defname !== node.defname.toUpperCase()) {
5913
- return `"${node.defname}"`;
6065
+ return quotes_1.QuoteUtils.quoteIdentifier(node.defname);
5914
6066
  }
5915
6067
  }
5916
6068
  return node.defname.toUpperCase();
@@ -5926,7 +6078,7 @@ class Deparser {
5926
6078
  }
5927
6079
  if (node.location) {
5928
6080
  output.push('LOCATION');
5929
- output.push(`'${node.location}'`);
6081
+ output.push(quotes_1.QuoteUtils.escape(node.location));
5930
6082
  }
5931
6083
  if (node.options && node.options.length > 0) {
5932
6084
  output.push('WITH');
@@ -5990,6 +6142,7 @@ class Deparser {
5990
6142
  if (node.extname) {
5991
6143
  output.push(this.quoteIfNeeded(node.extname));
5992
6144
  }
6145
+ output.push('UPDATE');
5993
6146
  if (node.options && node.options.length > 0) {
5994
6147
  const extContext = context.spawn('AlterExtensionStmt');
5995
6148
  const options = list_utils_1.ListUtils.unwrapList(node.options)
@@ -6094,7 +6247,7 @@ class Deparser {
6094
6247
  case 'REPLICA_IDENTITY_INDEX':
6095
6248
  output.push('USING', 'INDEX');
6096
6249
  if (node.name) {
6097
- output.push(quote_utils_1.QuoteUtils.quote(node.name));
6250
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.name));
6098
6251
  }
6099
6252
  break;
6100
6253
  default:
@@ -6153,7 +6306,7 @@ class Deparser {
6153
6306
  output.push('IF', 'EXISTS');
6154
6307
  }
6155
6308
  if (node.name) {
6156
- output.push(quote_utils_1.QuoteUtils.quote(node.name));
6309
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.name));
6157
6310
  }
6158
6311
  if (node.behavior === 'DROP_CASCADE') {
6159
6312
  output.push('CASCADE');
@@ -6162,7 +6315,7 @@ class Deparser {
6162
6315
  case 'AT_ValidateConstraint':
6163
6316
  output.push('VALIDATE', 'CONSTRAINT');
6164
6317
  if (node.name) {
6165
- output.push(quote_utils_1.QuoteUtils.quote(node.name));
6318
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.name));
6166
6319
  }
6167
6320
  break;
6168
6321
  case 'C':
@@ -6179,7 +6332,7 @@ class Deparser {
6179
6332
  output.push('IF', 'EXISTS');
6180
6333
  }
6181
6334
  if (node.name) {
6182
- output.push(quote_utils_1.QuoteUtils.quote(node.name));
6335
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.name));
6183
6336
  }
6184
6337
  if (node.behavior === 'DROP_CASCADE') {
6185
6338
  output.push('CASCADE');
@@ -6188,7 +6341,7 @@ class Deparser {
6188
6341
  case 'V':
6189
6342
  output.push('VALIDATE', 'CONSTRAINT');
6190
6343
  if (node.name) {
6191
- output.push(quote_utils_1.QuoteUtils.quote(node.name));
6344
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.name));
6192
6345
  }
6193
6346
  break;
6194
6347
  case 'O':
@@ -6259,7 +6412,7 @@ class Deparser {
6259
6412
  }
6260
6413
  if (node.payload !== null && node.payload !== undefined) {
6261
6414
  output.push(',');
6262
- output.push(`'${node.payload}'`);
6415
+ output.push(quotes_1.QuoteUtils.escape(node.payload));
6263
6416
  }
6264
6417
  return output.join(' ');
6265
6418
  }
@@ -6287,7 +6440,7 @@ class Deparser {
6287
6440
  if (!node.filename) {
6288
6441
  throw new Error('LoadStmt requires filename');
6289
6442
  }
6290
- return `LOAD '${node.filename}'`;
6443
+ return `LOAD ${quotes_1.QuoteUtils.escape(node.filename)}`;
6291
6444
  }
6292
6445
  DiscardStmt(node, context) {
6293
6446
  switch (node.target) {
@@ -6303,6 +6456,13 @@ class Deparser {
6303
6456
  throw new Error(`Unsupported DiscardStmt target: ${node.target}`);
6304
6457
  }
6305
6458
  }
6459
+ /** `schema.op` for an operator name list: schema parts quoted, the operator symbol as is. */
6460
+ qualifiedOperatorName(objname) {
6461
+ const names = list_utils_1.ListUtils.unwrapList(objname ?? []).map((n) => (n.String ? n.String.sval : 'unknown'));
6462
+ if (names.length === 0)
6463
+ return 'unknown';
6464
+ return [...names.slice(0, -1).map((n) => quotes_1.QuoteUtils.quoteIdentifier(n)), names[names.length - 1]].join('.');
6465
+ }
6306
6466
  CommentStmt(node, context) {
6307
6467
  const output = ['COMMENT ON'];
6308
6468
  if (node.objtype) {
@@ -6334,6 +6494,9 @@ class Deparser {
6334
6494
  case 'OBJECT_TABCONSTRAINT':
6335
6495
  output.push('CONSTRAINT');
6336
6496
  break;
6497
+ case 'OBJECT_DOMCONSTRAINT':
6498
+ output.push('CONSTRAINT');
6499
+ break;
6337
6500
  case 'OBJECT_TRIGGER':
6338
6501
  output.push('TRIGGER');
6339
6502
  break;
@@ -6410,23 +6573,30 @@ class Deparser {
6410
6573
  output.push(objectParts.join('.'));
6411
6574
  }
6412
6575
  }
6413
- else if (node.objtype === 'OBJECT_TRIGGER') {
6576
+ else if (node.objtype === 'OBJECT_DOMCONSTRAINT') {
6414
6577
  if (objectParts.length === 2) {
6415
- const [table, trigger] = objectParts;
6416
- output.push(trigger);
6578
+ const [domain, constraint] = objectParts;
6579
+ output.push(constraint, 'ON DOMAIN', domain);
6580
+ }
6581
+ else {
6582
+ output.push(objectParts.join('.'));
6583
+ }
6584
+ }
6585
+ else if (node.objtype === 'OBJECT_TRIGGER') {
6586
+ if (objectParts.length >= 2) {
6587
+ output.push(objectParts[objectParts.length - 1]);
6417
6588
  output.push('ON');
6418
- output.push(table);
6589
+ output.push(objectParts.slice(0, -1).join('.'));
6419
6590
  }
6420
6591
  else {
6421
6592
  output.push(objectParts.join('.'));
6422
6593
  }
6423
6594
  }
6424
6595
  else if (node.objtype === 'OBJECT_RULE') {
6425
- if (objectParts.length === 2) {
6426
- const [table, rule] = objectParts;
6427
- output.push(rule);
6596
+ if (objectParts.length >= 2) {
6597
+ output.push(objectParts[objectParts.length - 1]);
6428
6598
  output.push('ON');
6429
- output.push(table);
6599
+ output.push(objectParts.slice(0, -1).join('.'));
6430
6600
  }
6431
6601
  else {
6432
6602
  output.push(objectParts.join('.'));
@@ -6437,8 +6607,7 @@ class Deparser {
6437
6607
  // For operators, we need to handle ObjectWithArgs structure
6438
6608
  if (node.object && node.object.ObjectWithArgs) {
6439
6609
  const objWithArgs = node.object.ObjectWithArgs;
6440
- let operatorName = objWithArgs.objname && objWithArgs.objname[0] && objWithArgs.objname[0].String
6441
- ? objWithArgs.objname[0].String.sval : 'unknown';
6610
+ let operatorName = this.qualifiedOperatorName(objWithArgs.objname);
6442
6611
  if (operatorName.startsWith('"') && operatorName.endsWith('"')) {
6443
6612
  operatorName = operatorName.slice(1, -1);
6444
6613
  }
@@ -6476,7 +6645,13 @@ class Deparser {
6476
6645
  }
6477
6646
  else if (node.objtype === 'OBJECT_POLICY') {
6478
6647
  // Handle POLICY syntax: COMMENT ON POLICY policy_name ON table_name IS 'comment'
6479
- if (objectParts.length === 2) {
6648
+ if (objectParts.length === 3) {
6649
+ const [schema, table, policy] = objectParts;
6650
+ output.push(policy);
6651
+ output.push('ON');
6652
+ output.push(`${schema}.${table}`);
6653
+ }
6654
+ else if (objectParts.length === 2) {
6480
6655
  const [table, policy] = objectParts;
6481
6656
  output.push(policy);
6482
6657
  output.push('ON');
@@ -6499,6 +6674,9 @@ class Deparser {
6499
6674
  output.push(objectParts.join('.'));
6500
6675
  }
6501
6676
  }
6677
+ else if (node.objtype === 'OBJECT_CAST' && objectParts.length === 2) {
6678
+ output.push(`(${objectParts[0]} AS ${objectParts[1]})`);
6679
+ }
6502
6680
  else {
6503
6681
  output.push(objectParts.join('.'));
6504
6682
  }
@@ -6507,8 +6685,7 @@ class Deparser {
6507
6685
  else if (node.objtype === 'OBJECT_OPERATOR' && node.object && node.object.ObjectWithArgs) {
6508
6686
  // Handle direct ObjectWithArgs for OPERATOR syntax: COMMENT ON OPERATOR -(NONE, integer) IS 'comment'
6509
6687
  const objWithArgs = node.object.ObjectWithArgs;
6510
- let operatorName = objWithArgs.objname && objWithArgs.objname[0] && objWithArgs.objname[0].String
6511
- ? objWithArgs.objname[0].String.sval : 'unknown';
6688
+ let operatorName = this.qualifiedOperatorName(objWithArgs.objname);
6512
6689
  // Remove quotes from operator name if present
6513
6690
  if (operatorName.startsWith('"') && operatorName.endsWith('"')) {
6514
6691
  operatorName = operatorName.slice(1, -1);
@@ -6540,7 +6717,7 @@ class Deparser {
6540
6717
  output.push('NULL');
6541
6718
  }
6542
6719
  else if (node.comment) {
6543
- output.push(quote_utils_1.QuoteUtils.formatEString(node.comment));
6720
+ output.push(quotes_1.QuoteUtils.formatEString(node.comment));
6544
6721
  }
6545
6722
  return output.join(' ');
6546
6723
  }
@@ -6577,7 +6754,7 @@ class Deparser {
6577
6754
  const output = [];
6578
6755
  const initialParts = ['CREATE', 'POLICY'];
6579
6756
  if (node.policy_name) {
6580
- initialParts.push(quote_utils_1.QuoteUtils.quote(node.policy_name));
6757
+ initialParts.push(quotes_1.QuoteUtils.quoteIdentifier(node.policy_name));
6581
6758
  }
6582
6759
  output.push(initialParts.join(' '));
6583
6760
  // Add ON clause on new line in pretty mode
@@ -6654,7 +6831,7 @@ class Deparser {
6654
6831
  AlterPolicyStmt(node, context) {
6655
6832
  const output = ['ALTER', 'POLICY'];
6656
6833
  if (node.policy_name) {
6657
- output.push(quote_utils_1.QuoteUtils.quote(node.policy_name));
6834
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.policy_name));
6658
6835
  }
6659
6836
  if (node.table) {
6660
6837
  output.push('ON');
@@ -6690,7 +6867,7 @@ class Deparser {
6690
6867
  }
6691
6868
  output.push('SERVER');
6692
6869
  if (node.servername) {
6693
- output.push(`"${node.servername}"`);
6870
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.servername));
6694
6871
  }
6695
6872
  if (node.options && node.options.length > 0) {
6696
6873
  output.push('OPTIONS');
@@ -6738,10 +6915,10 @@ class Deparser {
6738
6915
  CreatePublicationStmt(node, context) {
6739
6916
  const output = ['CREATE', 'PUBLICATION'];
6740
6917
  if (node.pubname) {
6741
- output.push(`"${node.pubname}"`);
6918
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.pubname));
6742
6919
  }
6743
6920
  if (node.pubobjects && node.pubobjects.length > 0) {
6744
- output.push('FOR', 'TABLE');
6921
+ output.push('FOR');
6745
6922
  const tables = list_utils_1.ListUtils.unwrapList(node.pubobjects).map(table => this.visit(table, context));
6746
6923
  output.push(tables.join(', '));
6747
6924
  }
@@ -6758,11 +6935,11 @@ class Deparser {
6758
6935
  CreateSubscriptionStmt(node, context) {
6759
6936
  const output = ['CREATE', 'SUBSCRIPTION'];
6760
6937
  if (node.subname) {
6761
- output.push(`"${node.subname}"`);
6938
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.subname));
6762
6939
  }
6763
6940
  output.push('CONNECTION');
6764
6941
  if (node.conninfo) {
6765
- output.push(`'${node.conninfo}'`);
6942
+ output.push(quotes_1.QuoteUtils.escape(node.conninfo));
6766
6943
  }
6767
6944
  output.push('PUBLICATION');
6768
6945
  if (node.publication && node.publication.length > 0) {
@@ -6779,10 +6956,11 @@ class Deparser {
6779
6956
  AlterPublicationStmt(node, context) {
6780
6957
  const output = ['ALTER', 'PUBLICATION'];
6781
6958
  if (node.pubname) {
6782
- output.push(`"${node.pubname}"`);
6959
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.pubname));
6783
6960
  }
6784
- if (node.action) {
6785
- switch (node.action) {
6961
+ const hasObjects = node.pubobjects && node.pubobjects.length > 0;
6962
+ if (hasObjects) {
6963
+ switch (node.action || 'AP_AddObjects') {
6786
6964
  case 'AP_AddObjects':
6787
6965
  output.push('ADD');
6788
6966
  break;
@@ -6795,17 +6973,11 @@ class Deparser {
6795
6973
  default:
6796
6974
  throw new Error(`Unsupported AlterPublicationStmt action: ${node.action}`);
6797
6975
  }
6798
- }
6799
- if (node.for_all_tables) {
6800
- output.push('FOR ALL TABLES');
6801
- }
6802
- else if (node.pubobjects && node.pubobjects.length > 0) {
6803
- output.push('FOR TABLE');
6804
6976
  const objects = list_utils_1.ListUtils.unwrapList(node.pubobjects).map(obj => this.visit(obj, context));
6805
6977
  output.push(objects.join(', '));
6806
6978
  }
6807
- if (node.options && node.options.length > 0) {
6808
- output.push('WITH');
6979
+ else if (node.options && node.options.length > 0) {
6980
+ output.push('SET');
6809
6981
  const options = list_utils_1.ListUtils.unwrapList(node.options).map(opt => this.visit(opt, context));
6810
6982
  output.push(`(${options.join(', ')})`);
6811
6983
  }
@@ -6814,44 +6986,69 @@ class Deparser {
6814
6986
  AlterSubscriptionStmt(node, context) {
6815
6987
  const output = ['ALTER', 'SUBSCRIPTION'];
6816
6988
  if (node.subname) {
6817
- output.push(`"${node.subname}"`);
6818
- }
6819
- if (node.kind) {
6820
- switch (node.kind) {
6989
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.subname));
6990
+ }
6991
+ const options = node.options && node.options.length > 0
6992
+ ? `(${list_utils_1.ListUtils.unwrapList(node.options).map(opt => this.visit(opt, context)).join(', ')})`
6993
+ : null;
6994
+ const publications = node.publication && node.publication.length > 0
6995
+ ? list_utils_1.ListUtils.unwrapList(node.publication).map(pub => this.visit(pub, context)).join(', ')
6996
+ : null;
6997
+ {
6998
+ switch (node.kind || 'ALTER_SUBSCRIPTION_OPTIONS') {
6821
6999
  case 'ALTER_SUBSCRIPTION_OPTIONS':
6822
7000
  output.push('SET');
7001
+ if (options)
7002
+ output.push(options);
6823
7003
  break;
6824
7004
  case 'ALTER_SUBSCRIPTION_CONNECTION':
6825
7005
  output.push('CONNECTION');
6826
7006
  if (node.conninfo) {
6827
- output.push(`'${node.conninfo}'`);
7007
+ output.push(quotes_1.QuoteUtils.escape(node.conninfo));
6828
7008
  }
6829
7009
  break;
6830
7010
  case 'ALTER_SUBSCRIPTION_SET_PUBLICATION':
6831
7011
  output.push('SET PUBLICATION');
6832
- if (node.publication && node.publication.length > 0) {
6833
- const publications = list_utils_1.ListUtils.unwrapList(node.publication).map(pub => this.visit(pub, context));
6834
- output.push(publications.join(', '));
6835
- }
7012
+ if (publications)
7013
+ output.push(publications);
7014
+ if (options)
7015
+ output.push('WITH', options);
7016
+ break;
7017
+ case 'ALTER_SUBSCRIPTION_ADD_PUBLICATION':
7018
+ output.push('ADD PUBLICATION');
7019
+ if (publications)
7020
+ output.push(publications);
7021
+ if (options)
7022
+ output.push('WITH', options);
7023
+ break;
7024
+ case 'ALTER_SUBSCRIPTION_DROP_PUBLICATION':
7025
+ output.push('DROP PUBLICATION');
7026
+ if (publications)
7027
+ output.push(publications);
7028
+ if (options)
7029
+ output.push('WITH', options);
6836
7030
  break;
6837
7031
  case 'ALTER_SUBSCRIPTION_REFRESH':
6838
7032
  output.push('REFRESH PUBLICATION');
7033
+ if (options)
7034
+ output.push('WITH', options);
6839
7035
  break;
6840
- case 'ALTER_SUBSCRIPTION_ENABLED':
6841
- output.push('ENABLE');
7036
+ case 'ALTER_SUBSCRIPTION_ENABLED': {
7037
+ const enabled = list_utils_1.ListUtils.unwrapList(node.options).find(opt => opt.DefElem?.defname === 'enabled');
7038
+ const arg = enabled?.DefElem?.arg;
7039
+ const isEnabled = arg?.Boolean ? arg.Boolean.boolval !== false : true;
7040
+ output.push(isEnabled ? 'ENABLE' : 'DISABLE');
6842
7041
  break;
7042
+ }
6843
7043
  case 'ALTER_SUBSCRIPTION_SKIP':
6844
7044
  output.push('SKIP');
7045
+ if (options)
7046
+ output.push(options);
6845
7047
  break;
6846
7048
  default:
6847
7049
  throw new Error(`Unsupported AlterSubscriptionStmt kind: ${node.kind}`);
6848
7050
  }
6849
7051
  }
6850
- if (node.options && node.options.length > 0) {
6851
- output.push('WITH');
6852
- const options = list_utils_1.ListUtils.unwrapList(node.options).map(opt => this.visit(opt, context));
6853
- output.push(`(${options.join(', ')})`);
6854
- }
6855
7052
  return output.join(' ');
6856
7053
  }
6857
7054
  DropSubscriptionStmt(node, context) {
@@ -6860,7 +7057,7 @@ class Deparser {
6860
7057
  output.push('IF EXISTS');
6861
7058
  }
6862
7059
  if (node.subname) {
6863
- output.push(`"${node.subname}"`);
7060
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.subname));
6864
7061
  }
6865
7062
  if (node.behavior) {
6866
7063
  switch (node.behavior) {
@@ -7105,7 +7302,7 @@ class Deparser {
7105
7302
  ClosePortalStmt(node, context) {
7106
7303
  const output = ['CLOSE'];
7107
7304
  if (node.portalname) {
7108
- output.push(quote_utils_1.QuoteUtils.quote(node.portalname));
7305
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.portalname));
7109
7306
  }
7110
7307
  else {
7111
7308
  output.push('ALL');
@@ -7163,7 +7360,7 @@ class Deparser {
7163
7360
  output.push('ALL');
7164
7361
  }
7165
7362
  if (node.portalname) {
7166
- output.push(quote_utils_1.QuoteUtils.quote(node.portalname));
7363
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.portalname));
7167
7364
  }
7168
7365
  return output.join(' ');
7169
7366
  }
@@ -7233,7 +7430,7 @@ class Deparser {
7233
7430
  AlterFdwStmt(node, context) {
7234
7431
  const output = ['ALTER', 'FOREIGN', 'DATA', 'WRAPPER'];
7235
7432
  if (node.fdwname) {
7236
- output.push(quote_utils_1.QuoteUtils.quote(node.fdwname));
7433
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.fdwname));
7237
7434
  }
7238
7435
  if (node.func_options && node.func_options.length > 0) {
7239
7436
  const fdwContext = context.spawn('AlterFdwStmt');
@@ -7254,16 +7451,16 @@ class Deparser {
7254
7451
  output.push('IF', 'NOT', 'EXISTS');
7255
7452
  }
7256
7453
  if (node.servername) {
7257
- output.push(quote_utils_1.QuoteUtils.quote(node.servername));
7454
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.servername));
7258
7455
  }
7259
7456
  if (node.servertype) {
7260
- output.push('TYPE', quote_utils_1.QuoteUtils.escape(node.servertype));
7457
+ output.push('TYPE', quotes_1.QuoteUtils.escape(node.servertype));
7261
7458
  }
7262
7459
  if (node.version) {
7263
- output.push('VERSION', quote_utils_1.QuoteUtils.escape(node.version));
7460
+ output.push('VERSION', quotes_1.QuoteUtils.escape(node.version));
7264
7461
  }
7265
7462
  if (node.fdwname) {
7266
- output.push('FOREIGN', 'DATA', 'WRAPPER', quote_utils_1.QuoteUtils.quote(node.fdwname));
7463
+ output.push('FOREIGN', 'DATA', 'WRAPPER', quotes_1.QuoteUtils.quoteIdentifier(node.fdwname));
7267
7464
  }
7268
7465
  if (node.options && node.options.length > 0) {
7269
7466
  output.push('OPTIONS');
@@ -7278,10 +7475,10 @@ class Deparser {
7278
7475
  AlterForeignServerStmt(node, context) {
7279
7476
  const output = ['ALTER', 'SERVER'];
7280
7477
  if (node.servername) {
7281
- output.push(quote_utils_1.QuoteUtils.quote(node.servername));
7478
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.servername));
7282
7479
  }
7283
7480
  if (node.version) {
7284
- output.push('VERSION', quote_utils_1.QuoteUtils.escape(node.version));
7481
+ output.push('VERSION', quotes_1.QuoteUtils.escape(node.version));
7285
7482
  }
7286
7483
  if (node.options && node.options.length > 0) {
7287
7484
  output.push('OPTIONS');
@@ -7303,7 +7500,7 @@ class Deparser {
7303
7500
  }
7304
7501
  output.push('SERVER');
7305
7502
  if (node.servername) {
7306
- output.push(quote_utils_1.QuoteUtils.quote(node.servername));
7503
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.servername));
7307
7504
  }
7308
7505
  if (node.options && node.options.length > 0) {
7309
7506
  output.push('OPTIONS');
@@ -7327,14 +7524,14 @@ class Deparser {
7327
7524
  }
7328
7525
  output.push('SERVER');
7329
7526
  if (node.servername) {
7330
- output.push(quote_utils_1.QuoteUtils.quote(node.servername));
7527
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.servername));
7331
7528
  }
7332
7529
  return output.join(' ');
7333
7530
  }
7334
7531
  ImportForeignSchemaStmt(node, context) {
7335
7532
  const output = ['IMPORT', 'FOREIGN', 'SCHEMA'];
7336
7533
  if (node.remote_schema) {
7337
- output.push(quote_utils_1.QuoteUtils.quote(node.remote_schema));
7534
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.remote_schema));
7338
7535
  }
7339
7536
  if (node.list_type) {
7340
7537
  switch (node.list_type) {
@@ -7360,11 +7557,11 @@ class Deparser {
7360
7557
  }
7361
7558
  output.push('FROM', 'SERVER');
7362
7559
  if (node.server_name) {
7363
- output.push(quote_utils_1.QuoteUtils.quote(node.server_name));
7560
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.server_name));
7364
7561
  }
7365
7562
  output.push('INTO');
7366
7563
  if (node.local_schema) {
7367
- output.push(quote_utils_1.QuoteUtils.quote(node.local_schema));
7564
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.local_schema));
7368
7565
  }
7369
7566
  if (node.options && node.options.length > 0) {
7370
7567
  const importSchemaContext = context.spawn('ImportForeignSchemaStmt');
@@ -7378,7 +7575,7 @@ class Deparser {
7378
7575
  if (node.relation) {
7379
7576
  output.push(this.RangeVar(node.relation, context));
7380
7577
  if (node.indexname) {
7381
- output.push('USING', `"${node.indexname}"`);
7578
+ output.push('USING', quotes_1.QuoteUtils.quoteIdentifier(node.indexname));
7382
7579
  }
7383
7580
  }
7384
7581
  if (node.params && node.params.length > 0) {
@@ -7442,7 +7639,7 @@ class Deparser {
7442
7639
  output.push(this.RangeVar(node.relation, context));
7443
7640
  }
7444
7641
  if (node.name) {
7445
- output.push(`"${node.name}"`);
7642
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.name));
7446
7643
  }
7447
7644
  return output.join(' ');
7448
7645
  }
@@ -7482,7 +7679,7 @@ class Deparser {
7482
7679
  if (!node.dbname) {
7483
7680
  throw new Error('CreatedbStmt requires dbname');
7484
7681
  }
7485
- output.push(`"${node.dbname}"`);
7682
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.dbname));
7486
7683
  if (node.options && node.options.length > 0) {
7487
7684
  const options = list_utils_1.ListUtils.unwrapList(node.options)
7488
7685
  .map(option => this.visit(option, context))
@@ -7499,7 +7696,7 @@ class Deparser {
7499
7696
  if (!node.dbname) {
7500
7697
  throw new Error('DropdbStmt requires dbname');
7501
7698
  }
7502
- output.push(`"${node.dbname}"`);
7699
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.dbname));
7503
7700
  if (node.options && node.options.length > 0) {
7504
7701
  const options = list_utils_1.ListUtils.unwrapList(node.options)
7505
7702
  .map(option => this.visit(option, context))
@@ -7597,7 +7794,7 @@ class Deparser {
7597
7794
  case 'OBJECT_POLICY':
7598
7795
  output.push('POLICY');
7599
7796
  if (node.subname) {
7600
- output.push(quote_utils_1.QuoteUtils.quote(node.subname));
7797
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.subname));
7601
7798
  }
7602
7799
  break;
7603
7800
  case 'OBJECT_PUBLICATION':
@@ -7655,7 +7852,7 @@ class Deparser {
7655
7852
  }
7656
7853
  // Handle OBJECT_RULE special case: rule_name ON table_name format
7657
7854
  if (node.renameType === 'OBJECT_RULE' && node.subname && node.relation) {
7658
- output.push(quote_utils_1.QuoteUtils.quote(node.subname));
7855
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.subname));
7659
7856
  output.push('ON');
7660
7857
  output.push(this.RangeVar(node.relation, context));
7661
7858
  }
@@ -7674,12 +7871,21 @@ class Deparser {
7674
7871
  if (items.length === 2) {
7675
7872
  const accessMethod = items[0].String?.sval || '';
7676
7873
  const objectName = items[1].String?.sval || '';
7677
- output.push(`${quote_utils_1.QuoteUtils.quote(objectName)} USING ${accessMethod}`);
7874
+ output.push(`${quotes_1.QuoteUtils.quoteIdentifier(objectName)} USING ${accessMethod}`);
7678
7875
  }
7679
7876
  else {
7680
7877
  output.push(this.visit(node.object, context));
7681
7878
  }
7682
7879
  }
7880
+ else if ((node.renameType === 'OBJECT_TYPE' || node.renameType === 'OBJECT_DOMAIN') && node.object.List) {
7881
+ // Qualified type names - join List parts with dots
7882
+ const items = list_utils_1.ListUtils.unwrapList(node.object);
7883
+ const parts = items
7884
+ .map((item) => item.String?.sval)
7885
+ .filter((s) => typeof s === 'string')
7886
+ .map((s) => this.quoteIfNeeded(s));
7887
+ output.push(parts.join('.'));
7888
+ }
7683
7889
  else if (node.renameType === 'OBJECT_SCHEMA' && node.object.List) {
7684
7890
  // Handle schema names - extract from List structure
7685
7891
  const items = list_utils_1.ListUtils.unwrapList(node.object);
@@ -7695,19 +7901,19 @@ class Deparser {
7695
7901
  }
7696
7902
  }
7697
7903
  if (node.renameType === 'OBJECT_COLUMN' && node.subname) {
7698
- output.push('RENAME COLUMN', `"${node.subname}"`, 'TO');
7904
+ output.push('RENAME COLUMN', quotes_1.QuoteUtils.quoteIdentifier(node.subname), 'TO');
7699
7905
  }
7700
7906
  else if (node.renameType === 'OBJECT_DOMCONSTRAINT' && node.subname) {
7701
- output.push('RENAME CONSTRAINT', `"${node.subname}"`, 'TO');
7907
+ output.push('RENAME CONSTRAINT', quotes_1.QuoteUtils.quoteIdentifier(node.subname), 'TO');
7702
7908
  }
7703
7909
  else if (node.renameType === 'OBJECT_TABCONSTRAINT' && node.subname) {
7704
- output.push('RENAME CONSTRAINT', `"${node.subname}"`, 'TO');
7910
+ output.push('RENAME CONSTRAINT', quotes_1.QuoteUtils.quoteIdentifier(node.subname), 'TO');
7705
7911
  }
7706
7912
  else if (node.renameType === 'OBJECT_ATTRIBUTE' && node.subname) {
7707
- output.push('RENAME ATTRIBUTE', `"${node.subname}"`, 'TO');
7913
+ output.push('RENAME ATTRIBUTE', quotes_1.QuoteUtils.quoteIdentifier(node.subname), 'TO');
7708
7914
  }
7709
7915
  else if (node.renameType === 'OBJECT_ROLE' && node.subname) {
7710
- output.push(`"${node.subname}"`, 'RENAME TO');
7916
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.subname), 'RENAME TO');
7711
7917
  }
7712
7918
  else if (node.renameType === 'OBJECT_SCHEMA' && node.subname) {
7713
7919
  output.push(this.quoteIfNeeded(node.subname), 'RENAME TO');
@@ -7721,7 +7927,7 @@ class Deparser {
7721
7927
  if (!node.newname) {
7722
7928
  throw new Error('RenameStmt requires newname');
7723
7929
  }
7724
- output.push(quote_utils_1.QuoteUtils.quote(node.newname));
7930
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.newname));
7725
7931
  // Handle CASCADE/RESTRICT behavior for RENAME operations
7726
7932
  if (node.behavior === 'DROP_CASCADE') {
7727
7933
  output.push('CASCADE');
@@ -7744,7 +7950,7 @@ class Deparser {
7744
7950
  if (items.length === 2) {
7745
7951
  const accessMethod = items[0].String?.sval || '';
7746
7952
  const objectName = items[1].String?.sval || '';
7747
- output.push(`${quote_utils_1.QuoteUtils.quote(objectName)} USING ${accessMethod}`);
7953
+ output.push(`${quotes_1.QuoteUtils.quoteIdentifier(objectName)} USING ${accessMethod}`);
7748
7954
  }
7749
7955
  else {
7750
7956
  output.push(this.visit(node.object, context));
@@ -7819,6 +8025,9 @@ class Deparser {
7819
8025
  else if (node.objtype === 'OBJECT_LANGUAGE') {
7820
8026
  output.push('LANGUAGE');
7821
8027
  }
8028
+ else if (node.objtype === 'OBJECT_SEQUENCE') {
8029
+ output.push('SEQUENCE');
8030
+ }
7822
8031
  else if (node.objtype === 'OBJECT_FUNCTION') {
7823
8032
  output.push('FUNCTION');
7824
8033
  }
@@ -7844,8 +8053,11 @@ class Deparser {
7844
8053
  output.push('DATABASE');
7845
8054
  }
7846
8055
  if (node.objects && node.objects.length > 0) {
8056
+ const qualifiedKinds = ['OBJECT_TYPE', 'OBJECT_DOMAIN'];
7847
8057
  const objects = list_utils_1.ListUtils.unwrapList(node.objects)
7848
- .map(obj => this.visit(obj, context))
8058
+ .map(obj => qualifiedKinds.includes(node.objtype) && obj.List
8059
+ ? list_utils_1.ListUtils.unwrapList(obj.List.items).map((item) => this.visit(item, context)).join('.')
8060
+ : this.visit(obj, context))
7849
8061
  .join(', ');
7850
8062
  output.push(objects);
7851
8063
  }
@@ -7884,8 +8096,11 @@ class Deparser {
7884
8096
  break;
7885
8097
  default:
7886
8098
  if (node.objects && node.objects.length > 0) {
8099
+ const qualifiedKinds = ['OBJECT_TYPE', 'OBJECT_DOMAIN'];
7887
8100
  const objects = list_utils_1.ListUtils.unwrapList(node.objects)
7888
- .map(obj => this.visit(obj, context))
8101
+ .map(obj => qualifiedKinds.includes(node.objtype) && obj.List
8102
+ ? list_utils_1.ListUtils.unwrapList(obj.List.items).map((item) => this.visit(item, context)).join('.')
8103
+ : this.visit(obj, context))
7889
8104
  .join(', ');
7890
8105
  output.push(objects);
7891
8106
  }
@@ -7905,6 +8120,9 @@ class Deparser {
7905
8120
  if (node.grant_option && node.is_grant) {
7906
8121
  output.push('WITH GRANT OPTION');
7907
8122
  }
8123
+ if (node.grantor) {
8124
+ output.push('GRANTED BY', this.RoleSpec(node.grantor, context));
8125
+ }
7908
8126
  // Only add behavior clauses for REVOKE statements, not for GRANT statements in ALTER DEFAULT PRIVILEGES
7909
8127
  if (!node.is_grant) {
7910
8128
  if (node.behavior === 'DROP_CASCADE') {
@@ -7918,57 +8136,34 @@ class Deparser {
7918
8136
  }
7919
8137
  GrantRoleStmt(node, context) {
7920
8138
  const output = [];
7921
- // Check for inherit, admin, and set options first to place them correctly
7922
- let hasInheritOption = false;
7923
- let hasAdminOption = false;
7924
- let hasSetOption = false;
7925
- let inheritValue;
7926
- let adminValue;
7927
- let setValue;
7928
- if (node.opt && node.opt.length > 0) {
7929
- const options = list_utils_1.ListUtils.unwrapList(node.opt);
7930
- const inheritOption = options.find(opt => opt.DefElem && opt.DefElem.defname === 'inherit');
7931
- const adminOption = options.find(opt => (opt.String && opt.String.sval === 'admin') ||
7932
- (opt.DefElem && opt.DefElem.defname === 'admin'));
7933
- const setOption = options.find(opt => opt.DefElem && opt.DefElem.defname === 'set');
7934
- if (inheritOption && inheritOption.DefElem) {
7935
- hasInheritOption = true;
7936
- inheritValue = inheritOption.DefElem.arg?.Boolean?.boolval;
7937
- }
7938
- if (adminOption) {
7939
- hasAdminOption = true;
7940
- if (adminOption.DefElem && adminOption.DefElem.arg) {
7941
- adminValue = adminOption.DefElem.arg.Boolean?.boolval;
7942
- }
7943
- }
7944
- if (setOption && setOption.DefElem) {
7945
- hasSetOption = true;
7946
- setValue = setOption.DefElem.arg?.Boolean?.boolval;
7947
- }
7948
- }
8139
+ const options = list_utils_1.ListUtils.unwrapList(node.opt)
8140
+ .map(opt => opt.DefElem)
8141
+ .filter((opt) => !!opt && !!opt.defname);
8142
+ const optionValue = (opt) => {
8143
+ if (!opt.arg)
8144
+ return true;
8145
+ const argType = this.getNodeType(opt.arg);
8146
+ const argData = this.getNodeData(opt.arg);
8147
+ if (argType === 'Boolean')
8148
+ return argData.boolval !== false;
8149
+ if (argType === 'String')
8150
+ return argData.sval !== 'false';
8151
+ return true;
8152
+ };
8153
+ const roles = list_utils_1.ListUtils.unwrapList(node.granted_roles)
8154
+ .map(role => role.AccessPriv?.priv_name
8155
+ ? quotes_1.QuoteUtils.quoteIdentifier(role.AccessPriv.priv_name)
8156
+ : this.visit(role, context))
8157
+ .join(', ');
7949
8158
  if (node.is_grant) {
7950
- output.push('GRANT');
8159
+ output.push('GRANT', roles, 'TO');
7951
8160
  }
7952
8161
  else {
7953
8162
  output.push('REVOKE');
7954
- if (hasInheritOption) {
7955
- output.push('INHERIT OPTION FOR');
7956
- }
7957
- else if (hasAdminOption) {
7958
- output.push('ADMIN OPTION FOR');
8163
+ if (options.length > 0) {
8164
+ output.push(`${options[0].defname.toUpperCase()} OPTION FOR`);
7959
8165
  }
7960
- }
7961
- if (node.granted_roles && node.granted_roles.length > 0) {
7962
- const roles = list_utils_1.ListUtils.unwrapList(node.granted_roles)
7963
- .map(role => this.visit(role, context))
7964
- .join(', ');
7965
- output.push(roles);
7966
- }
7967
- if (node.is_grant) {
7968
- output.push('TO');
7969
- }
7970
- else {
7971
- output.push('FROM');
8166
+ output.push(roles, 'FROM');
7972
8167
  }
7973
8168
  if (node.grantee_roles && node.grantee_roles.length > 0) {
7974
8169
  const grantees = list_utils_1.ListUtils.unwrapList(node.grantee_roles)
@@ -7976,45 +8171,22 @@ class Deparser {
7976
8171
  .join(', ');
7977
8172
  output.push(grantees);
7978
8173
  }
7979
- if (node.is_grant) {
7980
- const withOptions = [];
7981
- if (hasAdminOption) {
7982
- if (adminValue === true) {
7983
- withOptions.push('ADMIN OPTION');
7984
- }
7985
- else if (adminValue === false) {
7986
- withOptions.push('ADMIN FALSE');
7987
- }
7988
- else {
7989
- withOptions.push('ADMIN OPTION');
7990
- }
7991
- }
7992
- if (hasInheritOption) {
7993
- if (inheritValue === true) {
7994
- withOptions.push('INHERIT OPTION');
7995
- }
7996
- else if (inheritValue === false) {
7997
- withOptions.push('INHERIT FALSE');
7998
- }
7999
- }
8000
- if (hasSetOption) {
8001
- if (setValue === true) {
8002
- withOptions.push('SET TRUE');
8003
- }
8004
- else if (setValue === false) {
8005
- withOptions.push('SET FALSE');
8006
- }
8007
- }
8008
- if (withOptions.length > 0) {
8009
- output.push('WITH', withOptions.join(', '));
8010
- }
8174
+ if (node.is_grant && options.length > 0) {
8175
+ const withOptions = options.map(opt => `${opt.defname.toUpperCase()} ${optionValue(opt) ? 'TRUE' : 'FALSE'}`);
8176
+ output.push('WITH', withOptions.join(', '));
8177
+ }
8178
+ if (node.grantor) {
8179
+ output.push('GRANTED BY', this.RoleSpec(node.grantor, context));
8180
+ }
8181
+ if (!node.is_grant && node.behavior === 'DROP_CASCADE') {
8182
+ output.push('CASCADE');
8011
8183
  }
8012
8184
  return output.join(' ');
8013
8185
  }
8014
8186
  SecLabelStmt(node, context) {
8015
8187
  const output = ['SECURITY LABEL'];
8016
8188
  if (node.provider) {
8017
- output.push('FOR', `"${node.provider}"`);
8189
+ output.push('FOR', quotes_1.QuoteUtils.quoteIdentifier(node.provider));
8018
8190
  }
8019
8191
  output.push('ON');
8020
8192
  if (node.objtype) {
@@ -8042,11 +8214,21 @@ class Deparser {
8042
8214
  }
8043
8215
  }
8044
8216
  if (node.object) {
8045
- output.push(this.visit(node.object, context));
8217
+ // Qualified names arrive as a List of String nodes and must be
8218
+ // dot-joined (visiting the List directly would comma-join them).
8219
+ if (typeof node.object === 'object' && 'List' in node.object) {
8220
+ const list = node.object.List;
8221
+ const objectParts = list_utils_1.ListUtils.unwrapList(list.items)
8222
+ .map(item => this.visit(item, context));
8223
+ output.push(objectParts.join('.'));
8224
+ }
8225
+ else {
8226
+ output.push(this.visit(node.object, context));
8227
+ }
8046
8228
  }
8047
8229
  output.push('IS');
8048
8230
  if (node.label) {
8049
- output.push(`'${node.label}'`);
8231
+ output.push(quotes_1.QuoteUtils.escape(node.label));
8050
8232
  }
8051
8233
  else {
8052
8234
  output.push('NULL');
@@ -8103,10 +8285,10 @@ class Deparser {
8103
8285
  output.push(conversionName);
8104
8286
  }
8105
8287
  if (node.for_encoding_name) {
8106
- output.push('FOR', `'${node.for_encoding_name}'`);
8288
+ output.push('FOR', quotes_1.QuoteUtils.escape(node.for_encoding_name));
8107
8289
  }
8108
8290
  if (node.to_encoding_name) {
8109
- output.push('TO', `'${node.to_encoding_name}'`);
8291
+ output.push('TO', quotes_1.QuoteUtils.escape(node.to_encoding_name));
8110
8292
  }
8111
8293
  if (node.func_name && node.func_name.length > 0) {
8112
8294
  output.push('FROM');
@@ -8167,7 +8349,7 @@ class Deparser {
8167
8349
  }
8168
8350
  output.push('LANGUAGE');
8169
8351
  if (node.plname) {
8170
- output.push(quote_utils_1.QuoteUtils.quote(node.plname));
8352
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.plname));
8171
8353
  }
8172
8354
  if (node.plhandler && node.plhandler.length > 0) {
8173
8355
  output.push('HANDLER');
@@ -8203,7 +8385,7 @@ class Deparser {
8203
8385
  }
8204
8386
  output.push('LANGUAGE');
8205
8387
  if (node.lang) {
8206
- output.push(quote_utils_1.QuoteUtils.quote(node.lang));
8388
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.lang));
8207
8389
  }
8208
8390
  output.push('(');
8209
8391
  const transforms = [];
@@ -8231,7 +8413,7 @@ class Deparser {
8231
8413
  }
8232
8414
  output.push('TRIGGER');
8233
8415
  if (node.trigname) {
8234
- output.push(quote_utils_1.QuoteUtils.quote(node.trigname));
8416
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.trigname));
8235
8417
  }
8236
8418
  if (context.isPretty()) {
8237
8419
  const components = [];
@@ -8269,6 +8451,9 @@ class Deparser {
8269
8451
  .join(' ');
8270
8452
  components.push(context.indent('REFERENCING ' + transitionClauses));
8271
8453
  }
8454
+ if (node.constrrel) {
8455
+ components.push(context.indent('FROM ' + this.RangeVar(node.constrrel, context)));
8456
+ }
8272
8457
  if (node.deferrable) {
8273
8458
  components.push(context.indent('DEFERRABLE'));
8274
8459
  }
@@ -8290,7 +8475,7 @@ class Deparser {
8290
8475
  const funcName = list_utils_1.ListUtils.unwrapList(node.funcname)
8291
8476
  .map(name => this.visit(name, context))
8292
8477
  .join('.');
8293
- executeStr += ' PROCEDURE ' + funcName;
8478
+ executeStr += ' FUNCTION ' + funcName;
8294
8479
  }
8295
8480
  if (node.args && node.args.length > 0) {
8296
8481
  const argContext = context.spawn('CreateTrigStmt', { isStringLiteral: true });
@@ -8395,14 +8580,14 @@ class Deparser {
8395
8580
  output.push('OLD TABLE AS');
8396
8581
  }
8397
8582
  if (node.name) {
8398
- output.push(quote_utils_1.QuoteUtils.quote(node.name));
8583
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.name));
8399
8584
  }
8400
8585
  return output.join(' ');
8401
8586
  }
8402
8587
  CreateEventTrigStmt(node, context) {
8403
8588
  const output = ['CREATE EVENT TRIGGER'];
8404
8589
  if (node.trigname) {
8405
- output.push(quote_utils_1.QuoteUtils.quote(node.trigname));
8590
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.trigname));
8406
8591
  }
8407
8592
  output.push('ON');
8408
8593
  if (node.eventname) {
@@ -8428,7 +8613,7 @@ class Deparser {
8428
8613
  AlterEventTrigStmt(node, context) {
8429
8614
  const output = ['ALTER EVENT TRIGGER'];
8430
8615
  if (node.trigname) {
8431
- output.push(quote_utils_1.QuoteUtils.quote(node.trigname));
8616
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.trigname));
8432
8617
  }
8433
8618
  if (node.tgenabled) {
8434
8619
  switch (node.tgenabled) {
@@ -8548,6 +8733,74 @@ class Deparser {
8548
8733
  .join(' ');
8549
8734
  output.push(whenClauses);
8550
8735
  }
8736
+ if (node.returningClause) {
8737
+ output.push(this.ReturningClause(node.returningClause, context));
8738
+ }
8739
+ return output.join(' ');
8740
+ }
8741
+ MergeSupportFunc(node, context) {
8742
+ return 'merge_action()';
8743
+ }
8744
+ MergeWhenClause(node, context) {
8745
+ const output = ['WHEN'];
8746
+ switch (node.matchKind) {
8747
+ case 'MERGE_WHEN_MATCHED':
8748
+ output.push('MATCHED');
8749
+ break;
8750
+ case 'MERGE_WHEN_NOT_MATCHED_BY_SOURCE':
8751
+ output.push('NOT MATCHED BY SOURCE');
8752
+ break;
8753
+ case 'MERGE_WHEN_NOT_MATCHED_BY_TARGET':
8754
+ output.push('NOT MATCHED');
8755
+ break;
8756
+ }
8757
+ if (node.condition) {
8758
+ output.push('AND');
8759
+ output.push(this.visit(node.condition, context));
8760
+ }
8761
+ output.push('THEN');
8762
+ switch (node.commandType) {
8763
+ case 'CMD_UPDATE': {
8764
+ output.push('UPDATE SET');
8765
+ if (node.targetList && node.targetList.length > 0) {
8766
+ output.push(this.formatUpdateAssignments(node.targetList, context));
8767
+ }
8768
+ break;
8769
+ }
8770
+ case 'CMD_INSERT': {
8771
+ output.push('INSERT');
8772
+ const targetList = list_utils_1.ListUtils.unwrapList(node.targetList);
8773
+ if (targetList.length > 0) {
8774
+ const columns = targetList
8775
+ .map(target => quotes_1.QuoteUtils.quoteIdentifier(target.ResTarget?.name))
8776
+ .join(', ');
8777
+ output.push(`(${columns})`);
8778
+ }
8779
+ if (node.override === 'OVERRIDING_USER_VALUE') {
8780
+ output.push('OVERRIDING USER VALUE');
8781
+ }
8782
+ else if (node.override === 'OVERRIDING_SYSTEM_VALUE') {
8783
+ output.push('OVERRIDING SYSTEM VALUE');
8784
+ }
8785
+ const values = list_utils_1.ListUtils.unwrapList(node.values);
8786
+ if (values.length > 0) {
8787
+ const valueItems = values
8788
+ .map(value => this.visit(value, context))
8789
+ .join(', ');
8790
+ output.push(`VALUES (${valueItems})`);
8791
+ }
8792
+ else {
8793
+ output.push('DEFAULT VALUES');
8794
+ }
8795
+ break;
8796
+ }
8797
+ case 'CMD_DELETE':
8798
+ output.push('DELETE');
8799
+ break;
8800
+ case 'CMD_NOTHING':
8801
+ output.push('DO NOTHING');
8802
+ break;
8803
+ }
8551
8804
  return output.join(' ');
8552
8805
  }
8553
8806
  AlterTableMoveAllStmt(node, context) {
@@ -8563,11 +8816,11 @@ class Deparser {
8563
8816
  }
8564
8817
  output.push('ALL', 'IN', 'TABLESPACE');
8565
8818
  if (node.orig_tablespacename) {
8566
- output.push(quote_utils_1.QuoteUtils.quote(node.orig_tablespacename));
8819
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.orig_tablespacename));
8567
8820
  }
8568
8821
  output.push('SET', 'TABLESPACE');
8569
8822
  if (node.new_tablespacename) {
8570
- output.push(quote_utils_1.QuoteUtils.quote(node.new_tablespacename));
8823
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.new_tablespacename));
8571
8824
  }
8572
8825
  if (node.nowait) {
8573
8826
  output.push('NOWAIT');
@@ -8591,10 +8844,10 @@ class Deparser {
8591
8844
  const sequenceName = [];
8592
8845
  const seq = node.sequence;
8593
8846
  if (seq.schemaname) {
8594
- sequenceName.push(quote_utils_1.QuoteUtils.quote(seq.schemaname));
8847
+ sequenceName.push(quotes_1.QuoteUtils.quoteIdentifier(seq.schemaname));
8595
8848
  }
8596
8849
  if (seq.relname) {
8597
- sequenceName.push(quote_utils_1.QuoteUtils.quote(seq.relname));
8850
+ sequenceName.push(quotes_1.QuoteUtils.quoteIdentifier(seq.relname));
8598
8851
  }
8599
8852
  output.push(sequenceName.join('.'));
8600
8853
  }
@@ -8628,10 +8881,10 @@ class Deparser {
8628
8881
  const sequenceName = [];
8629
8882
  const seq = node.sequence;
8630
8883
  if (seq.schemaname) {
8631
- sequenceName.push(quote_utils_1.QuoteUtils.quote(seq.schemaname));
8884
+ sequenceName.push(quotes_1.QuoteUtils.quoteIdentifier(seq.schemaname));
8632
8885
  }
8633
8886
  if (seq.relname) {
8634
- sequenceName.push(quote_utils_1.QuoteUtils.quote(seq.relname));
8887
+ sequenceName.push(quotes_1.QuoteUtils.quoteIdentifier(seq.relname));
8635
8888
  }
8636
8889
  output.push(sequenceName.join('.'));
8637
8890
  }
@@ -8916,6 +9169,13 @@ class Deparser {
8916
9169
  output.push('USING');
8917
9170
  output.push(node.into.accessMethod);
8918
9171
  }
9172
+ if (node.into && node.into.options && node.into.options.length > 0) {
9173
+ output.push('WITH');
9174
+ const options = list_utils_1.ListUtils.unwrapList(node.into.options)
9175
+ .map(option => this.visit(option, context.spawn('CreateStmt')))
9176
+ .join(', ');
9177
+ output.push(`(${options})`);
9178
+ }
8919
9179
  if (node.into && node.into.onCommit && node.into.onCommit !== 'ONCOMMIT_NOOP') {
8920
9180
  output.push('ON COMMIT');
8921
9181
  switch (node.into.onCommit) {
@@ -8930,17 +9190,13 @@ class Deparser {
8930
9190
  break;
8931
9191
  }
8932
9192
  }
9193
+ if (node.into && node.into.tableSpaceName) {
9194
+ output.push('TABLESPACE', quotes_1.QuoteUtils.quoteIdentifier(node.into.tableSpaceName));
9195
+ }
8933
9196
  output.push('AS');
8934
9197
  if (node.query) {
8935
9198
  output.push(this.visit(node.query, context));
8936
9199
  }
8937
- if (node.into && node.into.options && node.into.options.length > 0) {
8938
- output.push('WITH');
8939
- const options = list_utils_1.ListUtils.unwrapList(node.into.options)
8940
- .map(option => this.visit(option, context))
8941
- .join(', ');
8942
- output.push(`(${options})`);
8943
- }
8944
9200
  if (node.into && node.into.skipData) {
8945
9201
  output.push('WITH NO DATA');
8946
9202
  }
@@ -8978,7 +9234,7 @@ class Deparser {
8978
9234
  }
8979
9235
  aliasname(node, context) {
8980
9236
  if (typeof node === 'string') {
8981
- return quote_utils_1.QuoteUtils.quote(node);
9237
+ return quotes_1.QuoteUtils.quoteIdentifier(node);
8982
9238
  }
8983
9239
  return this.visit(node, context);
8984
9240
  }
@@ -9010,18 +9266,16 @@ class Deparser {
9010
9266
  const defName = defElem.defname;
9011
9267
  const defValue = defElem.arg;
9012
9268
  if (defName && defValue) {
9013
- let preservedDefName;
9014
- if (Deparser.needsQuotes(defName)) {
9015
- preservedDefName = `"${defName}"`;
9016
- }
9017
- else {
9018
- preservedDefName = this.preserveOperatorDefElemCase(defName);
9019
- }
9269
+ const quotedDefName = quotes_1.QuoteUtils.quoteIdentifier(defName);
9270
+ const preservedDefName = quotedDefName !== defName ? quotedDefName : this.preserveOperatorDefElemCase(defName);
9020
9271
  if ((defName.toLowerCase() === 'commutator' || defName.toLowerCase() === 'negator') && defValue.List) {
9021
9272
  const listItems = list_utils_1.ListUtils.unwrapList(defValue.List.items);
9022
9273
  if (listItems.length === 1 && listItems[0].String) {
9023
9274
  return `${preservedDefName} = ${listItems[0].String.sval}`;
9024
9275
  }
9276
+ if (listItems.length > 1 && listItems.every(item => item.String)) {
9277
+ return `${preservedDefName} = OPERATOR(${this.qualifiedOperatorName(listItems)})`;
9278
+ }
9025
9279
  }
9026
9280
  // For commutator/negator, we already handled them above
9027
9281
  if ((defName.toLowerCase() === 'commutator' || defName.toLowerCase() === 'negator')) {
@@ -9032,7 +9286,7 @@ class Deparser {
9032
9286
  else if (defName && !defValue) {
9033
9287
  // Handle boolean flags like HASHES, MERGES - preserve original case
9034
9288
  if (defName === 'Hashes' || defName === 'Merges') {
9035
- return `"${defName}"`;
9289
+ return quotes_1.QuoteUtils.quoteIdentifier(defName);
9036
9290
  }
9037
9291
  return this.preserveOperatorDefElemCase(defName).toUpperCase();
9038
9292
  }
@@ -9171,16 +9425,11 @@ class Deparser {
9171
9425
  const defName = defElem.defname;
9172
9426
  const defValue = defElem.arg;
9173
9427
  if (defName && defValue) {
9174
- let preservedDefName;
9175
- if (Deparser.needsQuotes(defName)) {
9176
- preservedDefName = `"${defName}"`;
9177
- }
9178
- else {
9179
- preservedDefName = defName;
9180
- }
9428
+ const quotedDefName = quotes_1.QuoteUtils.quoteIdentifier(defName);
9429
+ const preservedDefName = quotedDefName !== defName ? quotedDefName : defName;
9181
9430
  // Handle String arguments with single quotes for string literals
9182
9431
  if (defValue.String) {
9183
- return `${preservedDefName} = '${defValue.String.sval}'`;
9432
+ return `${preservedDefName} = ${quotes_1.QuoteUtils.escape(defValue.String.sval)}`;
9184
9433
  }
9185
9434
  return `${preservedDefName} = ${this.visit(defValue, context)}`;
9186
9435
  }
@@ -9303,7 +9552,7 @@ class Deparser {
9303
9552
  // For CREATE COLLATION, ensure String nodes are quoted as string literals
9304
9553
  let valueStr;
9305
9554
  if (defValue.String) {
9306
- valueStr = `'${defValue.String.sval}'`;
9555
+ valueStr = quotes_1.QuoteUtils.escape(defValue.String.sval);
9307
9556
  }
9308
9557
  else {
9309
9558
  valueStr = this.visit(defValue, context);
@@ -9332,7 +9581,7 @@ class Deparser {
9332
9581
  AlterDatabaseStmt(node, context) {
9333
9582
  const output = ['ALTER', 'DATABASE'];
9334
9583
  if (node.dbname) {
9335
- output.push(quote_utils_1.QuoteUtils.quote(node.dbname));
9584
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.dbname));
9336
9585
  }
9337
9586
  if (node.options && node.options.length > 0) {
9338
9587
  const options = list_utils_1.ListUtils.unwrapList(node.options).map(opt => this.visit(opt, context));
@@ -9343,7 +9592,7 @@ class Deparser {
9343
9592
  AlterDatabaseRefreshCollStmt(node, context) {
9344
9593
  const output = ['ALTER', 'DATABASE'];
9345
9594
  if (node.dbname) {
9346
- output.push(quote_utils_1.QuoteUtils.quote(node.dbname));
9595
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.dbname));
9347
9596
  }
9348
9597
  output.push('REFRESH', 'COLLATION', 'VERSION');
9349
9598
  return output.join(' ');
@@ -9351,7 +9600,7 @@ class Deparser {
9351
9600
  AlterDatabaseSetStmt(node, context) {
9352
9601
  const output = ['ALTER', 'DATABASE'];
9353
9602
  if (node.dbname) {
9354
- output.push(quote_utils_1.QuoteUtils.quote(node.dbname));
9603
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.dbname));
9355
9604
  }
9356
9605
  if (node.setstmt) {
9357
9606
  const setClause = this.VariableSetStmt(node.setstmt, context);
@@ -9362,7 +9611,7 @@ class Deparser {
9362
9611
  DeclareCursorStmt(node, context) {
9363
9612
  const output = ['DECLARE'];
9364
9613
  if (node.portalname) {
9365
- output.push(quote_utils_1.QuoteUtils.quote(node.portalname));
9614
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.portalname));
9366
9615
  }
9367
9616
  // Handle cursor options before CURSOR keyword
9368
9617
  const cursorOptions = [];
@@ -9404,7 +9653,7 @@ class Deparser {
9404
9653
  else if (node.pubobjtype === 'PUBLICATIONOBJ_TABLES_IN_SCHEMA') {
9405
9654
  output.push('TABLES IN SCHEMA');
9406
9655
  if (node.name) {
9407
- output.push(quote_utils_1.QuoteUtils.quote(node.name));
9656
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.name));
9408
9657
  }
9409
9658
  }
9410
9659
  else if (node.pubobjtype === 'PUBLICATIONOBJ_TABLES_IN_CUR_SCHEMA') {
@@ -9423,14 +9672,14 @@ class Deparser {
9423
9672
  }
9424
9673
  if (node.whereClause) {
9425
9674
  output.push('WHERE');
9426
- output.push(this.visit(node.whereClause, context));
9675
+ output.push(`(${this.visit(node.whereClause, context)})`);
9427
9676
  }
9428
9677
  return output.join(' ');
9429
9678
  }
9430
9679
  CreateAmStmt(node, context) {
9431
9680
  const output = ['CREATE', 'ACCESS', 'METHOD'];
9432
9681
  if (node.amname) {
9433
- output.push(quote_utils_1.QuoteUtils.quote(node.amname));
9682
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.amname));
9434
9683
  }
9435
9684
  output.push('TYPE');
9436
9685
  switch (node.amtype) {
@@ -9490,7 +9739,7 @@ class Deparser {
9490
9739
  }
9491
9740
  }
9492
9741
  if (node.tableSpaceName) {
9493
- output.push('TABLESPACE', quote_utils_1.QuoteUtils.quote(node.tableSpaceName));
9742
+ output.push('TABLESPACE', quotes_1.QuoteUtils.quoteIdentifier(node.tableSpaceName));
9494
9743
  }
9495
9744
  return output.join(' ');
9496
9745
  }
@@ -9570,6 +9819,23 @@ class Deparser {
9570
9819
  }
9571
9820
  return output.join(' ');
9572
9821
  }
9822
+ quoteDefElemArg(arg, argValue) {
9823
+ if (arg && this.getNodeType(arg) === 'String') {
9824
+ return quotes_1.QuoteUtils.escape(this.getNodeData(arg).sval || '');
9825
+ }
9826
+ return typeof argValue === 'string' && !argValue.startsWith("'")
9827
+ ? quotes_1.QuoteUtils.escape(argValue)
9828
+ : argValue;
9829
+ }
9830
+ formatOptionValue(arg, argValue) {
9831
+ if (arg && this.getNodeType(arg) === 'String') {
9832
+ const sval = this.getNodeData(arg).sval || '';
9833
+ return /^[a-z_][a-z0-9_]*$/.test(sval) && (0, quotes_1.keywordKindOf)(sval) === 'NO_KEYWORD'
9834
+ ? sval
9835
+ : quotes_1.QuoteUtils.escape(sval);
9836
+ }
9837
+ return argValue;
9838
+ }
9573
9839
  Var(node, context) {
9574
9840
  if (node.varno && node.varattno) {
9575
9841
  return `$${node.varno}.${node.varattno}`;
@@ -9609,7 +9875,7 @@ class Deparser {
9609
9875
  }
9610
9876
  if (node.rowexpr) {
9611
9877
  output.push(',');
9612
- output.push(`'${this.visit(node.rowexpr, context)}'`);
9878
+ output.push(this.visit(node.rowexpr, context));
9613
9879
  }
9614
9880
  if (node.colexprs && node.colexprs.length > 0) {
9615
9881
  output.push('COLUMNS');
@@ -9626,29 +9892,44 @@ class Deparser {
9626
9892
  if (node.lateral) {
9627
9893
  output.push('LATERAL');
9628
9894
  }
9629
- if (node.docexpr) {
9630
- output.push(this.visit(node.docexpr, context));
9895
+ const args = [];
9896
+ if (node.namespaces && node.namespaces.length > 0) {
9897
+ const namespaces = list_utils_1.ListUtils.unwrapList(node.namespaces).map(ns => {
9898
+ const target = this.getNodeData(ns);
9899
+ const uri = this.visit(target.val, context);
9900
+ return target.name ? `${uri} AS ${quotes_1.QuoteUtils.quoteIdentifier(target.name)}` : `DEFAULT ${uri}`;
9901
+ });
9902
+ args.push(`XMLNAMESPACES(${namespaces.join(', ')}),`);
9631
9903
  }
9632
9904
  if (node.rowexpr) {
9633
- output.push('PASSING');
9634
- output.push(this.visit(node.rowexpr, context));
9905
+ args.push(this.formatXmlTableExpr(node.rowexpr, context));
9906
+ }
9907
+ if (node.docexpr) {
9908
+ args.push('PASSING');
9909
+ args.push(this.formatXmlTableExpr(node.docexpr, context));
9635
9910
  }
9636
9911
  if (node.columns && node.columns.length > 0) {
9637
- output.push('COLUMNS');
9638
- const columns = list_utils_1.ListUtils.unwrapList(node.columns)
9912
+ args.push('COLUMNS');
9913
+ args.push(list_utils_1.ListUtils.unwrapList(node.columns)
9639
9914
  .map(col => this.visit(col, context))
9640
- .join(', ');
9641
- output.push(`(${columns})`);
9915
+ .join(', '));
9642
9916
  }
9917
+ output.push(`XMLTABLE(${args.join(' ')})`);
9643
9918
  if (node.alias) {
9644
9919
  output.push(this.Alias(node.alias, context));
9645
9920
  }
9646
9921
  return output.join(' ');
9647
9922
  }
9923
+ formatXmlTableExpr(expr, context) {
9924
+ const value = this.visit(expr, context);
9925
+ return ['A_Const', 'ColumnRef', 'ParamRef', 'FuncCall'].includes(this.getNodeType(expr))
9926
+ ? value
9927
+ : `(${value})`;
9928
+ }
9648
9929
  RangeTableFuncCol(node, context) {
9649
9930
  const output = [];
9650
9931
  if (node.colname) {
9651
- output.push(quote_utils_1.QuoteUtils.quote(node.colname));
9932
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.colname));
9652
9933
  }
9653
9934
  if (node.for_ordinality) {
9654
9935
  output.push('FOR ORDINALITY');
@@ -9658,32 +9939,193 @@ class Deparser {
9658
9939
  }
9659
9940
  if (node.colexpr) {
9660
9941
  output.push('PATH');
9661
- output.push(`'${this.visit(node.colexpr, context)}'`);
9942
+ output.push(this.visit(node.colexpr, context));
9662
9943
  }
9663
9944
  if (node.coldefexpr) {
9664
9945
  output.push('DEFAULT');
9665
9946
  output.push(this.visit(node.coldefexpr, context));
9666
9947
  }
9948
+ if (node.is_not_null) {
9949
+ output.push('NOT NULL');
9950
+ }
9667
9951
  return output.join(' ');
9668
9952
  }
9953
+ formatJsonFormat(format) {
9954
+ if (!format || !format.format_type || format.format_type === 'JS_FORMAT_DEFAULT') {
9955
+ return null;
9956
+ }
9957
+ const parts = ['FORMAT JSON'];
9958
+ switch (format.encoding) {
9959
+ case 'JS_ENC_UTF8':
9960
+ parts.push('ENCODING UTF8');
9961
+ break;
9962
+ case 'JS_ENC_UTF16':
9963
+ parts.push('ENCODING UTF16');
9964
+ break;
9965
+ case 'JS_ENC_UTF32':
9966
+ parts.push('ENCODING UTF32');
9967
+ break;
9968
+ }
9969
+ return parts.join(' ');
9970
+ }
9971
+ formatJsonOutput(output, context) {
9972
+ if (!output || !output.typeName)
9973
+ return null;
9974
+ const parts = ['RETURNING', this.TypeName(output.typeName, context)];
9975
+ const format = this.formatJsonFormat(output.returning?.format);
9976
+ if (format)
9977
+ parts.push(format);
9978
+ return parts.join(' ');
9979
+ }
9980
+ formatJsonNullClause(absentOnNull) {
9981
+ return absentOnNull ? 'ABSENT ON NULL' : 'NULL ON NULL';
9982
+ }
9983
+ formatJsonUniqueClause(unique) {
9984
+ return unique ? 'WITH UNIQUE KEYS' : null;
9985
+ }
9986
+ JsonValueExpr(node, context) {
9987
+ const parts = [];
9988
+ if (node.raw_expr) {
9989
+ parts.push(this.visit(node.raw_expr, context));
9990
+ }
9991
+ const format = this.formatJsonFormat(node.format);
9992
+ if (format)
9993
+ parts.push(format);
9994
+ return parts.join(' ');
9995
+ }
9996
+ JsonKeyValue(node, context) {
9997
+ const key = node.key ? this.visit(node.key, context) : '';
9998
+ const value = node.value ? this.JsonValueExpr(node.value, context) : '';
9999
+ return `${key} : ${value}`;
10000
+ }
10001
+ JsonObjectConstructor(node, context) {
10002
+ const args = [];
10003
+ if (node.exprs && node.exprs.length > 0) {
10004
+ args.push(list_utils_1.ListUtils.unwrapList(node.exprs).map(e => this.visit(e, context)).join(', '));
10005
+ args.push(this.formatJsonNullClause(node.absent_on_null));
10006
+ const unique = this.formatJsonUniqueClause(node.unique);
10007
+ if (unique)
10008
+ args.push(unique);
10009
+ }
10010
+ const output = this.formatJsonOutput(node.output, context);
10011
+ if (output)
10012
+ args.push(output);
10013
+ return `JSON_OBJECT(${args.join(' ')})`;
10014
+ }
10015
+ JsonArrayConstructor(node, context) {
10016
+ const args = [];
10017
+ if (node.exprs && node.exprs.length > 0) {
10018
+ args.push(list_utils_1.ListUtils.unwrapList(node.exprs).map(e => this.visit(e, context)).join(', '));
10019
+ args.push(this.formatJsonNullClause(node.absent_on_null));
10020
+ }
10021
+ const output = this.formatJsonOutput(node.output, context);
10022
+ if (output)
10023
+ args.push(output);
10024
+ return `JSON_ARRAY(${args.join(' ')})`;
10025
+ }
9669
10026
  JsonArrayQueryConstructor(node, context) {
9670
- const output = ['JSON_ARRAYAGG'];
10027
+ const args = [];
9671
10028
  if (node.query) {
9672
- output.push(`(${this.visit(node.query, context)})`);
10029
+ args.push(this.visit(node.query, context));
10030
+ }
10031
+ const format = this.formatJsonFormat(node.format);
10032
+ if (format)
10033
+ args.push(format);
10034
+ const output = this.formatJsonOutput(node.output, context);
10035
+ if (output)
10036
+ args.push(output);
10037
+ return `JSON_ARRAY(${args.join(' ')})`;
10038
+ }
10039
+ formatJsonAggSuffix(ctor, context) {
10040
+ if (!ctor)
10041
+ return '';
10042
+ let result = '';
10043
+ if (ctor.agg_filter) {
10044
+ result += ` FILTER (WHERE ${this.visit(ctor.agg_filter, context)})`;
9673
10045
  }
9674
- if (node.format) {
9675
- output.push('FORMAT JSON');
10046
+ if (ctor.over) {
10047
+ result += this.formatOverClause(ctor.over, context);
9676
10048
  }
9677
- if (node.output) {
9678
- output.push('RETURNING TEXT');
10049
+ return result;
10050
+ }
10051
+ JsonObjectAgg(node, context) {
10052
+ const args = [];
10053
+ if (node.arg) {
10054
+ args.push(this.JsonKeyValue(node.arg, context));
10055
+ }
10056
+ args.push(this.formatJsonNullClause(node.absent_on_null));
10057
+ const unique = this.formatJsonUniqueClause(node.unique);
10058
+ if (unique)
10059
+ args.push(unique);
10060
+ const output = this.formatJsonOutput(node.constructor?.output, context);
10061
+ if (output)
10062
+ args.push(output);
10063
+ return `JSON_OBJECTAGG(${args.join(' ')})${this.formatJsonAggSuffix(node.constructor, context)}`;
10064
+ }
10065
+ JsonArrayAgg(node, context) {
10066
+ const args = [];
10067
+ if (node.arg) {
10068
+ args.push(this.JsonValueExpr(node.arg, context));
9679
10069
  }
9680
- if (node.absent_on_null) {
9681
- output.push('ABSENT ON NULL');
10070
+ const aggOrder = node.constructor?.agg_order;
10071
+ if (aggOrder && aggOrder.length > 0) {
10072
+ const orderItems = list_utils_1.ListUtils.unwrapList(aggOrder).map(item => this.visit(item, context));
10073
+ args.push(`ORDER BY ${orderItems.join(', ')}`);
9682
10074
  }
9683
- else {
9684
- output.push('NULL ON NULL');
10075
+ args.push(this.formatJsonNullClause(node.absent_on_null));
10076
+ const output = this.formatJsonOutput(node.constructor?.output, context);
10077
+ if (output)
10078
+ args.push(output);
10079
+ return `JSON_ARRAYAGG(${args.join(' ')})${this.formatJsonAggSuffix(node.constructor, context)}`;
10080
+ }
10081
+ JsonParseExpr(node, context) {
10082
+ const args = [];
10083
+ if (node.expr) {
10084
+ args.push(this.JsonValueExpr(node.expr, context));
9685
10085
  }
9686
- return output.join(' ');
10086
+ const unique = this.formatJsonUniqueClause(node.unique_keys);
10087
+ if (unique)
10088
+ args.push(unique);
10089
+ return `JSON(${args.join(' ')})`;
10090
+ }
10091
+ JsonScalarExpr(node, context) {
10092
+ const expr = node.expr ? this.visit(node.expr, context) : '';
10093
+ return `JSON_SCALAR(${expr})`;
10094
+ }
10095
+ JsonSerializeExpr(node, context) {
10096
+ const args = [];
10097
+ if (node.expr) {
10098
+ args.push(this.JsonValueExpr(node.expr, context));
10099
+ }
10100
+ const output = this.formatJsonOutput(node.output, context);
10101
+ if (output)
10102
+ args.push(output);
10103
+ return `JSON_SERIALIZE(${args.join(' ')})`;
10104
+ }
10105
+ JsonIsPredicate(node, context) {
10106
+ const parts = [];
10107
+ if (node.expr) {
10108
+ parts.push(this.visit(node.expr, context));
10109
+ }
10110
+ const format = this.formatJsonFormat(node.format);
10111
+ if (format)
10112
+ parts.push(format);
10113
+ parts.push('IS JSON');
10114
+ switch (node.item_type) {
10115
+ case 'JS_TYPE_OBJECT':
10116
+ parts.push('OBJECT');
10117
+ break;
10118
+ case 'JS_TYPE_ARRAY':
10119
+ parts.push('ARRAY');
10120
+ break;
10121
+ case 'JS_TYPE_SCALAR':
10122
+ parts.push('SCALAR');
10123
+ break;
10124
+ }
10125
+ if (node.unique_keys) {
10126
+ parts.push('WITH UNIQUE KEYS');
10127
+ }
10128
+ return parts.join(' ');
9687
10129
  }
9688
10130
  RangeFunction(node, context) {
9689
10131
  const output = [];
@@ -9794,10 +10236,10 @@ class Deparser {
9794
10236
  if (node.op === 'IS_XMLPI') {
9795
10237
  if (node.name && node.args && node.args.length > 0) {
9796
10238
  const argStrs = list_utils_1.ListUtils.unwrapList(node.args).map(arg => this.visit(arg, context));
9797
- return `xmlpi(name ${quote_utils_1.QuoteUtils.quote(node.name)}, ${argStrs.join(', ')})`;
10239
+ return `xmlpi(name ${quotes_1.QuoteUtils.quoteIdentifier(node.name)}, ${argStrs.join(', ')})`;
9798
10240
  }
9799
10241
  else if (node.name) {
9800
- return `xmlpi(name ${quote_utils_1.QuoteUtils.quote(node.name)})`;
10242
+ return `xmlpi(name ${quotes_1.QuoteUtils.quoteIdentifier(node.name)})`;
9801
10243
  }
9802
10244
  else {
9803
10245
  return 'XMLPI()';
@@ -9812,7 +10254,7 @@ class Deparser {
9812
10254
  output.push('XMLELEMENT');
9813
10255
  const elementParts = [];
9814
10256
  if (node.name) {
9815
- elementParts.push(`NAME ${quote_utils_1.QuoteUtils.quote(node.name)}`);
10257
+ elementParts.push(`NAME ${quotes_1.QuoteUtils.quoteIdentifier(node.name)}`);
9816
10258
  }
9817
10259
  if (node.named_args && node.named_args.length > 0) {
9818
10260
  const namedArgStrs = list_utils_1.ListUtils.unwrapList(node.named_args).map(arg => this.visit(arg, context));
@@ -9877,6 +10319,7 @@ class Deparser {
9877
10319
  rootParts.push('STANDALONE NO VALUE');
9878
10320
  }
9879
10321
  else if (standaloneArg.A_Const.ival.ival === 3) {
10322
+ // STANDALONE omitted
9880
10323
  }
9881
10324
  else if (Object.keys(standaloneArg.A_Const.ival).length === 0) {
9882
10325
  rootParts.push('STANDALONE YES');
@@ -9912,7 +10355,7 @@ class Deparser {
9912
10355
  // Handle name and args for operations that don't have special handling
9913
10356
  if (node.op !== 'IS_XMLELEMENT' && node.op !== 'IS_XMLPARSE' && node.op !== 'IS_XMLROOT' && node.op !== 'IS_DOCUMENT') {
9914
10357
  if (node.name) {
9915
- const quotedName = quote_utils_1.QuoteUtils.quote(node.name);
10358
+ const quotedName = quotes_1.QuoteUtils.quoteIdentifier(node.name);
9916
10359
  output.push(`NAME ${quotedName}`);
9917
10360
  }
9918
10361
  if (node.args && node.args.length > 0) {
@@ -9933,26 +10376,26 @@ class Deparser {
9933
10376
  }
9934
10377
  schemaname(node, context) {
9935
10378
  if (typeof node === 'string') {
9936
- return quote_utils_1.QuoteUtils.quote(node);
10379
+ return quotes_1.QuoteUtils.quoteIdentifier(node);
9937
10380
  }
9938
10381
  if (node && node.String && node.String.sval) {
9939
- return quote_utils_1.QuoteUtils.quote(node.String.sval);
10382
+ return quotes_1.QuoteUtils.quoteIdentifier(node.String.sval);
9940
10383
  }
9941
10384
  // Handle other node types without recursion
9942
10385
  if (node && typeof node === 'object') {
9943
10386
  if (node.sval !== undefined) {
9944
- return quote_utils_1.QuoteUtils.quote(node.sval);
10387
+ return quotes_1.QuoteUtils.quoteIdentifier(node.sval);
9945
10388
  }
9946
10389
  // Handle List nodes that might contain schema names
9947
10390
  if (node.List && Array.isArray(node.List.items)) {
9948
10391
  const items = node.List.items;
9949
10392
  if (items.length > 0 && items[0].String && items[0].String.sval) {
9950
- return quote_utils_1.QuoteUtils.quote(items[0].String.sval);
10393
+ return quotes_1.QuoteUtils.quoteIdentifier(items[0].String.sval);
9951
10394
  }
9952
10395
  }
9953
10396
  // For other complex nodes, try to extract string value without recursion
9954
10397
  if (node.val !== undefined) {
9955
- return quote_utils_1.QuoteUtils.quote(node.val);
10398
+ return quotes_1.QuoteUtils.quoteIdentifier(node.val);
9956
10399
  }
9957
10400
  return '';
9958
10401
  }
@@ -10015,7 +10458,7 @@ class Deparser {
10015
10458
  }
10016
10459
  output.push('RULE');
10017
10460
  if (node.rulename) {
10018
- output.push(quote_utils_1.QuoteUtils.quote(node.rulename));
10461
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.rulename));
10019
10462
  }
10020
10463
  output.push('AS ON');
10021
10464
  if (node.event) {
@@ -10082,42 +10525,42 @@ class Deparser {
10082
10525
  }
10083
10526
  relname(node, context) {
10084
10527
  if (typeof node === 'string') {
10085
- return quote_utils_1.QuoteUtils.quote(node);
10528
+ return quotes_1.QuoteUtils.quoteIdentifier(node);
10086
10529
  }
10087
10530
  if (node && node.String && node.String.sval) {
10088
- return quote_utils_1.QuoteUtils.quote(node.String.sval);
10531
+ return quotes_1.QuoteUtils.quoteIdentifier(node.String.sval);
10089
10532
  }
10090
10533
  if (node && typeof node === 'object' && node.relname) {
10091
- return quote_utils_1.QuoteUtils.quote(node.relname);
10534
+ return quotes_1.QuoteUtils.quoteIdentifier(node.relname);
10092
10535
  }
10093
10536
  return this.visit(node, context);
10094
10537
  }
10095
10538
  rel(node, context) {
10096
10539
  if (typeof node === 'string') {
10097
- return quote_utils_1.QuoteUtils.quote(node);
10540
+ return quotes_1.QuoteUtils.quoteIdentifier(node);
10098
10541
  }
10099
10542
  if (node && node.String && node.String.sval) {
10100
- return quote_utils_1.QuoteUtils.quote(node.String.sval);
10543
+ return quotes_1.QuoteUtils.quoteIdentifier(node.String.sval);
10101
10544
  }
10102
10545
  if (node && node.RangeVar) {
10103
10546
  return this.RangeVar(node.RangeVar, context);
10104
10547
  }
10105
10548
  if (node && typeof node === 'object' && node.relname) {
10106
- return quote_utils_1.QuoteUtils.quote(node.relname);
10549
+ return quotes_1.QuoteUtils.quoteIdentifier(node.relname);
10107
10550
  }
10108
10551
  return this.visit(node, context);
10109
10552
  }
10110
10553
  objname(node, context) {
10111
10554
  if (typeof node === 'string') {
10112
- return quote_utils_1.QuoteUtils.quote(node);
10555
+ return quotes_1.QuoteUtils.quoteIdentifier(node);
10113
10556
  }
10114
10557
  if (node && node.String && node.String.sval) {
10115
- return quote_utils_1.QuoteUtils.quote(node.String.sval);
10558
+ return quotes_1.QuoteUtils.quoteIdentifier(node.String.sval);
10116
10559
  }
10117
10560
  if (Array.isArray(node)) {
10118
10561
  const parts = node.map(part => {
10119
10562
  if (part && part.String && part.String.sval) {
10120
- return quote_utils_1.QuoteUtils.quote(part.String.sval);
10563
+ return quotes_1.QuoteUtils.quoteIdentifier(part.String.sval);
10121
10564
  }
10122
10565
  return this.visit(part, context);
10123
10566
  });
@@ -10188,7 +10631,7 @@ class Deparser {
10188
10631
  CurrentOfExpr(node, context) {
10189
10632
  const output = ['CURRENT OF'];
10190
10633
  if (node.cursor_name) {
10191
- output.push(quote_utils_1.QuoteUtils.quote(node.cursor_name));
10634
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.cursor_name));
10192
10635
  }
10193
10636
  if (node.cursor_param > 0) {
10194
10637
  output.push(`$${node.cursor_param}`);
@@ -10271,7 +10714,7 @@ class Deparser {
10271
10714
  if (items.length === 2) {
10272
10715
  const schemaName = items[0].String?.sval || '';
10273
10716
  const domainName = items[1].String?.sval || '';
10274
- output.push(`${quote_utils_1.QuoteUtils.quote(schemaName)}.${quote_utils_1.QuoteUtils.quote(domainName)}`);
10717
+ output.push(quotes_1.QuoteUtils.quoteQualifiedIdentifier(schemaName, domainName));
10275
10718
  }
10276
10719
  else {
10277
10720
  output.push(this.visit(node.object, context));
@@ -10283,7 +10726,7 @@ class Deparser {
10283
10726
  if (items.length === 2) {
10284
10727
  const schemaName = items[0].String?.sval || '';
10285
10728
  const typeName = items[1].String?.sval || '';
10286
- output.push(`${quote_utils_1.QuoteUtils.quote(schemaName)}.${quote_utils_1.QuoteUtils.quote(typeName)}`);
10729
+ output.push(quotes_1.QuoteUtils.quoteQualifiedIdentifier(schemaName, typeName));
10287
10730
  }
10288
10731
  else {
10289
10732
  output.push(this.visit(node.object, context));
@@ -10295,7 +10738,7 @@ class Deparser {
10295
10738
  if (items.length === 2) {
10296
10739
  const schemaName = items[0].String?.sval || '';
10297
10740
  const conversionName = items[1].String?.sval || '';
10298
- output.push(`${quote_utils_1.QuoteUtils.quote(schemaName)}.${quote_utils_1.QuoteUtils.quote(conversionName)}`);
10741
+ output.push(quotes_1.QuoteUtils.quoteQualifiedIdentifier(schemaName, conversionName));
10299
10742
  }
10300
10743
  else {
10301
10744
  output.push(this.visit(node.object, context));
@@ -10307,7 +10750,7 @@ class Deparser {
10307
10750
  if (items.length === 2) {
10308
10751
  const schemaName = items[0].String?.sval || '';
10309
10752
  const parserName = items[1].String?.sval || '';
10310
- output.push(`${quote_utils_1.QuoteUtils.quote(schemaName)}.${quote_utils_1.QuoteUtils.quote(parserName)}`);
10753
+ output.push(quotes_1.QuoteUtils.quoteQualifiedIdentifier(schemaName, parserName));
10311
10754
  }
10312
10755
  else {
10313
10756
  output.push(this.visit(node.object, context));
@@ -10319,7 +10762,7 @@ class Deparser {
10319
10762
  if (items.length === 2) {
10320
10763
  const schemaName = items[0].String?.sval || '';
10321
10764
  const configName = items[1].String?.sval || '';
10322
- output.push(`${quote_utils_1.QuoteUtils.quote(schemaName)}.${quote_utils_1.QuoteUtils.quote(configName)}`);
10765
+ output.push(quotes_1.QuoteUtils.quoteQualifiedIdentifier(schemaName, configName));
10323
10766
  }
10324
10767
  else {
10325
10768
  output.push(this.visit(node.object, context));
@@ -10331,7 +10774,7 @@ class Deparser {
10331
10774
  if (items.length === 2) {
10332
10775
  const schemaName = items[0].String?.sval || '';
10333
10776
  const templateName = items[1].String?.sval || '';
10334
- output.push(`${quote_utils_1.QuoteUtils.quote(schemaName)}.${quote_utils_1.QuoteUtils.quote(templateName)}`);
10777
+ output.push(quotes_1.QuoteUtils.quoteQualifiedIdentifier(schemaName, templateName));
10335
10778
  }
10336
10779
  else {
10337
10780
  output.push(this.visit(node.object, context));
@@ -10343,7 +10786,7 @@ class Deparser {
10343
10786
  if (items.length === 2) {
10344
10787
  const schemaName = items[0].String?.sval || '';
10345
10788
  const dictionaryName = items[1].String?.sval || '';
10346
- output.push(`${quote_utils_1.QuoteUtils.quote(schemaName)}.${quote_utils_1.QuoteUtils.quote(dictionaryName)}`);
10789
+ output.push(quotes_1.QuoteUtils.quoteQualifiedIdentifier(schemaName, dictionaryName));
10347
10790
  }
10348
10791
  else {
10349
10792
  output.push(this.visit(node.object, context));
@@ -10355,13 +10798,13 @@ class Deparser {
10355
10798
  if (items.length === 2) {
10356
10799
  const accessMethod = items[0].String?.sval || '';
10357
10800
  const opClassName = items[1].String?.sval || '';
10358
- output.push(`${quote_utils_1.QuoteUtils.quote(opClassName)} USING ${accessMethod}`);
10801
+ output.push(`${quotes_1.QuoteUtils.quoteIdentifier(opClassName)} USING ${accessMethod}`);
10359
10802
  }
10360
10803
  else if (items.length === 3) {
10361
10804
  const accessMethod = items[0].String?.sval || '';
10362
10805
  const schemaName = items[1].String?.sval || '';
10363
10806
  const opClassName = items[2].String?.sval || '';
10364
- output.push(`${quote_utils_1.QuoteUtils.quote(schemaName)}.${quote_utils_1.QuoteUtils.quote(opClassName)} USING ${accessMethod}`);
10807
+ output.push(`${quotes_1.QuoteUtils.quoteQualifiedIdentifier(schemaName, opClassName)} USING ${accessMethod}`);
10365
10808
  }
10366
10809
  else {
10367
10810
  output.push(this.visit(node.object, context));
@@ -10373,13 +10816,13 @@ class Deparser {
10373
10816
  if (items.length === 2) {
10374
10817
  const accessMethod = items[0].String?.sval || '';
10375
10818
  const opFamilyName = items[1].String?.sval || '';
10376
- output.push(`${quote_utils_1.QuoteUtils.quote(opFamilyName)} USING ${accessMethod}`);
10819
+ output.push(`${quotes_1.QuoteUtils.quoteIdentifier(opFamilyName)} USING ${accessMethod}`);
10377
10820
  }
10378
10821
  else if (items.length === 3) {
10379
10822
  const accessMethod = items[0].String?.sval || '';
10380
10823
  const schemaName = items[1].String?.sval || '';
10381
10824
  const opFamilyName = items[2].String?.sval || '';
10382
- output.push(`${quote_utils_1.QuoteUtils.quote(schemaName)}.${quote_utils_1.QuoteUtils.quote(opFamilyName)} USING ${accessMethod}`);
10825
+ output.push(`${quotes_1.QuoteUtils.quoteQualifiedIdentifier(schemaName, opFamilyName)} USING ${accessMethod}`);
10383
10826
  }
10384
10827
  else {
10385
10828
  output.push(this.visit(node.object, context));
@@ -10391,7 +10834,7 @@ class Deparser {
10391
10834
  }
10392
10835
  output.push('SET SCHEMA');
10393
10836
  if (node.newschema) {
10394
- output.push(quote_utils_1.QuoteUtils.quote(node.newschema));
10837
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.newschema));
10395
10838
  }
10396
10839
  return output.join(' ');
10397
10840
  }
@@ -10460,7 +10903,7 @@ class Deparser {
10460
10903
  }
10461
10904
  if (node.servername) {
10462
10905
  output.push('SERVER');
10463
- output.push(quote_utils_1.QuoteUtils.quote(node.servername));
10906
+ output.push(quotes_1.QuoteUtils.quoteIdentifier(node.servername));
10464
10907
  }
10465
10908
  if (node.options && node.options.length > 0) {
10466
10909
  const foreignTableContext = context.spawn('CreateForeignTableStmt');
@@ -10469,9 +10912,5 @@ class Deparser {
10469
10912
  }
10470
10913
  return output.join(' ');
10471
10914
  }
10472
- containsMultilineStringLiteral(content) {
10473
- const stringLiteralRegex = /'[^']*\n[^']*'/g;
10474
- return stringLiteralRegex.test(content);
10475
- }
10476
10915
  }
10477
10916
  exports.Deparser = Deparser;