pgsql-deparser 18.3.7 → 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':
@@ -2966,7 +3001,7 @@ class Deparser {
2966
3001
  break;
2967
3002
  }
2968
3003
  // Handle deferrable constraints for all constraint types that support it
2969
- 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') {
2970
3005
  if (node.deferrable) {
2971
3006
  if (context.isPretty() && node.contype === 'CONSTR_FOREIGN') {
2972
3007
  output.push('\n' + context.indent('DEFERRABLE'));
@@ -2995,6 +3030,9 @@ class Deparser {
2995
3030
  output.push('NOT DEFERRABLE');
2996
3031
  }
2997
3032
  }
3033
+ else if (node.initdeferred) {
3034
+ output.push('INITIALLY DEFERRED');
3035
+ }
2998
3036
  }
2999
3037
  if (context.isPretty() && node.contype === 'CONSTR_FOREIGN') {
3000
3038
  let result = '';
@@ -3060,6 +3098,9 @@ class Deparser {
3060
3098
  output.push(node.name);
3061
3099
  }
3062
3100
  const windowParts = [];
3101
+ if (node.refname) {
3102
+ windowParts.push(node.refname);
3103
+ }
3063
3104
  if (node.partitionClause) {
3064
3105
  const partitions = list_utils_1.ListUtils.unwrapList(node.partitionClause);
3065
3106
  const partitionStrs = partitions.map(p => this.visit(p, context));
@@ -3070,12 +3111,9 @@ class Deparser {
3070
3111
  const orderStrs = orders.map(o => this.visit(o, context));
3071
3112
  windowParts.push(`ORDER BY ${orderStrs.join(', ')}`);
3072
3113
  }
3073
- // Only add frame clause if frameOptions indicates non-default framing
3074
- if (node.frameOptions && node.frameOptions !== 1058) {
3075
- const frameClause = this.formatWindowFrame(node, context.spawn('WindowDef'));
3076
- if (frameClause) {
3077
- windowParts.push(frameClause);
3078
- }
3114
+ const frameClause = this.formatWindowFrame(node, context.spawn('WindowDef'));
3115
+ if (frameClause) {
3116
+ windowParts.push(frameClause);
3079
3117
  }
3080
3118
  if (windowParts.length > 0) {
3081
3119
  if (node.name) {
@@ -3092,114 +3130,96 @@ class Deparser {
3092
3130
  }
3093
3131
  return output.join(' ');
3094
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
+ }
3095
3160
  formatWindowFrame(node, context) {
3096
- if (!node.frameOptions)
3161
+ if (!node.frameOptions || !(node.frameOptions & FRAMEOPTION_NONDEFAULT))
3097
3162
  return null;
3098
3163
  const frameOptions = node.frameOptions;
3099
- const EXCLUDE_MASK = 0x8000 | 0x10000 | 0x20000;
3100
- const baseFrameOptions = frameOptions & ~EXCLUDE_MASK;
3101
3164
  const frameParts = [];
3102
- if (frameOptions & 0x01) { // FRAMEOPTION_NONDEFAULT
3103
- if (frameOptions & 0x02) { // FRAMEOPTION_RANGE
3104
- frameParts.push('RANGE');
3105
- }
3106
- else if (frameOptions & 0x04) { // FRAMEOPTION_ROWS
3107
- frameParts.push('ROWS');
3108
- }
3109
- else if (frameOptions & 0x08) { // FRAMEOPTION_GROUPS
3110
- frameParts.push('GROUPS');
3111
- }
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');
3112
3173
  }
3113
3174
  if (frameParts.length === 0)
3114
3175
  return null;
3115
- const boundsParts = [];
3116
- // Handle specific frameOptions values that have known mappings
3117
- if (baseFrameOptions === 789) {
3118
- boundsParts.push('CURRENT ROW');
3119
- boundsParts.push('AND UNBOUNDED FOLLOWING');
3176
+ let start = null;
3177
+ if (frameOptions & FRAMEOPTION_START_UNBOUNDED_PRECEDING) {
3178
+ start = 'UNBOUNDED PRECEDING';
3120
3179
  }
3121
- else if (baseFrameOptions === 1077) {
3122
- boundsParts.push('UNBOUNDED PRECEDING');
3123
- boundsParts.push('AND CURRENT ROW');
3180
+ else if (frameOptions & FRAMEOPTION_START_UNBOUNDED_FOLLOWING) {
3181
+ start = 'UNBOUNDED FOLLOWING';
3124
3182
  }
3125
- else if (baseFrameOptions === 18453) {
3126
- if (node.startOffset && node.endOffset) {
3127
- boundsParts.push(`${this.visit(node.startOffset, context)} PRECEDING`);
3128
- boundsParts.push(`AND ${this.visit(node.endOffset, context)} FOLLOWING`);
3129
- }
3183
+ else if (frameOptions & FRAMEOPTION_START_CURRENT_ROW) {
3184
+ start = 'CURRENT ROW';
3130
3185
  }
3131
- else if (baseFrameOptions === 1557) {
3132
- boundsParts.push('CURRENT ROW');
3133
- boundsParts.push('AND CURRENT ROW');
3186
+ else if (frameOptions & FRAMEOPTION_START_OFFSET_PRECEDING && node.startOffset) {
3187
+ start = `${this.visit(node.startOffset, context)} PRECEDING`;
3134
3188
  }
3135
- else if (baseFrameOptions === 16917) {
3136
- boundsParts.push('CURRENT ROW');
3137
- if (node.endOffset) {
3138
- boundsParts.push(`AND ${this.visit(node.endOffset, context)} FOLLOWING`);
3139
- }
3189
+ else if (frameOptions & FRAMEOPTION_START_OFFSET_FOLLOWING && node.startOffset) {
3190
+ start = `${this.visit(node.startOffset, context)} FOLLOWING`;
3140
3191
  }
3141
- else if (baseFrameOptions === 1058) {
3142
- return null;
3192
+ let end = null;
3193
+ if (frameOptions & FRAMEOPTION_END_UNBOUNDED_PRECEDING) {
3194
+ end = 'UNBOUNDED PRECEDING';
3143
3195
  }
3144
- else {
3145
- // Handle start bound - prioritize explicit offset values over bit flags
3146
- if (node.startOffset) {
3147
- if (frameOptions & 0x400) { // FRAMEOPTION_START_VALUE_PRECEDING
3148
- boundsParts.push(`${this.visit(node.startOffset, context)} PRECEDING`);
3149
- }
3150
- else if (frameOptions & 0x800) { // FRAMEOPTION_START_VALUE_FOLLOWING
3151
- boundsParts.push(`${this.visit(node.startOffset, context)} FOLLOWING`);
3152
- }
3153
- else {
3154
- boundsParts.push(`${this.visit(node.startOffset, context)} PRECEDING`);
3155
- }
3156
- }
3157
- else if (frameOptions & 0x10) { // FRAMEOPTION_START_UNBOUNDED_PRECEDING
3158
- boundsParts.push('UNBOUNDED PRECEDING');
3159
- }
3160
- else if (frameOptions & 0x20) { // FRAMEOPTION_START_CURRENT_ROW
3161
- boundsParts.push('CURRENT ROW');
3162
- }
3163
- // Handle end bound - prioritize explicit offset values over bit flags
3164
- if (node.endOffset) {
3165
- if (boundsParts.length > 0) {
3166
- if (frameOptions & 0x1000) { // FRAMEOPTION_END_VALUE_PRECEDING
3167
- boundsParts.push(`AND ${this.visit(node.endOffset, context)} PRECEDING`);
3168
- }
3169
- else if (frameOptions & 0x2000) { // FRAMEOPTION_END_VALUE_FOLLOWING
3170
- boundsParts.push(`AND ${this.visit(node.endOffset, context)} FOLLOWING`);
3171
- }
3172
- else {
3173
- boundsParts.push(`AND ${this.visit(node.endOffset, context)} FOLLOWING`);
3174
- }
3175
- }
3176
- }
3177
- else if (frameOptions & 0x80) { // FRAMEOPTION_END_UNBOUNDED_FOLLOWING
3178
- if (boundsParts.length > 0) {
3179
- boundsParts.push('AND UNBOUNDED FOLLOWING');
3180
- }
3181
- }
3182
- else if (frameOptions & 0x100) { // FRAMEOPTION_END_CURRENT_ROW
3183
- if (boundsParts.length > 0) {
3184
- boundsParts.push('AND CURRENT ROW');
3185
- }
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'}`);
3186
3211
  }
3187
- else if (boundsParts.length > 0) {
3188
- boundsParts.push('AND CURRENT ROW');
3212
+ else {
3213
+ frameParts.push(start);
3189
3214
  }
3190
3215
  }
3191
- if (boundsParts.length > 0) {
3192
- frameParts.push('BETWEEN');
3193
- frameParts.push(boundsParts.join(' '));
3194
- }
3195
- // EXCLUDE clause
3196
- if (frameOptions & 0x8000) { // FRAMEOPTION_EXCLUDE_CURRENT_ROW
3216
+ if (frameOptions & FRAMEOPTION_EXCLUDE_CURRENT_ROW) {
3197
3217
  frameParts.push('EXCLUDE CURRENT ROW');
3198
3218
  }
3199
- else if (frameOptions & 0x10000) { // FRAMEOPTION_EXCLUDE_GROUP
3219
+ else if (frameOptions & FRAMEOPTION_EXCLUDE_GROUP) {
3200
3220
  frameParts.push('EXCLUDE GROUP');
3201
3221
  }
3202
- else if (frameOptions & 0x20000) { // FRAMEOPTION_EXCLUDE_TIES
3222
+ else if (frameOptions & FRAMEOPTION_EXCLUDE_TIES) {
3203
3223
  frameParts.push('EXCLUDE TIES');
3204
3224
  }
3205
3225
  return frameParts.join(' ');
@@ -3278,8 +3298,35 @@ class Deparser {
3278
3298
  if (node.ctequery) {
3279
3299
  output.push(context.parens(this.visit(node.ctequery, context)));
3280
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
+ }
3281
3319
  return output.join(' ');
3282
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
+ }
3283
3330
  ParamRef(node, context) {
3284
3331
  return `$${node.number}`;
3285
3332
  }
@@ -3669,9 +3716,9 @@ class Deparser {
3669
3716
  output.push(`(${upperValues})`);
3670
3717
  }
3671
3718
  }
3672
- else if (node.bound.strategy === 'h' && node.bound.modulus !== undefined) {
3719
+ else if (node.bound.strategy === 'h') {
3673
3720
  output.push('FOR VALUES WITH');
3674
- output.push(`(MODULUS ${node.bound.modulus}, REMAINDER ${node.bound.remainder ?? 0})`);
3721
+ output.push(`(MODULUS ${node.bound.modulus ?? 0}, REMAINDER ${node.bound.remainder ?? 0})`);
3675
3722
  }
3676
3723
  else if (node.bound.is_default) {
3677
3724
  output.push('DEFAULT');
@@ -4524,10 +4571,10 @@ class Deparser {
4524
4571
  output.push('PROGRAM');
4525
4572
  }
4526
4573
  if (node.filename) {
4527
- output.push(`'${node.filename}'`);
4574
+ output.push(quotes_1.QuoteUtils.escape(node.filename));
4528
4575
  }
4529
4576
  else {
4530
- output.push('STDIN');
4577
+ output.push(node.is_from ? 'STDIN' : 'STDOUT');
4531
4578
  }
4532
4579
  if (node.options && node.options.length > 0) {
4533
4580
  output.push('WITH');
@@ -4759,6 +4806,9 @@ class Deparser {
4759
4806
  const nodeData = this.getNodeData(node.def);
4760
4807
  if (nodeData && nodeData.typeName) {
4761
4808
  output.push(this.TypeName(nodeData.typeName, context));
4809
+ if (nodeData.collClause) {
4810
+ output.push(this.CollateClause(nodeData.collClause, context));
4811
+ }
4762
4812
  // Handle USING clause (stored in raw_default for ALTER COLUMN TYPE)
4763
4813
  if (nodeData.raw_default) {
4764
4814
  output.push('USING');
@@ -5239,9 +5289,8 @@ class Deparser {
5239
5289
  if (node.name) {
5240
5290
  output.push(quotes_1.QuoteUtils.quoteIdentifier(node.name));
5241
5291
  }
5242
- output.push('SET');
5243
5292
  if (node.def) {
5244
- output.push(this.visit(node.def, context));
5293
+ output.push(this.formatIdentityColumnOptions(node.def, context));
5245
5294
  }
5246
5295
  break;
5247
5296
  case 'AT_DropIdentity':
@@ -5250,11 +5299,8 @@ class Deparser {
5250
5299
  output.push(quotes_1.QuoteUtils.quoteIdentifier(node.name));
5251
5300
  }
5252
5301
  output.push('DROP IDENTITY');
5253
- if (node.behavior === 'DROP_CASCADE') {
5254
- output.push('CASCADE');
5255
- }
5256
- else if (node.behavior === 'DROP_RESTRICT') {
5257
- output.push('RESTRICT');
5302
+ if (node.missing_ok) {
5303
+ output.push('IF EXISTS');
5258
5304
  }
5259
5305
  break;
5260
5306
  case 'AT_ReAddStatistics':
@@ -5690,6 +5736,9 @@ class Deparser {
5690
5736
  if (node.arg && this.getNodeType(node.arg) === 'List') {
5691
5737
  const listData = this.getNodeData(node.arg);
5692
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
+ }
5693
5742
  const parts = listItems.map(item => {
5694
5743
  const itemData = this.getNodeData(item);
5695
5744
  if (this.getNodeType(item) === 'String') {
@@ -5867,12 +5916,15 @@ class Deparser {
5867
5916
  }
5868
5917
  // Handle CreateStmt table options - no quotes, compact formatting
5869
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);
5870
5922
  // For numeric values, use the raw value without quotes
5871
5923
  if (node.arg && this.getNodeType(node.arg) === 'Integer') {
5872
5924
  const integerData = this.getNodeData(node.arg);
5873
- return `${node.defname}=${integerData.ival}`;
5925
+ return `${relOptName}=${integerData.ival}`;
5874
5926
  }
5875
- return `${node.defname}=${argValue}`;
5927
+ return `${relOptName}=${argValue}`;
5876
5928
  }
5877
5929
  // Handle CreateEventTrigStmt WHEN clause - use IN syntax for List arguments
5878
5930
  if (context.parentNodeTypes.includes('CreateEventTrigStmt')) {
@@ -5911,15 +5963,27 @@ class Deparser {
5911
5963
  }
5912
5964
  // Handle CopyStmt WITH clause options - uppercase format without quotes
5913
5965
  if (context.parentNodeTypes.includes('CopyStmt')) {
5914
- if (node.defname === 'format' && node.arg && this.getNodeType(node.arg) === 'String') {
5915
- const stringData = this.getNodeData(node.arg);
5916
- return `FORMAT ${stringData.sval.toUpperCase()}`;
5966
+ const optName = node.defname.toUpperCase();
5967
+ if (!node.arg) {
5968
+ return optName;
5969
+ }
5970
+ const copyArgType = this.getNodeType(node.arg);
5971
+ if (copyArgType === 'Boolean' && this.getNodeData(node.arg).boolval !== false) {
5972
+ return optName;
5973
+ }
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(', ')})`;
5917
5978
  }
5918
- // Handle other COPY options with uppercase defname
5919
- if (node.arg) {
5920
- return `${node.defname.toUpperCase()} ${argValue}`;
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)}`;
5921
5985
  }
5922
- return node.defname.toUpperCase();
5986
+ return `${optName} ${argValue}`;
5923
5987
  }
5924
5988
  // Handle CREATE OPERATOR and CREATE TYPE context
5925
5989
  if (context.parentNodeTypes.includes('DefineStmt')) {
@@ -6000,6 +6064,10 @@ class Deparser {
6000
6064
  return `${node.defname} = ${argValue}`;
6001
6065
  }
6002
6066
  }
6067
+ const argType = this.getNodeType(node.arg);
6068
+ if (argType === 'TypeName' || argType === 'Integer' || argType === 'Float' || argType === 'Boolean') {
6069
+ return `${node.defname} = ${argValue}`;
6070
+ }
6003
6071
  const quotedValue = typeof argValue === 'string'
6004
6072
  ? quotes_1.QuoteUtils.escape(argValue)
6005
6073
  : argValue;
@@ -6433,6 +6501,9 @@ class Deparser {
6433
6501
  case 'OBJECT_TABCONSTRAINT':
6434
6502
  output.push('CONSTRAINT');
6435
6503
  break;
6504
+ case 'OBJECT_DOMCONSTRAINT':
6505
+ output.push('CONSTRAINT');
6506
+ break;
6436
6507
  case 'OBJECT_TRIGGER':
6437
6508
  output.push('TRIGGER');
6438
6509
  break;
@@ -6509,6 +6580,15 @@ class Deparser {
6509
6580
  output.push(objectParts.join('.'));
6510
6581
  }
6511
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
+ }
6512
6592
  else if (node.objtype === 'OBJECT_TRIGGER') {
6513
6593
  if (objectParts.length === 2) {
6514
6594
  const [table, trigger] = objectParts;
@@ -6840,7 +6920,7 @@ class Deparser {
6840
6920
  output.push(quotes_1.QuoteUtils.quoteIdentifier(node.pubname));
6841
6921
  }
6842
6922
  if (node.pubobjects && node.pubobjects.length > 0) {
6843
- output.push('FOR', 'TABLE');
6923
+ output.push('FOR');
6844
6924
  const tables = list_utils_1.ListUtils.unwrapList(node.pubobjects).map(table => this.visit(table, context));
6845
6925
  output.push(tables.join(', '));
6846
6926
  }
@@ -6880,8 +6960,9 @@ class Deparser {
6880
6960
  if (node.pubname) {
6881
6961
  output.push(quotes_1.QuoteUtils.quoteIdentifier(node.pubname));
6882
6962
  }
6883
- if (node.action) {
6884
- switch (node.action) {
6963
+ const hasObjects = node.pubobjects && node.pubobjects.length > 0;
6964
+ if (hasObjects) {
6965
+ switch (node.action || 'AP_AddObjects') {
6885
6966
  case 'AP_AddObjects':
6886
6967
  output.push('ADD');
6887
6968
  break;
@@ -6894,17 +6975,11 @@ class Deparser {
6894
6975
  default:
6895
6976
  throw new Error(`Unsupported AlterPublicationStmt action: ${node.action}`);
6896
6977
  }
6897
- }
6898
- if (node.for_all_tables) {
6899
- output.push('FOR ALL TABLES');
6900
- }
6901
- else if (node.pubobjects && node.pubobjects.length > 0) {
6902
- output.push('FOR TABLE');
6903
6978
  const objects = list_utils_1.ListUtils.unwrapList(node.pubobjects).map(obj => this.visit(obj, context));
6904
6979
  output.push(objects.join(', '));
6905
6980
  }
6906
- if (node.options && node.options.length > 0) {
6907
- output.push('WITH');
6981
+ else if (node.options && node.options.length > 0) {
6982
+ output.push('SET');
6908
6983
  const options = list_utils_1.ListUtils.unwrapList(node.options).map(opt => this.visit(opt, context));
6909
6984
  output.push(`(${options.join(', ')})`);
6910
6985
  }
@@ -6915,42 +6990,67 @@ class Deparser {
6915
6990
  if (node.subname) {
6916
6991
  output.push(quotes_1.QuoteUtils.quoteIdentifier(node.subname));
6917
6992
  }
6918
- if (node.kind) {
6919
- 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') {
6920
7001
  case 'ALTER_SUBSCRIPTION_OPTIONS':
6921
7002
  output.push('SET');
7003
+ if (options)
7004
+ output.push(options);
6922
7005
  break;
6923
7006
  case 'ALTER_SUBSCRIPTION_CONNECTION':
6924
7007
  output.push('CONNECTION');
6925
7008
  if (node.conninfo) {
6926
- output.push(`'${node.conninfo}'`);
7009
+ output.push(quotes_1.QuoteUtils.escape(node.conninfo));
6927
7010
  }
6928
7011
  break;
6929
7012
  case 'ALTER_SUBSCRIPTION_SET_PUBLICATION':
6930
7013
  output.push('SET PUBLICATION');
6931
- if (node.publication && node.publication.length > 0) {
6932
- const publications = list_utils_1.ListUtils.unwrapList(node.publication).map(pub => this.visit(pub, context));
6933
- output.push(publications.join(', '));
6934
- }
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);
6935
7032
  break;
6936
7033
  case 'ALTER_SUBSCRIPTION_REFRESH':
6937
7034
  output.push('REFRESH PUBLICATION');
7035
+ if (options)
7036
+ output.push('WITH', options);
6938
7037
  break;
6939
- case 'ALTER_SUBSCRIPTION_ENABLED':
6940
- 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');
6941
7043
  break;
7044
+ }
6942
7045
  case 'ALTER_SUBSCRIPTION_SKIP':
6943
7046
  output.push('SKIP');
7047
+ if (options)
7048
+ output.push(options);
6944
7049
  break;
6945
7050
  default:
6946
7051
  throw new Error(`Unsupported AlterSubscriptionStmt kind: ${node.kind}`);
6947
7052
  }
6948
7053
  }
6949
- if (node.options && node.options.length > 0) {
6950
- output.push('WITH');
6951
- const options = list_utils_1.ListUtils.unwrapList(node.options).map(opt => this.visit(opt, context));
6952
- output.push(`(${options.join(', ')})`);
6953
- }
6954
7054
  return output.join(' ');
6955
7055
  }
6956
7056
  DropSubscriptionStmt(node, context) {
@@ -8016,6 +8116,9 @@ class Deparser {
8016
8116
  if (node.grant_option && node.is_grant) {
8017
8117
  output.push('WITH GRANT OPTION');
8018
8118
  }
8119
+ if (node.grantor) {
8120
+ output.push('GRANTED BY', this.RoleSpec(node.grantor, context));
8121
+ }
8019
8122
  // Only add behavior clauses for REVOKE statements, not for GRANT statements in ALTER DEFAULT PRIVILEGES
8020
8123
  if (!node.is_grant) {
8021
8124
  if (node.behavior === 'DROP_CASCADE') {
@@ -8029,57 +8132,34 @@ class Deparser {
8029
8132
  }
8030
8133
  GrantRoleStmt(node, context) {
8031
8134
  const output = [];
8032
- // Check for inherit, admin, and set options first to place them correctly
8033
- let hasInheritOption = false;
8034
- let hasAdminOption = false;
8035
- let hasSetOption = false;
8036
- let inheritValue;
8037
- let adminValue;
8038
- let setValue;
8039
- if (node.opt && node.opt.length > 0) {
8040
- const options = list_utils_1.ListUtils.unwrapList(node.opt);
8041
- const inheritOption = options.find(opt => opt.DefElem && opt.DefElem.defname === 'inherit');
8042
- const adminOption = options.find(opt => (opt.String && opt.String.sval === 'admin') ||
8043
- (opt.DefElem && opt.DefElem.defname === 'admin'));
8044
- const setOption = options.find(opt => opt.DefElem && opt.DefElem.defname === 'set');
8045
- if (inheritOption && inheritOption.DefElem) {
8046
- hasInheritOption = true;
8047
- inheritValue = inheritOption.DefElem.arg?.Boolean?.boolval;
8048
- }
8049
- if (adminOption) {
8050
- hasAdminOption = true;
8051
- if (adminOption.DefElem && adminOption.DefElem.arg) {
8052
- adminValue = adminOption.DefElem.arg.Boolean?.boolval;
8053
- }
8054
- }
8055
- if (setOption && setOption.DefElem) {
8056
- hasSetOption = true;
8057
- setValue = setOption.DefElem.arg?.Boolean?.boolval;
8058
- }
8059
- }
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(', ');
8060
8154
  if (node.is_grant) {
8061
- output.push('GRANT');
8155
+ output.push('GRANT', roles, 'TO');
8062
8156
  }
8063
8157
  else {
8064
8158
  output.push('REVOKE');
8065
- if (hasInheritOption) {
8066
- output.push('INHERIT OPTION FOR');
8067
- }
8068
- else if (hasAdminOption) {
8069
- output.push('ADMIN OPTION FOR');
8159
+ if (options.length > 0) {
8160
+ output.push(`${options[0].defname.toUpperCase()} OPTION FOR`);
8070
8161
  }
8071
- }
8072
- if (node.granted_roles && node.granted_roles.length > 0) {
8073
- const roles = list_utils_1.ListUtils.unwrapList(node.granted_roles)
8074
- .map(role => this.visit(role, context))
8075
- .join(', ');
8076
- output.push(roles);
8077
- }
8078
- if (node.is_grant) {
8079
- output.push('TO');
8080
- }
8081
- else {
8082
- output.push('FROM');
8162
+ output.push(roles, 'FROM');
8083
8163
  }
8084
8164
  if (node.grantee_roles && node.grantee_roles.length > 0) {
8085
8165
  const grantees = list_utils_1.ListUtils.unwrapList(node.grantee_roles)
@@ -8087,38 +8167,15 @@ class Deparser {
8087
8167
  .join(', ');
8088
8168
  output.push(grantees);
8089
8169
  }
8090
- if (node.is_grant) {
8091
- const withOptions = [];
8092
- if (hasAdminOption) {
8093
- if (adminValue === true) {
8094
- withOptions.push('ADMIN OPTION');
8095
- }
8096
- else if (adminValue === false) {
8097
- withOptions.push('ADMIN FALSE');
8098
- }
8099
- else {
8100
- withOptions.push('ADMIN OPTION');
8101
- }
8102
- }
8103
- if (hasInheritOption) {
8104
- if (inheritValue === true) {
8105
- withOptions.push('INHERIT OPTION');
8106
- }
8107
- else if (inheritValue === false) {
8108
- withOptions.push('INHERIT FALSE');
8109
- }
8110
- }
8111
- if (hasSetOption) {
8112
- if (setValue === true) {
8113
- withOptions.push('SET TRUE');
8114
- }
8115
- else if (setValue === false) {
8116
- withOptions.push('SET FALSE');
8117
- }
8118
- }
8119
- if (withOptions.length > 0) {
8120
- output.push('WITH', withOptions.join(', '));
8121
- }
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');
8122
8179
  }
8123
8180
  return output.join(' ');
8124
8181
  }
@@ -8698,10 +8755,9 @@ class Deparser {
8698
8755
  switch (node.commandType) {
8699
8756
  case 'CMD_UPDATE': {
8700
8757
  output.push('UPDATE SET');
8701
- const assignments = list_utils_1.ListUtils.unwrapList(node.targetList)
8702
- .map(target => this.visit(target, context.spawn('UpdateStmt', { update: true })))
8703
- .join(', ');
8704
- output.push(assignments);
8758
+ if (node.targetList && node.targetList.length > 0) {
8759
+ output.push(this.formatUpdateAssignments(node.targetList, context));
8760
+ }
8705
8761
  break;
8706
8762
  }
8707
8763
  case 'CMD_INSERT': {
@@ -9106,6 +9162,13 @@ class Deparser {
9106
9162
  output.push('USING');
9107
9163
  output.push(node.into.accessMethod);
9108
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
+ }
9109
9172
  if (node.into && node.into.onCommit && node.into.onCommit !== 'ONCOMMIT_NOOP') {
9110
9173
  output.push('ON COMMIT');
9111
9174
  switch (node.into.onCommit) {
@@ -9120,17 +9183,13 @@ class Deparser {
9120
9183
  break;
9121
9184
  }
9122
9185
  }
9186
+ if (node.into && node.into.tableSpaceName) {
9187
+ output.push('TABLESPACE', quotes_1.QuoteUtils.quoteIdentifier(node.into.tableSpaceName));
9188
+ }
9123
9189
  output.push('AS');
9124
9190
  if (node.query) {
9125
9191
  output.push(this.visit(node.query, context));
9126
9192
  }
9127
- if (node.into && node.into.options && node.into.options.length > 0) {
9128
- output.push('WITH');
9129
- const options = list_utils_1.ListUtils.unwrapList(node.into.options)
9130
- .map(option => this.visit(option, context))
9131
- .join(', ');
9132
- output.push(`(${options})`);
9133
- }
9134
9193
  if (node.into && node.into.skipData) {
9135
9194
  output.push('WITH NO DATA');
9136
9195
  }
@@ -9603,7 +9662,7 @@ class Deparser {
9603
9662
  }
9604
9663
  if (node.whereClause) {
9605
9664
  output.push('WHERE');
9606
- output.push(this.visit(node.whereClause, context));
9665
+ output.push(`(${this.visit(node.whereClause, context)})`);
9607
9666
  }
9608
9667
  return output.join(' ');
9609
9668
  }
@@ -9846,24 +9905,182 @@ class Deparser {
9846
9905
  }
9847
9906
  return output.join(' ');
9848
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
+ }
9849
9981
  JsonArrayQueryConstructor(node, context) {
9850
- const output = ['JSON_ARRAYAGG'];
9982
+ const args = [];
9851
9983
  if (node.query) {
9852
- 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)})`;
9853
10000
  }
9854
- if (node.format) {
9855
- output.push('FORMAT JSON');
10001
+ if (ctor.over) {
10002
+ result += this.formatOverClause(ctor.over, context);
9856
10003
  }
9857
- if (node.output) {
9858
- 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));
9859
10024
  }
9860
- if (node.absent_on_null) {
9861
- 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(', ')}`);
9862
10029
  }
9863
- else {
9864
- 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));
9865
10040
  }
9866
- 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(' ');
9867
10084
  }
9868
10085
  RangeFunction(node, context) {
9869
10086
  const output = [];