pg_query 2.0.1 → 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +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!
|