pg_query 1.0.2 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (107) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +162 -40
  3. data/README.md +80 -69
  4. data/Rakefile +85 -4
  5. data/ext/pg_query/extconf.rb +4 -32
  6. data/ext/pg_query/guc-file.c +0 -0
  7. data/ext/pg_query/pg_query.c +104 -0
  8. data/ext/pg_query/pg_query.pb-c.c +37628 -0
  9. data/ext/pg_query/pg_query_deparse.c +9953 -0
  10. data/ext/pg_query/pg_query_fingerprint.c +292 -0
  11. data/ext/pg_query/pg_query_fingerprint.h +8 -0
  12. data/ext/pg_query/pg_query_internal.h +24 -0
  13. data/ext/pg_query/pg_query_json_plpgsql.c +738 -0
  14. data/ext/pg_query/pg_query_json_plpgsql.h +9 -0
  15. data/ext/pg_query/pg_query_normalize.c +437 -0
  16. data/ext/pg_query/pg_query_outfuncs.h +10 -0
  17. data/ext/pg_query/pg_query_outfuncs_json.c +297 -0
  18. data/ext/pg_query/pg_query_outfuncs_protobuf.c +237 -0
  19. data/ext/pg_query/pg_query_parse.c +148 -0
  20. data/ext/pg_query/pg_query_parse_plpgsql.c +460 -0
  21. data/ext/pg_query/pg_query_readfuncs.h +11 -0
  22. data/ext/pg_query/pg_query_readfuncs_protobuf.c +142 -0
  23. data/ext/pg_query/pg_query_ruby.c +108 -12
  24. data/ext/pg_query/pg_query_scan.c +173 -0
  25. data/ext/pg_query/pg_query_split.c +221 -0
  26. data/ext/pg_query/protobuf-c.c +3660 -0
  27. data/ext/pg_query/src_backend_catalog_namespace.c +1051 -0
  28. data/ext/pg_query/src_backend_catalog_pg_proc.c +142 -0
  29. data/ext/pg_query/src_backend_commands_define.c +117 -0
  30. data/ext/pg_query/src_backend_libpq_pqcomm.c +651 -0
  31. data/ext/pg_query/src_backend_nodes_bitmapset.c +513 -0
  32. data/ext/pg_query/src_backend_nodes_copyfuncs.c +6013 -0
  33. data/ext/pg_query/src_backend_nodes_equalfuncs.c +4003 -0
  34. data/ext/pg_query/src_backend_nodes_extensible.c +99 -0
  35. data/ext/pg_query/src_backend_nodes_list.c +922 -0
  36. data/ext/pg_query/src_backend_nodes_makefuncs.c +417 -0
  37. data/ext/pg_query/src_backend_nodes_nodeFuncs.c +1363 -0
  38. data/ext/pg_query/src_backend_nodes_value.c +84 -0
  39. data/ext/pg_query/src_backend_parser_gram.c +47456 -0
  40. data/ext/pg_query/src_backend_parser_parse_expr.c +313 -0
  41. data/ext/pg_query/src_backend_parser_parser.c +497 -0
  42. data/ext/pg_query/src_backend_parser_scan.c +7091 -0
  43. data/ext/pg_query/src_backend_parser_scansup.c +160 -0
  44. data/ext/pg_query/src_backend_postmaster_postmaster.c +2230 -0
  45. data/ext/pg_query/src_backend_storage_ipc_ipc.c +192 -0
  46. data/ext/pg_query/src_backend_storage_lmgr_s_lock.c +370 -0
  47. data/ext/pg_query/src_backend_tcop_postgres.c +776 -0
  48. data/ext/pg_query/src_backend_utils_adt_datum.c +326 -0
  49. data/ext/pg_query/src_backend_utils_adt_expandeddatum.c +98 -0
  50. data/ext/pg_query/src_backend_utils_adt_format_type.c +136 -0
  51. data/ext/pg_query/src_backend_utils_adt_ruleutils.c +1683 -0
  52. data/ext/pg_query/src_backend_utils_error_assert.c +74 -0
  53. data/ext/pg_query/src_backend_utils_error_elog.c +1748 -0
  54. data/ext/pg_query/src_backend_utils_fmgr_fmgr.c +570 -0
  55. data/ext/pg_query/src_backend_utils_hash_dynahash.c +1086 -0
  56. data/ext/pg_query/src_backend_utils_init_globals.c +168 -0
  57. data/ext/pg_query/src_backend_utils_mb_mbutils.c +839 -0
  58. data/ext/pg_query/src_backend_utils_misc_guc.c +1831 -0
  59. data/ext/pg_query/src_backend_utils_mmgr_aset.c +1560 -0
  60. data/ext/pg_query/src_backend_utils_mmgr_mcxt.c +1006 -0
  61. data/ext/pg_query/src_common_encnames.c +158 -0
  62. data/ext/pg_query/src_common_keywords.c +39 -0
  63. data/ext/pg_query/src_common_kwlist_d.h +1081 -0
  64. data/ext/pg_query/src_common_kwlookup.c +91 -0
  65. data/ext/pg_query/src_common_psprintf.c +158 -0
  66. data/ext/pg_query/src_common_string.c +86 -0
  67. data/ext/pg_query/src_common_stringinfo.c +336 -0
  68. data/ext/pg_query/src_common_wchar.c +1651 -0
  69. data/ext/pg_query/src_pl_plpgsql_src_pl_comp.c +1133 -0
  70. data/ext/pg_query/src_pl_plpgsql_src_pl_funcs.c +877 -0
  71. data/ext/pg_query/src_pl_plpgsql_src_pl_gram.c +6533 -0
  72. data/ext/pg_query/src_pl_plpgsql_src_pl_handler.c +107 -0
  73. data/ext/pg_query/src_pl_plpgsql_src_pl_reserved_kwlist_d.h +123 -0
  74. data/ext/pg_query/src_pl_plpgsql_src_pl_scanner.c +671 -0
  75. data/ext/pg_query/src_pl_plpgsql_src_pl_unreserved_kwlist_d.h +255 -0
  76. data/ext/pg_query/src_port_erand48.c +127 -0
  77. data/ext/pg_query/src_port_pg_bitutils.c +246 -0
  78. data/ext/pg_query/src_port_pgsleep.c +69 -0
  79. data/ext/pg_query/src_port_pgstrcasecmp.c +83 -0
  80. data/ext/pg_query/src_port_qsort.c +240 -0
  81. data/ext/pg_query/src_port_random.c +31 -0
  82. data/ext/pg_query/src_port_snprintf.c +1449 -0
  83. data/ext/pg_query/src_port_strerror.c +324 -0
  84. data/ext/pg_query/src_port_strnlen.c +39 -0
  85. data/ext/pg_query/xxhash.c +43 -0
  86. data/lib/pg_query.rb +7 -4
  87. data/lib/pg_query/constants.rb +21 -0
  88. data/lib/pg_query/deparse.rb +16 -991
  89. data/lib/pg_query/filter_columns.rb +86 -85
  90. data/lib/pg_query/fingerprint.rb +122 -87
  91. data/lib/pg_query/json_field_names.rb +1402 -0
  92. data/lib/pg_query/node.rb +31 -0
  93. data/lib/pg_query/param_refs.rb +42 -37
  94. data/lib/pg_query/parse.rb +220 -200
  95. data/lib/pg_query/parse_error.rb +1 -1
  96. data/lib/pg_query/pg_query_pb.rb +3211 -0
  97. data/lib/pg_query/scan.rb +23 -0
  98. data/lib/pg_query/treewalker.rb +24 -40
  99. data/lib/pg_query/truncate.rb +64 -43
  100. data/lib/pg_query/version.rb +2 -2
  101. metadata +102 -11
  102. data/ext/pg_query/pg_query_ruby.h +0 -10
  103. data/lib/pg_query/deep_dup.rb +0 -16
  104. data/lib/pg_query/deparse/alter_table.rb +0 -42
  105. data/lib/pg_query/deparse/interval.rb +0 -105
  106. data/lib/pg_query/legacy_parsetree.rb +0 -109
  107. data/lib/pg_query/node_types.rb +0 -282
