Class: ActiveRecord::ConnectionAdapters::PostgreSQLAdapter

Inherits:
Object
  • Object
show all
Defined in:
lib/postgres_ext/active_record/connection_adapters/postgres_adapter.rb

Defined Under Namespace

Classes: ColumnDefinition, Table, TableDefinition, UnsupportedFeature

Constant Summary collapse

EXTENDED_TYPES =
{ :inet => {:name => 'inet'}, :cidr => {:name => 'cidr'}, :macaddr => {:name => 'macaddr'},
:uuid => {:name => 'uuid'}, :citext => {:name => 'citext'}, :ean13 => {:name => 'ean13'}, :numrange => {:name => 'numrange'},
:daterange => {:name => 'daterange'}, :int4range => {:name => 'int4range'}, :int8range => {:name => 'int8range'}, :tsrange => {:name => 'tsrange'}, :tstzrange => {:name => 'tstzrange'} }

Instance Method Summary collapse

Instance Method Details

#add_column(table_name, column_name, type, options = {}) ⇒ Object

The activerecord-jbdc-adapter implements PostgreSQLAdapter#add_column differently from the active-record version so we have to patch that version in JRuby, but not in MRI/YARV



324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
# File 'lib/postgres_ext/active_record/connection_adapters/postgres_adapter.rb', line 324

def add_column(table_name, column_name, type, options = {})
  default = options[:default]
  notnull = options[:null] == false
  sql_type = type_to_sql(type, options[:limit], options[:precision], options[:scale])

  if options[:array]
    sql_type << '[]'
  end

  # Add the column.
  execute("ALTER TABLE #{quote_table_name(table_name)} ADD COLUMN #{quote_column_name(column_name)} #{sql_type}")

  change_column_default(table_name, column_name, default) if options_include_default?(options)
  change_column_null(table_name, column_name, false, default) if notnull
end

#add_column_options!(sql, options) ⇒ Object



284
285
286
287
288
289
# File 'lib/postgres_ext/active_record/connection_adapters/postgres_adapter.rb', line 284

def add_column_options!(sql, options)
  if options[:array] || options[:column].try(:array)
    sql << '[]'
  end
  super
end

#add_extension(extension_name, options = {}) ⇒ Object

Raises:



306
307
308
309
# File 'lib/postgres_ext/active_record/connection_adapters/postgres_adapter.rb', line 306

def add_extension(extension_name, options={})
  raise UnsupportedFeature.new('Extensions are not support by this version of PostgreSQL') unless supports_extensions?
  execute "CREATE extension IF NOT EXISTS \"#{extension_name}\""
end

#add_index(table_name, column_name, options = {}) ⇒ Object



291
292
293
294
295
296
297
298
299
300
301
302
303
304
# File 'lib/postgres_ext/active_record/connection_adapters/postgres_adapter.rb', line 291

def add_index(table_name, column_name, options = {})
  index_name, unique, index_columns, _ = add_index_options(table_name, column_name, options)
  if options.is_a? Hash
    index_type = options[:using] ? " USING #{options[:using]} " : ""
    index_options = options[:where] ? " WHERE #{options[:where]}" : ""
    index_opclass = options[:index_opclass]
    index_algorithm = options[:algorithm] == :concurrently ? ' CONCURRENTLY' : ''

    if options[:algorithm].present? && options[:algorithm] != :concurrently
      raise ArgumentError.new 'Algorithm must be one of the following: :concurrently'
    end
  end
  execute "CREATE #{unique} INDEX#{index_algorithm} #{quote_column_name(index_name)} ON #{quote_table_name(table_name)}#{index_type}(#{index_columns} #{index_opclass})#{index_options}"
end

#change_column_with_extended_types(table_name, column_name, type, options = {}) ⇒ Object



460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
# File 'lib/postgres_ext/active_record/connection_adapters/postgres_adapter.rb', line 460

def change_column_with_extended_types(table_name, column_name, type, options = {})
  if options[:array]
    clear_cache!
    quoted_table_name = quote_table_name(table_name)

    if type.to_s =~ /string|text/
      execute "ALTER TABLE #{quoted_table_name} ALTER COLUMN #{quote_column_name(column_name)} TYPE #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}[] USING string_to_array(#{quote_column_name(column_name)}, ',')"
    else
      execute "ALTER TABLE #{quoted_table_name} ALTER COLUMN #{quote_column_name(column_name)} TYPE #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}[]"
    end

    change_column_default(table_name, column_name, options[:default]) if options_include_default?(options)
    change_column_null(table_name, column_name, options[:null], options[:default]) if options.key?(:null)
  else
    change_column_without_extended_types(table_name, column_name, type, options)
  end
end

#change_table(table_name, options = {}) ⇒ Object



311
312
313
314
315
316
317
318
319
# File 'lib/postgres_ext/active_record/connection_adapters/postgres_adapter.rb', line 311

def change_table(table_name, options = {})
  if supports_bulk_alter? && options[:bulk]
    recorder = ActiveRecord::Migration::CommandRecorder.new(self)
    yield Table.new(table_name, recorder)
    bulk_change_table(table_name, recorder.commands)
  else
    yield Table.new(table_name, self)
  end
end

#extensionsObject



