pg_query 1.1.0 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +35 -0
- data/ext/pg_query/extconf.rb +1 -1
- data/lib/pg_query/deparse.rb +393 -31
- data/lib/pg_query/deparse/keywords.rb +760 -0
- data/lib/pg_query/deparse/rename.rb +41 -0
- data/lib/pg_query/node_types.rb +9 -0
- data/lib/pg_query/version.rb +1 -1
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9cb01b49c6ea65d1ff126562ce68adaa5635d37093ff726b1bc70d65c341ae9e
|
4
|
+
data.tar.gz: 4dc7fa1bf00d7ff6036a79d8a38fd9f3e383f449b21f0d53f0168be7d32df89a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ad48c885044147fcc9fa406543fc8a805c789fa227d71000bd1d25be0846aa1f7e183420e7ee86df262ff0d7ae668f2c4b1cd4ef15f5d305d5deeb5d86d6e8ad
|
7
|
+
data.tar.gz: 860aa2345238226eaf5594d20d34af5a6aed39177a0900e0b72e79771586f96bf2917ac73722d3672cf730e18c2977cd275617fe411e79b4af8266ac4e499124
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,40 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## 1.1.1 2019-11-10
|
4
|
+
|
5
|
+
* Deparsing improvements by [@emin100](https://github.com/emin100)
|
6
|
+
* Deparse ILIKE, COLLATE and DISCARD (#133)
|
7
|
+
* CREATE CAST (#136)
|
8
|
+
* CREATE SCHEMA (#136)
|
9
|
+
* UNION, UNION ALL and EXCEPT in SELECT queries (#136)
|
10
|
+
* CREATE DOMAIN (#145)
|
11
|
+
* Subquery indirection (#157)
|
12
|
+
* Fix Type Cast Parentheses Problem (#152)
|
13
|
+
* SELECT INTO (#151)
|
14
|
+
* SET DEFAULT in INSERT INTO (#154)
|
15
|
+
* REVOKE (#155)
|
16
|
+
* PREPARE and EXECUTE (#148)
|
17
|
+
* INSERT INTO ... RETURNING (#153)
|
18
|
+
* Fix Alter .. RENAME SQL (#146)
|
19
|
+
* Deparsing improvements by [@herwinw](https://github.com/herwinw)
|
20
|
+
* Fix subquery in COPY in deparse (#112)
|
21
|
+
* Function call indirection (#116)
|
22
|
+
* Function without parameters (#117)
|
23
|
+
* CREATE AGGREGATE
|
24
|
+
* CREATE OPERATOR
|
25
|
+
* CREATE TYPE
|
26
|
+
* GRANT statements
|
27
|
+
* DROP SCHEMA
|
28
|
+
* Deparsing improvements by [@akiellor](https://github.com/akiellor)
|
29
|
+
* Named window functions (#150)
|
30
|
+
* Deparsing improvements by [@himanshu](https://github.com/himanshu)
|
31
|
+
* Arguments in custom types (#143)
|
32
|
+
* Use "double precision" instead of "double" type name (#139)
|
33
|
+
* Use explicit -z flag to support OpenBSD tar (#134) [@sirn](https://github.com/sirn)
|
34
|
+
* Add Ruby 2.6 to Travis tests
|
35
|
+
* Escape identifiers in more cases, if necessary
|
36
|
+
|
37
|
+
|
3
38
|
## 1.1.0 2018-10-04
|
4
39
|
|
5
40
|
* Deparsing improvements by [@herwinw](https://github.com/herwinw)
|
data/ext/pg_query/extconf.rb
CHANGED
@@ -19,7 +19,7 @@ unless File.exist?("#{workdir}/libpg_query.tar.gz")
|
|
19
19
|
end
|
20
20
|
|
21
21
|
unless Dir.exist?(libdir)
|
22
|
-
system("tar -
|
22
|
+
system("tar -xzf #{workdir}/libpg_query.tar.gz") || raise('ERROR')
|
23
23
|
end
|
24
24
|
|
25
25
|
unless Dir.exist?(libfile)
|
data/lib/pg_query/deparse.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
|
-
require_relative 'deparse/interval'
|
2
1
|
require_relative 'deparse/alter_table'
|
2
|
+
require_relative 'deparse/rename'
|
3
|
+
require_relative 'deparse/interval'
|
4
|
+
require_relative 'deparse/keywords'
|
5
|
+
|
3
6
|
class PgQuery
|
4
7
|
# Reconstruct all of the parsed queries into their original form
|
5
8
|
def deparse(tree = @tree)
|
@@ -32,10 +35,14 @@ class PgQuery
|
|
32
35
|
case node['kind']
|
33
36
|
when AEXPR_OP
|
34
37
|
deparse_aexpr(node, context)
|
38
|
+
when AEXPR_OP_ALL
|
39
|
+
deparse_aexpr_all(node)
|
35
40
|
when AEXPR_OP_ANY
|
36
41
|
deparse_aexpr_any(node)
|
37
42
|
when AEXPR_IN
|
38
43
|
deparse_aexpr_in(node)
|
44
|
+
when AEXPR_ILIKE
|
45
|
+
deparse_aexpr_ilike(node)
|
39
46
|
when CONSTR_TYPE_FOREIGN
|
40
47
|
deparse_aexpr_like(node)
|
41
48
|
when AEXPR_BETWEEN, AEXPR_NOT_BETWEEN, AEXPR_BETWEEN_SYM, AEXPR_NOT_BETWEEN_SYM
|
@@ -45,6 +52,8 @@ class PgQuery
|
|
45
52
|
else
|
46
53
|
raise format("Can't deparse: %s: %s", type, node.inspect)
|
47
54
|
end
|
55
|
+
when ACCESS_PRIV
|
56
|
+
deparse_access_priv(node)
|
48
57
|
when ALIAS
|
49
58
|
deparse_alias(node)
|
50
59
|
when ALTER_TABLE_STMT
|
@@ -78,18 +87,32 @@ class PgQuery
|
|
78
87
|
deparse_case(node)
|
79
88
|
when COALESCE_EXPR
|
80
89
|
deparse_coalesce(node)
|
90
|
+
when COLLATE_CLAUSE
|
91
|
+
deparse_collate(node)
|
81
92
|
when COLUMN_DEF
|
82
93
|
deparse_columndef(node)
|
83
94
|
when COLUMN_REF
|
84
95
|
deparse_columnref(node)
|
85
96
|
when COMMON_TABLE_EXPR
|
86
97
|
deparse_cte(node)
|
98
|
+
when COMPOSITE_TYPE_STMT
|
99
|
+
deparse_composite_type(node)
|
87
100
|
when CONSTRAINT
|
88
101
|
deparse_constraint(node)
|
89
102
|
when COPY_STMT
|
90
103
|
deparse_copy(node)
|
104
|
+
when CREATE_CAST_STMT
|
105
|
+
deparse_create_cast(node)
|
106
|
+
when CREATE_DOMAIN_STMT
|
107
|
+
deparse_create_domain(node)
|
108
|
+
when CREATE_ENUM_STMT
|
109
|
+
deparse_create_enum(node)
|
91
110
|
when CREATE_FUNCTION_STMT
|
92
111
|
deparse_create_function(node)
|
112
|
+
when CREATE_RANGE_STMT
|
113
|
+
deparse_create_range(node)
|
114
|
+
when CREATE_SCHEMA_STMT
|
115
|
+
deparse_create_schema(node)
|
93
116
|
when CREATE_STMT
|
94
117
|
deparse_create_table(node)
|
95
118
|
when CREATE_TABLE_AS_STMT
|
@@ -98,16 +121,26 @@ class PgQuery
|
|
98
121
|
deparse_into_clause(node)
|
99
122
|
when DEF_ELEM
|
100
123
|
deparse_defelem(node)
|
124
|
+
when DEFINE_STMT
|
125
|
+
deparse_define_stmt(node)
|
101
126
|
when DELETE_STMT
|
102
127
|
deparse_delete_from(node)
|
128
|
+
when DISCARD_STMT
|
129
|
+
deparse_discard(node)
|
103
130
|
when DROP_STMT
|
104
131
|
deparse_drop(node)
|
105
132
|
when EXPLAIN_STMT
|
106
133
|
deparse_explain(node)
|
134
|
+
when EXECUTE_STMT
|
135
|
+
deparse_execute(node)
|
107
136
|
when FUNC_CALL
|
108
137
|
deparse_funccall(node)
|
109
138
|
when FUNCTION_PARAMETER
|
110
139
|
deparse_functionparameter(node)
|
140
|
+
when GRANT_ROLE_STMT
|
141
|
+
deparse_grant_role(node)
|
142
|
+
when GRANT_STMT
|
143
|
+
deparse_grant(node)
|
111
144
|
when INSERT_STMT
|
112
145
|
deparse_insert_into(node)
|
113
146
|
when JOIN_EXPR
|
@@ -118,8 +151,12 @@ class PgQuery
|
|
118
151
|
deparse_lockingclause(node)
|
119
152
|
when NULL_TEST
|
120
153
|
deparse_nulltest(node)
|
154
|
+
when OBJECT_WITH_ARGS
|
155
|
+
deparse_object_with_args(node)
|
121
156
|
when PARAM_REF
|
122
157
|
deparse_paramref(node)
|
158
|
+
when PREPARE_STMT
|
159
|
+
deparse_prepare(node)
|
123
160
|
when RANGE_FUNCTION
|
124
161
|
deparse_range_function(node)
|
125
162
|
when RANGE_SUBSELECT
|
@@ -132,6 +169,8 @@ class PgQuery
|
|
132
169
|
deparse_renamestmt(node)
|
133
170
|
when RES_TARGET
|
134
171
|
deparse_restarget(node, context)
|
172
|
+
when ROLE_SPEC
|
173
|
+
deparse_role_spec(node)
|
135
174
|
when ROW_EXPR
|
136
175
|
deparse_row(node)
|
137
176
|
when SELECT_STMT
|
@@ -164,13 +203,15 @@ class PgQuery
|
|
164
203
|
deparse_vacuum_stmt(node)
|
165
204
|
when DO_STMT
|
166
205
|
deparse_do_stmt(node)
|
206
|
+
when SET_TO_DEFAULT
|
207
|
+
'DEFAULT'
|
167
208
|
when STRING
|
168
209
|
if context == A_CONST
|
169
210
|
format("'%s'", node['str'].gsub("'", "''"))
|
170
211
|
elsif [FUNC_CALL, TYPE_NAME, :operator, :defname_as].include?(context)
|
171
212
|
node['str']
|
172
213
|
else
|
173
|
-
|
214
|
+
deparse_identifier(node['str'], escape_always: true)
|
174
215
|
end
|
175
216
|
when INTEGER
|
176
217
|
node['ival'].to_s
|
@@ -187,6 +228,15 @@ class PgQuery
|
|
187
228
|
nodes.map { |n| deparse_item(n, context) }
|
188
229
|
end
|
189
230
|
|
231
|
+
def deparse_identifier(ident, escape_always: false)
|
232
|
+
return if ident.nil?
|
233
|
+
if escape_always || !ident[/^\w+$/] || KEYWORDS.include?(ident.upcase)
|
234
|
+
format('"%s"', ident.gsub('"', '""'))
|
235
|
+
else
|
236
|
+
ident
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
190
240
|
def deparse_rangevar(node)
|
191
241
|
output = []
|
192
242
|
output << 'ONLY' unless node['inh']
|
@@ -200,19 +250,32 @@ class PgQuery
|
|
200
250
|
deparse_item(node[STMT_FIELD])
|
201
251
|
end
|
202
252
|
|
203
|
-
def
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
253
|
+
def deparse_renamestmt_decision(node, type)
|
254
|
+
if node[type]
|
255
|
+
if node[type].is_a?(String)
|
256
|
+
deparse_identifier(node[type])
|
257
|
+
elsif node[type].is_a?(Array)
|
258
|
+
deparse_item_list(node[type])
|
259
|
+
elsif node[type].is_a?(Object)
|
260
|
+
deparse_item(node[type])
|
261
|
+
end
|
212
262
|
else
|
213
|
-
|
263
|
+
type
|
214
264
|
end
|
265
|
+
end
|
215
266
|
|
267
|
+
def deparse_renamestmt(node)
|
268
|
+
output = []
|
269
|
+
output << 'ALTER'
|
270
|
+
command, type, options, type2, options2 = Rename.commands(node)
|
271
|
+
|
272
|
+
output << command if command
|
273
|
+
output << deparse_renamestmt_decision(node, type)
|
274
|
+
output << options if options
|
275
|
+
output << deparse_renamestmt_decision(node, type2) if type2
|
276
|
+
output << deparse_renamestmt_decision(node, options2) if options2
|
277
|
+
output << 'TO'
|
278
|
+
output << deparse_identifier(node['newname'], escape_always: true)
|
216
279
|
output.join(' ')
|
217
280
|
end
|
218
281
|
|
@@ -223,7 +286,7 @@ class PgQuery
|
|
223
286
|
end
|
224
287
|
|
225
288
|
def deparse_a_arrayexp(node)
|
226
|
-
'ARRAY[' + node['elements'].map do |element|
|
289
|
+
'ARRAY[' + (node['elements'] || []).map do |element|
|
227
290
|
deparse_item(element)
|
228
291
|
end.join(', ') + ']'
|
229
292
|
end
|
@@ -237,7 +300,13 @@ class PgQuery
|
|
237
300
|
end
|
238
301
|
|
239
302
|
def deparse_a_indirection(node)
|
240
|
-
output = [
|
303
|
+
output = []
|
304
|
+
arg = deparse_item(node['arg'])
|
305
|
+
output << if node['arg'].key?(FUNC_CALL) || node['arg'].key?(SUB_LINK)
|
306
|
+
"(#{arg})."
|
307
|
+
else
|
308
|
+
arg
|
309
|
+
end
|
241
310
|
node['indirection'].each do |subnode|
|
242
311
|
output << deparse_item(subnode)
|
243
312
|
end
|
@@ -253,13 +322,16 @@ class PgQuery
|
|
253
322
|
if node['colnames']
|
254
323
|
name + '(' + deparse_item_list(node['colnames']).join(', ') + ')'
|
255
324
|
else
|
256
|
-
name
|
325
|
+
deparse_identifier(name)
|
257
326
|
end
|
258
327
|
end
|
259
328
|
|
260
329
|
def deparse_alter_table(node)
|
261
330
|
output = []
|
262
|
-
output << 'ALTER
|
331
|
+
output << 'ALTER'
|
332
|
+
|
333
|
+
output << 'TABLE' if node['relkind'] == OBJECT_TYPE_TABLE
|
334
|
+
output << 'VIEW' if node['relkind'] == OBJECT_TYPE_VIEW
|
263
335
|
|
264
336
|
output << deparse_item(node['relation'])
|
265
337
|
|
@@ -284,6 +356,16 @@ class PgQuery
|
|
284
356
|
output.compact.join(' ')
|
285
357
|
end
|
286
358
|
|
359
|
+
def deparse_object_with_args(node)
|
360
|
+
output = []
|
361
|
+
output += node['objname'].map(&method(:deparse_item))
|
362
|
+
unless node['args_unspecified']
|
363
|
+
args = node.fetch('objargs', []).map(&method(:deparse_item)).join(', ')
|
364
|
+
output << "(#{args})"
|
365
|
+
end
|
366
|
+
output.join('')
|
367
|
+
end
|
368
|
+
|
287
369
|
def deparse_paramref(node)
|
288
370
|
if node['number'].nil?
|
289
371
|
'?'
|
@@ -292,9 +374,18 @@ class PgQuery
|
|
292
374
|
end
|
293
375
|
end
|
294
376
|
|
377
|
+
def deparse_prepare(node)
|
378
|
+
output = ['PREPARE']
|
379
|
+
output << deparse_identifier(node['name'])
|
380
|
+
output << "(#{deparse_item_list(node['argtypes']).join(', ')})" if node['argtypes']
|
381
|
+
output << 'AS'
|
382
|
+
output << deparse_item(node['query'])
|
383
|
+
output.join(' ')
|
384
|
+
end
|
385
|
+
|
295
386
|
def deparse_restarget(node, context)
|
296
387
|
if context == :select
|
297
|
-
[deparse_item(node['val']), node['name']].compact.join(' AS ')
|
388
|
+
[deparse_item(node['val']), deparse_identifier(node['name'])].compact.join(' AS ')
|
298
389
|
elsif context == :update
|
299
390
|
[node['name'], deparse_item(node['val'])].compact.join(' = ')
|
300
391
|
elsif node['val'].nil?
|
@@ -315,12 +406,14 @@ class PgQuery
|
|
315
406
|
name = (node['funcname'].map { |n| deparse_item(n, FUNC_CALL) } - ['pg_catalog']).join('.')
|
316
407
|
distinct = node['agg_distinct'] ? 'DISTINCT ' : ''
|
317
408
|
output << format('%s(%s%s)', name, distinct, args.join(', '))
|
318
|
-
output << format('OVER
|
409
|
+
output << format('OVER %s', deparse_item(node['over'])) if node['over']
|
319
410
|
|
320
411
|
output.join(' ')
|
321
412
|
end
|
322
413
|
|
323
414
|
def deparse_windowdef(node)
|
415
|
+
return deparse_identifier(node['name']) if node['name']
|
416
|
+
|
324
417
|
output = []
|
325
418
|
|
326
419
|
if node['partitionClause']
|
@@ -337,13 +430,84 @@ class PgQuery
|
|
337
430
|
end.join(', ')
|
338
431
|
end
|
339
432
|
|
340
|
-
output.join(' ')
|
433
|
+
format('(%s)', output.join(' '))
|
341
434
|
end
|
342
435
|
|
343
436
|
def deparse_functionparameter(node)
|
344
437
|
deparse_item(node['argType'])
|
345
438
|
end
|
346
439
|
|
440
|
+
def deparse_grant_role(node)
|
441
|
+
output = []
|
442
|
+
output << ['GRANT'] if node['is_grant']
|
443
|
+
output << ['REVOKE'] unless node['is_grant']
|
444
|
+
output << node['granted_roles'].map(&method(:deparse_item)).join(', ')
|
445
|
+
output << ['TO'] if node['is_grant']
|
446
|
+
output << ['FROM'] unless node['is_grant']
|
447
|
+
output << node['grantee_roles'].map(&method(:deparse_item)).join(', ')
|
448
|
+
output << 'WITH ADMIN OPTION' if node['admin_opt']
|
449
|
+
output.join(' ')
|
450
|
+
end
|
451
|
+
|
452
|
+
def deparse_grant(node) # rubocop:disable Metrics/CyclomaticComplexity
|
453
|
+
objtype, allow_all = deparse_grant_objtype(node)
|
454
|
+
output = []
|
455
|
+
output << ['GRANT'] if node['is_grant']
|
456
|
+
output << ['REVOKE'] unless node['is_grant']
|
457
|
+
output << if node.key?('privileges')
|
458
|
+
node['privileges'].map(&method(:deparse_item)).join(', ')
|
459
|
+
else
|
460
|
+
'ALL'
|
461
|
+
end
|
462
|
+
output << 'ON'
|
463
|
+
objects = node['objects']
|
464
|
+
objects = objects[0] if %w[DOMAIN TYPE].include?(objtype)
|
465
|
+
objects = objects.map do |object|
|
466
|
+
deparsed = deparse_item(object)
|
467
|
+
if object.key?(RANGE_VAR) || object.key?(OBJECT_WITH_ARGS) || !allow_all
|
468
|
+
objtype == 'TABLE' ? deparsed : "#{objtype} #{deparsed}"
|
469
|
+
else
|
470
|
+
"ALL #{objtype}S IN SCHEMA #{deparsed}"
|
471
|
+
end
|
472
|
+
end
|
473
|
+
output << objects.join(', ')
|
474
|
+
output << ['TO'] if node['is_grant']
|
475
|
+
output << ['FROM'] unless node['is_grant']
|
476
|
+
output << node['grantees'].map(&method(:deparse_item)).join(', ')
|
477
|
+
output << 'WITH GRANT OPTION' if node['grant_option']
|
478
|
+
output.join(' ')
|
479
|
+
end
|
480
|
+
|
481
|
+
def deparse_grant_objtype(node)
|
482
|
+
{
|
483
|
+
1 => ['TABLE', true],
|
484
|
+
2 => ['SEQUENCE', true],
|
485
|
+
3 => ['DATABASE', false],
|
486
|
+
4 => ['DOMAIN', false],
|
487
|
+
5 => ['FOREIGN DATA WRAPPER', false],
|
488
|
+
6 => ['FOREIGN SERVER', false],
|
489
|
+
7 => ['FUNCTION', true],
|
490
|
+
8 => ['LANGUAGE', false],
|
491
|
+
9 => ['LARGE OBJECT', false],
|
492
|
+
10 => ['SCHEMA', false],
|
493
|
+
11 => ['TABLESPACE', false],
|
494
|
+
12 => ['TYPE', false]
|
495
|
+
}.fetch(node['objtype'])
|
496
|
+
end
|
497
|
+
|
498
|
+
def deparse_access_priv(node)
|
499
|
+
output = [node['priv_name']]
|
500
|
+
output << "(#{node['cols'].map(&method(:deparse_item)).join(', ')})" if node.key?('cols')
|
501
|
+
output.join(' ')
|
502
|
+
end
|
503
|
+
|
504
|
+
def deparse_role_spec(node)
|
505
|
+
return 'CURRENT_USER' if node['roletype'] == 1
|
506
|
+
return 'SESSION_USER' if node['roletype'] == 2
|
507
|
+
return 'PUBLIC' if node['roletype'] == 3
|
508
|
+
deparse_identifier(node['rolename'], escape_always: true)
|
509
|
+
end
|
510
|
+
|
347
511
|
def deparse_aexpr_in(node)
|
348
512
|
rexpr = Array(node['rexpr']).map { |arg| deparse_item(arg) }
|
349
513
|
operator = node['name'].map { |n| deparse_item(n, :operator) } == ['='] ? 'IN' : 'NOT IN'
|
@@ -356,6 +520,12 @@ class PgQuery
|
|
356
520
|
format('%s %s %s', deparse_item(node['lexpr']), operator, value)
|
357
521
|
end
|
358
522
|
|
523
|
+
def deparse_aexpr_ilike(node)
|
524
|
+
value = deparse_item(node['rexpr'])
|
525
|
+
operator = node['name'][0]['String']['str'] == '~~*' ? 'ILIKE' : 'NOT ILIKE'
|
526
|
+
format('%s %s %s', deparse_item(node['lexpr']), operator, value)
|
527
|
+
end
|
528
|
+
|
359
529
|
def deparse_bool_expr_not(node)
|
360
530
|
format('NOT %s', deparse_item(node['args'][0]))
|
361
531
|
end
|
@@ -422,6 +592,13 @@ class PgQuery
|
|
422
592
|
output.join(' ' + deparse_item(node['name'][0], :operator) + ' ')
|
423
593
|
end
|
424
594
|
|
595
|
+
def deparse_aexpr_all(node)
|
596
|
+
output = []
|
597
|
+
output << deparse_item(node['lexpr'])
|
598
|
+
output << format('ALL(%s)', deparse_item(node['rexpr']))
|
599
|
+
output.join(' ' + deparse_item(node['name'][0], :operator) + ' ')
|
600
|
+
end
|
601
|
+
|
425
602
|
def deparse_aexpr_between(node)
|
426
603
|
between = case node['kind']
|
427
604
|
when AEXPR_BETWEEN
|
@@ -510,6 +687,14 @@ class PgQuery
|
|
510
687
|
output.join(' ')
|
511
688
|
end
|
512
689
|
|
690
|
+
def deparse_collate(node)
|
691
|
+
output = []
|
692
|
+
output << deparse_item(node['arg'])
|
693
|
+
output << 'COLLATE'
|
694
|
+
output << deparse_item_list(node['collname'])
|
695
|
+
output.join(' ')
|
696
|
+
end
|
697
|
+
|
513
698
|
def deparse_with_clause(node)
|
514
699
|
output = ['WITH']
|
515
700
|
output << 'RECURSIVE' if node['recursive']
|
@@ -614,9 +799,22 @@ class PgQuery
|
|
614
799
|
deparse_item(item)
|
615
800
|
end
|
616
801
|
end
|
802
|
+
if node['collClause']
|
803
|
+
output << 'COLLATE'
|
804
|
+
output += node['collClause']['CollateClause']['collname'].map(&method(:deparse_item))
|
805
|
+
end
|
617
806
|
output.compact.join(' ')
|
618
807
|
end
|
619
808
|
|
809
|
+
def deparse_composite_type(node)
|
810
|
+
output = ['CREATE TYPE']
|
811
|
+
output << deparse_rangevar(node['typevar'][RANGE_VAR].merge('inh' => true))
|
812
|
+
output << 'AS'
|
813
|
+
coldeflist = node['coldeflist'].map(&method(:deparse_item))
|
814
|
+
output << "(#{coldeflist.join(', ')})"
|
815
|
+
output.join(' ')
|
816
|
+
end
|
817
|
+
|
620
818
|
def deparse_constraint(node) # rubocop:disable Metrics/CyclomaticComplexity
|
621
819
|
output = []
|
622
820
|
if node['conname']
|
@@ -645,6 +843,7 @@ class PgQuery
|
|
645
843
|
if node['raw_expr']
|
646
844
|
expression = deparse_item(node['raw_expr'])
|
647
845
|
# Unless it's simple, put parentheses around it
|
846
|
+
expression = '(' + expression + ')' if node['raw_expr'][BOOL_EXPR]
|
648
847
|
expression = '(' + expression + ')' if node['raw_expr'][A_EXPR] && node['raw_expr'][A_EXPR]['kind'] == AEXPR_OP
|
649
848
|
output << expression
|
650
849
|
end
|
@@ -658,16 +857,63 @@ class PgQuery
|
|
658
857
|
|
659
858
|
def deparse_copy(node)
|
660
859
|
output = ['COPY']
|
661
|
-
|
860
|
+
if node.key?('relation')
|
861
|
+
output << deparse_item(node['relation'])
|
862
|
+
elsif node.key?('query')
|
863
|
+
output << "(#{deparse_item(node['query'])})"
|
864
|
+
end
|
662
865
|
columns = node.fetch('attlist', []).map { |column| deparse_item(column) }
|
663
866
|
output << "(#{columns.join(', ')})" unless columns.empty?
|
664
867
|
output << (node['is_from'] ? 'FROM' : 'TO')
|
665
868
|
output << 'PROGRAM' if node['is_program']
|
666
|
-
output <<
|
667
|
-
|
869
|
+
output << deparse_copy_output(node)
|
870
|
+
output.join(' ')
|
871
|
+
end
|
872
|
+
|
873
|
+
def deparse_copy_output(node)
|
874
|
+
return "'#{node['filename']}'" if node.key?('filename')
|
875
|
+
return 'STDIN' if node['is_from']
|
876
|
+
'STDOUT'
|
877
|
+
end
|
878
|
+
|
879
|
+
def deparse_create_enum(node)
|
880
|
+
output = ['CREATE TYPE']
|
881
|
+
output << deparse_item(node['typeName'][0])
|
882
|
+
output << 'AS ENUM'
|
883
|
+
vals = node['vals'].map { |val| deparse_item(val, A_CONST) }
|
884
|
+
output << "(#{vals.join(', ')})"
|
885
|
+
output.join(' ')
|
886
|
+
end
|
887
|
+
|
888
|
+
def deparse_create_cast(node)
|
889
|
+
output = []
|
890
|
+
output << 'CREATE'
|
891
|
+
output << 'CAST'
|
892
|
+
output << format('(%s AS %s)', deparse_item(node['sourcetype']), deparse_item(node['targettype']))
|
893
|
+
output << if node['func']
|
894
|
+
function = node['func']['ObjectWithArgs']
|
895
|
+
name = deparse_item_list(function['objname']).join('.')
|
896
|
+
arguments = deparse_item_list(function['objargs']).join(', ')
|
897
|
+
format('WITH FUNCTION %s(%s)', name, arguments)
|
898
|
+
elsif node['inout']
|
899
|
+
'WITH INOUT'
|
668
900
|
else
|
669
|
-
|
901
|
+
'WITHOUT FUNCTION'
|
670
902
|
end
|
903
|
+
output << 'AS IMPLICIT' if (node['context']).zero?
|
904
|
+
output << 'AS ASSIGNMENT' if node['context'] == 1
|
905
|
+
output.join(' ')
|
906
|
+
end
|
907
|
+
|
908
|
+
def deparse_create_domain(node)
|
909
|
+
output = []
|
910
|
+
output << 'CREATE'
|
911
|
+
output << 'DOMAIN'
|
912
|
+
output << deparse_item_list(node['domainname']).join('.')
|
913
|
+
output << 'AS'
|
914
|
+
output << deparse_item(node['typeName']) if node['typeName']
|
915
|
+
output << deparse_item(node['collClause']) if node['collClause']
|
916
|
+
output << deparse_item_list(node['constraints'])
|
671
917
|
output.join(' ')
|
672
918
|
end
|
673
919
|
|
@@ -677,7 +923,7 @@ class PgQuery
|
|
677
923
|
output << 'OR REPLACE' if node['replace']
|
678
924
|
output << 'FUNCTION'
|
679
925
|
|
680
|
-
arguments = deparse_item_list(node
|
926
|
+
arguments = deparse_item_list(node.fetch('parameters', [])).join(', ')
|
681
927
|
|
682
928
|
output << deparse_item_list(node['funcname']).join('.') + '(' + arguments + ')'
|
683
929
|
|
@@ -688,6 +934,30 @@ class PgQuery
|
|
688
934
|
output.join(' ')
|
689
935
|
end
|
690
936
|
|
937
|
+
def deparse_create_range(node)
|
938
|
+
output = ['CREATE TYPE']
|
939
|
+
output << deparse_item(node['typeName'][0])
|
940
|
+
output << 'AS RANGE'
|
941
|
+
params = node['params'].map do |param|
|
942
|
+
param_out = [param['DefElem']['defname']]
|
943
|
+
if param['DefElem'].key?('arg')
|
944
|
+
param_out << deparse_item(param['DefElem']['arg'])
|
945
|
+
end
|
946
|
+
param_out.join('=')
|
947
|
+
end
|
948
|
+
output << "(#{params.join(', ')})"
|
949
|
+
output.join(' ')
|
950
|
+
end
|
951
|
+
|
952
|
+
def deparse_create_schema(node)
|
953
|
+
output = ['CREATE SCHEMA']
|
954
|
+
output << 'IF NOT EXISTS' if node['if_not_exists']
|
955
|
+
output << deparse_identifier(node['schemaname']) if node.key?('schemaname')
|
956
|
+
output << format('AUTHORIZATION %s', deparse_item(node['authrole'])) if node.key?('authrole')
|
957
|
+
output << deparse_item_list(node['schemaElts']) if node.key?('schemaElts')
|
958
|
+
output.join(' ')
|
959
|
+
end
|
960
|
+
|
691
961
|
def deparse_create_table(node)
|
692
962
|
output = []
|
693
963
|
output << 'CREATE'
|
@@ -724,6 +994,13 @@ class PgQuery
|
|
724
994
|
output.join(' ')
|
725
995
|
end
|
726
996
|
|
997
|
+
def deparse_execute(node)
|
998
|
+
output = ['EXECUTE']
|
999
|
+
output << deparse_identifier(node['name'])
|
1000
|
+
output << "(#{deparse_item_list(node['params']).join(', ')})" if node['params']
|
1001
|
+
output.join(' ')
|
1002
|
+
end
|
1003
|
+
|
727
1004
|
def deparse_into_clause(node)
|
728
1005
|
deparse_item(node['rel'])
|
729
1006
|
end
|
@@ -739,6 +1016,8 @@ class PgQuery
|
|
739
1016
|
def deparse_sublink(node)
|
740
1017
|
if node['subLinkType'] == SUBLINK_TYPE_ANY
|
741
1018
|
format('%s IN (%s)', deparse_item(node['testexpr']), deparse_item(node['subselect']))
|
1019
|
+
elsif node['subLinkType'] == SUBLINK_TYPE_ALL
|
1020
|
+
format('%s %s ALL (%s)', deparse_item(node['testexpr']), deparse_item(node['operName'][0], :operator), deparse_item(node['subselect']))
|
742
1021
|
elsif node['subLinkType'] == SUBLINK_TYPE_EXISTS
|
743
1022
|
format('EXISTS(%s)', deparse_item(node['subselect']))
|
744
1023
|
else
|
@@ -762,15 +1041,22 @@ class PgQuery
|
|
762
1041
|
def deparse_select(node) # rubocop:disable Metrics/CyclomaticComplexity
|
763
1042
|
output = []
|
764
1043
|
|
1044
|
+
output << deparse_item(node['withClause']) if node['withClause']
|
1045
|
+
|
765
1046
|
if node['op'] == 1
|
766
1047
|
output << deparse_item(node['larg'])
|
767
1048
|
output << 'UNION'
|
768
1049
|
output << 'ALL' if node['all']
|
769
1050
|
output << deparse_item(node['rarg'])
|
770
|
-
|
1051
|
+
output.join(' ')
|
771
1052
|
end
|
772
1053
|
|
773
|
-
|
1054
|
+
if node['op'] == 3
|
1055
|
+
output << deparse_item(node['larg'])
|
1056
|
+
output << 'EXCEPT'
|
1057
|
+
output << deparse_item(node['rarg'])
|
1058
|
+
output.join(' ')
|
1059
|
+
end
|
774
1060
|
|
775
1061
|
if node[TARGET_LIST_FIELD]
|
776
1062
|
output << 'SELECT'
|
@@ -784,6 +1070,11 @@ class PgQuery
|
|
784
1070
|
output << node[TARGET_LIST_FIELD].map do |item|
|
785
1071
|
deparse_item(item, :select)
|
786
1072
|
end.join(', ')
|
1073
|
+
|
1074
|
+
if node['intoClause']
|
1075
|
+
output << 'INTO'
|
1076
|
+
output << deparse_item(node['intoClause'])
|
1077
|
+
end
|
787
1078
|
end
|
788
1079
|
|
789
1080
|
if node[FROM_CLAUSE_FIELD]
|
@@ -882,6 +1173,13 @@ class PgQuery
|
|
882
1173
|
|
883
1174
|
output << deparse_item(node['selectStmt'])
|
884
1175
|
|
1176
|
+
if node['returningList']
|
1177
|
+
output << 'RETURNING'
|
1178
|
+
output << node['returningList'].map do |column|
|
1179
|
+
deparse_item(column, :select)
|
1180
|
+
end.join(', ')
|
1181
|
+
end
|
1182
|
+
|
885
1183
|
output.join(' ')
|
886
1184
|
end
|
887
1185
|
|
@@ -920,7 +1218,8 @@ class PgQuery
|
|
920
1218
|
if deparse_item(node['typeName']) == 'boolean'
|
921
1219
|
deparse_item(node['arg']) == "'t'" ? 'true' : 'false'
|
922
1220
|
else
|
923
|
-
|
1221
|
+
context = true if node['arg']['A_Expr']
|
1222
|
+
deparse_item(node['arg'], context) + '::' + deparse_typename(node['typeName'][TYPE_NAME])
|
924
1223
|
end
|
925
1224
|
end
|
926
1225
|
|
@@ -950,7 +1249,7 @@ class PgQuery
|
|
950
1249
|
# Just pass along any custom types.
|
951
1250
|
# (The pg_catalog types are built-in Postgres system types and are
|
952
1251
|
# handled in the case statement below)
|
953
|
-
return names.join('.') if catalog != 'pg_catalog'
|
1252
|
+
return names.join('.') + (arguments.nil? ? '' : "(#{arguments})") if catalog != 'pg_catalog'
|
954
1253
|
|
955
1254
|
case type
|
956
1255
|
when 'bpchar'
|
@@ -972,7 +1271,7 @@ class PgQuery
|
|
972
1271
|
when 'real', 'float4'
|
973
1272
|
'real'
|
974
1273
|
when 'float8'
|
975
|
-
'double'
|
1274
|
+
'double precision'
|
976
1275
|
when 'time'
|
977
1276
|
'time'
|
978
1277
|
when 'timetz'
|
@@ -1055,6 +1354,57 @@ class PgQuery
|
|
1055
1354
|
end
|
1056
1355
|
end
|
1057
1356
|
|
1357
|
+
def deparse_define_stmt(node)
|
1358
|
+
dispatch = {
|
1359
|
+
1 => :deparse_create_aggregate,
|
1360
|
+
25 => :deparse_create_operator,
|
1361
|
+
45 => :deparse_create_type
|
1362
|
+
}
|
1363
|
+
method(dispatch.fetch(node['kind'])).call(node)
|
1364
|
+
end
|
1365
|
+
|
1366
|
+
def deparse_create_aggregate(node)
|
1367
|
+
output = ['CREATE AGGREGATE']
|
1368
|
+
output << node['defnames'].map(&method(:deparse_item))
|
1369
|
+
args = node['args'][0] || [{ A_STAR => nil }]
|
1370
|
+
output << "(#{args.map(&method(:deparse_item)).join(', ')})"
|
1371
|
+
definitions = node['definition'].map do |definition|
|
1372
|
+
definition_output = [definition['DefElem']['defname']]
|
1373
|
+
definition_output << definition['DefElem']['arg']['TypeName']['names'].map(&method(:deparse_item)).join(', ') if definition['DefElem'].key?('arg')
|
1374
|
+
definition_output.join('=')
|
1375
|
+
end
|
1376
|
+
output << "(#{definitions.join(', ')})"
|
1377
|
+
output.join(' ')
|
1378
|
+
end
|
1379
|
+
|
1380
|
+
def deparse_create_operator(node)
|
1381
|
+
output = ['CREATE OPERATOR']
|
1382
|
+
output << node['defnames'][0]['String']['str']
|
1383
|
+
definitions = node['definition'].map do |definition|
|
1384
|
+
definition_output = [definition['DefElem']['defname']]
|
1385
|
+
definition_output << definition['DefElem']['arg']['TypeName']['names'].map(&method(:deparse_item)).join(', ') if definition['DefElem'].key?('arg')
|
1386
|
+
definition_output.join('=')
|
1387
|
+
end
|
1388
|
+
output << "(#{definitions.join(', ')})"
|
1389
|
+
output.join(' ')
|
1390
|
+
end
|
1391
|
+
|
1392
|
+
def deparse_create_type(node)
|
1393
|
+
output = ['CREATE TYPE']
|
1394
|
+
output << node['defnames'].map(&method(:deparse_item))
|
1395
|
+
if node.key?('definition')
|
1396
|
+
definitions = node['definition'].map do |definition|
|
1397
|
+
definition_output = [definition['DefElem']['defname']]
|
1398
|
+
if definition['DefElem'].key?('arg')
|
1399
|
+
definition_output += definition['DefElem']['arg']['TypeName']['names'].map(&method(:deparse_item))
|
1400
|
+
end
|
1401
|
+
definition_output.join('=')
|
1402
|
+
end
|
1403
|
+
output << "(#{definitions.join(', ')})"
|
1404
|
+
end
|
1405
|
+
output.join(' ')
|
1406
|
+
end
|
1407
|
+
|
1058
1408
|
def deparse_delete_from(node)
|
1059
1409
|
output = []
|
1060
1410
|
output << deparse_item(node['withClause']) if node['withClause']
|
@@ -1085,13 +1435,25 @@ class PgQuery
|
|
1085
1435
|
output.join(' ')
|
1086
1436
|
end
|
1087
1437
|
|
1088
|
-
def
|
1438
|
+
def deparse_discard(node)
|
1439
|
+
output = ['DISCARD']
|
1440
|
+
output << 'ALL' if (node['target']).zero?
|
1441
|
+
output << 'PLANS' if node['target'] == 1
|
1442
|
+
output << 'SEQUENCES' if node['target'] == 2
|
1443
|
+
output << 'TEMP' if node['target'] == 3
|
1444
|
+
output.join(' ')
|
1445
|
+
end
|
1446
|
+
|
1447
|
+
def deparse_drop(node) # rubocop:disable Metrics/CyclomaticComplexity
|
1089
1448
|
output = ['DROP']
|
1090
1449
|
output << 'TABLE' if node['removeType'] == OBJECT_TYPE_TABLE
|
1450
|
+
output << 'SCHEMA' if node['removeType'] == OBJECT_TYPE_SCHEMA
|
1091
1451
|
output << 'CONCURRENTLY' if node['concurrent']
|
1092
1452
|
output << 'IF EXISTS' if node['missing_ok']
|
1093
1453
|
|
1094
|
-
|
1454
|
+
objects = node['objects']
|
1455
|
+
objects = [objects] unless objects[0].is_a?(Array)
|
1456
|
+
output << objects.map { |list| list.map { |object| deparse_item(object) } }.join(', ')
|
1095
1457
|
|
1096
1458
|
output << 'CASCADE' if node['behavior'] == 1
|
1097
1459
|
|