class ActiveRecord::ConnectionAdapters::PostgreSQLAdapter

Patched version: 3.1.3

Patched methods
  • indexes

Constants

INDEX_COLUMN_EXPRESSION

Regex to find columns used in index statements

INDEX_WHERE_EXPRESION

Regex to find where clause in index statements

Public Instance Methods

find_column_names(table_name, index) click to toggle source

Find column names from index attributes. If the columns are virtual (ie this is an expression index) then it will try to return the functions that represent each column

@param [String] table_name the name of the table @param [Hash] index index attributes @return [Array]

# File lib/core_ext/active_record/connection_adapters/postgresql_adapter.rb, line 76
      def find_column_names(table_name, index)
        columns = Hash[query(<<-SQL, "Columns for index #{index[:name]} on #{table_name}")]
          SELECT a.attnum, a.attname
          FROM pg_attribute a
          WHERE a.attrelid = #{index[:id]}
          AND a.attnum IN (#{index[:keys].join(",")})
        SQL

        column_names = columns.values_at(*index[:keys]).compact

        if column_names.empty?
          definition = index[:definition].sub(INDEX_WHERE_EXPRESION, '')
          if column_expression = definition.match(INDEX_COLUMN_EXPRESSION)[1]
            column_names = split_expression(column_expression).map do |functional_name|
              remove_type(functional_name)
            end
          end
        end

        column_names
      end
find_lengths(index) click to toggle source

Find length of index TODO Update lengths once we merge in ActiveRecord code that supports it. -dresselm 20120305

@param [Hash] index index attributes @return [Array]

# File lib/core_ext/active_record/connection_adapters/postgresql_adapter.rb, line 138
def find_lengths(index)
  []
end
find_where_statement(index) click to toggle source

Find where statement from index definition

@param [Hash] index index attributes @return [String] where statement

# File lib/core_ext/active_record/connection_adapters/postgresql_adapter.rb, line 129
def find_where_statement(index)
  index[:definition].scan(INDEX_WHERE_EXPRESION).flatten[0]
end
indexes(table_name, name = nil) click to toggle source

Returns an array of indexes for the given table.

Patch 1 reason:

Since {ActiveRecord::SchemaDumper#tables} is patched to process tables with a schema prefix, the {#indexes} method receives table_name as “<schema>.<table>”. This patch allows it to handle table names with a schema prefix.

Patch 1:

Search using provided schema if table_name includes schema name.

Patch 2 reason:

{ActiveRecord::ConnectionAdapters::PostgreSQLAdapter#indexes} is patched to support partial indexes using :where clause.

Patch 2:

Search the postgres indexdef for the where clause and pass the output to the custom {PgPower::ConnectionAdapters::IndexDefinition}

# File lib/core_ext/active_record/connection_adapters/postgresql_adapter.rb, line 31
      def indexes(table_name, name = nil)
        schema, table = Utils.extract_schema_and_table(table_name)
        schemas = schema ? "ARRAY['#{schema}']" : 'current_schemas(false)'

        result = query(<<-SQL, name)
          SELECT distinct i.relname, d.indisunique, d.indkey,  pg_get_indexdef(d.indexrelid), t.oid, am.amname
          FROM pg_class t
          INNER JOIN pg_index d ON t.oid = d.indrelid
          INNER JOIN pg_class i ON d.indexrelid = i.oid
          INNER JOIN pg_am    am ON i.relam = am.oid
          WHERE i.relkind = 'i'
            AND d.indisprimary = 'f'
            AND t.relname = '#{table}'
            AND i.relnamespace IN (SELECT oid FROM pg_namespace WHERE nspname = ANY (#{schemas}) )
         ORDER BY i.relname
        SQL

        result.map do |row|
          index = {
            :name          => row[0],
            :unique        => row[1] == 't',
            :keys          => row[2].split(" "),
            :definition    => row[3],
            :id            => row[4],
            :access_method => row[5]
          }

          column_names = find_column_names(table_name, index)

          unless column_names.empty?
            where   = find_where_statement(index)
            lengths = find_lengths(index)

            PgPower::ConnectionAdapters::IndexDefinition.new(table_name, index[:name], index[:unique], column_names, lengths, where, index[:access_method])
          end
        end.compact
      end
remove_type(column_with_type) click to toggle source

Remove type specification from stored Postgres index definitions

@param [String] column_with_type the name of the column with type @return [String]

@example

remove_type("((col)::text")
=> "col"
# File lib/core_ext/active_record/connection_adapters/postgresql_adapter.rb, line 150
def remove_type(column_with_type)
  column_with_type.sub(/\((\w+)\)::\w+/, '\1')
end
split_expression(expression) click to toggle source

Splits only on commas outside of parens

# File lib/core_ext/active_record/connection_adapters/postgresql_adapter.rb, line 99
def split_expression(expression)
  result = []
  parens = 0
  buffer = ""

  expression.chars do |char|
    case char
    when ','
      if parens == 0
        result.push(buffer)
        buffer = ""
        next
      end
    when '('
      parens += 1
    when ')'
      parens -= 1
    end

    buffer << char
  end

  result << buffer unless buffer.empty?
  result
end