@@ -1,997 +1,22 @@
1
- require_relative 'deparse/interval'
2
- require_relative 'deparse/alter_table'
3
- class PgQuery
4
- # Reconstruct all of the parsed queries into their original form
5
- def deparse(tree = @tree)
6
- tree.map do |item|
7
- Deparse.from(item)
8
- end.join('; ')
9
- end
10
-
11
- # rubocop:disable Metrics/ModuleLength
12
- module Deparse
13
- extend self
14
-
15
- # Given one element of the PgQuery#parsetree reconstruct it back into the
16
- # original query.
17
- def from(item)
18
- deparse_item(item)
19
- end
20
-
21
- private
22
-
23
- def deparse_item(item, context = nil) # rubocop:disable Metrics/CyclomaticComplexity
24
- return if item.nil?
25
- return item if item.is_a?(Integer)
26
-
27
- type = item.keys[0]
28
- node = item.values[0]
29
-
30
- case type
31
- when A_EXPR
32
- case node['kind']
33
- when AEXPR_OP
34
- deparse_aexpr(node, context)
35
- when AEXPR_OP_ANY
36
- deparse_aexpr_any(node)
37
- when AEXPR_IN
38
- deparse_aexpr_in(node)
39
- when CONSTR_TYPE_FOREIGN
40
- deparse_aexpr_like(node)
41
- when AEXPR_BETWEEN, AEXPR_NOT_BETWEEN, AEXPR_BETWEEN_SYM, AEXPR_NOT_BETWEEN_SYM
42
- deparse_aexpr_between(node)
43
- when AEXPR_NULLIF
44
- deparse_aexpr_nullif(node)
45
- else
46
- raise format("Can't deparse: %s: %s", type, node.inspect)
47
- end
48
- when ALIAS
49
- deparse_alias(node)
50
- when ALTER_TABLE_STMT
51
- deparse_alter_table(node)
52
- when ALTER_TABLE_CMD
53
- deparse_alter_table_cmd(node)
54
- when A_ARRAY_EXPR
55
- deparse_a_arrayexp(node)
56
- when A_CONST
57
- deparse_a_const(node)
58
- when A_INDICES
59
- deparse_a_indices(node)
60
- when A_INDIRECTION
61
- deparse_a_indirection(node)
62
- when A_STAR
63
- deparse_a_star(node)
64
- when A_TRUNCATED
65
- '...' # pg_query internal
66
- when BOOL_EXPR
67
- case node['boolop']
68
- when BOOL_EXPR_AND
69
- deparse_bool_expr_and(node)
70
- when BOOL_EXPR_OR
71
- deparse_bool_expr_or(node)
72
- when BOOL_EXPR_NOT
73
- deparse_bool_expr_not(node)
74
- end
75
- when BOOLEAN_TEST
76
- deparse_boolean_test(node)
77
- when CASE_EXPR
78
- deparse_case(node)
79
- when COALESCE_EXPR
80
- deparse_coalesce(node)
81
- when COLUMN_DEF
82
- deparse_columndef(node)
83
- when COLUMN_REF
84
- deparse_columnref(node)
85
- when COMMON_TABLE_EXPR
86
- deparse_cte(node)
87
- when CONSTRAINT
88
- deparse_constraint(node)
89
- when CREATE_FUNCTION_STMT
90
- deparse_create_function(node)
91
- when CREATE_STMT
92
- deparse_create_table(node)
93
- when DEF_ELEM
94
- deparse_defelem(node)
95
- when DELETE_STMT
96
- deparse_delete_from(node)
97
- when DROP_STMT
98
- deparse_drop(node)
99
- when FUNC_CALL
100
- deparse_funccall(node)
101
- when FUNCTION_PARAMETER
102
- deparse_functionparameter(node)
103
- when INSERT_STMT
104
- deparse_insert_into(node)
105
- when JOIN_EXPR
106
- deparse_joinexpr(node)
107
- when LOCKING_CLAUSE
108
- deparse_lockingclause(node)
109
- when NULL_TEST
110
- deparse_nulltest(node)
111
- when PARAM_REF
112
- deparse_paramref(node)
113
- when RANGE_FUNCTION
114
- deparse_range_function(node)
115
- when RANGE_SUBSELECT
116
- deparse_rangesubselect(node)
117
- when RANGE_VAR
118
- deparse_rangevar(node)
119
- when RAW_STMT
120
- deparse_raw_stmt(node)
121
- when RENAME_STMT
122
- deparse_renamestmt(node)
123
- when RES_TARGET
124
- deparse_restarget(node, context)
125
- when ROW_EXPR
126
- deparse_row(node)
127
- when SELECT_STMT
128
- deparse_select(node)
129
- when SORT_BY
130
- deparse_sortby(node)
131
- when SUB_LINK
132
- deparse_sublink(node)
133
- when TRANSACTION_STMT
134
- deparse_transaction(node)
135
- when TYPE_CAST
136
- deparse_typecast(node)
137
- when TYPE_NAME
138
- deparse_typename(node)
139
- when UPDATE_STMT
140
- deparse_update(node)
141
- when CASE_WHEN
142
- deparse_when(node)
143
- when WINDOW_DEF
144
- deparse_windowdef(node)
145
- when WITH_CLAUSE
146
- deparse_with_clause(node)
147
- when VIEW_STMT
148
- deparse_viewstmt(node)
149
- when VARIABLE_SET_STMT
150
- deparse_variable_set_stmt(node)
151
- when STRING
152
- if context == A_CONST
153
- format("'%s'", node['str'].gsub("'", "''"))
154
- elsif [FUNC_CALL, TYPE_NAME, :operator, :defname_as].include?(context)
155
- node['str']
156
- else
157
- format('"%s"', node['str'].gsub('"', '""'))
158
- end
159
- when INTEGER
160
- node['ival'].to_s
161
- when FLOAT
162
- node['str']
163
- when NULL
164
- 'NULL'
165
- else
166
- raise format("Can't deparse: %s: %s", type, node.inspect)
167
- end
168
- end
169
-
170
- def deparse_item_list(nodes, context = nil)
171
- nodes.map { |n| deparse_item(n, context) }
172
- end
173
-
174
- def deparse_rangevar(node)
175
- output = []
176
- output << 'ONLY' unless node['inh']
177
- schema = node['schemaname'] ? '"' + node['schemaname'] + '".' : ''
178
- output << schema + '"' + node['relname'] + '"'
179
- output << deparse_item(node['alias']) if node['alias']
180
- output.join(' ')
181
- end
182
-
183
- def deparse_raw_stmt(node)
184
- deparse_item(node[STMT_FIELD])
185
- end
186
-
187
- def deparse_renamestmt(node)
188
- output = []
189
-
190
- case node['renameType']
191
- when OBJECT_TYPE_TABLE
192
- output << 'ALTER TABLE'
193
- output << deparse_item(node['relation'])
194
- output << 'RENAME TO'
195
- output << node['newname']
196
- else
197
- raise format("Can't deparse: %s", node.inspect)
198
- end
199
-
200
- output.join(' ')
201
- end
202
-
203
- def deparse_columnref(node)
204
- node['fields'].map do |field|
205
- field.is_a?(String) ? '"' + field + '"' : deparse_item(field)
206
- end.join('.')
207
- end
208
-
209
- def deparse_a_arrayexp(node)
210
- 'ARRAY[' + node['elements'].map do |element|
211
- deparse_item(element)
212
- end.join(', ') + ']'
213
- end
214
-
215
- def deparse_a_const(node)
216
- deparse_item(node['val'], A_CONST)
217
- end
218
-
219
- def deparse_a_star(_node)
220
- '*'
221
- end
222
-
223
- def deparse_a_indirection(node)
224
- output = [deparse_item(node['arg'])]
225
- node['indirection'].each do |subnode|
226
- output << deparse_item(subnode)
227
- end
228
- output.join
229
- end
230
-
231
- def deparse_a_indices(node)
232
- format('[%s]', deparse_item(node['uidx']))
233
- end
234
-
235
- def deparse_alias(node)
236
- name = node['aliasname']
237
- if node['colnames']
238
- name + '(' + deparse_item_list(node['colnames']).join(', ') + ')'
239
- else
240
- name
241
- end
242
- end
243
-
244
- def deparse_alter_table(node)
245
- output = []
246
- output << 'ALTER TABLE'
247
-
248
- output << deparse_item(node['relation'])
249
-
250
- output << node['cmds'].map do |item|
251
- deparse_item(item)
252
- end.join(', ')
253
-
254
- output.join(' ')
255
- end
256
-
257
- def deparse_alter_table_cmd(node)
258
- command, options = AlterTable.commands(node)
259
-
260
- output = []
261
- output << command if command
262
- output << 'IF EXISTS' if node['missing_ok']
263
- output << node['name']
264
- output << options if options
265
- output << deparse_item(node['def']) if node['def']
266
- output << 'CASCADE' if node['behavior'] == 1
267
-
268
- output.compact.join(' ')
269
- end
270
-
271
- def deparse_paramref(node)
272
- if node['number'].nil?
273
- '?'
274
- else
275
- format('$%d', node['number'])
276
- end
277
- end
278
-
279
- def deparse_restarget(node, context)
280
- if context == :select
281
- [deparse_item(node['val']), node['name']].compact.join(' AS ')
282
- elsif context == :update
283
- [node['name'], deparse_item(node['val'])].compact.join(' = ')
284
- elsif node['val'].nil?
285
- node['name']
286
- else
287
- raise format("Can't deparse %s in context %s", node.inspect, context)
288
- end
289
- end
290
-
291
- def deparse_funccall(node)
292
- output = []
293
-
294
- # SUM(a, b)
295
- args = Array(node['args']).map { |arg| deparse_item(arg) }
296
- # COUNT(*)
297
- args << '*' if node['agg_star']
298
-
299
- name = (node['funcname'].map { |n| deparse_item(n, FUNC_CALL) } - ['pg_catalog']).join('.')
300
- distinct = node['agg_distinct'] ? 'DISTINCT ' : ''
301
- output << format('%s(%s%s)', name, distinct, args.join(', '))
302
- output << format('OVER (%s)', deparse_item(node['over'])) if node['over']
303
-
304
- output.join(' ')
305
- end
306
-
307
- def deparse_windowdef(node)
308
- output = []
309
-
310
- if node['partitionClause']
311
- output << 'PARTITION BY'
312
- output << node['partitionClause'].map do |item|
313
- deparse_item(item)
314
- end.join(', ')
315
- end
316
-
317
- if node['orderClause']
318
- output << 'ORDER BY'
319
- output << node['orderClause'].map do |item|
320
- deparse_item(item)
321
- end.join(', ')
322
- end
323
-
324
- output.join(' ')
325
- end
326
-
327
- def deparse_functionparameter(node)
328
- deparse_item(node['argType'])
329
- end
330
-
331
- def deparse_aexpr_in(node)
332
- rexpr = Array(node['rexpr']).map { |arg| deparse_item(arg) }
333
- operator = node['name'].map { |n| deparse_item(n, :operator) } == ['='] ? 'IN' : 'NOT IN'
334
- format('%s %s (%s)', deparse_item(node['lexpr']), operator, rexpr.join(', '))
335
- end
336
-
337
- def deparse_aexpr_like(node)
338
- value = deparse_item(node['rexpr'])
339
- operator = node['name'].map { |n| deparse_item(n, :operator) } == ['~~'] ? 'LIKE' : 'NOT LIKE'
340
- format('%s %s %s', deparse_item(node['lexpr']), operator, value)
341
- end
342
-
343
- def deparse_bool_expr_not(node)
344
- format('NOT %s', deparse_item(node['args'][0]))
345
- end
346
-
347
- BOOLEAN_TEST_TYPE_TO_STRING = {
348
- BOOLEAN_TEST_TRUE => ' IS TRUE',
349
- BOOLEAN_TEST_NOT_TRUE => ' IS NOT TRUE',
350
- BOOLEAN_TEST_FALSE => ' IS FALSE',
351
- BOOLEAN_TEST_NOT_FALSE => ' IS NOT FALSE',
352
- BOOLEAN_TEST_UNKNOWN => ' IS UNKNOWN',
353
- BOOLEAN_TEST_NOT_UNKNOWN => ' IS NOT UNKNOWN'
354
- }.freeze
355
- def deparse_boolean_test(node)
356
- deparse_item(node['arg']) + BOOLEAN_TEST_TYPE_TO_STRING[node['booltesttype']]
357
- end
358
-
359
- def deparse_range_function(node)
360
- output = []
361
- output << 'LATERAL' if node['lateral']
362
- output << deparse_item(node['functions'][0][0]) # FIXME: Needs more test cases
363
- output << deparse_item(node['alias']) if node['alias']
364
- output << "#{node['alias'] ? '' : 'AS '}(#{deparse_item_list(node['coldeflist']).join(', ')})" if node['coldeflist']
365
- output.join(' ')
366
- end
367
-
368
- def deparse_aexpr(node, context = false)
369
- output = []
370
- output << deparse_item(node['lexpr'], context || true)
371
- output << deparse_item(node['rexpr'], context || true)
372
- output = output.join(' ' + deparse_item(node['name'][0], :operator) + ' ')
373
- if context
374
- # This is a nested expression, add parentheses.
375
- output = '(' + output + ')'
376
- end
377
- output
378
- end
379
-
380
- def deparse_bool_expr_and(node)
381
- # Only put parantheses around OR nodes that are inside this one
382
- node['args'].map do |arg|
383
- if [BOOL_EXPR_OR].include?(arg.values[0]['boolop'])
384
- format('(%s)', deparse_item(arg))
385
- else
386
- deparse_item(arg)
387
- end
388
- end.join(' AND ')
389
- end
390
-
391
- def deparse_bool_expr_or(node)
392
- # Put parantheses around AND + OR nodes that are inside
393
- node['args'].map do |arg|
394
- if [BOOL_EXPR_AND, BOOL_EXPR_OR].include?(arg.values[0]['boolop'])
395
- format('(%s)', deparse_item(arg))
396
- else
397
- deparse_item(arg)
398
- end
399
- end.join(' OR ')
400
- end
401
-
402
- def deparse_aexpr_any(node)
403
- output = []
404
- output << deparse_item(node['lexpr'])
405
- output << format('ANY(%s)', deparse_item(node['rexpr']))
406
- output.join(' ' + deparse_item(node['name'][0], :operator) + ' ')
407
- end
408
-
409
- def deparse_aexpr_between(node)
410
- between = case node['kind']
411
- when AEXPR_BETWEEN
412
- ' BETWEEN '
413
- when AEXPR_NOT_BETWEEN
414
- ' NOT BETWEEN '
415
- when AEXPR_BETWEEN_SYM
416
- ' BETWEEN SYMMETRIC '
417
- when AEXPR_NOT_BETWEEN_SYM
418
- ' NOT BETWEEN SYMMETRIC '
419
- end
420
- name = deparse_item(node['lexpr'])
421
- output = node['rexpr'].map { |n| deparse_item(n) }
422
- name << between << output.join(' AND ')
1
+ module PgQuery
2
+ class ParserResult
3
+ def deparse
4
+ PgQuery.deparse(@tree)
423
5
  end
