pgsql-deparser 18.3.9 → 18.3.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -6
- package/deparser.d.ts +3 -0
- package/deparser.js +103 -65
- package/esm/deparser.js +103 -65
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -69,27 +69,29 @@ console.log(deparse(stmt));
|
|
|
69
69
|
// Output: SELECT * FROM another_table
|
|
70
70
|
```
|
|
71
71
|
|
|
72
|
-
### Latest Version (PostgreSQL
|
|
72
|
+
### Latest Version (PostgreSQL 18)
|
|
73
73
|
|
|
74
74
|
```sh
|
|
75
75
|
npm install pgsql-deparser
|
|
76
76
|
```
|
|
77
77
|
|
|
78
|
-
### Version-Specific Packages (PostgreSQL 13-
|
|
78
|
+
### Version-Specific Packages (PostgreSQL 13-17)
|
|
79
79
|
|
|
80
|
-
|
|
80
|
+
We recommend PG18. PG17 remains fully supported; for PostgreSQL versions 13-17, use the version-specific packages:
|
|
81
81
|
|
|
82
82
|
```sh
|
|
83
83
|
npm install pgsql-deparser@pg13 # PostgreSQL 13
|
|
84
84
|
npm install pgsql-deparser@pg14 # PostgreSQL 14
|
|
85
85
|
npm install pgsql-deparser@pg15 # PostgreSQL 15
|
|
86
86
|
npm install pgsql-deparser@pg16 # PostgreSQL 16
|
|
87
|
+
npm install pgsql-deparser@pg17 # PostgreSQL 17
|
|
87
88
|
```
|
|
88
89
|
|
|
89
90
|
**Version Status:**
|
|
90
|
-
- **
|
|
91
|
-
- **
|
|
92
|
-
- **
|
|
91
|
+
- **PG18**: 🚀 Recommended (stable + modern AST)
|
|
92
|
+
- **PG17**: Stable (modern AST)
|
|
93
|
+
- **PG14-16**: Legacy (modern AST, not actively developed)
|
|
94
|
+
- **PG13**: Legacy (legacy AST format)
|
|
93
95
|
|
|
94
96
|
## Options
|
|
95
97
|
|
package/deparser.d.ts
CHANGED
|
@@ -260,9 +260,12 @@ export declare class Deparser implements DeparserVisitor {
|
|
|
260
260
|
OnConflictExpr(node: t.OnConflictExpr, context: DeparserContext): string;
|
|
261
261
|
ScanToken(node: t.ScanToken, context: DeparserContext): string;
|
|
262
262
|
CreateOpClassItem(node: t.CreateOpClassItem, context: DeparserContext): string;
|
|
263
|
+
private quoteDefElemArg;
|
|
264
|
+
private formatOptionValue;
|
|
263
265
|
Var(node: t.Var, context: DeparserContext): string;
|
|
264
266
|
TableFunc(node: t.TableFunc, context: DeparserContext): string;
|
|
265
267
|
RangeTableFunc(node: t.RangeTableFunc, context: DeparserContext): string;
|
|
268
|
+
private formatXmlTableExpr;
|
|
266
269
|
RangeTableFuncCol(node: t.RangeTableFuncCol, context: DeparserContext): string;
|
|
267
270
|
formatJsonFormat(format: t.JsonFormat | undefined): string | null;
|
|
268
271
|
formatJsonOutput(output: t.JsonOutput | undefined, context: DeparserContext): string | null;
|
package/deparser.js
CHANGED
|
@@ -132,6 +132,21 @@ function formatBitString(bsval) {
|
|
|
132
132
|
}
|
|
133
133
|
return `b'${quote(bsval)}'`;
|
|
134
134
|
}
|
|
135
|
+
const NUMERIC_LITERAL = /^[+-]?(?:0[xX](?:_?[0-9A-Fa-f])+|0[oO](?:_?[0-7])+|0[bB](?:_?[01])+|(?:\d(?:_?\d)*(?:\.(?:\d(?:_?\d)*)?)?|\.\d(?:_?\d)*)(?:[eE][+-]?\d(?:_?\d)*)?)$/;
|
|
136
|
+
function formatInteger(ival) {
|
|
137
|
+
const value = String(ival);
|
|
138
|
+
if (!/^[+-]?\d+$/.test(value)) {
|
|
139
|
+
throw new Error(`Invalid integer literal: ${value}`);
|
|
140
|
+
}
|
|
141
|
+
return value;
|
|
142
|
+
}
|
|
143
|
+
function formatNumeric(fval) {
|
|
144
|
+
const value = String(fval);
|
|
145
|
+
if (!NUMERIC_LITERAL.test(value)) {
|
|
146
|
+
throw new Error(`Invalid numeric literal: ${value}`);
|
|
147
|
+
}
|
|
148
|
+
return value;
|
|
149
|
+
}
|
|
135
150
|
class Deparser {
|
|
136
151
|
tree;
|
|
137
152
|
options;
|
|
@@ -1600,39 +1615,39 @@ class Deparser {
|
|
|
1600
1615
|
if (nodeAny.ival !== undefined) {
|
|
1601
1616
|
if (typeof nodeAny.ival === 'object' && nodeAny.ival !== null) {
|
|
1602
1617
|
if (nodeAny.ival.ival !== undefined) {
|
|
1603
|
-
return nodeAny.ival.ival
|
|
1618
|
+
return formatInteger(nodeAny.ival.ival);
|
|
1604
1619
|
}
|
|
1605
1620
|
else if (Object.keys(nodeAny.ival).length === 0) {
|
|
1606
1621
|
return '0';
|
|
1607
1622
|
}
|
|
1608
1623
|
else {
|
|
1609
|
-
return nodeAny.ival
|
|
1624
|
+
return formatInteger(nodeAny.ival);
|
|
1610
1625
|
}
|
|
1611
1626
|
}
|
|
1612
1627
|
else if (nodeAny.ival === null) {
|
|
1613
1628
|
return 'NULL';
|
|
1614
1629
|
}
|
|
1615
1630
|
else {
|
|
1616
|
-
return nodeAny.ival
|
|
1631
|
+
return formatInteger(nodeAny.ival);
|
|
1617
1632
|
}
|
|
1618
1633
|
}
|
|
1619
1634
|
else if (nodeAny.fval !== undefined) {
|
|
1620
1635
|
if (typeof nodeAny.fval === 'object' && nodeAny.fval !== null) {
|
|
1621
1636
|
if (nodeAny.fval.fval !== undefined) {
|
|
1622
|
-
return nodeAny.fval.fval
|
|
1637
|
+
return formatNumeric(nodeAny.fval.fval);
|
|
1623
1638
|
}
|
|
1624
1639
|
else if (Object.keys(nodeAny.fval).length === 0) {
|
|
1625
1640
|
return '0.0';
|
|
1626
1641
|
}
|
|
1627
1642
|
else {
|
|
1628
|
-
return nodeAny.fval
|
|
1643
|
+
return formatNumeric(nodeAny.fval);
|
|
1629
1644
|
}
|
|
1630
1645
|
}
|
|
1631
1646
|
else if (nodeAny.fval === null) {
|
|
1632
1647
|
return 'NULL';
|
|
1633
1648
|
}
|
|
1634
1649
|
else {
|
|
1635
|
-
return nodeAny.fval
|
|
1650
|
+
return formatNumeric(nodeAny.fval);
|
|
1636
1651
|
}
|
|
1637
1652
|
}
|
|
1638
1653
|
else if (nodeAny.sval !== undefined) {
|
|
@@ -1697,10 +1712,10 @@ class Deparser {
|
|
|
1697
1712
|
}
|
|
1698
1713
|
if (nodeAny.val) {
|
|
1699
1714
|
if (nodeAny.val.Integer?.ival !== undefined) {
|
|
1700
|
-
return nodeAny.val.Integer.ival
|
|
1715
|
+
return formatInteger(nodeAny.val.Integer.ival);
|
|
1701
1716
|
}
|
|
1702
1717
|
else if (nodeAny.val.Float?.fval !== undefined) {
|
|
1703
|
-
return nodeAny.val.Float.fval
|
|
1718
|
+
return formatNumeric(nodeAny.val.Float.fval);
|
|
1704
1719
|
}
|
|
1705
1720
|
else if (nodeAny.val.String?.sval !== undefined) {
|
|
1706
1721
|
return quotes_1.QuoteUtils.escape(nodeAny.val.String.sval);
|
|
@@ -1721,15 +1736,15 @@ class Deparser {
|
|
|
1721
1736
|
}
|
|
1722
1737
|
if (nodeAny.Integer !== undefined) {
|
|
1723
1738
|
if (typeof nodeAny.Integer === 'object' && nodeAny.Integer.ival !== undefined) {
|
|
1724
|
-
return nodeAny.Integer.ival
|
|
1739
|
+
return formatInteger(nodeAny.Integer.ival);
|
|
1725
1740
|
}
|
|
1726
|
-
return nodeAny.Integer
|
|
1741
|
+
return formatInteger(nodeAny.Integer);
|
|
1727
1742
|
}
|
|
1728
1743
|
if (nodeAny.Float !== undefined) {
|
|
1729
1744
|
if (typeof nodeAny.Float === 'object' && nodeAny.Float.fval !== undefined) {
|
|
1730
|
-
return nodeAny.Float.fval
|
|
1745
|
+
return formatNumeric(nodeAny.Float.fval);
|
|
1731
1746
|
}
|
|
1732
|
-
return nodeAny.Float
|
|
1747
|
+
return formatNumeric(nodeAny.Float);
|
|
1733
1748
|
}
|
|
1734
1749
|
if (nodeAny.String !== undefined) {
|
|
1735
1750
|
if (typeof nodeAny.String === 'object' && nodeAny.String.sval !== undefined) {
|
|
@@ -2380,10 +2395,10 @@ class Deparser {
|
|
|
2380
2395
|
return quotes_1.QuoteUtils.quoteIdentifier(value);
|
|
2381
2396
|
}
|
|
2382
2397
|
Integer(node, context) {
|
|
2383
|
-
return node.ival
|
|
2398
|
+
return node.ival === undefined || node.ival === null ? '0' : formatInteger(node.ival);
|
|
2384
2399
|
}
|
|
2385
2400
|
Float(node, context) {
|
|
2386
|
-
return node.fval
|
|
2401
|
+
return node.fval ? formatNumeric(node.fval) : '0.0';
|
|
2387
2402
|
}
|
|
2388
2403
|
Boolean(node, context) {
|
|
2389
2404
|
return node.boolval ? 'true' : 'false';
|
|
@@ -3621,7 +3636,7 @@ class Deparser {
|
|
|
3621
3636
|
const opclassOpts = list_utils_1.ListUtils.unwrapList(node.opclassopts).map(opt => {
|
|
3622
3637
|
if (opt.DefElem && opt.DefElem.arg && this.getNodeType(opt.DefElem.arg) === 'String') {
|
|
3623
3638
|
const stringData = this.getNodeData(opt.DefElem.arg);
|
|
3624
|
-
return `${opt.DefElem.defname}
|
|
3639
|
+
return `${quotes_1.QuoteUtils.quoteIdentifierAfterDot(opt.DefElem.defname)}=${quotes_1.QuoteUtils.escape(stringData.sval)}`;
|
|
3625
3640
|
}
|
|
3626
3641
|
return this.visit(opt, context.spawn('IndexElem'));
|
|
3627
3642
|
});
|
|
@@ -3922,19 +3937,19 @@ class Deparser {
|
|
|
3922
3937
|
case 'TRANS_STMT_PREPARE':
|
|
3923
3938
|
output.push('PREPARE TRANSACTION');
|
|
3924
3939
|
if (node.gid) {
|
|
3925
|
-
output.push(
|
|
3940
|
+
output.push(quotes_1.QuoteUtils.escape(node.gid));
|
|
3926
3941
|
}
|
|
3927
3942
|
break;
|
|
3928
3943
|
case 'TRANS_STMT_COMMIT_PREPARED':
|
|
3929
3944
|
output.push('COMMIT PREPARED');
|
|
3930
3945
|
if (node.gid) {
|
|
3931
|
-
output.push(
|
|
3946
|
+
output.push(quotes_1.QuoteUtils.escape(node.gid));
|
|
3932
3947
|
}
|
|
3933
3948
|
break;
|
|
3934
3949
|
case 'TRANS_STMT_ROLLBACK_PREPARED':
|
|
3935
3950
|
output.push('ROLLBACK PREPARED');
|
|
3936
3951
|
if (node.gid) {
|
|
3937
|
-
output.push(
|
|
3952
|
+
output.push(quotes_1.QuoteUtils.escape(node.gid));
|
|
3938
3953
|
}
|
|
3939
3954
|
break;
|
|
3940
3955
|
default:
|
|
@@ -4010,8 +4025,8 @@ class Deparser {
|
|
|
4010
4025
|
const nodeData = this.getNodeData(arg);
|
|
4011
4026
|
if (nodeData.sval !== undefined) {
|
|
4012
4027
|
const svalValue = typeof nodeData.sval === 'object' ? nodeData.sval.sval : nodeData.sval;
|
|
4013
|
-
if (svalValue
|
|
4014
|
-
return
|
|
4028
|
+
if (!/^[a-z_][a-z0-9_]*$/.test(svalValue) || svalValue.includes(' ') || svalValue.includes('-') || /[A-Z]/.test(svalValue) || /^\d/.test(svalValue) || svalValue.includes('.') || svalValue.includes('$') || svalValue.toLowerCase() === 'all' || /^[+-]\d/.test(svalValue)) {
|
|
4029
|
+
return quotes_1.QuoteUtils.escape(svalValue);
|
|
4015
4030
|
}
|
|
4016
4031
|
return svalValue;
|
|
4017
4032
|
}
|
|
@@ -5538,9 +5553,9 @@ class Deparser {
|
|
|
5538
5553
|
if (context.parentNodeTypes.includes('IndexElem')) {
|
|
5539
5554
|
if (node.arg && this.getNodeType(node.arg) === 'String') {
|
|
5540
5555
|
const stringData = this.getNodeData(node.arg);
|
|
5541
|
-
return `${node.defname}
|
|
5556
|
+
return `${quotes_1.QuoteUtils.quoteIdentifierAfterDot(node.defname)}=${quotes_1.QuoteUtils.escape(stringData.sval)}`;
|
|
5542
5557
|
}
|
|
5543
|
-
return `${node.defname}=${this.visit(node.arg, context.spawn('DefElem'))}`;
|
|
5558
|
+
return `${quotes_1.QuoteUtils.quoteIdentifierAfterDot(node.defname)}=${this.formatOptionValue(node.arg, this.visit(node.arg, context.spawn('DefElem')))}`;
|
|
5544
5559
|
}
|
|
5545
5560
|
// Handle CREATE OPERATOR boolean flags - MUST be first to preserve case
|
|
5546
5561
|
if (context.parentNodeTypes.includes('DefineStmt') &&
|
|
@@ -5565,9 +5580,7 @@ class Deparser {
|
|
|
5565
5580
|
const defElemContext = context.spawn('DefElem');
|
|
5566
5581
|
const argValue = this.visit(node.arg, defElemContext);
|
|
5567
5582
|
if (context.parentNodeTypes.includes('CreateFdwStmt') || context.parentNodeTypes.includes('AlterFdwStmt')) {
|
|
5568
|
-
const finalValue =
|
|
5569
|
-
? `'${argValue}'`
|
|
5570
|
-
: argValue;
|
|
5583
|
+
const finalValue = this.quoteDefElemArg(node.arg, argValue);
|
|
5571
5584
|
const quotedDefname = quotes_1.QuoteUtils.quoteIdentifier(node.defname);
|
|
5572
5585
|
if (node.defaction === 'DEFELEM_ADD') {
|
|
5573
5586
|
return `ADD ${quotedDefname} ${finalValue}`;
|
|
@@ -5580,9 +5593,7 @@ class Deparser {
|
|
|
5580
5593
|
}
|
|
5581
5594
|
return `${quotedDefname} ${finalValue}`;
|
|
5582
5595
|
}
|
|
5583
|
-
const quotedValue =
|
|
5584
|
-
? `'${argValue}'`
|
|
5585
|
-
: argValue;
|
|
5596
|
+
const quotedValue = this.quoteDefElemArg(node.arg, argValue);
|
|
5586
5597
|
if (node.defaction === 'DEFELEM_ADD') {
|
|
5587
5598
|
return `ADD ${node.defname} ${quotedValue}`;
|
|
5588
5599
|
}
|
|
@@ -5614,9 +5625,7 @@ class Deparser {
|
|
|
5614
5625
|
}
|
|
5615
5626
|
const defElemContext = context.spawn('DefElem');
|
|
5616
5627
|
const argValue = this.visit(node.arg, defElemContext);
|
|
5617
|
-
const quotedValue =
|
|
5618
|
-
? `'${argValue}'`
|
|
5619
|
-
: argValue;
|
|
5628
|
+
const quotedValue = this.quoteDefElemArg(node.arg, argValue);
|
|
5620
5629
|
return `PASSWORD ${quotedValue}`;
|
|
5621
5630
|
}
|
|
5622
5631
|
}
|
|
@@ -5681,9 +5690,7 @@ class Deparser {
|
|
|
5681
5690
|
}
|
|
5682
5691
|
}
|
|
5683
5692
|
if (node.defname === 'validUntil') {
|
|
5684
|
-
const quotedValue =
|
|
5685
|
-
? `'${argValue}'`
|
|
5686
|
-
: argValue;
|
|
5693
|
+
const quotedValue = this.quoteDefElemArg(node.arg, argValue);
|
|
5687
5694
|
return `VALID UNTIL ${quotedValue}`;
|
|
5688
5695
|
}
|
|
5689
5696
|
if (node.defname === 'adminmembers') {
|
|
@@ -5863,9 +5870,7 @@ class Deparser {
|
|
|
5863
5870
|
if (context.parentNodeTypes.includes('AlterExtensionStmt')) {
|
|
5864
5871
|
if (node.defname === 'new_version') {
|
|
5865
5872
|
// argValue is unquoted due to DefElem context, so we need to quote it
|
|
5866
|
-
const quotedValue =
|
|
5867
|
-
? `'${argValue}'`
|
|
5868
|
-
: argValue;
|
|
5873
|
+
const quotedValue = this.quoteDefElemArg(node.arg, argValue);
|
|
5869
5874
|
return `UPDATE TO ${quotedValue}`;
|
|
5870
5875
|
}
|
|
5871
5876
|
if (node.defname === 'schema') {
|
|
@@ -5890,15 +5895,15 @@ class Deparser {
|
|
|
5890
5895
|
}
|
|
5891
5896
|
// Handle IndexStmt WITH clause options - no quotes, compact formatting
|
|
5892
5897
|
if (context.parentNodeTypes.includes('IndexStmt')) {
|
|
5893
|
-
return `${node.defname}=${argValue}`;
|
|
5898
|
+
return `${quotes_1.QuoteUtils.quoteIdentifierAfterDot(node.defname)}=${this.formatOptionValue(node.arg, argValue)}`;
|
|
5894
5899
|
}
|
|
5895
5900
|
// Handle IndexElem opclassopts - preserve string values as strings
|
|
5896
5901
|
if (context.parentNodeTypes.includes('IndexElem')) {
|
|
5897
5902
|
if (node.arg && this.getNodeType(node.arg) === 'String') {
|
|
5898
5903
|
const stringData = this.getNodeData(node.arg);
|
|
5899
|
-
return `${node.defname}
|
|
5904
|
+
return `${quotes_1.QuoteUtils.quoteIdentifierAfterDot(node.defname)}=${quotes_1.QuoteUtils.escape(stringData.sval)}`;
|
|
5900
5905
|
}
|
|
5901
|
-
return `${node.defname}=${argValue}`;
|
|
5906
|
+
return `${quotes_1.QuoteUtils.quoteIdentifierAfterDot(node.defname)}=${this.formatOptionValue(node.arg, argValue)}`;
|
|
5902
5907
|
}
|
|
5903
5908
|
// Handle CreateStmt table options - no quotes, compact formatting
|
|
5904
5909
|
if (context.parentNodeTypes.includes('CreateStmt')) {
|
|
@@ -5908,9 +5913,9 @@ class Deparser {
|
|
|
5908
5913
|
// For numeric values, use the raw value without quotes
|
|
5909
5914
|
if (node.arg && this.getNodeType(node.arg) === 'Integer') {
|
|
5910
5915
|
const integerData = this.getNodeData(node.arg);
|
|
5911
|
-
return `${relOptName}=${integerData.ival}`;
|
|
5916
|
+
return `${relOptName}=${formatInteger(integerData.ival)}`;
|
|
5912
5917
|
}
|
|
5913
|
-
return `${relOptName}=${argValue}`;
|
|
5918
|
+
return `${relOptName}=${this.formatOptionValue(node.arg, argValue)}`;
|
|
5914
5919
|
}
|
|
5915
5920
|
// Handle CreateEventTrigStmt WHEN clause - use IN syntax for List arguments
|
|
5916
5921
|
if (context.parentNodeTypes.includes('CreateEventTrigStmt')) {
|
|
@@ -5920,7 +5925,7 @@ class Deparser {
|
|
|
5920
5925
|
const values = listItems.map(item => {
|
|
5921
5926
|
if (this.getNodeType(item) === 'String') {
|
|
5922
5927
|
const stringData = this.getNodeData(item);
|
|
5923
|
-
return
|
|
5928
|
+
return quotes_1.QuoteUtils.escape(stringData.sval || '');
|
|
5924
5929
|
}
|
|
5925
5930
|
return this.visit(item, context);
|
|
5926
5931
|
});
|
|
@@ -5935,7 +5940,7 @@ class Deparser {
|
|
|
5935
5940
|
if (node.arg && this.getNodeType(node.arg) === 'TypeName') {
|
|
5936
5941
|
return `${optionName} = ${argValue}`;
|
|
5937
5942
|
}
|
|
5938
|
-
return `${optionName} = ${argValue}`;
|
|
5943
|
+
return `${optionName} = ${this.formatOptionValue(node.arg, argValue)}`;
|
|
5939
5944
|
}
|
|
5940
5945
|
// Handle ViewStmt WITH options - don't quote numeric values
|
|
5941
5946
|
if (context.parentNodeTypes.includes('ViewStmt')) {
|
|
@@ -6008,7 +6013,7 @@ class Deparser {
|
|
|
6008
6013
|
return `${quotedDefname} = ${stringData.sval}`;
|
|
6009
6014
|
}
|
|
6010
6015
|
// Regular string literals get single quotes
|
|
6011
|
-
return `${quotedDefname} =
|
|
6016
|
+
return `${quotedDefname} = ${quotes_1.QuoteUtils.escape(stringData.sval)}`;
|
|
6012
6017
|
}
|
|
6013
6018
|
return `${quotedDefname} = ${argValue}`;
|
|
6014
6019
|
}
|
|
@@ -6029,7 +6034,7 @@ class Deparser {
|
|
|
6029
6034
|
return `${node.defname} = ${stringData.sval}`;
|
|
6030
6035
|
}
|
|
6031
6036
|
// Regular string literals get single quotes
|
|
6032
|
-
return `${node.defname} =
|
|
6037
|
+
return `${node.defname} = ${quotes_1.QuoteUtils.escape(stringData.sval)}`;
|
|
6033
6038
|
}
|
|
6034
6039
|
if (node.arg && this.getNodeType(node.arg) === 'Boolean') {
|
|
6035
6040
|
const boolData = this.getNodeData(node.arg);
|
|
@@ -6079,7 +6084,7 @@ class Deparser {
|
|
|
6079
6084
|
}
|
|
6080
6085
|
if (node.location) {
|
|
6081
6086
|
output.push('LOCATION');
|
|
6082
|
-
output.push(
|
|
6087
|
+
output.push(quotes_1.QuoteUtils.escape(node.location));
|
|
6083
6088
|
}
|
|
6084
6089
|
if (node.options && node.options.length > 0) {
|
|
6085
6090
|
output.push('WITH');
|
|
@@ -6412,7 +6417,7 @@ class Deparser {
|
|
|
6412
6417
|
}
|
|
6413
6418
|
if (node.payload !== null && node.payload !== undefined) {
|
|
6414
6419
|
output.push(',');
|
|
6415
|
-
output.push(
|
|
6420
|
+
output.push(quotes_1.QuoteUtils.escape(node.payload));
|
|
6416
6421
|
}
|
|
6417
6422
|
return output.join(' ');
|
|
6418
6423
|
}
|
|
@@ -6440,7 +6445,7 @@ class Deparser {
|
|
|
6440
6445
|
if (!node.filename) {
|
|
6441
6446
|
throw new Error('LoadStmt requires filename');
|
|
6442
6447
|
}
|
|
6443
|
-
return `LOAD
|
|
6448
|
+
return `LOAD ${quotes_1.QuoteUtils.escape(node.filename)}`;
|
|
6444
6449
|
}
|
|
6445
6450
|
DiscardStmt(node, context) {
|
|
6446
6451
|
switch (node.target) {
|
|
@@ -6927,7 +6932,7 @@ class Deparser {
|
|
|
6927
6932
|
}
|
|
6928
6933
|
output.push('CONNECTION');
|
|
6929
6934
|
if (node.conninfo) {
|
|
6930
|
-
output.push(
|
|
6935
|
+
output.push(quotes_1.QuoteUtils.escape(node.conninfo));
|
|
6931
6936
|
}
|
|
6932
6937
|
output.push('PUBLICATION');
|
|
6933
6938
|
if (node.publication && node.publication.length > 0) {
|
|
@@ -8210,7 +8215,7 @@ class Deparser {
|
|
|
8210
8215
|
}
|
|
8211
8216
|
output.push('IS');
|
|
8212
8217
|
if (node.label) {
|
|
8213
|
-
output.push(
|
|
8218
|
+
output.push(quotes_1.QuoteUtils.escape(node.label));
|
|
8214
8219
|
}
|
|
8215
8220
|
else {
|
|
8216
8221
|
output.push('NULL');
|
|
@@ -8267,10 +8272,10 @@ class Deparser {
|
|
|
8267
8272
|
output.push(conversionName);
|
|
8268
8273
|
}
|
|
8269
8274
|
if (node.for_encoding_name) {
|
|
8270
|
-
output.push('FOR',
|
|
8275
|
+
output.push('FOR', quotes_1.QuoteUtils.escape(node.for_encoding_name));
|
|
8271
8276
|
}
|
|
8272
8277
|
if (node.to_encoding_name) {
|
|
8273
|
-
output.push('TO',
|
|
8278
|
+
output.push('TO', quotes_1.QuoteUtils.escape(node.to_encoding_name));
|
|
8274
8279
|
}
|
|
8275
8280
|
if (node.func_name && node.func_name.length > 0) {
|
|
8276
8281
|
output.push('FROM');
|
|
@@ -9405,7 +9410,7 @@ class Deparser {
|
|
|
9405
9410
|
const preservedDefName = quotedDefName !== defName ? quotedDefName : defName;
|
|
9406
9411
|
// Handle String arguments with single quotes for string literals
|
|
9407
9412
|
if (defValue.String) {
|
|
9408
|
-
return `${preservedDefName} =
|
|
9413
|
+
return `${preservedDefName} = ${quotes_1.QuoteUtils.escape(defValue.String.sval)}`;
|
|
9409
9414
|
}
|
|
9410
9415
|
return `${preservedDefName} = ${this.visit(defValue, context)}`;
|
|
9411
9416
|
}
|
|
@@ -9528,7 +9533,7 @@ class Deparser {
|
|
|
9528
9533
|
// For CREATE COLLATION, ensure String nodes are quoted as string literals
|
|
9529
9534
|
let valueStr;
|
|
9530
9535
|
if (defValue.String) {
|
|
9531
|
-
valueStr =
|
|
9536
|
+
valueStr = quotes_1.QuoteUtils.escape(defValue.String.sval);
|
|
9532
9537
|
}
|
|
9533
9538
|
else {
|
|
9534
9539
|
valueStr = this.visit(defValue, context);
|
|
@@ -9795,6 +9800,21 @@ class Deparser {
|
|
|
9795
9800
|
}
|
|
9796
9801
|
return output.join(' ');
|
|
9797
9802
|
}
|
|
9803
|
+
quoteDefElemArg(arg, argValue) {
|
|
9804
|
+
if (arg && this.getNodeType(arg) === 'String') {
|
|
9805
|
+
return quotes_1.QuoteUtils.escape(this.getNodeData(arg).sval || '');
|
|
9806
|
+
}
|
|
9807
|
+
return typeof argValue === 'string' && !argValue.startsWith("'")
|
|
9808
|
+
? quotes_1.QuoteUtils.escape(argValue)
|
|
9809
|
+
: argValue;
|
|
9810
|
+
}
|
|
9811
|
+
formatOptionValue(arg, argValue) {
|
|
9812
|
+
if (arg && this.getNodeType(arg) === 'String') {
|
|
9813
|
+
const sval = this.getNodeData(arg).sval || '';
|
|
9814
|
+
return /^[A-Za-z_][A-Za-z0-9_]*$/.test(sval) ? sval : quotes_1.QuoteUtils.escape(sval);
|
|
9815
|
+
}
|
|
9816
|
+
return argValue;
|
|
9817
|
+
}
|
|
9798
9818
|
Var(node, context) {
|
|
9799
9819
|
if (node.varno && node.varattno) {
|
|
9800
9820
|
return `$${node.varno}.${node.varattno}`;
|
|
@@ -9834,7 +9854,7 @@ class Deparser {
|
|
|
9834
9854
|
}
|
|
9835
9855
|
if (node.rowexpr) {
|
|
9836
9856
|
output.push(',');
|
|
9837
|
-
output.push(
|
|
9857
|
+
output.push(this.visit(node.rowexpr, context));
|
|
9838
9858
|
}
|
|
9839
9859
|
if (node.colexprs && node.colexprs.length > 0) {
|
|
9840
9860
|
output.push('COLUMNS');
|
|
@@ -9851,25 +9871,40 @@ class Deparser {
|
|
|
9851
9871
|
if (node.lateral) {
|
|
9852
9872
|
output.push('LATERAL');
|
|
9853
9873
|
}
|
|
9854
|
-
|
|
9855
|
-
|
|
9874
|
+
const args = [];
|
|
9875
|
+
if (node.namespaces && node.namespaces.length > 0) {
|
|
9876
|
+
const namespaces = list_utils_1.ListUtils.unwrapList(node.namespaces).map(ns => {
|
|
9877
|
+
const target = this.getNodeData(ns);
|
|
9878
|
+
const uri = this.visit(target.val, context);
|
|
9879
|
+
return target.name ? `${uri} AS ${quotes_1.QuoteUtils.quoteIdentifier(target.name)}` : `DEFAULT ${uri}`;
|
|
9880
|
+
});
|
|
9881
|
+
args.push(`XMLNAMESPACES(${namespaces.join(', ')}),`);
|
|
9856
9882
|
}
|
|
9857
9883
|
if (node.rowexpr) {
|
|
9858
|
-
|
|
9859
|
-
|
|
9884
|
+
args.push(this.formatXmlTableExpr(node.rowexpr, context));
|
|
9885
|
+
}
|
|
9886
|
+
if (node.docexpr) {
|
|
9887
|
+
args.push('PASSING');
|
|
9888
|
+
args.push(this.formatXmlTableExpr(node.docexpr, context));
|
|
9860
9889
|
}
|
|
9861
9890
|
if (node.columns && node.columns.length > 0) {
|
|
9862
|
-
|
|
9863
|
-
|
|
9891
|
+
args.push('COLUMNS');
|
|
9892
|
+
args.push(list_utils_1.ListUtils.unwrapList(node.columns)
|
|
9864
9893
|
.map(col => this.visit(col, context))
|
|
9865
|
-
.join(', ');
|
|
9866
|
-
output.push(`(${columns})`);
|
|
9894
|
+
.join(', '));
|
|
9867
9895
|
}
|
|
9896
|
+
output.push(`XMLTABLE(${args.join(' ')})`);
|
|
9868
9897
|
if (node.alias) {
|
|
9869
9898
|
output.push(this.Alias(node.alias, context));
|
|
9870
9899
|
}
|
|
9871
9900
|
return output.join(' ');
|
|
9872
9901
|
}
|
|
9902
|
+
formatXmlTableExpr(expr, context) {
|
|
9903
|
+
const value = this.visit(expr, context);
|
|
9904
|
+
return ['A_Const', 'ColumnRef', 'ParamRef', 'FuncCall'].includes(this.getNodeType(expr))
|
|
9905
|
+
? value
|
|
9906
|
+
: `(${value})`;
|
|
9907
|
+
}
|
|
9873
9908
|
RangeTableFuncCol(node, context) {
|
|
9874
9909
|
const output = [];
|
|
9875
9910
|
if (node.colname) {
|
|
@@ -9883,12 +9918,15 @@ class Deparser {
|
|
|
9883
9918
|
}
|
|
9884
9919
|
if (node.colexpr) {
|
|
9885
9920
|
output.push('PATH');
|
|
9886
|
-
output.push(
|
|
9921
|
+
output.push(this.visit(node.colexpr, context));
|
|
9887
9922
|
}
|
|
9888
9923
|
if (node.coldefexpr) {
|
|
9889
9924
|
output.push('DEFAULT');
|
|
9890
9925
|
output.push(this.visit(node.coldefexpr, context));
|
|
9891
9926
|
}
|
|
9927
|
+
if (node.is_not_null) {
|
|
9928
|
+
output.push('NOT NULL');
|
|
9929
|
+
}
|
|
9892
9930
|
return output.join(' ');
|
|
9893
9931
|
}
|
|
9894
9932
|
formatJsonFormat(format) {
|
package/esm/deparser.js
CHANGED
|
@@ -129,6 +129,21 @@ function formatBitString(bsval) {
|
|
|
129
129
|
}
|
|
130
130
|
return `b'${quote(bsval)}'`;
|
|
131
131
|
}
|
|
132
|
+
const NUMERIC_LITERAL = /^[+-]?(?:0[xX](?:_?[0-9A-Fa-f])+|0[oO](?:_?[0-7])+|0[bB](?:_?[01])+|(?:\d(?:_?\d)*(?:\.(?:\d(?:_?\d)*)?)?|\.\d(?:_?\d)*)(?:[eE][+-]?\d(?:_?\d)*)?)$/;
|
|
133
|
+
function formatInteger(ival) {
|
|
134
|
+
const value = String(ival);
|
|
135
|
+
if (!/^[+-]?\d+$/.test(value)) {
|
|
136
|
+
throw new Error(`Invalid integer literal: ${value}`);
|
|
137
|
+
}
|
|
138
|
+
return value;
|
|
139
|
+
}
|
|
140
|
+
function formatNumeric(fval) {
|
|
141
|
+
const value = String(fval);
|
|
142
|
+
if (!NUMERIC_LITERAL.test(value)) {
|
|
143
|
+
throw new Error(`Invalid numeric literal: ${value}`);
|
|
144
|
+
}
|
|
145
|
+
return value;
|
|
146
|
+
}
|
|
132
147
|
export class Deparser {
|
|
133
148
|
tree;
|
|
134
149
|
options;
|
|
@@ -1597,39 +1612,39 @@ export class Deparser {
|
|
|
1597
1612
|
if (nodeAny.ival !== undefined) {
|
|
1598
1613
|
if (typeof nodeAny.ival === 'object' && nodeAny.ival !== null) {
|
|
1599
1614
|
if (nodeAny.ival.ival !== undefined) {
|
|
1600
|
-
return nodeAny.ival.ival
|
|
1615
|
+
return formatInteger(nodeAny.ival.ival);
|
|
1601
1616
|
}
|
|
1602
1617
|
else if (Object.keys(nodeAny.ival).length === 0) {
|
|
1603
1618
|
return '0';
|
|
1604
1619
|
}
|
|
1605
1620
|
else {
|
|
1606
|
-
return nodeAny.ival
|
|
1621
|
+
return formatInteger(nodeAny.ival);
|
|
1607
1622
|
}
|
|
1608
1623
|
}
|
|
1609
1624
|
else if (nodeAny.ival === null) {
|
|
1610
1625
|
return 'NULL';
|
|
1611
1626
|
}
|
|
1612
1627
|
else {
|
|
1613
|
-
return nodeAny.ival
|
|
1628
|
+
return formatInteger(nodeAny.ival);
|
|
1614
1629
|
}
|
|
1615
1630
|
}
|
|
1616
1631
|
else if (nodeAny.fval !== undefined) {
|
|
1617
1632
|
if (typeof nodeAny.fval === 'object' && nodeAny.fval !== null) {
|
|
1618
1633
|
if (nodeAny.fval.fval !== undefined) {
|
|
1619
|
-
return nodeAny.fval.fval
|
|
1634
|
+
return formatNumeric(nodeAny.fval.fval);
|
|
1620
1635
|
}
|
|
1621
1636
|
else if (Object.keys(nodeAny.fval).length === 0) {
|
|
1622
1637
|
return '0.0';
|
|
1623
1638
|
}
|
|
1624
1639
|
else {
|
|
1625
|
-
return nodeAny.fval
|
|
1640
|
+
return formatNumeric(nodeAny.fval);
|
|
1626
1641
|
}
|
|
1627
1642
|
}
|
|
1628
1643
|
else if (nodeAny.fval === null) {
|
|
1629
1644
|
return 'NULL';
|
|
1630
1645
|
}
|
|
1631
1646
|
else {
|
|
1632
|
-
return nodeAny.fval
|
|
1647
|
+
return formatNumeric(nodeAny.fval);
|
|
1633
1648
|
}
|
|
1634
1649
|
}
|
|
1635
1650
|
else if (nodeAny.sval !== undefined) {
|
|
@@ -1694,10 +1709,10 @@ export class Deparser {
|
|
|
1694
1709
|
}
|
|
1695
1710
|
if (nodeAny.val) {
|
|
1696
1711
|
if (nodeAny.val.Integer?.ival !== undefined) {
|
|
1697
|
-
return nodeAny.val.Integer.ival
|
|
1712
|
+
return formatInteger(nodeAny.val.Integer.ival);
|
|
1698
1713
|
}
|
|
1699
1714
|
else if (nodeAny.val.Float?.fval !== undefined) {
|
|
1700
|
-
return nodeAny.val.Float.fval
|
|
1715
|
+
return formatNumeric(nodeAny.val.Float.fval);
|
|
1701
1716
|
}
|
|
1702
1717
|
else if (nodeAny.val.String?.sval !== undefined) {
|
|
1703
1718
|
return QuoteUtils.escape(nodeAny.val.String.sval);
|
|
@@ -1718,15 +1733,15 @@ export class Deparser {
|
|
|
1718
1733
|
}
|
|
1719
1734
|
if (nodeAny.Integer !== undefined) {
|
|
1720
1735
|
if (typeof nodeAny.Integer === 'object' && nodeAny.Integer.ival !== undefined) {
|
|
1721
|
-
return nodeAny.Integer.ival
|
|
1736
|
+
return formatInteger(nodeAny.Integer.ival);
|
|
1722
1737
|
}
|
|
1723
|
-
return nodeAny.Integer
|
|
1738
|
+
return formatInteger(nodeAny.Integer);
|
|
1724
1739
|
}
|
|
1725
1740
|
if (nodeAny.Float !== undefined) {
|
|
1726
1741
|
if (typeof nodeAny.Float === 'object' && nodeAny.Float.fval !== undefined) {
|
|
1727
|
-
return nodeAny.Float.fval
|
|
1742
|
+
return formatNumeric(nodeAny.Float.fval);
|
|
1728
1743
|
}
|
|
1729
|
-
return nodeAny.Float
|
|
1744
|
+
return formatNumeric(nodeAny.Float);
|
|
1730
1745
|
}
|
|
1731
1746
|
if (nodeAny.String !== undefined) {
|
|
1732
1747
|
if (typeof nodeAny.String === 'object' && nodeAny.String.sval !== undefined) {
|
|
@@ -2377,10 +2392,10 @@ export class Deparser {
|
|
|
2377
2392
|
return QuoteUtils.quoteIdentifier(value);
|
|
2378
2393
|
}
|
|
2379
2394
|
Integer(node, context) {
|
|
2380
|
-
return node.ival
|
|
2395
|
+
return node.ival === undefined || node.ival === null ? '0' : formatInteger(node.ival);
|
|
2381
2396
|
}
|
|
2382
2397
|
Float(node, context) {
|
|
2383
|
-
return node.fval
|
|
2398
|
+
return node.fval ? formatNumeric(node.fval) : '0.0';
|
|
2384
2399
|
}
|
|
2385
2400
|
Boolean(node, context) {
|
|
2386
2401
|
return node.boolval ? 'true' : 'false';
|
|
@@ -3618,7 +3633,7 @@ export class Deparser {
|
|
|
3618
3633
|
const opclassOpts = ListUtils.unwrapList(node.opclassopts).map(opt => {
|
|
3619
3634
|
if (opt.DefElem && opt.DefElem.arg && this.getNodeType(opt.DefElem.arg) === 'String') {
|
|
3620
3635
|
const stringData = this.getNodeData(opt.DefElem.arg);
|
|
3621
|
-
return `${opt.DefElem.defname}
|
|
3636
|
+
return `${QuoteUtils.quoteIdentifierAfterDot(opt.DefElem.defname)}=${QuoteUtils.escape(stringData.sval)}`;
|
|
3622
3637
|
}
|
|
3623
3638
|
return this.visit(opt, context.spawn('IndexElem'));
|
|
3624
3639
|
});
|
|
@@ -3919,19 +3934,19 @@ export class Deparser {
|
|
|
3919
3934
|
case 'TRANS_STMT_PREPARE':
|
|
3920
3935
|
output.push('PREPARE TRANSACTION');
|
|
3921
3936
|
if (node.gid) {
|
|
3922
|
-
output.push(
|
|
3937
|
+
output.push(QuoteUtils.escape(node.gid));
|
|
3923
3938
|
}
|
|
3924
3939
|
break;
|
|
3925
3940
|
case 'TRANS_STMT_COMMIT_PREPARED':
|
|
3926
3941
|
output.push('COMMIT PREPARED');
|
|
3927
3942
|
if (node.gid) {
|
|
3928
|
-
output.push(
|
|
3943
|
+
output.push(QuoteUtils.escape(node.gid));
|
|
3929
3944
|
}
|
|
3930
3945
|
break;
|
|
3931
3946
|
case 'TRANS_STMT_ROLLBACK_PREPARED':
|
|
3932
3947
|
output.push('ROLLBACK PREPARED');
|
|
3933
3948
|
if (node.gid) {
|
|
3934
|
-
output.push(
|
|
3949
|
+
output.push(QuoteUtils.escape(node.gid));
|
|
3935
3950
|
}
|
|
3936
3951
|
break;
|
|
3937
3952
|
default:
|
|
@@ -4007,8 +4022,8 @@ export class Deparser {
|
|
|
4007
4022
|
const nodeData = this.getNodeData(arg);
|
|
4008
4023
|
if (nodeData.sval !== undefined) {
|
|
4009
4024
|
const svalValue = typeof nodeData.sval === 'object' ? nodeData.sval.sval : nodeData.sval;
|
|
4010
|
-
if (svalValue
|
|
4011
|
-
return
|
|
4025
|
+
if (!/^[a-z_][a-z0-9_]*$/.test(svalValue) || svalValue.includes(' ') || svalValue.includes('-') || /[A-Z]/.test(svalValue) || /^\d/.test(svalValue) || svalValue.includes('.') || svalValue.includes('$') || svalValue.toLowerCase() === 'all' || /^[+-]\d/.test(svalValue)) {
|
|
4026
|
+
return QuoteUtils.escape(svalValue);
|
|
4012
4027
|
}
|
|
4013
4028
|
return svalValue;
|
|
4014
4029
|
}
|
|
@@ -5535,9 +5550,9 @@ export class Deparser {
|
|
|
5535
5550
|
if (context.parentNodeTypes.includes('IndexElem')) {
|
|
5536
5551
|
if (node.arg && this.getNodeType(node.arg) === 'String') {
|
|
5537
5552
|
const stringData = this.getNodeData(node.arg);
|
|
5538
|
-
return `${node.defname}
|
|
5553
|
+
return `${QuoteUtils.quoteIdentifierAfterDot(node.defname)}=${QuoteUtils.escape(stringData.sval)}`;
|
|
5539
5554
|
}
|
|
5540
|
-
return `${node.defname}=${this.visit(node.arg, context.spawn('DefElem'))}`;
|
|
5555
|
+
return `${QuoteUtils.quoteIdentifierAfterDot(node.defname)}=${this.formatOptionValue(node.arg, this.visit(node.arg, context.spawn('DefElem')))}`;
|
|
5541
5556
|
}
|
|
5542
5557
|
// Handle CREATE OPERATOR boolean flags - MUST be first to preserve case
|
|
5543
5558
|
if (context.parentNodeTypes.includes('DefineStmt') &&
|
|
@@ -5562,9 +5577,7 @@ export class Deparser {
|
|
|
5562
5577
|
const defElemContext = context.spawn('DefElem');
|
|
5563
5578
|
const argValue = this.visit(node.arg, defElemContext);
|
|
5564
5579
|
if (context.parentNodeTypes.includes('CreateFdwStmt') || context.parentNodeTypes.includes('AlterFdwStmt')) {
|
|
5565
|
-
const finalValue =
|
|
5566
|
-
? `'${argValue}'`
|
|
5567
|
-
: argValue;
|
|
5580
|
+
const finalValue = this.quoteDefElemArg(node.arg, argValue);
|
|
5568
5581
|
const quotedDefname = QuoteUtils.quoteIdentifier(node.defname);
|
|
5569
5582
|
if (node.defaction === 'DEFELEM_ADD') {
|
|
5570
5583
|
return `ADD ${quotedDefname} ${finalValue}`;
|
|
@@ -5577,9 +5590,7 @@ export class Deparser {
|
|
|
5577
5590
|
}
|
|
5578
5591
|
return `${quotedDefname} ${finalValue}`;
|
|
5579
5592
|
}
|
|
5580
|
-
const quotedValue =
|
|
5581
|
-
? `'${argValue}'`
|
|
5582
|
-
: argValue;
|
|
5593
|
+
const quotedValue = this.quoteDefElemArg(node.arg, argValue);
|
|
5583
5594
|
if (node.defaction === 'DEFELEM_ADD') {
|
|
5584
5595
|
return `ADD ${node.defname} ${quotedValue}`;
|
|
5585
5596
|
}
|
|
@@ -5611,9 +5622,7 @@ export class Deparser {
|
|
|
5611
5622
|
}
|
|
5612
5623
|
const defElemContext = context.spawn('DefElem');
|
|
5613
5624
|
const argValue = this.visit(node.arg, defElemContext);
|
|
5614
|
-
const quotedValue =
|
|
5615
|
-
? `'${argValue}'`
|
|
5616
|
-
: argValue;
|
|
5625
|
+
const quotedValue = this.quoteDefElemArg(node.arg, argValue);
|
|
5617
5626
|
return `PASSWORD ${quotedValue}`;
|
|
5618
5627
|
}
|
|
5619
5628
|
}
|
|
@@ -5678,9 +5687,7 @@ export class Deparser {
|
|
|
5678
5687
|
}
|
|
5679
5688
|
}
|
|
5680
5689
|
if (node.defname === 'validUntil') {
|
|
5681
|
-
const quotedValue =
|
|
5682
|
-
? `'${argValue}'`
|
|
5683
|
-
: argValue;
|
|
5690
|
+
const quotedValue = this.quoteDefElemArg(node.arg, argValue);
|
|
5684
5691
|
return `VALID UNTIL ${quotedValue}`;
|
|
5685
5692
|
}
|
|
5686
5693
|
if (node.defname === 'adminmembers') {
|
|
@@ -5860,9 +5867,7 @@ export class Deparser {
|
|
|
5860
5867
|
if (context.parentNodeTypes.includes('AlterExtensionStmt')) {
|
|
5861
5868
|
if (node.defname === 'new_version') {
|
|
5862
5869
|
// argValue is unquoted due to DefElem context, so we need to quote it
|
|
5863
|
-
const quotedValue =
|
|
5864
|
-
? `'${argValue}'`
|
|
5865
|
-
: argValue;
|
|
5870
|
+
const quotedValue = this.quoteDefElemArg(node.arg, argValue);
|
|
5866
5871
|
return `UPDATE TO ${quotedValue}`;
|
|
5867
5872
|
}
|
|
5868
5873
|
if (node.defname === 'schema') {
|
|
@@ -5887,15 +5892,15 @@ export class Deparser {
|
|
|
5887
5892
|
}
|
|
5888
5893
|
// Handle IndexStmt WITH clause options - no quotes, compact formatting
|
|
5889
5894
|
if (context.parentNodeTypes.includes('IndexStmt')) {
|
|
5890
|
-
return `${node.defname}=${argValue}`;
|
|
5895
|
+
return `${QuoteUtils.quoteIdentifierAfterDot(node.defname)}=${this.formatOptionValue(node.arg, argValue)}`;
|
|
5891
5896
|
}
|
|
5892
5897
|
// Handle IndexElem opclassopts - preserve string values as strings
|
|
5893
5898
|
if (context.parentNodeTypes.includes('IndexElem')) {
|
|
5894
5899
|
if (node.arg && this.getNodeType(node.arg) === 'String') {
|
|
5895
5900
|
const stringData = this.getNodeData(node.arg);
|
|
5896
|
-
return `${node.defname}
|
|
5901
|
+
return `${QuoteUtils.quoteIdentifierAfterDot(node.defname)}=${QuoteUtils.escape(stringData.sval)}`;
|
|
5897
5902
|
}
|
|
5898
|
-
return `${node.defname}=${argValue}`;
|
|
5903
|
+
return `${QuoteUtils.quoteIdentifierAfterDot(node.defname)}=${this.formatOptionValue(node.arg, argValue)}`;
|
|
5899
5904
|
}
|
|
5900
5905
|
// Handle CreateStmt table options - no quotes, compact formatting
|
|
5901
5906
|
if (context.parentNodeTypes.includes('CreateStmt')) {
|
|
@@ -5905,9 +5910,9 @@ export class Deparser {
|
|
|
5905
5910
|
// For numeric values, use the raw value without quotes
|
|
5906
5911
|
if (node.arg && this.getNodeType(node.arg) === 'Integer') {
|
|
5907
5912
|
const integerData = this.getNodeData(node.arg);
|
|
5908
|
-
return `${relOptName}=${integerData.ival}`;
|
|
5913
|
+
return `${relOptName}=${formatInteger(integerData.ival)}`;
|
|
5909
5914
|
}
|
|
5910
|
-
return `${relOptName}=${argValue}`;
|
|
5915
|
+
return `${relOptName}=${this.formatOptionValue(node.arg, argValue)}`;
|
|
5911
5916
|
}
|
|
5912
5917
|
// Handle CreateEventTrigStmt WHEN clause - use IN syntax for List arguments
|
|
5913
5918
|
if (context.parentNodeTypes.includes('CreateEventTrigStmt')) {
|
|
@@ -5917,7 +5922,7 @@ export class Deparser {
|
|
|
5917
5922
|
const values = listItems.map(item => {
|
|
5918
5923
|
if (this.getNodeType(item) === 'String') {
|
|
5919
5924
|
const stringData = this.getNodeData(item);
|
|
5920
|
-
return
|
|
5925
|
+
return QuoteUtils.escape(stringData.sval || '');
|
|
5921
5926
|
}
|
|
5922
5927
|
return this.visit(item, context);
|
|
5923
5928
|
});
|
|
@@ -5932,7 +5937,7 @@ export class Deparser {
|
|
|
5932
5937
|
if (node.arg && this.getNodeType(node.arg) === 'TypeName') {
|
|
5933
5938
|
return `${optionName} = ${argValue}`;
|
|
5934
5939
|
}
|
|
5935
|
-
return `${optionName} = ${argValue}`;
|
|
5940
|
+
return `${optionName} = ${this.formatOptionValue(node.arg, argValue)}`;
|
|
5936
5941
|
}
|
|
5937
5942
|
// Handle ViewStmt WITH options - don't quote numeric values
|
|
5938
5943
|
if (context.parentNodeTypes.includes('ViewStmt')) {
|
|
@@ -6005,7 +6010,7 @@ export class Deparser {
|
|
|
6005
6010
|
return `${quotedDefname} = ${stringData.sval}`;
|
|
6006
6011
|
}
|
|
6007
6012
|
// Regular string literals get single quotes
|
|
6008
|
-
return `${quotedDefname} =
|
|
6013
|
+
return `${quotedDefname} = ${QuoteUtils.escape(stringData.sval)}`;
|
|
6009
6014
|
}
|
|
6010
6015
|
return `${quotedDefname} = ${argValue}`;
|
|
6011
6016
|
}
|
|
@@ -6026,7 +6031,7 @@ export class Deparser {
|
|
|
6026
6031
|
return `${node.defname} = ${stringData.sval}`;
|
|
6027
6032
|
}
|
|
6028
6033
|
// Regular string literals get single quotes
|
|
6029
|
-
return `${node.defname} =
|
|
6034
|
+
return `${node.defname} = ${QuoteUtils.escape(stringData.sval)}`;
|
|
6030
6035
|
}
|
|
6031
6036
|
if (node.arg && this.getNodeType(node.arg) === 'Boolean') {
|
|
6032
6037
|
const boolData = this.getNodeData(node.arg);
|
|
@@ -6076,7 +6081,7 @@ export class Deparser {
|
|
|
6076
6081
|
}
|
|
6077
6082
|
if (node.location) {
|
|
6078
6083
|
output.push('LOCATION');
|
|
6079
|
-
output.push(
|
|
6084
|
+
output.push(QuoteUtils.escape(node.location));
|
|
6080
6085
|
}
|
|
6081
6086
|
if (node.options && node.options.length > 0) {
|
|
6082
6087
|
output.push('WITH');
|
|
@@ -6409,7 +6414,7 @@ export class Deparser {
|
|
|
6409
6414
|
}
|
|
6410
6415
|
if (node.payload !== null && node.payload !== undefined) {
|
|
6411
6416
|
output.push(',');
|
|
6412
|
-
output.push(
|
|
6417
|
+
output.push(QuoteUtils.escape(node.payload));
|
|
6413
6418
|
}
|
|
6414
6419
|
return output.join(' ');
|
|
6415
6420
|
}
|
|
@@ -6437,7 +6442,7 @@ export class Deparser {
|
|
|
6437
6442
|
if (!node.filename) {
|
|
6438
6443
|
throw new Error('LoadStmt requires filename');
|
|
6439
6444
|
}
|
|
6440
|
-
return `LOAD
|
|
6445
|
+
return `LOAD ${QuoteUtils.escape(node.filename)}`;
|
|
6441
6446
|
}
|
|
6442
6447
|
DiscardStmt(node, context) {
|
|
6443
6448
|
switch (node.target) {
|
|
@@ -6924,7 +6929,7 @@ export class Deparser {
|
|
|
6924
6929
|
}
|
|
6925
6930
|
output.push('CONNECTION');
|
|
6926
6931
|
if (node.conninfo) {
|
|
6927
|
-
output.push(
|
|
6932
|
+
output.push(QuoteUtils.escape(node.conninfo));
|
|
6928
6933
|
}
|
|
6929
6934
|
output.push('PUBLICATION');
|
|
6930
6935
|
if (node.publication && node.publication.length > 0) {
|
|
@@ -8207,7 +8212,7 @@ export class Deparser {
|
|
|
8207
8212
|
}
|
|
8208
8213
|
output.push('IS');
|
|
8209
8214
|
if (node.label) {
|
|
8210
|
-
output.push(
|
|
8215
|
+
output.push(QuoteUtils.escape(node.label));
|
|
8211
8216
|
}
|
|
8212
8217
|
else {
|
|
8213
8218
|
output.push('NULL');
|
|
@@ -8264,10 +8269,10 @@ export class Deparser {
|
|
|
8264
8269
|
output.push(conversionName);
|
|
8265
8270
|
}
|
|
8266
8271
|
if (node.for_encoding_name) {
|
|
8267
|
-
output.push('FOR',
|
|
8272
|
+
output.push('FOR', QuoteUtils.escape(node.for_encoding_name));
|
|
8268
8273
|
}
|
|
8269
8274
|
if (node.to_encoding_name) {
|
|
8270
|
-
output.push('TO',
|
|
8275
|
+
output.push('TO', QuoteUtils.escape(node.to_encoding_name));
|
|
8271
8276
|
}
|
|
8272
8277
|
if (node.func_name && node.func_name.length > 0) {
|
|
8273
8278
|
output.push('FROM');
|
|
@@ -9402,7 +9407,7 @@ export class Deparser {
|
|
|
9402
9407
|
const preservedDefName = quotedDefName !== defName ? quotedDefName : defName;
|
|
9403
9408
|
// Handle String arguments with single quotes for string literals
|
|
9404
9409
|
if (defValue.String) {
|
|
9405
|
-
return `${preservedDefName} =
|
|
9410
|
+
return `${preservedDefName} = ${QuoteUtils.escape(defValue.String.sval)}`;
|
|
9406
9411
|
}
|
|
9407
9412
|
return `${preservedDefName} = ${this.visit(defValue, context)}`;
|
|
9408
9413
|
}
|
|
@@ -9525,7 +9530,7 @@ export class Deparser {
|
|
|
9525
9530
|
// For CREATE COLLATION, ensure String nodes are quoted as string literals
|
|
9526
9531
|
let valueStr;
|
|
9527
9532
|
if (defValue.String) {
|
|
9528
|
-
valueStr =
|
|
9533
|
+
valueStr = QuoteUtils.escape(defValue.String.sval);
|
|
9529
9534
|
}
|
|
9530
9535
|
else {
|
|
9531
9536
|
valueStr = this.visit(defValue, context);
|
|
@@ -9792,6 +9797,21 @@ export class Deparser {
|
|
|
9792
9797
|
}
|
|
9793
9798
|
return output.join(' ');
|
|
9794
9799
|
}
|
|
9800
|
+
quoteDefElemArg(arg, argValue) {
|
|
9801
|
+
if (arg && this.getNodeType(arg) === 'String') {
|
|
9802
|
+
return QuoteUtils.escape(this.getNodeData(arg).sval || '');
|
|
9803
|
+
}
|
|
9804
|
+
return typeof argValue === 'string' && !argValue.startsWith("'")
|
|
9805
|
+
? QuoteUtils.escape(argValue)
|
|
9806
|
+
: argValue;
|
|
9807
|
+
}
|
|
9808
|
+
formatOptionValue(arg, argValue) {
|
|
9809
|
+
if (arg && this.getNodeType(arg) === 'String') {
|
|
9810
|
+
const sval = this.getNodeData(arg).sval || '';
|
|
9811
|
+
return /^[A-Za-z_][A-Za-z0-9_]*$/.test(sval) ? sval : QuoteUtils.escape(sval);
|
|
9812
|
+
}
|
|
9813
|
+
return argValue;
|
|
9814
|
+
}
|
|
9795
9815
|
Var(node, context) {
|
|
9796
9816
|
if (node.varno && node.varattno) {
|
|
9797
9817
|
return `$${node.varno}.${node.varattno}`;
|
|
@@ -9831,7 +9851,7 @@ export class Deparser {
|
|
|
9831
9851
|
}
|
|
9832
9852
|
if (node.rowexpr) {
|
|
9833
9853
|
output.push(',');
|
|
9834
|
-
output.push(
|
|
9854
|
+
output.push(this.visit(node.rowexpr, context));
|
|
9835
9855
|
}
|
|
9836
9856
|
if (node.colexprs && node.colexprs.length > 0) {
|
|
9837
9857
|
output.push('COLUMNS');
|
|
@@ -9848,25 +9868,40 @@ export class Deparser {
|
|
|
9848
9868
|
if (node.lateral) {
|
|
9849
9869
|
output.push('LATERAL');
|
|
9850
9870
|
}
|
|
9851
|
-
|
|
9852
|
-
|
|
9871
|
+
const args = [];
|
|
9872
|
+
if (node.namespaces && node.namespaces.length > 0) {
|
|
9873
|
+
const namespaces = ListUtils.unwrapList(node.namespaces).map(ns => {
|
|
9874
|
+
const target = this.getNodeData(ns);
|
|
9875
|
+
const uri = this.visit(target.val, context);
|
|
9876
|
+
return target.name ? `${uri} AS ${QuoteUtils.quoteIdentifier(target.name)}` : `DEFAULT ${uri}`;
|
|
9877
|
+
});
|
|
9878
|
+
args.push(`XMLNAMESPACES(${namespaces.join(', ')}),`);
|
|
9853
9879
|
}
|
|
9854
9880
|
if (node.rowexpr) {
|
|
9855
|
-
|
|
9856
|
-
|
|
9881
|
+
args.push(this.formatXmlTableExpr(node.rowexpr, context));
|
|
9882
|
+
}
|
|
9883
|
+
if (node.docexpr) {
|
|
9884
|
+
args.push('PASSING');
|
|
9885
|
+
args.push(this.formatXmlTableExpr(node.docexpr, context));
|
|
9857
9886
|
}
|
|
9858
9887
|
if (node.columns && node.columns.length > 0) {
|
|
9859
|
-
|
|
9860
|
-
|
|
9888
|
+
args.push('COLUMNS');
|
|
9889
|
+
args.push(ListUtils.unwrapList(node.columns)
|
|
9861
9890
|
.map(col => this.visit(col, context))
|
|
9862
|
-
.join(', ');
|
|
9863
|
-
output.push(`(${columns})`);
|
|
9891
|
+
.join(', '));
|
|
9864
9892
|
}
|
|
9893
|
+
output.push(`XMLTABLE(${args.join(' ')})`);
|
|
9865
9894
|
if (node.alias) {
|
|
9866
9895
|
output.push(this.Alias(node.alias, context));
|
|
9867
9896
|
}
|
|
9868
9897
|
return output.join(' ');
|
|
9869
9898
|
}
|
|
9899
|
+
formatXmlTableExpr(expr, context) {
|
|
9900
|
+
const value = this.visit(expr, context);
|
|
9901
|
+
return ['A_Const', 'ColumnRef', 'ParamRef', 'FuncCall'].includes(this.getNodeType(expr))
|
|
9902
|
+
? value
|
|
9903
|
+
: `(${value})`;
|
|
9904
|
+
}
|
|
9870
9905
|
RangeTableFuncCol(node, context) {
|
|
9871
9906
|
const output = [];
|
|
9872
9907
|
if (node.colname) {
|
|
@@ -9880,12 +9915,15 @@ export class Deparser {
|
|
|
9880
9915
|
}
|
|
9881
9916
|
if (node.colexpr) {
|
|
9882
9917
|
output.push('PATH');
|
|
9883
|
-
output.push(
|
|
9918
|
+
output.push(this.visit(node.colexpr, context));
|
|
9884
9919
|
}
|
|
9885
9920
|
if (node.coldefexpr) {
|
|
9886
9921
|
output.push('DEFAULT');
|
|
9887
9922
|
output.push(this.visit(node.coldefexpr, context));
|
|
9888
9923
|
}
|
|
9924
|
+
if (node.is_not_null) {
|
|
9925
|
+
output.push('NOT NULL');
|
|
9926
|
+
}
|
|
9889
9927
|
return output.join(' ');
|
|
9890
9928
|
}
|
|
9891
9929
|
formatJsonFormat(format) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pgsql-deparser",
|
|
3
|
-
"version": "18.3.
|
|
3
|
+
"version": "18.3.11",
|
|
4
4
|
"author": "Constructive <developers@constructive.io>",
|
|
5
5
|
"description": "PostgreSQL AST Deparser",
|
|
6
6
|
"main": "index.js",
|
|
@@ -60,5 +60,5 @@
|
|
|
60
60
|
"@pgsql/quotes": "18.2.4",
|
|
61
61
|
"@pgsql/types": "^18.0.0"
|
|
62
62
|
},
|
|
63
|
-
"gitHead": "
|
|
63
|
+
"gitHead": "253de85d89081d866200077492ce69c3a2e96b04"
|
|
64
64
|
}
|