Class: Sequel::Postgres::Dataset

Inherits:
Dataset show all
Defined in:
lib/sequel/adapters/postgres.rb

Constant Summary collapse

FOR_UPDATE =
' FOR UPDATE'.freeze
FOR_SHARE =
' FOR SHARE'.freeze
EXPLAIN =
'EXPLAIN '.freeze
EXPLAIN_ANALYZE =
'EXPLAIN ANALYZE '.freeze
QUERY_PLAN =
'QUERY PLAN'.to_sym
LOCK =
'LOCK TABLE %s IN %s MODE'.freeze
ACCESS_SHARE =
'ACCESS SHARE'.freeze
ROW_SHARE =
'ROW SHARE'.freeze
ROW_EXCLUSIVE =
'ROW EXCLUSIVE'.freeze
SHARE_UPDATE_EXCLUSIVE =
'SHARE UPDATE EXCLUSIVE'.freeze
SHARE =
'SHARE'.freeze
SHARE_ROW_EXCLUSIVE =
'SHARE ROW EXCLUSIVE'.freeze
EXCLUSIVE =
'EXCLUSIVE'.freeze
ACCESS_EXCLUSIVE =
'ACCESS EXCLUSIVE'.freeze
@@converters_mutex =
Mutex.new
@@converters =
{}
@@array_tuples_converters_mutex =
Mutex.new
@@array_tuples_converters =
{}

Constants inherited from Dataset

Dataset::NOTIMPL_MSG, Dataset::STOCK_TRANSFORMS

Constants included from Dataset::Convenience

Dataset::Convenience::COMMA_SEPARATOR, Dataset::Convenience::MAGIC_METHODS, Dataset::Convenience::MUTATION_RE, Dataset::Convenience::NAKED_HASH

Constants included from Dataset::SQL

Dataset::SQL::ALIASED_REGEXP, Dataset::SQL::AND_SEPARATOR, Dataset::SQL::COMMA_SEPARATOR, Dataset::SQL::DATE_FORMAT, Dataset::SQL::FALSE, Dataset::SQL::JOIN_TYPES, Dataset::SQL::NULL, Dataset::SQL::QUALIFIED_REGEXP, Dataset::SQL::QUESTION_MARK, Dataset::SQL::STOCK_COUNT_OPTS, Dataset::SQL::TIMESTAMP_FORMAT, Dataset::SQL::TRUE, Dataset::SQL::WILDCARD

Constants included from Dataset::Sequelizer

Dataset::Sequelizer::JOIN_AND, Dataset::Sequelizer::JOIN_COMMA

Instance Attribute Summary

Attributes inherited from Dataset

#db, #opts

Attributes included from Dataset::Convenience

#current_page, #page_count, #page_size, #pagination_record_count

Instance Method Summary collapse

Methods inherited from Dataset

#<<, #clone_merge, #columns, dataset_classes, #each, #extend_with_destroy, inherited, #initialize, #model_classes, #naked, #polymorphic_key, #remove_row_proc, #set, #set_model, #set_options, #set_row_proc, #transform, #transform_load, #transform_save, #update_each_method

Methods included from Dataset::Convenience

#[], #[]=, #avg, #create_or_replace_view, #create_view, #current_page_record_count, #current_page_record_range, #each_hash, #empty?, #first, #group_and_count, #interval, #last, #magic_method_missing, #map, #max, #method_missing, #min, #multi_insert, #next_page, #page_range, #paginate, #prev_page, #print, #query, #range, #set_pagination_info, #single_record, #single_value, #sum, #to_csv, #to_hash

Methods included from Dataset::SQL

#and, #column_list, #count, #delete_sql, #except, #exclude, #exists, #expression_list, #filter, #from, #full_outer_join, #group, #having, #inner_join, #insert_multiple, #insert_sql, #intersect, #invert_order, #join_expr, #join_table, #left_outer_join, #limit, #or, #order, #qualified_column_name, #quote_column_ref, #reverse_order, #right_outer_join, #select, #source_list, #to_table_reference, #union, #uniq, #update_sql, #where

Methods included from Dataset::Sequelizer

#call_expr, #compare_expr, #eval_expr, #ext_expr, #fcall_expr, #iter_expr, #proc_to_sql, #pt_expr, #replace_dvars, #unfold_each_expr, #value_to_parse_tree, #vcall_expr

Methods included from Enumerable

#send_each

Constructor Details

This class inherits a constructor from Sequel::Dataset

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class Sequel::Dataset::Convenience

Instance Method Details

#analyze(opts = nil) ⇒ Object



373
374
375
376
377
378
379
# File 'lib/sequel/adapters/postgres.rb', line 373

def analyze(opts = nil)
  analysis = []
  fetch_rows(EXPLAIN_ANALYZE + select_sql(opts)) do |r|
    analysis << r[QUERY_PLAN]
  end
  analysis.join("\r\n")
end

#array_tuples_compile_converter(columns, translators) ⇒ Object



508
509
510
511
512
513
514
515
516
# File 'lib/sequel/adapters/postgres.rb', line 508

def array_tuples_compile_converter(columns, translators)
  tr = []
  columns.each_with_index do |column, idx|
    if !AUTO_TRANSLATE and t = translators[idx]
      tr << "if (v = r[#{idx}]); r[#{idx}] = v.#{t}; end"
    end
  end
  eval("lambda {|r| r.keys = columns; #{tr.join(';')}; r}")
end

#array_tuples_fetch_rows(sql, &block) ⇒ Object



479
480
481
482
483
484
485
486
487
488
489
# File 'lib/sequel/adapters/postgres.rb', line 479

