pg_query 1.0.2 → 2.0.0
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 +5 -5
- data/CHANGELOG.md +162 -40
- data/README.md +80 -69
- data/Rakefile +85 -4
- data/ext/pg_query/extconf.rb +4 -32
- data/ext/pg_query/guc-file.c +0 -0
- data/ext/pg_query/pg_query.c +104 -0
- data/ext/pg_query/pg_query.pb-c.c +37628 -0
- data/ext/pg_query/pg_query_deparse.c +9953 -0
- data/ext/pg_query/pg_query_fingerprint.c +292 -0
- data/ext/pg_query/pg_query_fingerprint.h +8 -0
- data/ext/pg_query/pg_query_internal.h +24 -0
- data/ext/pg_query/pg_query_json_plpgsql.c +738 -0
- data/ext/pg_query/pg_query_json_plpgsql.h +9 -0
- data/ext/pg_query/pg_query_normalize.c +437 -0
- data/ext/pg_query/pg_query_outfuncs.h +10 -0
- data/ext/pg_query/pg_query_outfuncs_json.c +297 -0
- data/ext/pg_query/pg_query_outfuncs_protobuf.c +237 -0
- data/ext/pg_query/pg_query_parse.c +148 -0
- data/ext/pg_query/pg_query_parse_plpgsql.c +460 -0
- data/ext/pg_query/pg_query_readfuncs.h +11 -0
- data/ext/pg_query/pg_query_readfuncs_protobuf.c +142 -0
- data/ext/pg_query/pg_query_ruby.c +108 -12
- data/ext/pg_query/pg_query_scan.c +173 -0
- data/ext/pg_query/pg_query_split.c +221 -0
- data/ext/pg_query/protobuf-c.c +3660 -0
- data/ext/pg_query/src_backend_catalog_namespace.c +1051 -0
- data/ext/pg_query/src_backend_catalog_pg_proc.c +142 -0
- data/ext/pg_query/src_backend_commands_define.c +117 -0
- data/ext/pg_query/src_backend_libpq_pqcomm.c +651 -0
- data/ext/pg_query/src_backend_nodes_bitmapset.c +513 -0
- data/ext/pg_query/src_backend_nodes_copyfuncs.c +6013 -0
- data/ext/pg_query/src_backend_nodes_equalfuncs.c +4003 -0
- data/ext/pg_query/src_backend_nodes_extensible.c +99 -0
- data/ext/pg_query/src_backend_nodes_list.c +922 -0
- data/ext/pg_query/src_backend_nodes_makefuncs.c +417 -0
- data/ext/pg_query/src_backend_nodes_nodeFuncs.c +1363 -0
- data/ext/pg_query/src_backend_nodes_value.c +84 -0
- data/ext/pg_query/src_backend_parser_gram.c +47456 -0
- data/ext/pg_query/src_backend_parser_parse_expr.c +313 -0
- data/ext/pg_query/src_backend_parser_parser.c +497 -0
- data/ext/pg_query/src_backend_parser_scan.c +7091 -0
- data/ext/pg_query/src_backend_parser_scansup.c +160 -0
- data/ext/pg_query/src_backend_postmaster_postmaster.c +2230 -0
- data/ext/pg_query/src_backend_storage_ipc_ipc.c +192 -0
- data/ext/pg_query/src_backend_storage_lmgr_s_lock.c +370 -0
- data/ext/pg_query/src_backend_tcop_postgres.c +776 -0
- data/ext/pg_query/src_backend_utils_adt_datum.c +326 -0
- data/ext/pg_query/src_backend_utils_adt_expandeddatum.c +98 -0
- data/ext/pg_query/src_backend_utils_adt_format_type.c +136 -0
- data/ext/pg_query/src_backend_utils_adt_ruleutils.c +1683 -0
- data/ext/pg_query/src_backend_utils_error_assert.c +74 -0
- data/ext/pg_query/src_backend_utils_error_elog.c +1748 -0
- data/ext/pg_query/src_backend_utils_fmgr_fmgr.c +570 -0
- data/ext/pg_query/src_backend_utils_hash_dynahash.c +1086 -0
- data/ext/pg_query/src_backend_utils_init_globals.c +168 -0
- data/ext/pg_query/src_backend_utils_mb_mbutils.c +839 -0
- data/ext/pg_query/src_backend_utils_misc_guc.c +1831 -0
- data/ext/pg_query/src_backend_utils_mmgr_aset.c +1560 -0
- data/ext/pg_query/src_backend_utils_mmgr_mcxt.c +1006 -0
- data/ext/pg_query/src_common_encnames.c +158 -0
- data/ext/pg_query/src_common_keywords.c +39 -0
- data/ext/pg_query/src_common_kwlist_d.h +1081 -0
- data/ext/pg_query/src_common_kwlookup.c +91 -0
- data/ext/pg_query/src_common_psprintf.c +158 -0
- data/ext/pg_query/src_common_string.c +86 -0
- data/ext/pg_query/src_common_stringinfo.c +336 -0
- data/ext/pg_query/src_common_wchar.c +1651 -0
- data/ext/pg_query/src_pl_plpgsql_src_pl_comp.c +1133 -0
- data/ext/pg_query/src_pl_plpgsql_src_pl_funcs.c +877 -0
- data/ext/pg_query/src_pl_plpgsql_src_pl_gram.c +6533 -0
- data/ext/pg_query/src_pl_plpgsql_src_pl_handler.c +107 -0
- data/ext/pg_query/src_pl_plpgsql_src_pl_reserved_kwlist_d.h +123 -0
- data/ext/pg_query/src_pl_plpgsql_src_pl_scanner.c +671 -0
- data/ext/pg_query/src_pl_plpgsql_src_pl_unreserved_kwlist_d.h +255 -0
- data/ext/pg_query/src_port_erand48.c +127 -0
- data/ext/pg_query/src_port_pg_bitutils.c +246 -0
- data/ext/pg_query/src_port_pgsleep.c +69 -0
- data/ext/pg_query/src_port_pgstrcasecmp.c +83 -0
- data/ext/pg_query/src_port_qsort.c +240 -0
- data/ext/pg_query/src_port_random.c +31 -0
- data/ext/pg_query/src_port_snprintf.c +1449 -0
- data/ext/pg_query/src_port_strerror.c +324 -0
- data/ext/pg_query/src_port_strnlen.c +39 -0
- data/ext/pg_query/xxhash.c +43 -0
- data/lib/pg_query.rb +7 -4
- data/lib/pg_query/constants.rb +21 -0
- data/lib/pg_query/deparse.rb +16 -991
- data/lib/pg_query/filter_columns.rb +86 -85
- data/lib/pg_query/fingerprint.rb +122 -87
- data/lib/pg_query/json_field_names.rb +1402 -0
- data/lib/pg_query/node.rb +31 -0
- data/lib/pg_query/param_refs.rb +42 -37
- data/lib/pg_query/parse.rb +220 -200
- data/lib/pg_query/parse_error.rb +1 -1
- data/lib/pg_query/pg_query_pb.rb +3211 -0
- data/lib/pg_query/scan.rb +23 -0
- data/lib/pg_query/treewalker.rb +24 -40
- data/lib/pg_query/truncate.rb +64 -43
- data/lib/pg_query/version.rb +2 -2
- metadata +102 -11
- data/ext/pg_query/pg_query_ruby.h +0 -10
- data/lib/pg_query/deep_dup.rb +0 -16
- data/lib/pg_query/deparse/alter_table.rb +0 -42
- data/lib/pg_query/deparse/interval.rb +0 -105
- data/lib/pg_query/legacy_parsetree.rb +0 -109
- data/lib/pg_query/node_types.rb +0 -282
data/lib/pg_query/deparse.rb
CHANGED
|
@@ -1,997 +1,22 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
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
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
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
|
-
|
|
985
|
-
|
|
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
|
-
|
|
988
|
-
|
|
989
|
-
|
|
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
|