pg_query 6.2.3 → 6.2.5
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 +37 -1
- data/Rakefile +2 -2
- data/ext/pg_query/include/pg_query_fingerprint_defs.c +8 -0
- data/ext/pg_query/include/pg_query_outfuncs_defs.c +4 -0
- data/ext/pg_query/include/pg_query_readfuncs_defs.c +4 -0
- data/ext/pg_query/include/postgres/copyfuncs.funcs.c +4 -0
- data/ext/pg_query/include/postgres/equalfuncs.funcs.c +4 -0
- data/ext/pg_query/include/postgres/nodes/parsenodes.h +8 -0
- data/ext/pg_query/include/protobuf/pg_query.pb-c.h +282 -278
- data/ext/pg_query/pg_query.pb-c.c +64 -12
- data/ext/pg_query/pg_query_normalize.c +45 -47
- data/ext/pg_query/pg_query_readfuncs_protobuf.c +8 -5
- data/ext/pg_query/postgres_deparse.c +224 -5
- data/ext/pg_query/src_backend_nodes_makefuncs.c +2 -0
- data/ext/pg_query/src_backend_parser_gram.c +30322 -30090
- data/lib/pg_query/fingerprint.rb +6 -0
- data/lib/pg_query/parse.rb +77 -1
- data/lib/pg_query/pg_query_pb.rb +1 -1
- data/lib/pg_query/version.rb +1 -1
- metadata +2 -2
data/lib/pg_query/fingerprint.rb
CHANGED
|
@@ -93,6 +93,12 @@ module PgQuery
|
|
|
93
93
|
case postgres_field_name
|
|
94
94
|
when 'location'
|
|
95
95
|
next
|
|
96
|
+
when 'arg_location'
|
|
97
|
+
next if node.is_a?(DefElem)
|
|
98
|
+
when 'payload_location'
|
|
99
|
+
next if node.is_a?(NotifyStmt)
|
|
100
|
+
when 'conninfo_location'
|
|
101
|
+
next if [CreateSubscriptionStmt, AlterSubscriptionStmt].include?(node.class)
|
|
96
102
|
when 'name'
|
|
97
103
|
next if [PrepareStmt, ExecuteStmt, DeallocateStmt, FunctionParameter].include?(node.class)
|
|
98
104
|
next if node.is_a?(ResTarget) && parent_node_name == 'SelectStmt' && parent_field_name == 'targetList'
|
data/lib/pg_query/parse.rb
CHANGED
|
@@ -102,6 +102,7 @@ module PgQuery
|
|
|
102
102
|
@cte_names = []
|
|
103
103
|
@aliases = {}
|
|
104
104
|
@functions = [] # types: call, ddl
|
|
105
|
+
@cte_self_reference_locations = []
|
|
105
106
|
|
|
106
107
|
statements = @tree.stmts.dup.to_a.map(&:stmt)
|
|
107
108
|
from_clause_items = [] # types: select, dml, ddl
|
|
@@ -135,6 +136,7 @@ module PgQuery
|
|
|
135
136
|
end
|
|
136
137
|
|
|
137
138
|
if statement.select_stmt.with_clause
|
|
139
|
+
record_cte_self_references!(statement.select_stmt.with_clause)
|
|
138
140
|
cte_statements, cte_names = statements_and_cte_names_for_with_clause(statement.select_stmt.with_clause)
|
|
139
141
|
@cte_names.concat(cte_names)
|
|
140
142
|
statements.concat(cte_statements)
|
|
@@ -173,6 +175,7 @@ module PgQuery
|
|
|
173
175
|
end
|
|
174
176
|
|
|
175
177
|
if value.with_clause
|
|
178
|
+
record_cte_self_references!(value.with_clause)
|
|
176
179
|
cte_statements, cte_names = statements_and_cte_names_for_with_clause(value.with_clause)
|
|
177
180
|
@cte_names.concat(cte_names)
|
|
178
181
|
statements.concat(cte_statements)
|
|
@@ -347,7 +350,7 @@ module PgQuery
|
|
|
347
350
|
from_clause_items += next_item[:item].row_expr.args.map { |a| { item: a, type: next_item[:type] } }
|
|
348
351
|
when :range_var
|
|
349
352
|
rangevar = next_item[:item].range_var
|
|
350
|
-
next if
|
|
353
|
+
next if cte_reference?(rangevar, next_item[:type])
|
|
351
354
|
|
|
352
355
|
table = [rangevar.schemaname, rangevar.relname].reject { |s| s.nil? || s.empty? }.join('.')
|
|
353
356
|
@tables << {
|
|
@@ -386,5 +389,78 @@ module PgQuery
|
|
|
386
389
|
|
|
387
390
|
[statements, cte_names]
|
|
388
391
|
end
|
|
392
|
+
|
|
393
|
+
# Determines whether a RangeVar refers to a CTE rather than to a relation.
|
|
394
|
+
#
|
|
395
|
+
# Only plain (SELECT-style) references can resolve to a CTE: a CTE is not a
|
|
396
|
+
# valid target for DML (INSERT/UPDATE/DELETE/COPY) or DDL, so those always
|
|
397
|
+
# name a real relation even when a CTE in the same statement shares the name.
|
|
398
|
+
def cte_reference?(rangevar, type)
|
|
399
|
+
return false unless type == :select
|
|
400
|
+
return false unless rangevar.schemaname.empty?
|
|
401
|
+
return false unless @cte_names.include?(rangevar.relname)
|
|
402
|
+
|
|
403
|
+
!@cte_self_reference_locations.include?(rangevar.location)
|
|
404
|
+
end
|
|
405
|
+
|
|
406
|
+
# A non-recursive CTE is not visible inside its own definition, so a
|
|
407
|
+
# reference to its own name there resolves to a real relation:
|
|
408
|
+
#
|
|
409
|
+
# WITH users AS (SELECT * FROM users) SELECT * FROM users
|
|
410
|
+
# ^^^^^ the table ^^^^^ the CTE
|
|
411
|
+
#
|
|
412
|
+
# Records the locations of those self-references so they are not mistaken
|
|
413
|
+
# for CTE references. Locations uniquely identify a RangeVar occurrence,
|
|
414
|
+
# which keeps the outer (genuine) CTE reference above excluded.
|
|
415
|
+
def record_cte_self_references!(with_clause)
|
|
416
|
+
return if with_clause.recursive
|
|
417
|
+
|
|
418
|
+
with_clause.ctes.each do |item|
|
|
419
|
+
next unless item.node == :common_table_expr
|
|
420
|
+
|
|
421
|
+
record_self_references_for_cte!(item.common_table_expr)
|
|
422
|
+
end
|
|
423
|
+
end
|
|
424
|
+
|
|
425
|
+
def record_self_references_for_cte!(cte)
|
|
426
|
+
return if cte.ctequery.nil?
|
|
427
|
+
return if @cte_names.include?(cte.ctename)
|
|
428
|
+
|
|
429
|
+
record_self_references_in(cte.ctequery, cte.ctename)
|
|
430
|
+
end
|
|
431
|
+
|
|
432
|
+
# Depth-first scan of a CTE definition for unqualified RangeVars matching
|
|
433
|
+
# the CTE's own name.
|
|
434
|
+
#
|
|
435
|
+
# This deliberately avoids #walk!, which yields every node and iterates all
|
|
436
|
+
# of PgQuery::Node's oneof fields. Following the oneof directly via #inner
|
|
437
|
+
# keeps this proportional to the nodes actually present.
|
|
438
|
+
def record_self_references_in(node, cte_name)
|
|
439
|
+
case node
|
|
440
|
+
when PgQuery::Node
|
|
441
|
+
record_self_references_in(node.inner, cte_name)
|
|
442
|
+
when PgQuery::RangeVar
|
|
443
|
+
@cte_self_reference_locations << node.location if cte_self_reference?(node, cte_name)
|
|
444
|
+
when Google::Protobuf::RepeatedField
|
|
445
|
+
node.each { |child| record_self_references_in(child, cte_name) }
|
|
446
|
+
when Google::Protobuf::MessageExts
|
|
447
|
+
record_self_references_in_message(node, cte_name)
|
|
448
|
+
end
|
|
449
|
+
end
|
|
450
|
+
|
|
451
|
+
def record_self_references_in_message(message, cte_name)
|
|
452
|
+
message.class.descriptor.each do |field_descriptor|
|
|
453
|
+
child = field_descriptor.get(message)
|
|
454
|
+
next unless child.is_a?(Google::Protobuf::MessageExts) || child.is_a?(Google::Protobuf::RepeatedField)
|
|
455
|
+
|
|
456
|
+
record_self_references_in(child, cte_name)
|
|
457
|
+
end
|
|
458
|
+
end
|
|
459
|
+
|
|
460
|
+
def cte_self_reference?(node, cte_name)
|
|
461
|
+
node.schemaname.empty? &&
|
|
462
|
+
node.relname == cte_name &&
|
|
463
|
+
!node.location.negative?
|
|
464
|
+
end
|
|
389
465
|
end
|
|
390
466
|
end
|