def array_tuples_fetch_rows(sql, &block)
  @db.synchronize do
    result = @db.execute(sql)
    begin
      conv = array_tuples_row_converter(result)
      result.each {|r| yield conv[r]}
    ensure
      result.clear
    end
  end
end

#array_tuples_row_converter(result) ⇒ Object



494
495
496
497
498
499
500
501
502
503
504
505
506
# File 'lib/sequel/adapters/postgres.rb', line 494

def array_tuples_row_converter(result)
  @columns = []; translators = []
  result.fields.each_with_index do |f, idx|
    @columns << f.to_sym
    translators << PG_TYPES[result.type(idx)]
  end
  
  # create result signature and memoize the converter
  sig = [@columns, translators].hash
  @@array_tuples_converters_mutex.synchronize do
    @@array_tuples_converters[sig] ||= array_tuples_compile_converter(@columns, translators)
  end
end

#compile_converter(columns, translators) ⇒ Object



463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
# File 'lib/sequel/adapters/postgres.rb', line 463

def compile_converter(columns, translators)
  used_columns = []
  kvs = []
  columns.each_with_index do |column, idx|
    next if used_columns.include?(column)
    used_columns << column
  
    if !AUTO_TRANSLATE and translator = translators[idx]
      kvs << ":\"#{column}\" => ((t = r[#{idx}]) ? t.#{translator} : nil)"
    else
      kvs << ":\"#{column}\" => r[#{idx}]"
    end
  end
  eval("lambda {|r| {#{kvs.join(COMMA_SEPARATOR)}}}")
end

#delete(opts = nil) ⇒ Object



422
423
424
425
426
427
428
429
430
431
432
# File 'lib/sequel/adapters/postgres.rb', line 422

def delete(opts = nil)
  @db.synchronize do
    result = @db.execute(delete_sql(opts))
    begin
      affected = result.cmdtuples
    ensure
      result.clear
    end
    affected
  end
end

#explain(opts = nil) ⇒ Object



365
366
367
368
369
370
371
# File 'lib/sequel/adapters/postgres.rb', line 365

def explain(opts = nil)
  analysis = []
  fetch_rows(EXPLAIN + select_sql(opts)) do |r|
    analysis << r[QUERY_PLAN]
  end
  analysis.join("\r\n")
end

#fetch_rows(sql, &block) ⇒ Object



434
435
436
437
438
439
440
441
442
443
444
# File 'lib/sequel/adapters/postgres.rb', line 434

def fetch_rows(sql, &block)
  @db.synchronize do
    result = @db.execute(sql)
    begin
      conv = row_converter(result)
      result.each {|r| yield conv[r]}
    ensure
      result.clear
    end
  end
end

#for_shareObject



357
358
359
# File 'lib/sequel/adapters/postgres.rb', line 357

def for_share
  clone_merge(:lock => :share)
end

#for_updateObject



353
354
355
# File 'lib/sequel/adapters/postgres.rb', line 353

def for_update
  clone_merge(:lock => :update)
end

#insert(*values) ⇒ Object



405
406
407
408
# File 'lib/sequel/adapters/postgres.rb', line 405

def insert(*values)
  @db.execute_insert(insert_sql(*values), @opts[:from],
    values.size == 1 ? values.first : values)
end

#literal(v) ⇒ Object



316
317
318
319
320
321
322
323
324
325
# File 'lib/sequel/adapters/postgres.rb', line 316

def literal(v)
  case v
  when LiteralString
    v
  when String, Fixnum, Float, TrueClass, FalseClass
    PGconn.quote(v)
  else
    super
  end
end

#lock(mode, &block) ⇒ Object

Locks the table with the specified mode.



393
394
395
396
397
398
399
400
401
402
403
# File 'lib/sequel/adapters/postgres.rb', line 393

def lock(mode, &block)
  sql = LOCK % [@opts[:from], mode]
  @db.synchronize do
    if block # perform locking inside a transaction and yield to block
      @db.transaction {@db.execute_and_forget(sql); yield}
    else
      @db.execute_and_forget(sql) # lock without a transaction
      self
    end
  end
end

#match_expr(l, r) ⇒ Object



327
328
329
330
331
332
333
334
335
336
# File 'lib/sequel/adapters/postgres.rb', line 327

def match_expr(l, r)
  case r
  when Regexp
    r.casefold? ? \
      "(#{literal(l)} ~* #{literal(r.source)})" :
      "(#{literal(l)} ~ #{literal(r.source)})"
  else
    super
  end
end

#row_converter(result) ⇒ Object



449
450
451
452
453
454
455
456
457
458
459
460
461
# File 'lib/sequel/adapters/postgres.rb', line 449

def row_converter(result)
  @columns = []; translators = []
  result.fields.each_with_index do |f, idx|
    @columns << f.to_sym
    translators << PG_TYPES[result.type(idx)]
  end
  
  # create result signature and memoize the converter
  sig = [@columns, translators].hash
  @@converters_mutex.synchronize do
    @@converters[sig] ||= compile_converter(@columns, translators)
  end
end

#select_sql(opts = nil) ⇒ Object



341
342
343
344
345
346
347
348
349
350
351
# File 'lib/sequel/adapters/postgres.rb', line 341

def select_sql(opts = nil)
  row_lock_mode = opts ? opts[:lock] : @opts[:lock]
  sql = super
  case row_lock_mode
  when :update
    sql << FOR_UPDATE
  when :share
    sql << FOR_SHARE
  end
  sql
end

#update(*args, &block) ⇒ Object



410
411
412
413
414
415
416
417
418
419
420
# File 'lib/sequel/adapters/postgres.rb', line 410

def update(*args, &block)
  @db.synchronize do
    result = @db.execute(update_sql(*args, &block))
    begin
      affected = result.cmdtuples
    ensure
      result.clear
    end
    affected
  end
end