456
457
458
# File 'lib/postgres_ext/active_record/connection_adapters/postgres_adapter.rb', line 456

def extensions
  select_rows('select extname from pg_extension', 'extensions').map { |row| row[0] }.delete_if {|name| name == 'plpgsql'}
end

#indexes(table_name, name = nil) ⇒ Object

this is based upon rails 4 changes to include different index methods Returns an array of indexes for the given table.



406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
# File 'lib/postgres_ext/active_record/connection_adapters/postgres_adapter.rb', line 406

def indexes(table_name, name = nil)
  opclasses
   result = select_rows(<<-SQL, name)
     SELECT distinct i.relname, d.indisunique, d.indkey, pg_get_indexdef(d.indexrelid), t.oid
     FROM pg_class t
     INNER JOIN pg_index d ON t.oid = d.indrelid
     INNER JOIN pg_class i ON d.indexrelid = i.oid
     WHERE i.relkind = 'i'
       AND d.indisprimary = 'f'
       AND t.relname = '#{table_name}'
       AND i.relnamespace IN (SELECT oid FROM pg_namespace WHERE nspname = ANY (current_schemas(false)) )
    ORDER BY i.relname
  SQL
  result.map do |row|
    index_name = row[0]
    unique = row[1] == 't'
    indkey = row[2].split(" ")
    inddef = row[3]
    oid = row[4]

    columns = Hash[select_rows(<<-SQL, "Columns for index #{row[0]} on #{table_name}")]
    SELECT a.attnum::text, a.attname
    FROM pg_attribute a
    WHERE a.attrelid = #{oid}
    AND a.attnum IN (#{indkey.join(",")})
    SQL
    column_names = columns.values_at(*indkey).compact

    # add info on sort order for columns (only desc order is explicitly specified, asc is the default)
    desc_order_columns = inddef.scan(/(\w+) DESC/).flatten
    orders = desc_order_columns.any? ? Hash[desc_order_columns.map {|order_column| [order_column, :desc]}] : {}
    #changed from rails 3.2
    where = inddef.scan(/WHERE (.+)$/).flatten[0]
    using = inddef.scan(/USING (.+?) /).flatten[0].to_sym
    if using
      index_op = inddef.scan(/USING .+? \(.+? (#{opclasses.join('|')})\)/).flatten
      index_op = index_op[0].to_sym if index_op.present?
    end
    if column_names.present?
      index_def = IndexDefinition.new(table_name, index_name, unique, column_names, [], orders)
      index_def.where = where
      index_def.using = using if using && using != :btree
      index_def.index_opclass = index_op if using && using != :btree && index_op
      index_def
    # else nil
    end
    #/changed
  end.compact
end

#opclassesObject



400
401
402
# File 'lib/postgres_ext/active_record/connection_adapters/postgres_adapter.rb', line 400

def opclasses
  @opclasses ||= select_rows('SELECT opcname FROM pg_opclass').flatten.uniq
end

#quote_with_extended_types(value, column = nil) ⇒ Object



385
386
387
388
389
390
391
392
393
394
395
396
397
# File 'lib/postgres_ext/active_record/connection_adapters/postgres_adapter.rb', line 385

def quote_with_extended_types(value, column = nil)
  if value.is_a? IPAddr
    "'#{type_cast(value, column)}'"
  elsif value.is_a? Array
    "'#{array_to_string(value, column, true)}'"
  elsif column.respond_to?(:array) && column.array && value =~ /^\{.*\}$/
    "'#{value}'"
  elsif value.is_a? Range
    "'#{type_cast(value, column)}'"
  else
    quote_without_extended_types(value, column)
  end
end

#supports_extensions?Boolean

Returns:

  • (Boolean)


280
281
282
# File 'lib/postgres_ext/active_record/connection_adapters/postgres_adapter.rb', line 280

def supports_extensions?
  postgresql_version > 90100
end

#type_cast_extended(value, column, part_array = false) ⇒ Object



341
342
343
344
345
346
347
348
349
350
351
352
353
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
# File 'lib/postgres_ext/active_record/connection_adapters/postgres_adapter.rb', line 341

def type_cast_extended(value, column, part_array = false)
  case value
  when NilClass
    if column.array && part_array
      'NULL'
    elsif column.array && !part_array
      value
    else
      type_cast_without_extended_types(value, column)
    end
  when Float
    if [:numrange,:int4range,:int8range,:daterange].include?(column.type)&& value.abs == (1.0/0.0)
      ''
    else
      type_cast_without_extended_types(value, column)
    end
  when Date, DateTime, Time
    if column.type == :tstzrange
      quoted_date(value)
    elsif column.type == :tsrange
      value.to_s(:db)
    else
      type_cast_without_extended_types(value, column)
    end
  when Range
    range_to_string(value, column)
  when Array
    if column.array
      array_to_string(value, column)
    else
      type_cast_without_extended_types(value, column)
    end
  when IPAddr
    ipaddr_to_string(value)
  else
    type_cast_without_extended_types(value, column)
  end
end

#type_cast_with_extended_types(value, column) ⇒ Object



380
381
382
# File 'lib/postgres_ext/active_record/connection_adapters/postgres_adapter.rb', line 380

def type_cast_with_extended_types(value, column)
  type_cast_extended(value, column)
end