load_tables_and_aliases!

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