pg_query 2.0.1 → 2.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 +220 -114
- data/README.md +12 -0
- data/Rakefile +6 -21
- data/ext/pg_query/extconf.rb +5 -2
- data/ext/pg_query/include/c.h +12 -0
- data/ext/pg_query/include/executor/executor.h +6 -0
- data/ext/pg_query/include/nodes/execnodes.h +9 -6
- data/ext/pg_query/include/nodes/pathnodes.h +1 -1
- data/ext/pg_query/include/optimizer/paths.h +8 -0
- data/ext/pg_query/include/pg_config.h +10 -6
- data/ext/pg_query/include/pg_config_manual.h +7 -0
- data/ext/pg_query/include/pg_query.h +2 -2
- data/ext/pg_query/include/pg_query_outfuncs_defs.c +1 -0
- data/ext/pg_query/include/pg_query_readfuncs_defs.c +1 -0
- data/ext/pg_query/include/protobuf/pg_query.pb-c.h +472 -467
- data/ext/pg_query/include/protobuf-c/protobuf-c.h +7 -3
- data/ext/pg_query/include/protobuf-c.h +7 -3
- data/ext/pg_query/include/utils/array.h +1 -0
- data/ext/pg_query/include/utils/lsyscache.h +1 -0
- data/ext/pg_query/include/utils/probes.h +57 -57
- data/ext/pg_query/pg_query.pb-c.c +502 -487
- data/ext/pg_query/pg_query_deparse.c +33 -21
- data/ext/pg_query/pg_query_fingerprint.c +123 -33
- data/ext/pg_query/pg_query_fingerprint.h +3 -1
- data/ext/pg_query/pg_query_normalize.c +222 -61
- data/ext/pg_query/pg_query_parse_plpgsql.c +21 -1
- data/ext/pg_query/pg_query_ruby.sym +1 -0
- data/ext/pg_query/protobuf-c.c +34 -27
- data/ext/pg_query/src_backend_utils_mmgr_mcxt.c +36 -0
- data/ext/pg_query/src_common_hashfn.c +420 -0
- data/ext/pg_query/src_pl_plpgsql_src_pl_gram.c +1 -1
- data/lib/pg_query/filter_columns.rb +3 -1
- data/lib/pg_query/fingerprint.rb +1 -3
- data/lib/pg_query/parse.rb +101 -46
- data/lib/pg_query/pg_query_pb.rb +1385 -1383
- data/lib/pg_query/truncate.rb +12 -4
- data/lib/pg_query/version.rb +1 -1
- data/lib/pg_query.rb +0 -1
- metadata +8 -8
- data/lib/pg_query/json_field_names.rb +0 -1402
data/lib/pg_query/parse.rb
CHANGED
@@ -4,8 +4,8 @@ module PgQuery
|
|
4
4
|
|
5
5
|
begin
|
6
6
|
result = PgQuery::ParseResult.decode(result)
|
7
|
-
rescue Google::Protobuf::ParseError
|
8
|
-
raise PgQuery::ParseError.new('Failed to parse tree', __FILE__, __LINE__, -1)
|
7
|
+
rescue Google::Protobuf::ParseError => e
|
8
|
+
raise PgQuery::ParseError.new(format('Failed to parse tree: %s', e.message), __FILE__, __LINE__, -1)
|
9
9
|
end
|
10
10
|
|
11
11
|
warnings = []
|
@@ -29,6 +29,7 @@ module PgQuery
|
|
29
29
|
@tables = nil
|
30
30
|
@aliases = nil
|
31
31
|
@cte_names = nil
|
32
|
+
@functions = nil
|
32
33
|
end
|
33
34
|
|
34
35
|
def dup_tree
|
@@ -51,27 +52,52 @@ module PgQuery
|
|
51
52
|
tables_with_details.select { |t| t[:type] == :ddl }.map { |t| t[:name] }.uniq
|
52
53
|
end
|
53
54
|
|
55
|
+
# Returns function names, ignoring their argument types. This may be insufficient
|
56
|
+
# if you need to disambiguate two functions with the same name but different argument
|
57
|
+
# types.
|
58
|
+
def functions
|
59
|
+
functions_with_details.map { |f| f[:function] }.uniq
|
60
|
+
end
|
61
|
+
|
62
|
+
def ddl_functions
|
63
|
+
functions_with_details.select { |f| f[:type] == :ddl }.map { |f| f[:function] }.uniq
|
64
|
+
end
|
65
|
+
|
66
|
+
def call_functions
|
67
|
+
functions_with_details.select { |f| f[:type] == :call }.map { |f| f[:function] }.uniq
|
68
|
+
end
|
69
|
+
|
54
70
|
def cte_names
|
55
|
-
|
71
|
+
load_objects! if @cte_names.nil?
|
56
72
|
@cte_names
|
57
73
|
end
|
58
74
|
|
59
75
|
def aliases
|
60
|
-
|
76
|
+
load_objects! if @aliases.nil?
|
61
77
|
@aliases
|
62
78
|
end
|
63
79
|
|
64
80
|
def tables_with_details
|
65
|
-
|
81
|
+
load_objects! if @tables.nil?
|
66
82
|
@tables
|
67
83
|
end
|
68
84
|
|
85
|
+
def functions_with_details
|
86
|
+
load_objects! if @functions.nil?
|
87
|
+
@functions
|
88
|
+
end
|
89
|
+
|
69
90
|
protected
|
70
91
|
|
71
|
-
|
92
|
+
# Parses the query and finds table and function references
|
93
|
+
#
|
94
|
+
# Note we use ".to_ary" on arrays from the Protobuf library before
|
95
|
+
# passing them to concat, because of https://bugs.ruby-lang.org/issues/18140
|
96
|
+
def load_objects! # rubocop:disable Metrics/CyclomaticComplexity
|
72
97
|
@tables = [] # types: select, dml, ddl
|
73
98
|
@cte_names = []
|
74
99
|
@aliases = {}
|
100
|
+
@functions = [] # types: call, ddl
|
75
101
|
|
76
102
|
statements = @tree.stmts.dup.to_a.map(&:stmt)
|
77
103
|
from_clause_items = [] # types: select, dml, ddl
|
@@ -86,20 +112,16 @@ module PgQuery
|
|
86
112
|
# The following statement types do not modify tables and are added to from_clause_items
|
87
113
|
# (and subsequently @tables)
|
88
114
|
when :select_stmt
|
89
|
-
subselect_items.concat(statement.select_stmt.target_list)
|
115
|
+
subselect_items.concat(statement.select_stmt.target_list.to_ary)
|
90
116
|
subselect_items << statement.select_stmt.where_clause if statement.select_stmt.where_clause
|
91
117
|
subselect_items.concat(statement.select_stmt.sort_clause.collect { |h| h.sort_by.node })
|
92
|
-
subselect_items.concat(statement.select_stmt.group_clause)
|
118
|
+
subselect_items.concat(statement.select_stmt.group_clause.to_ary)
|
93
119
|
subselect_items << statement.select_stmt.having_clause if statement.select_stmt.having_clause
|
94
120
|
|
95
121
|
case statement.select_stmt.op
|
96
122
|
when :SETOP_NONE
|
97
123
|
(statement.select_stmt.from_clause || []).each do |item|
|
98
|
-
|
99
|
-
statements << item.range_subselect.subquery
|
100
|
-
else
|
101
|
-
from_clause_items << { item: item, type: :select }
|
102
|
-
end
|
124
|
+
from_clause_items << { item: item, type: :select }
|
103
125
|
end
|
104
126
|
when :SETOP_UNION
|
105
127
|
statements << PgQuery::Node.new(select_stmt: statement.select_stmt.larg) if statement.select_stmt.larg
|
@@ -117,7 +139,13 @@ module PgQuery
|
|
117
139
|
from_clause_items << { item: PgQuery::Node.new(range_var: value.relation), type: :dml }
|
118
140
|
statements << value.select_stmt if statement.node == :insert_stmt && value.select_stmt
|
119
141
|
|
120
|
-
|
142
|
+
if statement.node == :update_stmt
|
143
|
+
value.from_clause.each do |item|
|
144
|
+
from_clause_items << { item: item, type: :select }
|
145
|
+
end
|
146
|
+
subselect_items.concat(statement.update_stmt.target_list.to_ary)
|
147
|
+
end
|
148
|
+
|
121
149
|
subselect_items << statement.update_stmt.where_clause if statement.node == :update_stmt && statement.update_stmt.where_clause
|
122
150
|
subselect_items << statement.delete_stmt.where_clause if statement.node == :delete_stmt && statement.delete_stmt.where_clause
|
123
151
|
|
@@ -168,6 +196,10 @@ module PgQuery
|
|
168
196
|
@tables += objects.map { |r| { name: r.join('.'), type: :ddl } }
|
169
197
|
when :OBJECT_RULE, :OBJECT_TRIGGER
|
170
198
|
@tables += objects.map { |r| { name: r[0..-2].join('.'), type: :ddl } }
|
199
|
+
when :OBJECT_FUNCTION
|
200
|
+
# Only one function can be dropped in a statement
|
201
|
+
obj = statement.drop_stmt.objects[0].object_with_args
|
202
|
+
@functions << { function: obj.objname[0].string.str, type: :ddl }
|
171
203
|
end
|
172
204
|
when :grant_stmt
|
173
205
|
objects = statement.grant_stmt.objects
|
@@ -184,12 +216,28 @@ module PgQuery
|
|
184
216
|
# The following are other statements that don't fit into query/DML/DDL
|
185
217
|
when :explain_stmt
|
186
218
|
statements << statement.explain_stmt.query
|
219
|
+
when :create_function_stmt
|
220
|
+
@functions << {
|
221
|
+
function: statement.create_function_stmt.funcname[0].string.str,
|
222
|
+
type: :ddl
|
223
|
+
}
|
224
|
+
when :rename_stmt
|
225
|
+
if statement.rename_stmt.rename_type == :OBJECT_FUNCTION
|
226
|
+
original_name = statement.rename_stmt.object.object_with_args.objname[0].string.str
|
227
|
+
new_name = statement.rename_stmt.newname
|
228
|
+
@functions += [
|
229
|
+
{ function: original_name, type: :ddl },
|
230
|
+
{ function: new_name, type: :ddl }
|
231
|
+
]
|
232
|
+
end
|
187
233
|
end
|
188
234
|
end
|
189
235
|
|
190
236
|
next_item = subselect_items.shift
|
191
237
|
if next_item
|
192
238
|
case next_item.node
|
239
|
+
when :list
|
240
|
+
subselect_items += next_item.list.items
|
193
241
|
when :a_expr
|
194
242
|
%w[lexpr rexpr].each do |side|
|
195
243
|
elem = next_item.a_expr.public_send(side)
|
@@ -201,47 +249,54 @@ module PgQuery
|
|
201
249
|
end
|
202
250
|
end
|
203
251
|
when :bool_expr
|
204
|
-
subselect_items.concat(next_item.bool_expr.args)
|
252
|
+
subselect_items.concat(next_item.bool_expr.args.to_ary)
|
253
|
+
when :coalesce_expr
|
254
|
+
subselect_items.concat(next_item.coalesce_expr.args.to_ary)
|
255
|
+
when :min_max_expr
|
256
|
+
subselect_items.concat(next_item.min_max_expr.args.to_ary)
|
205
257
|
when :res_target
|
206
258
|
subselect_items << next_item.res_target.val
|
207
259
|
when :sub_link
|
208
260
|
statements << next_item.sub_link.subselect
|
261
|
+
when :func_call
|
262
|
+
subselect_items.concat(next_item.func_call.args.to_ary)
|
263
|
+
@functions << {
|
264
|
+
function: next_item.func_call.funcname.map { |f| f.string.str }.join('.'),
|
265
|
+
type: :call
|
266
|
+
}
|
209
267
|
end
|
210
268
|
end
|
211
269
|
|
212
|
-
break if subselect_items.empty? && statements.empty?
|
213
|
-
end
|
214
|
-
|
215
|
-
loop do
|
216
270
|
next_item = from_clause_items.shift
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
from_clause_items += from_clause.map { |r| { item: r, type: next_item[:type] } } if from_clause
|
271
|
+
if next_item && next_item[:item]
|
272
|
+
case next_item[:item].node
|
273
|
+
when :join_expr
|
274
|
+
from_clause_items << { item: next_item[:item].join_expr.larg, type: next_item[:type] }
|
275
|
+
from_clause_items << { item: next_item[:item].join_expr.rarg, type: next_item[:type] }
|
276
|
+
when :row_expr
|
277
|
+
from_clause_items += next_item[:item].row_expr.args.map { |a| { item: a, type: next_item[:type] } }
|
278
|
+
when :range_var
|
279
|
+
rangevar = next_item[:item].range_var
|
280
|
+
next if rangevar.schemaname.empty? && @cte_names.include?(rangevar.relname)
|
281
|
+
|
282
|
+
table = [rangevar.schemaname, rangevar.relname].reject { |s| s.nil? || s.empty? }.join('.')
|
283
|
+
@tables << {
|
284
|
+
name: table,
|
285
|
+
type: next_item[:type],
|
286
|
+
location: rangevar.location,
|
287
|
+
schemaname: (rangevar.schemaname unless rangevar.schemaname.empty?),
|
288
|
+
relname: rangevar.relname,
|
289
|
+
inh: rangevar.inh
|
290
|
+
}
|
291
|
+
@aliases[rangevar.alias.aliasname] = table if rangevar.alias
|
292
|
+
when :range_subselect
|
293
|
+
statements << next_item[:item].range_subselect.subquery
|
294
|
+
when :range_function
|
295
|
+
subselect_items += next_item[:item].range_function.functions
|
296
|
+
end
|
244
297
|
end
|
298
|
+
|
299
|
+
break if subselect_items.empty? && statements.empty? && from_clause_items.empty?
|
245
300
|
end
|
246
301
|
|
247
302
|
@tables.uniq!
|