Class: RDBI::Driver::PostgreSQL::Statement

Inherits:
Statement
  • Object
show all
Defined in:
lib/rdbi/driver/postgresql.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(query, dbh) ⇒ Statement

Returns a new instance of Statement.



282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
# 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

Instance Attribute Details

#pg_resultObject

Returns the value of attribute pg_result.



279
280
281
# File 'lib/rdbi/driver/postgresql.rb', line 279

def pg_result
  @pg_result
end

#stmt_nameObject

Returns the value of attribute stmt_name.



280
281
282
# File 'lib/rdbi/driver/postgresql.rb', line 280

def stmt_name
  @stmt_name
end

Instance Method Details

#new_execution(*binds) ⇒ Object

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



354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
# 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) ⇒ Object



346
347
348
349
350
351
# 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