class RDBI::Driver::PostgreSQL::Statement

Attributes

pg_result[RW]
stmt_name[RW]

Public Class Methods

new( query, dbh ) click to toggle source
Calls superclass method
# File lib/rdbi/driver/postgresql.rb, line 282
def initialize( query, dbh )
  super( query, dbh )
  @stmt_name = ('stmt_' + Time.now.to_f.to_s).tr('.', '_')

  ep = Epoxy.new( query )
  @index_map = ep.indexed_binds
  query = ep.quote(Hash[@index_map.compact.zip([])]) do |x|
    case x
    when Integer
      "$#{x+1}"
    when Symbol
      num = @index_map.index(x)
      "$#{num+1}"
    else
      x
    end
  end

  @pg_result = dbh.pg_conn.prepare(
    @stmt_name,
    query
  )

  # @input_type_map initialized in superclass
  @output_type_map = RDBI::Type.create_type_hash( RDBI::Type::Out )
  @output_type_map[ :bigint ] = RDBI::Type.filterlist( RDBI::Type::Filters::STR_TO_INT )

  # PostgreSQL returns timestamps with and without subseconds.
  # RDBI by default doesn't handle timestamps with subseconds,
  # so here we account for that in our PostgreSQL driver
  check = proc do |obj|
    begin
      if obj.include?('.')
        format = "%Y-%m-%d %H:%M:%S.%N %z"
        converted_and_back = DateTime.strptime(obj, format).strftime(format)
        # Strip trailing zeros in subseconds
        converted_and_back.gsub(/\.(\d+?)0* /, ".\\1 ") == obj.gsub(/\.(\d+?)0* /, ".\\1 ")
      else
        format = "%Y-%m-%d %H:%M:%S %z"
        DateTime.strptime(obj, format).strftime(format) == obj
      end
    rescue ArgumentError => e
      if e.message == 'invalid date'
        false
      else
        raise e
      end
    end
  end
  convert = proc do |obj|
    if obj.include?('.')
      DateTime.strptime(obj, "%Y-%m-%d %H:%M:%S.%N %z")
    else
      DateTime.strptime(obj, "%Y-%m-%d %H:%M:%S %z")
    end
  end
  @output_type_map[ :timestamp ] = RDBI::Type.filterlist( TypeLib::Filter.new(check, convert) )

  @finish_block = Proc.new {
    @dbh.pg_conn.exec("DEALLOCATE #{@stmt_name}")
    @pg_result.clear
  }
end

Public Instance Methods

new_execution( *binds ) click to toggle source

Returns an Array of things used to fill out the parameters to RDBI::Result.new

# File lib/rdbi/driver/postgresql.rb, line 354
def new_execution( *binds )
  binds = RDBI::Util.index_binds(binds, @index_map)

  pg_result = @dbh.pg_conn.exec_prepared( @stmt_name, binds )

  columns = []
  column_query = (0...pg_result.num_fields).map do |x|
    "format_type(#{ pg_result.ftype(x) }, #{ pg_result.fmod(x) }) as col#{x}"
  end.join(", ")

  unless column_query.empty?
    @dbh.pg_conn.exec("select #{column_query}")[0].values.each_with_index do |type, i|
      c = RDBI::Column.new
      c.name = pg_result.fname( i ).to_sym
      c.type = type
      if c.type.start_with? 'timestamp'
        c.ruby_type = 'timestamp'.to_sym
      else
        c.ruby_type = c.type.to_sym
      end
      columns << c
    end
  end

  this_schema = RDBI::Schema.new
  this_schema.columns = columns

  [ Cursor.new(pg_result, this_schema), this_schema, @output_type_map ]
end
new_modification(*binds) click to toggle source
# File lib/rdbi/driver/postgresql.rb, line 346
def new_modification(*binds)
  binds = RDBI::Util.index_binds(binds, @index_map)

  pg_result = @dbh.pg_conn.exec_prepared( @stmt_name, binds )
  return pg_result.cmd_tuples
end