6
+ end
424
7
 
425
- def deparse_aexpr_nullif(node)
426
- lexpr = deparse_item(node['lexpr'])
427
- rexpr = deparse_item(node['rexpr'])
428
- format('NULLIF(%s, %s)', lexpr, rexpr)
429
- end
430
-
431
- def deparse_joinexpr(node) # rubocop:disable Metrics/CyclomaticComplexity
432
- output = []
433
- output << deparse_item(node['larg'])
434
- case node['jointype']
435
- when 0
436
- if node['isNatural']
437
- output << 'NATURAL'
438
- elsif node['quals'].nil? && node['usingClause'].nil?
439
- output << 'CROSS'
440
- end
441
- when 1
442
- output << 'LEFT'
443
- when 2
444
- output << 'FULL'
445
- when 3
446
- output << 'RIGHT'
447
- end
448
- output << 'JOIN'
449
- output << deparse_item(node['rarg'])
450
-
451
- if node['quals']
452
- output << 'ON'
453
- output << deparse_item(node['quals'])
454
- end
455
-
456
- output << format('USING (%s)', node['usingClause'].map { |n| deparse_item(n) }.join(', ')) if node['usingClause']
457
-
458
- output.join(' ')
459
- end
460
-
461
- LOCK_CLAUSE_STRENGTH = {
462
- LCS_FORKEYSHARE => 'FOR KEY SHARE',
463
- LCS_FORSHARE => 'FOR SHARE',
464
- LCS_FORNOKEYUPDATE => 'FOR NO KEY UPDATE',
465
- LCS_FORUPDATE => 'FOR UPDATE'
466
- }.freeze
467
- def deparse_lockingclause(node)
468
- output = []
469
- output << LOCK_CLAUSE_STRENGTH[node['strength']]
470
- if node['lockedRels']
471
- output << 'OF'
472
- output << node['lockedRels'].map do |item|
473
- deparse_item(item)
474
- end.join(', ')
475
- end
476
- output.join(' ')
477
- end
478
-
479
- def deparse_sortby(node)
480
- output = []
481
- output << deparse_item(node['node'])
482
- output << 'ASC' if node['sortby_dir'] == 1
483
- output << 'DESC' if node['sortby_dir'] == 2
484
- output.join(' ')
485
- end
486
-
487
- def deparse_with_clause(node)
488
- output = ['WITH']
489
- output << 'RECURSIVE' if node['recursive']
490
- output << node['ctes'].map do |cte|
491
- deparse_item(cte)
492
- end.join(', ')
493
- output.join(' ')
494
- end
495
-
496
- def deparse_viewstmt(node)
497
- output = []
498
- output << 'CREATE'
499
- output << 'OR REPLACE' if node['replace']
500
-
501
- persistence = relpersistence(node['view'])
502
- output << persistence if persistence
503
-
504
- output << 'VIEW'
505
- output << node['view'][RANGE_VAR]['relname']
506
- output << format('(%s)', deparse_item_list(node['aliases']).join(', ')) if node['aliases']
507
-
508
- output << 'AS'
509
- output << deparse_item(node['query'])
510
-
511
- case node['withCheckOption']
512
- when 1
513
- output << 'WITH CHECK OPTION'
514
- when 2
515
- output << 'WITH CASCADED CHECK OPTION'
516
- end
517
- output.join(' ')
518
- end
519
-
520
- def deparse_variable_set_stmt(node)
521
- output = []
522
- output << 'SET'
523
- output << 'LOCAL' if node['is_local']
524
- output << node['name']
525
- output << 'TO'
526
- output << node['args'].map { |arg| deparse_item(arg) }.join(', ')
527
- output.join(' ')
528
- end
529
-
530
- def deparse_cte(node)
531
- output = []
532
- output << node['ctename']
533
- output << format('(%s)', node['aliascolnames'].map { |n| deparse_item(n) }.join(', ')) if node['aliascolnames']
534
- output << format('AS (%s)', deparse_item(node['ctequery']))
535
- output.join(' ')
536
- end
537
-
538
- def deparse_case(node)
539
- output = ['CASE']
540
- output << deparse_item(node['arg']) if node['arg']
541
- output += node['args'].map { |arg| deparse_item(arg) }
542
- if node['defresult']
543
- output << 'ELSE'
544
- output << deparse_item(node['defresult'])
545
- end
546
- output << 'END'
547
- output.join(' ')
548
- end
549
-
550
- def deparse_columndef(node)
551
- output = [node['colname']]
552
- output << deparse_item(node['typeName'])
553
- if node['raw_default']
554
- output << 'USING'
555
- output << deparse_item(node['raw_default'])
556
- end
557
- if node['constraints']
558
- output += node['constraints'].map do |item|
559
- deparse_item(item)
560
- end
561
- end
562
- output.compact.join(' ')
563
- end
564
-
565
- def deparse_constraint(node) # rubocop:disable Metrics/CyclomaticComplexity
566
- output = []
567
- if node['conname']
568
- output << 'CONSTRAINT'
569
- output << node['conname']
570
- end
571
- case node['contype']
572
- when CONSTR_TYPE_NULL
573
- output << 'NULL'
574
- when CONSTR_TYPE_NOTNULL
575
- output << 'NOT NULL'
576
- when CONSTR_TYPE_DEFAULT
577
- output << 'DEFAULT'
578
- when CONSTR_TYPE_CHECK
579
- output << 'CHECK'
580
- when CONSTR_TYPE_PRIMARY
581
- output << 'PRIMARY KEY'
582
- when CONSTR_TYPE_UNIQUE
583
- output << 'UNIQUE'
584
- when CONSTR_TYPE_EXCLUSION
585
- output << 'EXCLUSION'
586
- when CONSTR_TYPE_FOREIGN
587
- output << 'FOREIGN KEY'
588
- end
589
-
590
- if node['raw_expr']
591
- expression = deparse_item(node['raw_expr'])
592
- # Unless it's simple, put parentheses around it
593
- expression = '(' + expression + ')' if node['raw_expr'][A_EXPR] && node['raw_expr'][A_EXPR]['kind'] == AEXPR_OP
594
- output << expression
595
- end
596
- output << '(' + deparse_item_list(node['keys']).join(', ') + ')' if node['keys']
597
- output << '(' + deparse_item_list(node['fk_attrs']).join(', ') + ')' if node['fk_attrs']
598
- output << 'REFERENCES ' + deparse_item(node['pktable']) + ' (' + deparse_item_list(node['pk_attrs']).join(', ') + ')' if node['pktable']
599
- output << 'NOT VALID' if node['skip_validation']
600
- output << "USING INDEX #{node['indexname']}" if node['indexname']
601
- output.join(' ')
602
- end
603
-
604
- def deparse_create_function(node)
605
- output = []
606
- output << 'CREATE'
607
- output << 'OR REPLACE' if node['replace']
608
- output << 'FUNCTION'
609
-
610
- arguments = deparse_item_list(node['parameters']).join(', ')
611
-
612
- output << deparse_item_list(node['funcname']).join('.') + '(' + arguments + ')'
613
-
614
- output << 'RETURNS'
615
- output << deparse_item(node['returnType'])
616
- output += node['options'].map { |item| deparse_item(item) }
617
-
618
- output.join(' ')
619
- end
620
-
621
- def deparse_create_table(node)
622
- output = []
623
- output << 'CREATE'
624
-
625
- persistence = relpersistence(node['relation'])
626
- output << persistence if persistence
627
-
628
- output << 'TABLE'
629
-
630
- output << 'IF NOT EXISTS' if node['if_not_exists']
631
-
632
- output << deparse_item(node['relation'])
633
-
634
- output << '(' + node['tableElts'].map do |item|
635
- deparse_item(item)
636
- end.join(', ') + ')'
637
-
638
- if node['inhRelations']
639
- output << 'INHERITS'
640
- output << '(' + node['inhRelations'].map do |relation|
641
- deparse_item(relation)
642
- end.join(', ') + ')'
643
- end
644
-
645
- output.join(' ')
646
- end
647
-
648
- def deparse_when(node)
649
- output = ['WHEN']
650
- output << deparse_item(node['expr'])
651
- output << 'THEN'
652
- output << deparse_item(node['result'])
653
- output.join(' ')
654
- end
655
-
656
- def deparse_sublink(node)
657
- if node['subLinkType'] == SUBLINK_TYPE_ANY
658
- format('%s IN (%s)', deparse_item(node['testexpr']), deparse_item(node['subselect']))
659
- elsif node['subLinkType'] == SUBLINK_TYPE_EXISTS
660
- format('EXISTS(%s)', deparse_item(node['subselect']))
661
- else
662
- format('(%s)', deparse_item(node['subselect']))
663
- end
664
- end
665
-
666
- def deparse_rangesubselect(node)
667
- output = '(' + deparse_item(node['subquery']) + ')'
668
- if node['alias']
669
- output + ' ' + deparse_item(node['alias'])
670
- else
671
- output
672
- end
673
- end
674
-
675
- def deparse_row(node)
676
- 'ROW(' + node['args'].map { |arg| deparse_item(arg) }.join(', ') + ')'
677
- end
678
-
679
- def deparse_select(node) # rubocop:disable Metrics/CyclomaticComplexity
680
- output = []
681
-
682
- if node['op'] == 1
683
- output << deparse_item(node['larg'])
684
- output << 'UNION'
685
- output << 'ALL' if node['all']
686
- output << deparse_item(node['rarg'])
687
- return output.join(' ')
688
- end
689
-
690
- output << deparse_item(node['withClause']) if node['withClause']
691
-
692
- if node[TARGET_LIST_FIELD]
693
- output << 'SELECT'
694
- output << 'DISTINCT' if node['distinctClause']
695
- output << node[TARGET_LIST_FIELD].map do |item|
696
- deparse_item(item, :select)
697
- end.join(', ')
698
- end
699
-
700
- if node[FROM_CLAUSE_FIELD]
701
- output << 'FROM'
702
- output << node[FROM_CLAUSE_FIELD].map do |item|
703
- deparse_item(item)
704
- end.join(', ')
705
- end
706
-
707
- if node['whereClause']
708
- output << 'WHERE'
709
- output << deparse_item(node['whereClause'])
710
- end
711
-
712
- if node['valuesLists']
713
- output << 'VALUES'
714
- output << node['valuesLists'].map do |value_list|
715
- '(' + value_list.map { |v| deparse_item(v) }.join(', ') + ')'
716
- end.join(', ')
717
- end
718
-
719
- if node['groupClause']
720
- output << 'GROUP BY'
721
- output << node['groupClause'].map do |item|
722
- deparse_item(item)
723
- end.join(', ')
724
- end
725
-
726
- if node['havingClause']
727
- output << 'HAVING'
728
- output << deparse_item(node['havingClause'])
729
- end
730
-
731
- if node['sortClause']
732
- output << 'ORDER BY'
733
- output << node['sortClause'].map do |item|
734
- deparse_item(item)
735
- end.join(', ')
736
- end
737
-
738
- if node['limitCount']
739
- output << 'LIMIT'
740
- output << deparse_item(node['limitCount'])
741
- end
742
-
743
- if node['limitOffset']
744
- output << 'OFFSET'
745
- output << deparse_item(node['limitOffset'])
746
- end
747
-
748
- if node['lockingClause']
749
- node['lockingClause'].map do |item|
750
- output << deparse_item(item)
751
- end
752
- end
753
-
754
- output.join(' ')
755
- end
756
-
757
- def deparse_insert_into(node)
758
- output = []
759
- output << deparse_item(node['withClause']) if node['withClause']
760
-
761
- output << 'INSERT INTO'
762
- output << deparse_item(node['relation'])
763
-
764
- if node['cols']
765
- output << '(' + node['cols'].map do |column|
766
- deparse_item(column)
767
- end.join(', ') + ')'
768
- end
769
-
770
- output << deparse_item(node['selectStmt'])
771
-
772
- output.join(' ')
773
- end
774
-
775
- def deparse_update(node)
776
- output = []
777
- output << deparse_item(node['withClause']) if node['withClause']
778
-
779
- output << 'UPDATE'
780
- output << deparse_item(node['relation'])
781
-
782
- if node[TARGET_LIST_FIELD]
783
- output << 'SET'
784
- node[TARGET_LIST_FIELD].each do |item|
785
- output << deparse_item(item, :update)
786
- end
787
- end
788
-
789
- if node['whereClause']
790
- output << 'WHERE'
791
- output << deparse_item(node['whereClause'])
792
- end
793
-
794
- if node['returningList']
795
- output << 'RETURNING'
796
- output << node['returningList'].map do |item|
797
- # RETURNING is formatted like a SELECT
798
- deparse_item(item, :select)
799
- end.join(', ')
800
- end
801
-
802
- output.join(' ')
803
- end
804
-
805
- def deparse_typecast(node)
806
- if deparse_item(node['typeName']) == 'boolean'
807
- deparse_item(node['arg']) == "'t'" ? 'true' : 'false'
808
- else
809
- deparse_item(node['arg']) + '::' + deparse_typename(node['typeName'][TYPE_NAME])
810
- end
811
- end
812
-
813
- def deparse_typename(node)
814
- names = node['names'].map { |n| deparse_item(n, TYPE_NAME) }
815
-
816
- # Intervals are tricky and should be handled in a separate method because
817
- # they require performing some bitmask operations.
818
- return deparse_interval_type(node) if names == %w[pg_catalog interval]
819
-
820
- output = []
821
- output << 'SETOF' if node['setof']
822
-
823
- if node['typmods']
824
- arguments = node['typmods'].map do |item|
825
- deparse_item(item)
826
- end.join(', ')
827
- end
828
- output << deparse_typename_cast(names, arguments)
829
- output.last << '[]' if node['arrayBounds']
830
-
831
- output.join(' ')
832
- end
833
-
834
- def deparse_typename_cast(names, arguments) # rubocop:disable Metrics/CyclomaticComplexity
835
- catalog, type = names
836
- # Just pass along any custom types.
837
- # (The pg_catalog types are built-in Postgres system types and are
838
- # handled in the case statement below)
839
- return names.join('.') if catalog != 'pg_catalog'
840
-
841
- case type
842
- when 'bpchar'
843
- # char(2) or char(9)
844
- "char(#{arguments})"
845
- when 'varchar'
846
- arguments.nil? ? 'varchar' : "varchar(#{arguments})"
847
- when 'numeric'
848
- # numeric(3, 5)
849
- arguments.nil? ? 'numeric' : "numeric(#{arguments})"
850
- when 'bool'
851
- 'boolean'
852
- when 'int2'
853
- 'smallint'
854
- when 'int4'
855
- 'int'
856
- when 'int8'
857
- 'bigint'
858
- when 'real', 'float4'
859
- 'real'
860
- when 'float8'
861
- 'double'
862
- when 'time'
863
- 'time'
864
- when 'timetz'
865
- 'time with time zone'
866
- when 'timestamp'
867
- 'timestamp'
868
- when 'timestamptz'
869
- 'timestamp with time zone'
870
- else
871
- raise format("Can't deparse type: %s", type)
872
- end
873
- end
874
-
875
- # Deparses interval type expressions like `interval year to month` or
876
- # `interval hour to second(5)`
877
- def deparse_interval_type(node)
878
- type = ['interval']
879
-
880
- if node['typmods']
881
- typmods = node['typmods'].map { |typmod| deparse_item(typmod) }
882
- type << Interval.from_int(typmods.first.to_i).map do |part|
883
- # only the `second` type can take an argument.
884
- if part == 'second' && typmods.size == 2
885
- "second(#{typmods.last})"
886
- else
887
- part
888
- end.downcase
889
- end.join(' to ')
890
- end
891
-
892
- type.join(' ')
893
- end
894
-
895
- def deparse_nulltest(node)
896
- output = [deparse_item(node['arg'])]
897
- case node['nulltesttype']
898
- when 0
899
- output << 'IS NULL'
900
- when 1
901
- output << 'IS NOT NULL'
902
- end
903
- output.join(' ')
904
- end
905
-
906
- TRANSACTION_CMDS = {
907
- TRANS_STMT_BEGIN => 'BEGIN',
908
- TRANS_STMT_COMMIT => 'COMMIT',
909
- TRANS_STMT_ROLLBACK => 'ROLLBACK',
910
- TRANS_STMT_SAVEPOINT => 'SAVEPOINT',
911
- TRANS_STMT_RELEASE => 'RELEASE',
912
- TRANS_STMT_ROLLBACK_TO => 'ROLLBACK TO SAVEPOINT'
913
- }.freeze
914
- def deparse_transaction(node)
915
- output = []
916
- output << TRANSACTION_CMDS[node['kind']] || raise(format("Can't deparse TRANSACTION %s", node.inspect))
917
-
918
- if node['options']
919
- output += node['options'].map { |item| deparse_item(item) }
920
- end
921
-
922
- output.join(' ')
923
- end
924
-
925
- def deparse_coalesce(node)
926
- format('COALESCE(%s)', node['args'].map { |a| deparse_item(a) }.join(', '))
927
- end
928
-
929
- def deparse_defelem(node)
930
- case node['defname']
931
- when 'as'
932
- "AS $$#{deparse_item_list(node['arg'], :defname_as).join("\n")}$$"
933
- when 'language'
934
- "language #{deparse_item(node['arg'])}"
935
- when 'volatility'
936
- node['arg']['String']['str'].upcase # volatility does not need to be quoted
937
- when 'strict'
938
- deparse_item(node['arg']) == '1' ? 'RETURNS NULL ON NULL INPUT' : 'CALLED ON NULL INPUT'
939
- else
940
- deparse_item(node['arg'])
941
- end
942
- end
943
-
944
- def deparse_delete_from(node)
945
- output = []
946
- output << deparse_item(node['withClause']) if node['withClause']
947
-
948
- output << 'DELETE FROM'
949
- output << deparse_item(node['relation'])
950
-
951
- if node['usingClause']
952
- output << 'USING'
953
- output << node['usingClause'].map do |item|
954
- deparse_item(item)
955
- end.join(', ')
956
- end
957
-
958
- if node['whereClause']
959
- output << 'WHERE'
960
- output << deparse_item(node['whereClause'])
961
- end
962
-
963
- if node['returningList']
964
- output << 'RETURNING'
965
- output << node['returningList'].map do |item|
966
- # RETURNING is formatted like a SELECT
967
- deparse_item(item, :select)
968
- end.join(', ')
969
- end
970
-
971
- output.join(' ')
972
- end
973
-
974
- def deparse_drop(node)
975
- output = ['DROP']
976
- output << 'TABLE' if node['removeType'] == OBJECT_TYPE_TABLE
977
- output << 'CONCURRENTLY' if node['concurrent']
978
- output << 'IF EXISTS' if node['missing_ok']
979
-
980
- output << node['objects'].map { |list| list.map { |object| deparse_item(object) } }.join(', ')
981
-
982
- output << 'CASCADE' if node['behavior'] == 1
8
+ # Reconstruct all of the parsed queries into their original form
9
+ def self.deparse(tree)
10
+ PgQuery.deparse_protobuf(PgQuery::ParseResult.encode(tree)).force_encoding('UTF-8')
11
+ end
983
12
 
984
- output.join(' ')
985
- end
13
+ # Convenience method for deparsing a statement of a specific type
14
+ def self.deparse_stmt(stmt)
15
+ deparse(PgQuery::ParseResult.new(version: PG_VERSION_NUM, stmts: [PgQuery::RawStmt.new(stmt: PgQuery::Node.from(stmt))]))
16
+ end
986
17
 
987
- # The PG parser adds several pieces of view data onto the RANGEVAR
988
- # that need to be printed before deparse_rangevar is called.
989
- def relpersistence(rangevar)
990
- if rangevar[RANGE_VAR]['relpersistence'] == 't'
991
- 'TEMPORARY'
992
- elsif rangevar[RANGE_VAR]['relpersistence'] == 'u'
993
- 'UNLOGGED'
994
- end
995
- end
18
+ # Convenience method for deparsing an expression
19
+ def self.deparse_expr(expr)
20
+ deparse_stmt(PgQuery::SelectStmt.new(where_clause: expr, op: :SETOP_NONE)).gsub('SELECT WHERE ', '')
996
21
  end
997
22
  end