pg_query 1.1.0 → 1.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|