pgsql-deparser 18.3.6 → 18.3.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/deparser.js CHANGED
@@ -5,6 +5,25 @@ const quotes_1 = require("@pgsql/quotes");
5
5
  const list_utils_1 = require("./utils/list-utils");
6
6
  const sql_formatter_1 = require("./utils/sql-formatter");
7
7
  const base_1 = require("./visitors/base");
8
+ // WindowDef.frameOptions bit flags (src/include/nodes/parsenodes.h)
9
+ const FRAMEOPTION_NONDEFAULT = 0x00001;
10
+ const FRAMEOPTION_RANGE = 0x00002;
11
+ const FRAMEOPTION_ROWS = 0x00004;
12
+ const FRAMEOPTION_GROUPS = 0x00008;
13
+ const FRAMEOPTION_BETWEEN = 0x00010;
14
+ const FRAMEOPTION_START_UNBOUNDED_PRECEDING = 0x00020;
15
+ const FRAMEOPTION_END_UNBOUNDED_PRECEDING = 0x00040;
16
+ const FRAMEOPTION_START_UNBOUNDED_FOLLOWING = 0x00080;
17
+ const FRAMEOPTION_END_UNBOUNDED_FOLLOWING = 0x00100;
18
+ const FRAMEOPTION_START_CURRENT_ROW = 0x00200;
19
+ const FRAMEOPTION_END_CURRENT_ROW = 0x00400;
20
+ const FRAMEOPTION_START_OFFSET_PRECEDING = 0x00800;
21
+ const FRAMEOPTION_END_OFFSET_PRECEDING = 0x01000;
22
+ const FRAMEOPTION_START_OFFSET_FOLLOWING = 0x02000;
23
+ const FRAMEOPTION_END_OFFSET_FOLLOWING = 0x04000;
24
+ const FRAMEOPTION_EXCLUDE_CURRENT_ROW = 0x08000;
25
+ const FRAMEOPTION_EXCLUDE_GROUP = 0x10000;
26
+ const FRAMEOPTION_EXCLUDE_TIES = 0x20000;
8
27
  /**
9
28
  * List of real PostgreSQL built-in types as they appear in pg_catalog.pg_type.typname.
10
29
  * These are stored in lowercase in PostgreSQL system catalogs.
@@ -984,6 +1003,12 @@ class Deparser {
984
1003
  output.push(context.parens(columnNames.join(', ')));
985
1004
  }
986
1005
  }
1006
+ if (node.override === 'OVERRIDING_USER_VALUE') {
1007
+ output.push('OVERRIDING USER VALUE');
1008
+ }
1009
+ else if (node.override === 'OVERRIDING_SYSTEM_VALUE') {
1010
+ output.push('OVERRIDING SYSTEM VALUE');
1011
+ }
987
1012
  if (node.selectStmt) {
988
1013
  output.push(this.visit(node.selectStmt, context));
989
1014
  }
@@ -1060,38 +1085,8 @@ class Deparser {
1060
1085
  output.push(this.RangeVar(node.relation, context));
1061
1086
  }
1062
1087
  output.push('SET');
1063
- const targetList = list_utils_1.ListUtils.unwrapList(node.targetList);
1064
- if (targetList && targetList.length) {
1065
- const firstTarget = targetList[0];
1066
- const processedTargets = new Set();
1067
- const assignmentParts = [];
1068
- for (let i = 0; i < targetList.length; i++) {
1069
- if (processedTargets.has(i))
1070
- continue;
1071
- const target = targetList[i];
1072
- const multiAssignRef = target.ResTarget?.val?.MultiAssignRef;
1073
- if (multiAssignRef) {
1074
- const relatedTargets = [];
1075
- for (let j = i; j < targetList.length; j++) {
1076
- const otherTarget = targetList[j];
1077
- const otherMultiAssignRef = otherTarget.ResTarget?.val?.MultiAssignRef;
1078
- if (otherMultiAssignRef &&
1079
- JSON.stringify(otherMultiAssignRef.source) === JSON.stringify(multiAssignRef.source)) {
1080
- relatedTargets.push(otherTarget);
1081
- processedTargets.add(j);
1082
- }
1083
- }
1084
- const names = relatedTargets.map(t => t.ResTarget.name);
1085
- const multiAssignment = `${context.parens(names.join(', '))} = ${this.visit(multiAssignRef.source, context)}`;
1086
- assignmentParts.push(multiAssignment);
1087
- }
1088
- else {
1089
- // Handle regular single-column assignment
1090
- assignmentParts.push(this.visit(target, context.spawn('UpdateStmt', { update: true })));
1091
- processedTargets.add(i);
1092
- }
1093
- }
1094
- output.push(assignmentParts.join(','));
1088
+ if (node.targetList && node.targetList.length > 0) {
1089
+ output.push(this.formatUpdateAssignments(node.targetList, context));
1095
1090
  }
1096
1091
  if (node.fromClause) {
1097
1092
  output.push('FROM');
@@ -1108,6 +1103,36 @@ class Deparser {
1108
1103
  }
1109
1104
  return output.join(' ');
1110
1105
  }
1106
+ formatUpdateAssignments(targets, context) {
1107
+ const targetList = list_utils_1.ListUtils.unwrapList(targets);
1108
+ const processedTargets = new Set();
1109
+ const assignmentParts = [];
1110
+ for (let i = 0; i < targetList.length; i++) {
1111
+ if (processedTargets.has(i))
1112
+ continue;
1113
+ const target = targetList[i];
1114
+ const multiAssignRef = target.ResTarget?.val?.MultiAssignRef;
1115
+ if (multiAssignRef) {
1116
+ const relatedTargets = [];
1117
+ for (let j = i; j < targetList.length; j++) {
1118
+ const otherTarget = targetList[j];
1119
+ const otherMultiAssignRef = otherTarget.ResTarget?.val?.MultiAssignRef;
1120
+ if (otherMultiAssignRef &&
1121
+ JSON.stringify(otherMultiAssignRef.source) === JSON.stringify(multiAssignRef.source)) {
1122
+ relatedTargets.push(otherTarget);
1123
+ processedTargets.add(j);
1124
+ }
1125
+ }
1126
+ const names = relatedTargets.map(t => quotes_1.QuoteUtils.quoteIdentifier(t.ResTarget.name));
1127
+ assignmentParts.push(`${context.parens(names.join(', '))} = ${this.visit(multiAssignRef.source, context)}`);
1128
+ }
1129
+ else {
1130
+ assignmentParts.push(this.visit(target, context.spawn('UpdateStmt', { update: true })));
1131
+ processedTargets.add(i);
1132
+ }
1133
+ }
1134
+ return assignmentParts.join(', ');
1135
+ }
1111
1136
  DeleteStmt(node, context) {
1112
1137
  try {
1113
1138
  const output = [];
@@ -1520,43 +1545,41 @@ class Deparser {
1520
1545
  result += ` FILTER (WHERE ${this.visit(node.agg_filter, context)})`;
1521
1546
  }
1522
1547
  if (node.over) {
1523
- // Handle named window references first
1524
- if (node.over.name) {
1525
- result += ` OVER ${node.over.name}`;
1526
- }
1527
- else {
1528
- const windowParts = [];
1529
- if (node.over.partitionClause) {
1530
- const partitions = list_utils_1.ListUtils.unwrapList(node.over.partitionClause);
1531
- const partitionStrs = partitions.map(p => this.visit(p, context));
1532
- windowParts.push(`PARTITION BY ${partitionStrs.join(', ')}`);
1533
- }
1534
- if (node.over.orderClause) {
1535
- const orders = list_utils_1.ListUtils.unwrapList(node.over.orderClause);
1536
- const orderStrs = orders.map(o => this.visit(o, context));
1537
- windowParts.push(`ORDER BY ${orderStrs.join(', ')}`);
1538
- }
1539
- // Handle window frame specifications using the dedicated formatWindowFrame method
1540
- const frameClause = this.formatWindowFrame(node.over, context.spawn('FuncCall'));
1541
- if (frameClause) {
1542
- windowParts.push(frameClause);
1543
- }
1544
- if (windowParts.length > 0) {
1545
- if (context.isPretty() && windowParts.length > 1) {
1546
- const formattedParts = windowParts.map(part => context.indent(part));
1547
- result += ` OVER (${context.newline()}${formattedParts.join(context.newline())}${context.newline()})`;
1548
- }
1549
- else {
1550
- result += ` OVER (${windowParts.join(' ')})`;
1551
- }
1552
- }
1553
- else {
1554
- result += ` OVER ()`;
1555
- }
1556
- }
1548
+ result += this.formatOverClause(node.over, context);
1557
1549
  }
1558
1550
  return result;
1559
1551
  }
1552
+ formatOverClause(over, context) {
1553
+ if (over.name) {
1554
+ return ` OVER ${over.name}`;
1555
+ }
1556
+ const windowParts = [];
1557
+ if (over.refname) {
1558
+ windowParts.push(over.refname);
1559
+ }
1560
+ if (over.partitionClause) {
1561
+ const partitions = list_utils_1.ListUtils.unwrapList(over.partitionClause);
1562
+ const partitionStrs = partitions.map(p => this.visit(p, context));
1563
+ windowParts.push(`PARTITION BY ${partitionStrs.join(', ')}`);
1564
+ }
1565
+ if (over.orderClause) {
1566
+ const orders = list_utils_1.ListUtils.unwrapList(over.orderClause);
1567
+ const orderStrs = orders.map(o => this.visit(o, context));
1568
+ windowParts.push(`ORDER BY ${orderStrs.join(', ')}`);
1569
+ }
1570
+ const frameClause = this.formatWindowFrame(over, context.spawn('FuncCall'));
1571
+ if (frameClause) {
1572
+ windowParts.push(frameClause);
1573
+ }
1574
+ if (windowParts.length === 0) {
1575
+ return ' OVER ()';
1576
+ }
1577
+ if (context.isPretty() && windowParts.length > 1) {
1578
+ const formattedParts = windowParts.map(part => context.indent(part));
1579
+ return ` OVER (${context.newline()}${formattedParts.join(context.newline())}${context.newline()})`;
1580
+ }
1581
+ return ` OVER (${windowParts.join(' ')})`;
1582
+ }
1560
1583
  FuncExpr(node, context) {
1561
1584
  const funcName = `func_${node.funcid}`;
1562
1585
  const args = node.args ? list_utils_1.ListUtils.unwrapList(node.args).map(arg => this.visit(arg, context)).join(', ') : '';
@@ -2419,7 +2442,7 @@ class Deparser {
2419
2442
  output.push(context.parens(elementStrs.join(', ')));
2420
2443
  }
2421
2444
  }
2422
- else if (node.tableElts) {
2445
+ else if (node.tableElts && !node.partbound) {
2423
2446
  const elements = list_utils_1.ListUtils.unwrapList(node.tableElts);
2424
2447
  const elementStrs = elements.map(el => {
2425
2448
  return this.deparse(el, context.spawn('CreateStmt'));
@@ -2447,7 +2470,16 @@ class Deparser {
2447
2470
  const inherits = list_utils_1.ListUtils.unwrapList(node.inhRelations);
2448
2471
  const inheritStrs = inherits.map(rel => this.visit(rel, context));
2449
2472
  output.push(inheritStrs[0]);
2450
- if (node.partbound.strategy === 'l' && node.partbound.listdatums) {
2473
+ if (node.tableElts) {
2474
+ const elementStrs = list_utils_1.ListUtils.unwrapList(node.tableElts).map(el => {
2475
+ return this.deparse(el, context.spawn('CreateStmt'));
2476
+ });
2477
+ output.push(context.parens(elementStrs.join(', ')));
2478
+ }
2479
+ if (node.partbound.is_default) {
2480
+ output.push('DEFAULT');
2481
+ }
2482
+ else if (node.partbound.strategy === 'l' && node.partbound.listdatums) {
2451
2483
  output.push('FOR VALUES IN');
2452
2484
  const listValues = list_utils_1.ListUtils.unwrapList(node.partbound.listdatums)
2453
2485
  .map(datum => this.visit(datum, context))
@@ -2470,13 +2502,9 @@ class Deparser {
2470
2502
  output.push(`(${upperValues})`);
2471
2503
  }
2472
2504
  }
2473
- else if (node.partbound.strategy === 'h' && node.partbound.modulus !== undefined) {
2505
+ else if (node.partbound.strategy === 'h') {
2474
2506
  output.push('FOR VALUES WITH');
2475
- const remainder = node.partbound.remainder !== undefined ? node.partbound.remainder : 0;
2476
- output.push(`(MODULUS ${node.partbound.modulus}, REMAINDER ${remainder})`);
2477
- }
2478
- else if (node.partbound.is_default) {
2479
- output.push('DEFAULT');
2507
+ output.push(`(MODULUS ${node.partbound.modulus ?? 0}, REMAINDER ${node.partbound.remainder ?? 0})`);
2480
2508
  }
2481
2509
  }
2482
2510
  else if (node.inhRelations) {
@@ -2542,6 +2570,12 @@ class Deparser {
2542
2570
  if (node.typeName) {
2543
2571
  output.push(this.TypeName(node.typeName, context));
2544
2572
  }
2573
+ if (node.storage_name) {
2574
+ output.push('STORAGE', node.storage_name.toUpperCase());
2575
+ }
2576
+ if (node.compression) {
2577
+ output.push('COMPRESSION', quotes_1.QuoteUtils.quoteIdentifier(node.compression));
2578
+ }
2545
2579
  if (node.fdwoptions && node.fdwoptions.length > 0) {
2546
2580
  output.push('OPTIONS');
2547
2581
  const columnContext = context.spawn('ColumnDef');
@@ -2602,7 +2636,8 @@ class Deparser {
2602
2636
  case 'CONSTR_DEFAULT':
2603
2637
  output.push('DEFAULT');
2604
2638
  if (node.raw_expr) {
2605
- output.push(this.visit(node.raw_expr, context));
2639
+ const defaultExpr = this.visit(node.raw_expr, context);
2640
+ output.push(this.needsBExprParens(node.raw_expr) ? `(${defaultExpr})` : defaultExpr);
2606
2641
  }
2607
2642
  break;
2608
2643
  case 'CONSTR_CHECK':
@@ -2870,6 +2905,15 @@ class Deparser {
2870
2905
  deleteClause += 'SET DEFAULT';
2871
2906
  break;
2872
2907
  }
2908
+ if ((node.fk_del_action === 'n' || node.fk_del_action === 'd') && node.fk_del_set_cols && node.fk_del_set_cols.length > 0) {
2909
+ const setColumns = list_utils_1.ListUtils.unwrapList(node.fk_del_set_cols)
2910
+ .map(column => {
2911
+ const stringNode = column.String;
2912
+ return quotes_1.QuoteUtils.quoteIdentifier(stringNode.sval || stringNode.str || '');
2913
+ })
2914
+ .join(', ');
2915
+ deleteClause += ` (${setColumns})`;
2916
+ }
2873
2917
  if (context.isPretty()) {
2874
2918
  output.push('\n' + context.indent(deleteClause));
2875
2919
  }
@@ -2957,7 +3001,7 @@ class Deparser {
2957
3001
  break;
2958
3002
  }
2959
3003
  // Handle deferrable constraints for all constraint types that support it
2960
- if (node.contype === 'CONSTR_PRIMARY' || node.contype === 'CONSTR_UNIQUE' || node.contype === 'CONSTR_FOREIGN') {
3004
+ if (node.contype === 'CONSTR_PRIMARY' || node.contype === 'CONSTR_UNIQUE' || node.contype === 'CONSTR_FOREIGN' || node.contype === 'CONSTR_EXCLUSION') {
2961
3005
  if (node.deferrable) {
2962
3006
  if (context.isPretty() && node.contype === 'CONSTR_FOREIGN') {
2963
3007
  output.push('\n' + context.indent('DEFERRABLE'));
@@ -2986,6 +3030,9 @@ class Deparser {
2986
3030
  output.push('NOT DEFERRABLE');
2987
3031
  }
2988
3032
  }
3033
+ else if (node.initdeferred) {
3034
+ output.push('INITIALLY DEFERRED');
3035
+ }
2989
3036
  }
2990
3037
  if (context.isPretty() && node.contype === 'CONSTR_FOREIGN') {
2991
3038
  let result = '';
@@ -3051,6 +3098,9 @@ class Deparser {
3051
3098
  output.push(node.name);
3052
3099
  }
3053
3100
  const windowParts = [];
3101
+ if (node.refname) {
3102
+ windowParts.push(node.refname);
3103
+ }
3054
3104
  if (node.partitionClause) {
3055
3105
  const partitions = list_utils_1.ListUtils.unwrapList(node.partitionClause);
3056
3106
  const partitionStrs = partitions.map(p => this.visit(p, context));
@@ -3061,12 +3111,9 @@ class Deparser {
3061
3111
  const orderStrs = orders.map(o => this.visit(o, context));
3062
3112
  windowParts.push(`ORDER BY ${orderStrs.join(', ')}`);
3063
3113
  }
3064
- // Only add frame clause if frameOptions indicates non-default framing
3065
- if (node.frameOptions && node.frameOptions !== 1058) {
3066
- const frameClause = this.formatWindowFrame(node, context.spawn('WindowDef'));
3067
- if (frameClause) {
3068
- windowParts.push(frameClause);
3069
- }
3114
+ const frameClause = this.formatWindowFrame(node, context.spawn('WindowDef'));
3115
+ if (frameClause) {
3116
+ windowParts.push(frameClause);
3070
3117
  }
3071
3118
  if (windowParts.length > 0) {
3072
3119
  if (node.name) {
@@ -3083,114 +3130,96 @@ class Deparser {
3083
3130
  }
3084
3131
  return output.join(' ');
3085
3132
  }
3133
+ formatIdentityColumnOptions(def, context) {
3134
+ const seqContext = context.spawn('AlterSeqStmt');
3135
+ return list_utils_1.ListUtils.unwrapList(def).map(item => {
3136
+ const el = item.DefElem;
3137
+ if (!el)
3138
+ return this.visit(item, context);
3139
+ if (el.defname === 'generated') {
3140
+ const ival = el.arg?.Integer?.ival ?? 0;
3141
+ return ival === 97 ? 'SET GENERATED ALWAYS' : 'SET GENERATED BY DEFAULT';
3142
+ }
3143
+ if (el.defname === 'restart') {
3144
+ return el.arg ? `RESTART WITH ${this.visit(el.arg, context)}` : 'RESTART';
3145
+ }
3146
+ return `SET ${this.visit(item, seqContext)}`;
3147
+ }).join(' ');
3148
+ }
3149
+ // b_expr (used by DEFAULT) excludes IN/LIKE/BETWEEN and boolean operators.
3150
+ needsBExprParens(node) {
3151
+ const nodeType = this.getNodeType(node);
3152
+ if (nodeType === 'BoolExpr')
3153
+ return true;
3154
+ if (nodeType === 'A_Expr') {
3155
+ const kind = this.getNodeData(node).kind;
3156
+ return kind !== 'AEXPR_OP' && kind !== 'AEXPR_DISTINCT' && kind !== 'AEXPR_NOT_DISTINCT';
3157
+ }
3158
+ return false;
3159
+ }
3086
3160
  formatWindowFrame(node, context) {
3087
- if (!node.frameOptions)
3161
+ if (!node.frameOptions || !(node.frameOptions & FRAMEOPTION_NONDEFAULT))
3088
3162
  return null;
3089
3163
  const frameOptions = node.frameOptions;
3090
- const EXCLUDE_MASK = 0x8000 | 0x10000 | 0x20000;
3091
- const baseFrameOptions = frameOptions & ~EXCLUDE_MASK;
3092
3164
  const frameParts = [];
3093
- if (frameOptions & 0x01) { // FRAMEOPTION_NONDEFAULT
3094
- if (frameOptions & 0x02) { // FRAMEOPTION_RANGE
3095
- frameParts.push('RANGE');
3096
- }
3097
- else if (frameOptions & 0x04) { // FRAMEOPTION_ROWS
3098
- frameParts.push('ROWS');
3099
- }
3100
- else if (frameOptions & 0x08) { // FRAMEOPTION_GROUPS
3101
- frameParts.push('GROUPS');
3102
- }
3165
+ if (frameOptions & FRAMEOPTION_RANGE) {
3166
+ frameParts.push('RANGE');
3167
+ }
3168
+ else if (frameOptions & FRAMEOPTION_ROWS) {
3169
+ frameParts.push('ROWS');
3170
+ }
3171
+ else if (frameOptions & FRAMEOPTION_GROUPS) {
3172
+ frameParts.push('GROUPS');
3103
3173
  }
3104
3174
  if (frameParts.length === 0)
3105
3175
  return null;
3106
- const boundsParts = [];
3107
- // Handle specific frameOptions values that have known mappings
3108
- if (baseFrameOptions === 789) {
3109
- boundsParts.push('CURRENT ROW');
3110
- boundsParts.push('AND UNBOUNDED FOLLOWING');
3176
+ let start = null;
3177
+ if (frameOptions & FRAMEOPTION_START_UNBOUNDED_PRECEDING) {
3178
+ start = 'UNBOUNDED PRECEDING';
3111
3179
  }
3112
- else if (baseFrameOptions === 1077) {
3113
- boundsParts.push('UNBOUNDED PRECEDING');
3114
- boundsParts.push('AND CURRENT ROW');
3180
+ else if (frameOptions & FRAMEOPTION_START_UNBOUNDED_FOLLOWING) {
3181
+ start = 'UNBOUNDED FOLLOWING';
3115
3182
  }
3116
- else if (baseFrameOptions === 18453) {
3117
- if (node.startOffset && node.endOffset) {
3118
- boundsParts.push(`${this.visit(node.startOffset, context)} PRECEDING`);
3119
- boundsParts.push(`AND ${this.visit(node.endOffset, context)} FOLLOWING`);
3120
- }
3183
+ else if (frameOptions & FRAMEOPTION_START_CURRENT_ROW) {
3184
+ start = 'CURRENT ROW';
3121
3185
  }
3122
- else if (baseFrameOptions === 1557) {
3123
- boundsParts.push('CURRENT ROW');
3124
- boundsParts.push('AND CURRENT ROW');
3186
+ else if (frameOptions & FRAMEOPTION_START_OFFSET_PRECEDING && node.startOffset) {
3187
+ start = `${this.visit(node.startOffset, context)} PRECEDING`;
3125
3188
  }
3126
- else if (baseFrameOptions === 16917) {
3127
- boundsParts.push('CURRENT ROW');
3128
- if (node.endOffset) {
3129
- boundsParts.push(`AND ${this.visit(node.endOffset, context)} FOLLOWING`);
3130
- }
3189
+ else if (frameOptions & FRAMEOPTION_START_OFFSET_FOLLOWING && node.startOffset) {
3190
+ start = `${this.visit(node.startOffset, context)} FOLLOWING`;
3131
3191
  }
3132
- else if (baseFrameOptions === 1058) {
3133
- return null;
3192
+ let end = null;
3193
+ if (frameOptions & FRAMEOPTION_END_UNBOUNDED_PRECEDING) {
3194
+ end = 'UNBOUNDED PRECEDING';
3134
3195
  }
3135
- else {
3136
- // Handle start bound - prioritize explicit offset values over bit flags
3137
- if (node.startOffset) {
3138
- if (frameOptions & 0x400) { // FRAMEOPTION_START_VALUE_PRECEDING
3139
- boundsParts.push(`${this.visit(node.startOffset, context)} PRECEDING`);
3140
- }
3141
- else if (frameOptions & 0x800) { // FRAMEOPTION_START_VALUE_FOLLOWING
3142
- boundsParts.push(`${this.visit(node.startOffset, context)} FOLLOWING`);
3143
- }
3144
- else {
3145
- boundsParts.push(`${this.visit(node.startOffset, context)} PRECEDING`);
3146
- }
3147
- }
3148
- else if (frameOptions & 0x10) { // FRAMEOPTION_START_UNBOUNDED_PRECEDING
3149
- boundsParts.push('UNBOUNDED PRECEDING');
3150
- }
3151
- else if (frameOptions & 0x20) { // FRAMEOPTION_START_CURRENT_ROW
3152
- boundsParts.push('CURRENT ROW');
3153
- }
3154
- // Handle end bound - prioritize explicit offset values over bit flags
3155
- if (node.endOffset) {
3156
- if (boundsParts.length > 0) {
3157
- if (frameOptions & 0x1000) { // FRAMEOPTION_END_VALUE_PRECEDING
3158
- boundsParts.push(`AND ${this.visit(node.endOffset, context)} PRECEDING`);
3159
- }
3160
- else if (frameOptions & 0x2000) { // FRAMEOPTION_END_VALUE_FOLLOWING
3161
- boundsParts.push(`AND ${this.visit(node.endOffset, context)} FOLLOWING`);
3162
- }
3163
- else {
3164
- boundsParts.push(`AND ${this.visit(node.endOffset, context)} FOLLOWING`);
3165
- }
3166
- }
3167
- }
3168
- else if (frameOptions & 0x80) { // FRAMEOPTION_END_UNBOUNDED_FOLLOWING
3169
- if (boundsParts.length > 0) {
3170
- boundsParts.push('AND UNBOUNDED FOLLOWING');
3171
- }
3172
- }
3173
- else if (frameOptions & 0x100) { // FRAMEOPTION_END_CURRENT_ROW
3174
- if (boundsParts.length > 0) {
3175
- boundsParts.push('AND CURRENT ROW');
3176
- }
3196
+ else if (frameOptions & FRAMEOPTION_END_UNBOUNDED_FOLLOWING) {
3197
+ end = 'UNBOUNDED FOLLOWING';
3198
+ }
3199
+ else if (frameOptions & FRAMEOPTION_END_CURRENT_ROW) {
3200
+ end = 'CURRENT ROW';
3201
+ }
3202
+ else if (frameOptions & FRAMEOPTION_END_OFFSET_PRECEDING && node.endOffset) {
3203
+ end = `${this.visit(node.endOffset, context)} PRECEDING`;
3204
+ }
3205
+ else if (frameOptions & FRAMEOPTION_END_OFFSET_FOLLOWING && node.endOffset) {
3206
+ end = `${this.visit(node.endOffset, context)} FOLLOWING`;
3207
+ }
3208
+ if (start) {
3209
+ if (frameOptions & FRAMEOPTION_BETWEEN) {
3210
+ frameParts.push(`BETWEEN ${start} AND ${end ?? 'CURRENT ROW'}`);
3177
3211
  }
3178
- else if (boundsParts.length > 0) {
3179
- boundsParts.push('AND CURRENT ROW');
3212
+ else {
3213
+ frameParts.push(start);
3180
3214
  }
3181
3215
  }
3182
- if (boundsParts.length > 0) {
3183
- frameParts.push('BETWEEN');
3184
- frameParts.push(boundsParts.join(' '));
3185
- }
3186
- // EXCLUDE clause
3187
- if (frameOptions & 0x8000) { // FRAMEOPTION_EXCLUDE_CURRENT_ROW
3216
+ if (frameOptions & FRAMEOPTION_EXCLUDE_CURRENT_ROW) {
3188
3217
  frameParts.push('EXCLUDE CURRENT ROW');
3189
3218
  }
3190
- else if (frameOptions & 0x10000) { // FRAMEOPTION_EXCLUDE_GROUP
3219
+ else if (frameOptions & FRAMEOPTION_EXCLUDE_GROUP) {
3191
3220
  frameParts.push('EXCLUDE GROUP');
3192
3221
  }
3193
- else if (frameOptions & 0x20000) { // FRAMEOPTION_EXCLUDE_TIES
3222
+ else if (frameOptions & FRAMEOPTION_EXCLUDE_TIES) {
3194
3223
  frameParts.push('EXCLUDE TIES');
3195
3224
  }
3196
3225
  return frameParts.join(' ');
@@ -3269,8 +3298,35 @@ class Deparser {
3269
3298
  if (node.ctequery) {
3270
3299
  output.push(context.parens(this.visit(node.ctequery, context)));
3271
3300
  }
3301
+ if (node.search_clause) {
3302
+ const sc = node.search_clause;
3303
+ const cols = list_utils_1.ListUtils.unwrapList(sc.search_col_list).map(c => this.visit(c, context));
3304
+ output.push('SEARCH', sc.search_breadth_first ? 'BREADTH' : 'DEPTH', 'FIRST BY');
3305
+ output.push(cols.join(', '));
3306
+ output.push('SET', quotes_1.QuoteUtils.quoteIdentifier(sc.search_seq_column));
3307
+ }
3308
+ if (node.cycle_clause) {
3309
+ const cc = node.cycle_clause;
3310
+ const cols = list_utils_1.ListUtils.unwrapList(cc.cycle_col_list).map(c => this.visit(c, context));
3311
+ output.push('CYCLE', cols.join(', '));
3312
+ output.push('SET', quotes_1.QuoteUtils.quoteIdentifier(cc.cycle_mark_column));
3313
+ if (cc.cycle_mark_value && cc.cycle_mark_default) {
3314
+ output.push('TO', this.formatAexprConst(cc.cycle_mark_value, context));
3315
+ output.push('DEFAULT', this.formatAexprConst(cc.cycle_mark_default, context));
3316
+ }
3317
+ output.push('USING', quotes_1.QuoteUtils.quoteIdentifier(cc.cycle_path_column));
3318
+ }
3272
3319
  return output.join(' ');
3273
3320
  }
3321
+ // Renders a constant in the restricted AexprConst grammar (e.g. `point '(1,1)'`
3322
+ // rather than `CAST('(1,1)' AS point)`).
3323
+ formatAexprConst(node, context) {
3324
+ const cast = node.TypeCast;
3325
+ if (cast?.arg?.A_Const?.sval && cast.typeName) {
3326
+ return `${this.TypeName(cast.typeName, context)} ${this.visit(cast.arg, context)}`;
3327
+ }
3328
+ return this.visit(node, context);
3329
+ }
3274
3330
  ParamRef(node, context) {
3275
3331
  return `$${node.number}`;
3276
3332
  }
@@ -3630,12 +3686,12 @@ class Deparser {
3630
3686
  }
3631
3687
  PartitionCmd(node, context) {
3632
3688
  const output = [];
3689
+ if (node.name) {
3690
+ output.push(this.RangeVar(node.name, context));
3691
+ }
3633
3692
  if (node.concurrent) {
3634
3693
  output.push('CONCURRENTLY');
3635
3694
  }
3636
- if (node.name) {
3637
- output.push(this.visit(node.name, context));
3638
- }
3639
3695
  if (node.bound) {
3640
3696
  if (node.bound.strategy === 'l' && node.bound.listdatums) {
3641
3697
  output.push('FOR VALUES IN');
@@ -3660,9 +3716,9 @@ class Deparser {
3660
3716
  output.push(`(${upperValues})`);
3661
3717
  }
3662
3718
  }
3663
- else if (node.bound.strategy === 'h' && node.bound.modulus !== undefined && node.bound.remainder !== undefined) {
3719
+ else if (node.bound.strategy === 'h') {
3664
3720
  output.push('FOR VALUES WITH');
3665
- output.push(`(modulus ${node.bound.modulus}, remainder ${node.bound.remainder})`);
3721
+ output.push(`(MODULUS ${node.bound.modulus ?? 0}, REMAINDER ${node.bound.remainder ?? 0})`);
3666
3722
  }
3667
3723
  else if (node.bound.is_default) {
3668
3724
  output.push('DEFAULT');
@@ -4515,10 +4571,10 @@ class Deparser {
4515
4571
  output.push('PROGRAM');
4516
4572
  }
4517
4573
  if (node.filename) {
4518
- output.push(`'${node.filename}'`);
4574
+ output.push(quotes_1.QuoteUtils.escape(node.filename));
4519
4575
  }
4520
4576
  else {
4521
- output.push('STDIN');
4577
+ output.push(node.is_from ? 'STDIN' : 'STDOUT');
4522
4578
  }
4523
4579
  if (node.options && node.options.length > 0) {
4524
4580
  output.push('WITH');
@@ -4750,6 +4806,9 @@ class Deparser {
4750
4806
  const nodeData = this.getNodeData(node.def);
4751
4807
  if (nodeData && nodeData.typeName) {
4752
4808
  output.push(this.TypeName(nodeData.typeName, context));
4809
+ if (nodeData.collClause) {
4810
+ output.push(this.CollateClause(nodeData.collClause, context));
4811
+ }
4753
4812
  // Handle USING clause (stored in raw_default for ALTER COLUMN TYPE)
4754
4813
  if (nodeData.raw_default) {
4755
4814
  output.push('USING');
@@ -5230,9 +5289,8 @@ class Deparser {
5230
5289
  if (node.name) {
5231
5290
  output.push(quotes_1.QuoteUtils.quoteIdentifier(node.name));
5232
5291
  }
5233
- output.push('SET');
5234
5292
  if (node.def) {
5235
- output.push(this.visit(node.def, context));
5293
+ output.push(this.formatIdentityColumnOptions(node.def, context));
5236
5294
  }
5237
5295
  break;
5238
5296
  case 'AT_DropIdentity':
@@ -5241,11 +5299,8 @@ class Deparser {
5241
5299
  output.push(quotes_1.QuoteUtils.quoteIdentifier(node.name));
5242
5300
  }
5243
5301
  output.push('DROP IDENTITY');
5244
- if (node.behavior === 'DROP_CASCADE') {
5245
- output.push('CASCADE');
5246
- }
5247
- else if (node.behavior === 'DROP_RESTRICT') {
5248
- output.push('RESTRICT');
5302
+ if (node.missing_ok) {
5303
+ output.push('IF EXISTS');
5249
5304
  }
5250
5305
  break;
5251
5306
  case 'AT_ReAddStatistics':
@@ -5681,6 +5736,9 @@ class Deparser {
5681
5736
  if (node.arg && this.getNodeType(node.arg) === 'List') {
5682
5737
  const listData = this.getNodeData(node.arg);
5683
5738
  const listItems = list_utils_1.ListUtils.unwrapList(listData.items);
5739
+ if (listItems.length === 1 && listItems[0].String?.sval === 'none') {
5740
+ return 'OWNED BY NONE';
5741
+ }
5684
5742
  const parts = listItems.map(item => {
5685
5743
  const itemData = this.getNodeData(item);
5686
5744
  if (this.getNodeType(item) === 'String') {
@@ -5858,12 +5916,15 @@ class Deparser {
5858
5916
  }
5859
5917
  // Handle CreateStmt table options - no quotes, compact formatting
5860
5918
  if (context.parentNodeTypes.includes('CreateStmt')) {
5919
+ const relOptName = node.defnamespace
5920
+ ? `${quotes_1.QuoteUtils.quoteIdentifier(node.defnamespace)}.${quotes_1.QuoteUtils.quoteIdentifier(node.defname)}`
5921
+ : quotes_1.QuoteUtils.quoteIdentifier(node.defname);
5861
5922
  // For numeric values, use the raw value without quotes
5862
5923
  if (node.arg && this.getNodeType(node.arg) === 'Integer') {
5863
5924
  const integerData = this.getNodeData(node.arg);
5864
- return `${node.defname}=${integerData.ival}`;
5925
+ return `${relOptName}=${integerData.ival}`;
5865
5926
  }
5866
- return `${node.defname}=${argValue}`;
5927
+ return `${relOptName}=${argValue}`;
5867
5928
  }
5868
5929
  // Handle CreateEventTrigStmt WHEN clause - use IN syntax for List arguments
5869
5930
  if (context.parentNodeTypes.includes('CreateEventTrigStmt')) {
@@ -5902,15 +5963,27 @@ class Deparser {
5902
5963
  }
5903
5964
  // Handle CopyStmt WITH clause options - uppercase format without quotes
5904
5965
  if (context.parentNodeTypes.includes('CopyStmt')) {
5905
- if (node.defname === 'format' && node.arg && this.getNodeType(node.arg) === 'String') {
5906
- const stringData = this.getNodeData(node.arg);
5907
- return `FORMAT ${stringData.sval.toUpperCase()}`;
5966
+ const optName = node.defname.toUpperCase();
5967
+ if (!node.arg) {
5968
+ return optName;
5908
5969
  }
5909
- // Handle other COPY options with uppercase defname
5910
- if (node.arg) {
5911
- return `${node.defname.toUpperCase()} ${argValue}`;
5970
+ const copyArgType = this.getNodeType(node.arg);
5971
+ if (copyArgType === 'Boolean' && this.getNodeData(node.arg).boolval !== false) {
5972
+ return optName;
5912
5973
  }
5913
- return node.defname.toUpperCase();
5974
+ if (copyArgType === 'List') {
5975
+ const items = list_utils_1.ListUtils.unwrapList(this.getNodeData(node.arg).items)
5976
+ .map(item => this.visit(item, context));
5977
+ return `${optName} (${items.join(', ')})`;
5978
+ }
5979
+ if (copyArgType === 'String') {
5980
+ const sval = this.getNodeData(node.arg).sval;
5981
+ if (node.defname === 'format') {
5982
+ return `${optName} ${sval}`;
5983
+ }
5984
+ return `${optName} ${quotes_1.QuoteUtils.escape(sval)}`;
5985
+ }
5986
+ return `${optName} ${argValue}`;
5914
5987
  }
5915
5988
  // Handle CREATE OPERATOR and CREATE TYPE context
5916
5989
  if (context.parentNodeTypes.includes('DefineStmt')) {
@@ -5991,6 +6064,10 @@ class Deparser {
5991
6064
  return `${node.defname} = ${argValue}`;
5992
6065
  }
5993
6066
  }
6067
+ const argType = this.getNodeType(node.arg);
6068
+ if (argType === 'TypeName' || argType === 'Integer' || argType === 'Float' || argType === 'Boolean') {
6069
+ return `${node.defname} = ${argValue}`;
6070
+ }
5994
6071
  const quotedValue = typeof argValue === 'string'
5995
6072
  ? quotes_1.QuoteUtils.escape(argValue)
5996
6073
  : argValue;
@@ -6424,6 +6501,9 @@ class Deparser {
6424
6501
  case 'OBJECT_TABCONSTRAINT':
6425
6502
  output.push('CONSTRAINT');
6426
6503
  break;
6504
+ case 'OBJECT_DOMCONSTRAINT':
6505
+ output.push('CONSTRAINT');
6506
+ break;
6427
6507
  case 'OBJECT_TRIGGER':
6428
6508
  output.push('TRIGGER');
6429
6509
  break;
@@ -6500,6 +6580,15 @@ class Deparser {
6500
6580
  output.push(objectParts.join('.'));
6501
6581
  }
6502
6582
  }
6583
+ else if (node.objtype === 'OBJECT_DOMCONSTRAINT') {
6584
+ if (objectParts.length === 2) {
6585
+ const [domain, constraint] = objectParts;
6586
+ output.push(constraint, 'ON DOMAIN', domain);
6587
+ }
6588
+ else {
6589
+ output.push(objectParts.join('.'));
6590
+ }
6591
+ }
6503
6592
  else if (node.objtype === 'OBJECT_TRIGGER') {
6504
6593
  if (objectParts.length === 2) {
6505
6594
  const [table, trigger] = objectParts;
@@ -6831,7 +6920,7 @@ class Deparser {
6831
6920
  output.push(quotes_1.QuoteUtils.quoteIdentifier(node.pubname));
6832
6921
  }
6833
6922
  if (node.pubobjects && node.pubobjects.length > 0) {
6834
- output.push('FOR', 'TABLE');
6923
+ output.push('FOR');
6835
6924
  const tables = list_utils_1.ListUtils.unwrapList(node.pubobjects).map(table => this.visit(table, context));
6836
6925
  output.push(tables.join(', '));
6837
6926
  }
@@ -6871,8 +6960,9 @@ class Deparser {
6871
6960
  if (node.pubname) {
6872
6961
  output.push(quotes_1.QuoteUtils.quoteIdentifier(node.pubname));
6873
6962
  }
6874
- if (node.action) {
6875
- switch (node.action) {
6963
+ const hasObjects = node.pubobjects && node.pubobjects.length > 0;
6964
+ if (hasObjects) {
6965
+ switch (node.action || 'AP_AddObjects') {
6876
6966
  case 'AP_AddObjects':
6877
6967
  output.push('ADD');
6878
6968
  break;
@@ -6885,17 +6975,11 @@ class Deparser {
6885
6975
  default:
6886
6976
  throw new Error(`Unsupported AlterPublicationStmt action: ${node.action}`);
6887
6977
  }
6888
- }
6889
- if (node.for_all_tables) {
6890
- output.push('FOR ALL TABLES');
6891
- }
6892
- else if (node.pubobjects && node.pubobjects.length > 0) {
6893
- output.push('FOR TABLE');
6894
6978
  const objects = list_utils_1.ListUtils.unwrapList(node.pubobjects).map(obj => this.visit(obj, context));
6895
6979
  output.push(objects.join(', '));
6896
6980
  }
6897
- if (node.options && node.options.length > 0) {
6898
- output.push('WITH');
6981
+ else if (node.options && node.options.length > 0) {
6982
+ output.push('SET');
6899
6983
  const options = list_utils_1.ListUtils.unwrapList(node.options).map(opt => this.visit(opt, context));
6900
6984
  output.push(`(${options.join(', ')})`);
6901
6985
  }
@@ -6906,42 +6990,67 @@ class Deparser {
6906
6990
  if (node.subname) {
6907
6991
  output.push(quotes_1.QuoteUtils.quoteIdentifier(node.subname));
6908
6992
  }
6909
- if (node.kind) {
6910
- switch (node.kind) {
6993
+ const options = node.options && node.options.length > 0
6994
+ ? `(${list_utils_1.ListUtils.unwrapList(node.options).map(opt => this.visit(opt, context)).join(', ')})`
6995
+ : null;
6996
+ const publications = node.publication && node.publication.length > 0
6997
+ ? list_utils_1.ListUtils.unwrapList(node.publication).map(pub => this.visit(pub, context)).join(', ')
6998
+ : null;
6999
+ {
7000
+ switch (node.kind || 'ALTER_SUBSCRIPTION_OPTIONS') {
6911
7001
  case 'ALTER_SUBSCRIPTION_OPTIONS':
6912
7002
  output.push('SET');
7003
+ if (options)
7004
+ output.push(options);
6913
7005
  break;
6914
7006
  case 'ALTER_SUBSCRIPTION_CONNECTION':
6915
7007
  output.push('CONNECTION');
6916
7008
  if (node.conninfo) {
6917
- output.push(`'${node.conninfo}'`);
7009
+ output.push(quotes_1.QuoteUtils.escape(node.conninfo));
6918
7010
  }
6919
7011
  break;
6920
7012
  case 'ALTER_SUBSCRIPTION_SET_PUBLICATION':
6921
7013
  output.push('SET PUBLICATION');
6922
- if (node.publication && node.publication.length > 0) {
6923
- const publications = list_utils_1.ListUtils.unwrapList(node.publication).map(pub => this.visit(pub, context));
6924
- output.push(publications.join(', '));
6925
- }
7014
+ if (publications)
7015
+ output.push(publications);
7016
+ if (options)
7017
+ output.push('WITH', options);
7018
+ break;
7019
+ case 'ALTER_SUBSCRIPTION_ADD_PUBLICATION':
7020
+ output.push('ADD PUBLICATION');
7021
+ if (publications)
7022
+ output.push(publications);
7023
+ if (options)
7024
+ output.push('WITH', options);
7025
+ break;
7026
+ case 'ALTER_SUBSCRIPTION_DROP_PUBLICATION':
7027
+ output.push('DROP PUBLICATION');
7028
+ if (publications)
7029
+ output.push(publications);
7030
+ if (options)
7031
+ output.push('WITH', options);
6926
7032
  break;
6927
7033
  case 'ALTER_SUBSCRIPTION_REFRESH':
6928
7034
  output.push('REFRESH PUBLICATION');
7035
+ if (options)
7036
+ output.push('WITH', options);
6929
7037
  break;
6930
- case 'ALTER_SUBSCRIPTION_ENABLED':
6931
- output.push('ENABLE');
7038
+ case 'ALTER_SUBSCRIPTION_ENABLED': {
7039
+ const enabled = list_utils_1.ListUtils.unwrapList(node.options).find(opt => opt.DefElem?.defname === 'enabled');
7040
+ const arg = enabled?.DefElem?.arg;
7041
+ const isEnabled = arg?.Boolean ? arg.Boolean.boolval !== false : true;
7042
+ output.push(isEnabled ? 'ENABLE' : 'DISABLE');
6932
7043
  break;
7044
+ }
6933
7045
  case 'ALTER_SUBSCRIPTION_SKIP':
6934
7046
  output.push('SKIP');
7047
+ if (options)
7048
+ output.push(options);
6935
7049
  break;
6936
7050
  default:
6937
7051
  throw new Error(`Unsupported AlterSubscriptionStmt kind: ${node.kind}`);
6938
7052
  }
6939
7053
  }
6940
- if (node.options && node.options.length > 0) {
6941
- output.push('WITH');
6942
- const options = list_utils_1.ListUtils.unwrapList(node.options).map(opt => this.visit(opt, context));
6943
- output.push(`(${options.join(', ')})`);
6944
- }
6945
7054
  return output.join(' ');
6946
7055
  }
6947
7056
  DropSubscriptionStmt(node, context) {
@@ -8007,6 +8116,9 @@ class Deparser {
8007
8116
  if (node.grant_option && node.is_grant) {
8008
8117
  output.push('WITH GRANT OPTION');
8009
8118
  }
8119
+ if (node.grantor) {
8120
+ output.push('GRANTED BY', this.RoleSpec(node.grantor, context));
8121
+ }
8010
8122
  // Only add behavior clauses for REVOKE statements, not for GRANT statements in ALTER DEFAULT PRIVILEGES
8011
8123
  if (!node.is_grant) {
8012
8124
  if (node.behavior === 'DROP_CASCADE') {
@@ -8020,57 +8132,34 @@ class Deparser {
8020
8132
  }
8021
8133
  GrantRoleStmt(node, context) {
8022
8134
  const output = [];
8023
- // Check for inherit, admin, and set options first to place them correctly
8024
- let hasInheritOption = false;
8025
- let hasAdminOption = false;
8026
- let hasSetOption = false;
8027
- let inheritValue;
8028
- let adminValue;
8029
- let setValue;
8030
- if (node.opt && node.opt.length > 0) {
8031
- const options = list_utils_1.ListUtils.unwrapList(node.opt);
8032
- const inheritOption = options.find(opt => opt.DefElem && opt.DefElem.defname === 'inherit');
8033
- const adminOption = options.find(opt => (opt.String && opt.String.sval === 'admin') ||
8034
- (opt.DefElem && opt.DefElem.defname === 'admin'));
8035
- const setOption = options.find(opt => opt.DefElem && opt.DefElem.defname === 'set');
8036
- if (inheritOption && inheritOption.DefElem) {
8037
- hasInheritOption = true;
8038
- inheritValue = inheritOption.DefElem.arg?.Boolean?.boolval;
8039
- }
8040
- if (adminOption) {
8041
- hasAdminOption = true;
8042
- if (adminOption.DefElem && adminOption.DefElem.arg) {
8043
- adminValue = adminOption.DefElem.arg.Boolean?.boolval;
8044
- }
8045
- }
8046
- if (setOption && setOption.DefElem) {
8047
- hasSetOption = true;
8048
- setValue = setOption.DefElem.arg?.Boolean?.boolval;
8049
- }
8050
- }
8135
+ const options = list_utils_1.ListUtils.unwrapList(node.opt)
8136
+ .map(opt => opt.DefElem)
8137
+ .filter((opt) => !!opt && !!opt.defname);
8138
+ const optionValue = (opt) => {
8139
+ if (!opt.arg)
8140
+ return true;
8141
+ const argType = this.getNodeType(opt.arg);
8142
+ const argData = this.getNodeData(opt.arg);
8143
+ if (argType === 'Boolean')
8144
+ return argData.boolval !== false;
8145
+ if (argType === 'String')
8146
+ return argData.sval !== 'false';
8147
+ return true;
8148
+ };
8149
+ const roles = list_utils_1.ListUtils.unwrapList(node.granted_roles)
8150
+ .map(role => role.AccessPriv?.priv_name
8151
+ ? quotes_1.QuoteUtils.quoteIdentifier(role.AccessPriv.priv_name)
8152
+ : this.visit(role, context))
8153
+ .join(', ');
8051
8154
  if (node.is_grant) {
8052
- output.push('GRANT');
8155
+ output.push('GRANT', roles, 'TO');
8053
8156
  }
8054
8157
  else {
8055
8158
  output.push('REVOKE');
8056
- if (hasInheritOption) {
8057
- output.push('INHERIT OPTION FOR');
8058
- }
8059
- else if (hasAdminOption) {
8060
- output.push('ADMIN OPTION FOR');
8159
+ if (options.length > 0) {
8160
+ output.push(`${options[0].defname.toUpperCase()} OPTION FOR`);
8061
8161
  }
8062
- }
8063
- if (node.granted_roles && node.granted_roles.length > 0) {
8064
- const roles = list_utils_1.ListUtils.unwrapList(node.granted_roles)
8065
- .map(role => this.visit(role, context))
8066
- .join(', ');
8067
- output.push(roles);
8068
- }
8069
- if (node.is_grant) {
8070
- output.push('TO');
8071
- }
8072
- else {
8073
- output.push('FROM');
8162
+ output.push(roles, 'FROM');
8074
8163
  }
8075
8164
  if (node.grantee_roles && node.grantee_roles.length > 0) {
8076
8165
  const grantees = list_utils_1.ListUtils.unwrapList(node.grantee_roles)
@@ -8078,38 +8167,15 @@ class Deparser {
8078
8167
  .join(', ');
8079
8168
  output.push(grantees);
8080
8169
  }
8081
- if (node.is_grant) {
8082
- const withOptions = [];
8083
- if (hasAdminOption) {
8084
- if (adminValue === true) {
8085
- withOptions.push('ADMIN OPTION');
8086
- }
8087
- else if (adminValue === false) {
8088
- withOptions.push('ADMIN FALSE');
8089
- }
8090
- else {
8091
- withOptions.push('ADMIN OPTION');
8092
- }
8093
- }
8094
- if (hasInheritOption) {
8095
- if (inheritValue === true) {
8096
- withOptions.push('INHERIT OPTION');
8097
- }
8098
- else if (inheritValue === false) {
8099
- withOptions.push('INHERIT FALSE');
8100
- }
8101
- }
8102
- if (hasSetOption) {
8103
- if (setValue === true) {
8104
- withOptions.push('SET TRUE');
8105
- }
8106
- else if (setValue === false) {
8107
- withOptions.push('SET FALSE');
8108
- }
8109
- }
8110
- if (withOptions.length > 0) {
8111
- output.push('WITH', withOptions.join(', '));
8112
- }
8170
+ if (node.is_grant && options.length > 0) {
8171
+ const withOptions = options.map(opt => `${opt.defname.toUpperCase()} ${optionValue(opt) ? 'TRUE' : 'FALSE'}`);
8172
+ output.push('WITH', withOptions.join(', '));
8173
+ }
8174
+ if (node.grantor) {
8175
+ output.push('GRANTED BY', this.RoleSpec(node.grantor, context));
8176
+ }
8177
+ if (!node.is_grant && node.behavior === 'DROP_CASCADE') {
8178
+ output.push('CASCADE');
8113
8179
  }
8114
8180
  return output.join(' ');
8115
8181
  }
@@ -8689,10 +8755,9 @@ class Deparser {
8689
8755
  switch (node.commandType) {
8690
8756
  case 'CMD_UPDATE': {
8691
8757
  output.push('UPDATE SET');
8692
- const assignments = list_utils_1.ListUtils.unwrapList(node.targetList)
8693
- .map(target => this.visit(target, context.spawn('UpdateStmt', { update: true })))
8694
- .join(', ');
8695
- output.push(assignments);
8758
+ if (node.targetList && node.targetList.length > 0) {
8759
+ output.push(this.formatUpdateAssignments(node.targetList, context));
8760
+ }
8696
8761
  break;
8697
8762
  }
8698
8763
  case 'CMD_INSERT': {
@@ -9097,6 +9162,13 @@ class Deparser {
9097
9162
  output.push('USING');
9098
9163
  output.push(node.into.accessMethod);
9099
9164
  }
9165
+ if (node.into && node.into.options && node.into.options.length > 0) {
9166
+ output.push('WITH');
9167
+ const options = list_utils_1.ListUtils.unwrapList(node.into.options)
9168
+ .map(option => this.visit(option, context.spawn('CreateStmt')))
9169
+ .join(', ');
9170
+ output.push(`(${options})`);
9171
+ }
9100
9172
  if (node.into && node.into.onCommit && node.into.onCommit !== 'ONCOMMIT_NOOP') {
9101
9173
  output.push('ON COMMIT');
9102
9174
  switch (node.into.onCommit) {
@@ -9111,17 +9183,13 @@ class Deparser {
9111
9183
  break;
9112
9184
  }
9113
9185
  }
9186
+ if (node.into && node.into.tableSpaceName) {
9187
+ output.push('TABLESPACE', quotes_1.QuoteUtils.quoteIdentifier(node.into.tableSpaceName));
9188
+ }
9114
9189
  output.push('AS');
9115
9190
  if (node.query) {
9116
9191
  output.push(this.visit(node.query, context));
9117
9192
  }
9118
- if (node.into && node.into.options && node.into.options.length > 0) {
9119
- output.push('WITH');
9120
- const options = list_utils_1.ListUtils.unwrapList(node.into.options)
9121
- .map(option => this.visit(option, context))
9122
- .join(', ');
9123
- output.push(`(${options})`);
9124
- }
9125
9193
  if (node.into && node.into.skipData) {
9126
9194
  output.push('WITH NO DATA');
9127
9195
  }
@@ -9594,7 +9662,7 @@ class Deparser {
9594
9662
  }
9595
9663
  if (node.whereClause) {
9596
9664
  output.push('WHERE');
9597
- output.push(this.visit(node.whereClause, context));
9665
+ output.push(`(${this.visit(node.whereClause, context)})`);
9598
9666
  }
9599
9667
  return output.join(' ');
9600
9668
  }
@@ -9837,24 +9905,182 @@ class Deparser {
9837
9905
  }
9838
9906
  return output.join(' ');
9839
9907
  }
9908
+ formatJsonFormat(format) {
9909
+ if (!format || !format.format_type || format.format_type === 'JS_FORMAT_DEFAULT') {
9910
+ return null;
9911
+ }
9912
+ const parts = ['FORMAT JSON'];
9913
+ switch (format.encoding) {
9914
+ case 'JS_ENC_UTF8':
9915
+ parts.push('ENCODING UTF8');
9916
+ break;
9917
+ case 'JS_ENC_UTF16':
9918
+ parts.push('ENCODING UTF16');
9919
+ break;
9920
+ case 'JS_ENC_UTF32':
9921
+ parts.push('ENCODING UTF32');
9922
+ break;
9923
+ }
9924
+ return parts.join(' ');
9925
+ }
9926
+ formatJsonOutput(output, context) {
9927
+ if (!output || !output.typeName)
9928
+ return null;
9929
+ const parts = ['RETURNING', this.TypeName(output.typeName, context)];
9930
+ const format = this.formatJsonFormat(output.returning?.format);
9931
+ if (format)
9932
+ parts.push(format);
9933
+ return parts.join(' ');
9934
+ }
9935
+ formatJsonNullClause(absentOnNull) {
9936
+ return absentOnNull ? 'ABSENT ON NULL' : 'NULL ON NULL';
9937
+ }
9938
+ formatJsonUniqueClause(unique) {
9939
+ return unique ? 'WITH UNIQUE KEYS' : null;
9940
+ }
9941
+ JsonValueExpr(node, context) {
9942
+ const parts = [];
9943
+ if (node.raw_expr) {
9944
+ parts.push(this.visit(node.raw_expr, context));
9945
+ }
9946
+ const format = this.formatJsonFormat(node.format);
9947
+ if (format)
9948
+ parts.push(format);
9949
+ return parts.join(' ');
9950
+ }
9951
+ JsonKeyValue(node, context) {
9952
+ const key = node.key ? this.visit(node.key, context) : '';
9953
+ const value = node.value ? this.JsonValueExpr(node.value, context) : '';
9954
+ return `${key} : ${value}`;
9955
+ }
9956
+ JsonObjectConstructor(node, context) {
9957
+ const args = [];
9958
+ if (node.exprs && node.exprs.length > 0) {
9959
+ args.push(list_utils_1.ListUtils.unwrapList(node.exprs).map(e => this.visit(e, context)).join(', '));
9960
+ args.push(this.formatJsonNullClause(node.absent_on_null));
9961
+ const unique = this.formatJsonUniqueClause(node.unique);
9962
+ if (unique)
9963
+ args.push(unique);
9964
+ }
9965
+ const output = this.formatJsonOutput(node.output, context);
9966
+ if (output)
9967
+ args.push(output);
9968
+ return `JSON_OBJECT(${args.join(' ')})`;
9969
+ }
9970
+ JsonArrayConstructor(node, context) {
9971
+ const args = [];
9972
+ if (node.exprs && node.exprs.length > 0) {
9973
+ args.push(list_utils_1.ListUtils.unwrapList(node.exprs).map(e => this.visit(e, context)).join(', '));
9974
+ args.push(this.formatJsonNullClause(node.absent_on_null));
9975
+ }
9976
+ const output = this.formatJsonOutput(node.output, context);
9977
+ if (output)
9978
+ args.push(output);
9979
+ return `JSON_ARRAY(${args.join(' ')})`;
9980
+ }
9840
9981
  JsonArrayQueryConstructor(node, context) {
9841
- const output = ['JSON_ARRAYAGG'];
9982
+ const args = [];
9842
9983
  if (node.query) {
9843
- output.push(`(${this.visit(node.query, context)})`);
9984
+ args.push(this.visit(node.query, context));
9985
+ }
9986
+ const format = this.formatJsonFormat(node.format);
9987
+ if (format)
9988
+ args.push(format);
9989
+ const output = this.formatJsonOutput(node.output, context);
9990
+ if (output)
9991
+ args.push(output);
9992
+ return `JSON_ARRAY(${args.join(' ')})`;
9993
+ }
9994
+ formatJsonAggSuffix(ctor, context) {
9995
+ if (!ctor)
9996
+ return '';
9997
+ let result = '';
9998
+ if (ctor.agg_filter) {
9999
+ result += ` FILTER (WHERE ${this.visit(ctor.agg_filter, context)})`;
9844
10000
  }
9845
- if (node.format) {
9846
- output.push('FORMAT JSON');
10001
+ if (ctor.over) {
10002
+ result += this.formatOverClause(ctor.over, context);
9847
10003
  }
9848
- if (node.output) {
9849
- output.push('RETURNING TEXT');
10004
+ return result;
10005
+ }
10006
+ JsonObjectAgg(node, context) {
10007
+ const args = [];
10008
+ if (node.arg) {
10009
+ args.push(this.JsonKeyValue(node.arg, context));
10010
+ }
10011
+ args.push(this.formatJsonNullClause(node.absent_on_null));
10012
+ const unique = this.formatJsonUniqueClause(node.unique);
10013
+ if (unique)
10014
+ args.push(unique);
10015
+ const output = this.formatJsonOutput(node.constructor?.output, context);
10016
+ if (output)
10017
+ args.push(output);
10018
+ return `JSON_OBJECTAGG(${args.join(' ')})${this.formatJsonAggSuffix(node.constructor, context)}`;
10019
+ }
10020
+ JsonArrayAgg(node, context) {
10021
+ const args = [];
10022
+ if (node.arg) {
10023
+ args.push(this.JsonValueExpr(node.arg, context));
9850
10024
  }
9851
- if (node.absent_on_null) {
9852
- output.push('ABSENT ON NULL');
10025
+ const aggOrder = node.constructor?.agg_order;
10026
+ if (aggOrder && aggOrder.length > 0) {
10027
+ const orderItems = list_utils_1.ListUtils.unwrapList(aggOrder).map(item => this.visit(item, context));
10028
+ args.push(`ORDER BY ${orderItems.join(', ')}`);
9853
10029
  }
9854
- else {
9855
- output.push('NULL ON NULL');
10030
+ args.push(this.formatJsonNullClause(node.absent_on_null));
10031
+ const output = this.formatJsonOutput(node.constructor?.output, context);
10032
+ if (output)
10033
+ args.push(output);
10034
+ return `JSON_ARRAYAGG(${args.join(' ')})${this.formatJsonAggSuffix(node.constructor, context)}`;
10035
+ }
10036
+ JsonParseExpr(node, context) {
10037
+ const args = [];
10038
+ if (node.expr) {
10039
+ args.push(this.JsonValueExpr(node.expr, context));
9856
10040
  }
9857
- return output.join(' ');
10041
+ const unique = this.formatJsonUniqueClause(node.unique_keys);
10042
+ if (unique)
10043
+ args.push(unique);
10044
+ return `JSON(${args.join(' ')})`;
10045
+ }
10046
+ JsonScalarExpr(node, context) {
10047
+ const expr = node.expr ? this.visit(node.expr, context) : '';
10048
+ return `JSON_SCALAR(${expr})`;
10049
+ }
10050
+ JsonSerializeExpr(node, context) {
10051
+ const args = [];
10052
+ if (node.expr) {
10053
+ args.push(this.JsonValueExpr(node.expr, context));
10054
+ }
10055
+ const output = this.formatJsonOutput(node.output, context);
10056
+ if (output)
10057
+ args.push(output);
10058
+ return `JSON_SERIALIZE(${args.join(' ')})`;
10059
+ }
10060
+ JsonIsPredicate(node, context) {
10061
+ const parts = [];
10062
+ if (node.expr) {
10063
+ parts.push(this.visit(node.expr, context));
10064
+ }
10065
+ const format = this.formatJsonFormat(node.format);
10066
+ if (format)
10067
+ parts.push(format);
10068
+ parts.push('IS JSON');
10069
+ switch (node.item_type) {
10070
+ case 'JS_TYPE_OBJECT':
10071
+ parts.push('OBJECT');
10072
+ break;
10073
+ case 'JS_TYPE_ARRAY':
10074
+ parts.push('ARRAY');
10075
+ break;
10076
+ case 'JS_TYPE_SCALAR':
10077
+ parts.push('SCALAR');
10078
+ break;
10079
+ }
10080
+ if (node.unique_keys) {
10081
+ parts.push('WITH UNIQUE KEYS');
10082
+ }
10083
+ return parts.join(' ');
9858
10084
  }
9859
10085
  RangeFunction(node, context) {
9860
10086
  const output = [];