in lib/pg_query/parse.rb [70:249]
def load_tables_and_aliases!
@tables = []
@cte_names = []
@aliases = {}
statements = @tree.stmts.dup.to_a.map(&:stmt)
from_clause_items = []
subselect_items = []
loop do
statement = statements.shift
if statement
case statement.node
when :list
statements += statement.list.items
when :select_stmt
subselect_items.concat(statement.select_stmt.target_list)
subselect_items << statement.select_stmt.where_clause if statement.select_stmt.where_clause
subselect_items.concat(statement.select_stmt.sort_clause.collect { |h| h.sort_by.node })
subselect_items.concat(statement.select_stmt.group_clause)
subselect_items << statement.select_stmt.having_clause if statement.select_stmt.having_clause
case statement.select_stmt.op
when :SETOP_NONE
(statement.select_stmt.from_clause || []).each do |item|
if item.node == :range_subselect
statements << item.range_subselect.subquery
else
from_clause_items << { item: item, type: :select }
end
end
when :SETOP_UNION
statements << PgQuery::Node.new(select_stmt: statement.select_stmt.larg) if statement.select_stmt.larg
statements << PgQuery::Node.new(select_stmt: statement.select_stmt.rarg) if statement.select_stmt.rarg
end
if statement.select_stmt.with_clause
cte_statements, cte_names = statements_and_cte_names_for_with_clause(statement.select_stmt.with_clause)
@cte_names.concat(cte_names)
statements.concat(cte_statements)
end
when :insert_stmt, :update_stmt, :delete_stmt
value = statement.public_send(statement.node)
from_clause_items << { item: PgQuery::Node.new(range_var: value.relation), type: :dml }
statements << value.select_stmt if statement.node == :insert_stmt && value.select_stmt
subselect_items.concat(statement.update_stmt.target_list) if statement.node == :update_stmt
subselect_items << statement.update_stmt.where_clause if statement.node == :update_stmt && statement.update_stmt.where_clause
subselect_items << statement.delete_stmt.where_clause if statement.node == :delete_stmt && statement.delete_stmt.where_clause
if value.with_clause
cte_statements, cte_names = statements_and_cte_names_for_with_clause(value.with_clause)
@cte_names.concat(cte_names)
statements.concat(cte_statements)
end
when :copy_stmt
from_clause_items << { item: PgQuery::Node.new(range_var: statement.copy_stmt.relation), type: :dml } if statement.copy_stmt.relation
statements << statement.copy_stmt.query
when :alter_table_stmt
from_clause_items << { item: PgQuery::Node.new(range_var: statement.alter_table_stmt.relation), type: :ddl }
when :create_stmt
from_clause_items << { item: PgQuery::Node.new(range_var: statement.create_stmt.relation), type: :ddl }
when :create_table_as_stmt
if statement.create_table_as_stmt.into && statement.create_table_as_stmt.into.rel
from_clause_items << { item: PgQuery::Node.new(range_var: statement.create_table_as_stmt.into.rel), type: :ddl }
end
statements << statement.create_table_as_stmt.query if statement.create_table_as_stmt.query
when :truncate_stmt
from_clause_items += statement.truncate_stmt.relations.map { |r| { item: r, type: :ddl } }
when :view_stmt
from_clause_items << { item: PgQuery::Node.new(range_var: statement.view_stmt.view), type: :ddl }
statements << statement.view_stmt.query
when :index_stmt
from_clause_items << { item: PgQuery::Node.new(range_var: statement.index_stmt.relation), type: :ddl }
when :create_trig_stmt
from_clause_items << { item: PgQuery::Node.new(range_var: statement.create_trig_stmt.relation), type: :ddl }
when :rule_stmt
from_clause_items << { item: PgQuery::Node.new(range_var: statement.rule_stmt.relation), type: :ddl }
when :vacuum_stmt
from_clause_items += statement.vacuum_stmt.rels.map { |r| { item: PgQuery::Node.new(range_var: r.vacuum_relation.relation), type: :ddl } if r.node == :vacuum_relation }
when :refresh_mat_view_stmt
from_clause_items << { item: PgQuery::Node.new(range_var: statement.refresh_mat_view_stmt.relation), type: :ddl }
when :drop_stmt
objects = statement.drop_stmt.objects.map do |obj|
case obj.node
when :list
obj.list.items.map { |obj2| obj2.string.str if obj2.node == :string }
when :string
obj.string.str
end
end
case statement.drop_stmt.remove_type
when :OBJECT_TABLE
@tables += objects.map { |r| { name: r.join('.'), type: :ddl } }
when :OBJECT_RULE, :OBJECT_TRIGGER
@tables += objects.map { |r| { name: r[0..-2].join('.'), type: :ddl } }
end
when :grant_stmt
objects = statement.grant_stmt.objects
case statement.grant_stmt.objtype
when :OBJECT_COLUMN
when :OBJECT_TABLE
from_clause_items += objects.map { |o| { item: o, type: :ddl } }
when :OBJECT_SEQUENCE
end
when :lock_stmt
from_clause_items += statement.lock_stmt.relations.map { |r| { item: r, type: :ddl } }
when :explain_stmt
statements << statement.explain_stmt.query
end
end
next_item = subselect_items.shift
if next_item
case next_item.node
when :a_expr
%w[lexpr rexpr].each do |side|
elem = next_item.a_expr.public_send(side)
next unless elem
if elem.is_a?(Array)
subselect_items += elem
else
subselect_items << elem
end
end
when :bool_expr
subselect_items.concat(next_item.bool_expr.args)
when :res_target
subselect_items << next_item.res_target.val
when :sub_link
statements << next_item.sub_link.subselect
end
end
break if subselect_items.empty? && statements.empty?
end
loop do
next_item = from_clause_items.shift
break unless next_item && next_item[:item]
case next_item[:item].node
when :join_expr
from_clause_items << { item: next_item[:item].join_expr.larg, type: next_item[:type] }
from_clause_items << { item: next_item[:item].join_expr.rarg, type: next_item[:type] }
when :row_expr
from_clause_items += next_item[:item].row_expr.args.map { |a| { item: a, type: next_item[:type] } }
when :range_var
rangevar = next_item[:item].range_var
next if rangevar.schemaname.empty? && @cte_names.include?(rangevar.relname)
table = [rangevar.schemaname, rangevar.relname].reject { |s| s.nil? || s.empty? }.join('.')
@tables << {
name: table,
type: next_item[:type],
location: rangevar.location,
schemaname: (rangevar.schemaname unless rangevar.schemaname.empty?),
relname: rangevar.relname,
inh: rangevar.inh
}
@aliases[rangevar.alias.aliasname] = table if rangevar.alias
when :range_subselect
from_clause_items << { item: next_item[:item].range_subselect.subquery, type: next_item[:type] }
when :select_stmt
from_clause = next_item[:item].select_stmt.from_clause
from_clause_items += from_clause.map { |r| { item: r, type: next_item[:type] } } if from_clause
end
end
@tables.uniq!
@cte_names.uniq!
end