Class: ActiveRecord::ConnectionAdapters::RedshiftAdapter

Inherits:
AbstractAdapter
  • Object
show all
Includes:
ActiveRecord::ConnectionAdapters::Redshift::DatabaseStatements, ActiveRecord::ConnectionAdapters::Redshift::Quoting, ActiveRecord::ConnectionAdapters::Redshift::ReferentialIntegrity, ActiveRecord::ConnectionAdapters::Redshift::SchemaStatements
Defined in:
lib/active_record/connection_adapters/redshift_adapter.rb

Overview

The PostgreSQL adapter works with the native C (bitbucket.org/ged/ruby-pg) driver.

Options:

  • :host - Defaults to a Unix-domain socket in /tmp. On machines without Unix-domain sockets, the default is to connect to localhost.

  • :port - Defaults to 5432.

  • :username - Defaults to be the same as the operating system name of the user running the application.

  • :password - Password to be used if the server demands password authentication.

  • :database - Defaults to be the same as the user name.

  • :schema_search_path - An optional schema search path for the connection given as a string of comma-separated schema names. This is backward-compatible with the :schema_order option.

  • :encoding - An optional client encoding that is used in a SET client_encoding TO <encoding> call on the connection.

  • :min_messages - An optional client min messages that is used in a SET client_min_messages TO <min_messages> call on the connection.

  • :variables - An optional hash of additional parameters that will be used in SET SESSION key = val calls on the connection.

  • :insert_returning - Does nothing for Redshift.

Any further options are used as connection parameters to libpq. See www.postgresql.org/docs/9.1/static/libpq-connect.html for the list of parameters.

In addition, default connection parameters of libpq can be set per environment variables. See www.postgresql.org/docs/9.1/static/libpq-envars.html .

Defined Under Namespace

Classes: StatementPool

Constant Summary collapse

ADAPTER_NAME =
'Redshift'
NATIVE_DATABASE_TYPES =
{
  primary_key: 'integer identity primary key',
  string: { name: 'varchar' },
  text: { name: 'varchar' },
  integer: { name: 'integer' },
  float: { name: 'decimal' },
  decimal: { name: 'decimal' },
  datetime: { name: 'timestamp' },
  time: { name: 'timestamp' },
  date: { name: 'date' },
  bigint: { name: 'bigint' },
  boolean: { name: 'boolean' }
}.freeze
OID =

:nodoc:

Redshift::OID
OPERATION_ALIASES =

:nodoc:

{ # :nodoc:
  'maximum' => 'max',
  'minimum' => 'min',
  'average' => 'avg'
}.freeze

Constants included from ActiveRecord::ConnectionAdapters::Redshift::DatabaseStatements

ActiveRecord::ConnectionAdapters::Redshift::DatabaseStatements::BYTEA_COLUMN_TYPE_OID, ActiveRecord::ConnectionAdapters::Redshift::DatabaseStatements::MONEY_COLUMN_TYPE_OID

Constants included from ActiveRecord::ConnectionAdapters::Redshift::SchemaStatements

ActiveRecord::ConnectionAdapters::Redshift::SchemaStatements::FOREIGN_KEY_ACTIONS

Class Method Summary collapse

Instance Method Summary collapse

Methods included from ActiveRecord::ConnectionAdapters::Redshift::DatabaseStatements

#begin_db_transaction, #begin_isolated_db_transaction, #commit_db_transaction, #exec_delete, #exec_insert, #exec_query, #exec_rollback_db_transaction, #execute, #explain, #internal_exec_query, #query, #result_as_array, #select_rows, #select_value, #select_values, #sql_for_insert

Methods included from ActiveRecord::ConnectionAdapters::Redshift::SchemaStatements

#add_column, #add_index, #change_column, #change_column_default, #change_column_null, #collation, #columns, #columns_for_distinct, #create_database, #create_schema, #ctype, #current_database, #current_schema, #data_source_exists?, #data_sources, #default_sequence_name, #drop_database, #drop_schema, #drop_table, #encoding, #extract_foreign_key_action, #fetch_type_metadata, #foreign_keys, #index_name_exists?, #index_name_length, #indexes, #new_column, #pk_and_sequence_for, #primary_keys, #recreate_database, #remove_index!, #rename_column, #rename_index, #rename_table, #reset_pk_sequence!, #schema_exists?, #schema_names, #schema_search_path, #schema_search_path=, #serial_sequence, #set_pk_sequence!, #table_exists?, #tables, #type_to_sql, #view_exists?, #views

Methods included from ActiveRecord::ConnectionAdapters::Redshift::ReferentialIntegrity

#disable_referential_integrity, #supports_disable_referential_integrity?

Methods included from ActiveRecord::ConnectionAdapters::Redshift::Quoting

#escape_bytea, #quote, #quote_column_name, #quote_default_value, #quote_schema_name, #quote_string, #quote_table_name, #quote_table_name_for_assignment, #quoted_date, #type_cast, #unescape_bytea

Constructor Details

#initialize(config_or_deprecated_connection, deprecated_logger = nil, deprecated_connection_options = nil, deprecated_config = nil) ⇒ RedshiftAdapter

Initializes and connects a PostgreSQL adapter.



169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
# File 'lib/active_record/connection_adapters/redshift_adapter.rb', line 169

def initialize(config_or_deprecated_connection, deprecated_logger = nil, deprecated_connection_options = nil, deprecated_config = nil) # :nodoc:
  super(config_or_deprecated_connection, deprecated_logger, deprecated_connection_options, deprecated_config)

  @visitor = Arel::Visitors::PostgreSQL.new self
  @visitor.extend(ConnectionAdapters::DetermineIfPreparableVisitor) if defined?(ConnectionAdapters::DetermineIfPreparableVisitor)
  @prepared_statements = false

  conn_params = config_or_deprecated_connection.compact
  conn_params[:user] = conn_params.delete(:username) if conn_params[:username]
  conn_params[:dbname] = conn_params.delete(:database) if conn_params[:database]

  valid_conn_param_keys = PG::Connection.conndefaults_hash.keys + [:requiressl]
  conn_params.slice!(*valid_conn_param_keys)

  @connection_parameters = conn_params

  # @local_tz is initialized as nil to avoid warnings when connect tries to use it
  @local_tz = nil
  @table_alias_length = nil

  connect
  @statements = StatementPool.new @connection,
                                  self.class.type_cast_config_to_integer(conn_params[:statement_limit])

  @type_map = Type::HashLookupTypeMap.new
  initialize_type_map(type_map)
  @local_tz = execute('SHOW TIME ZONE', 'SCHEMA').first['TimeZone']
  @use_insert_returning = @config.key?(:insert_returning) ? self.class.type_cast_config_to_boolean(@config[:insert_returning]) : false
end

Class Method Details

.initialize_type_map(m) ⇒ Object

:nodoc:



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
383
384
385
386
387
388
389
390
391
392
393
394
395
396
# File 'lib/active_record/connection_adapters/redshift_adapter.rb', line 355

def initialize_type_map(m) # :nodoc:
  register_class_with_limit m, 'int2', Type::Integer
  register_class_with_limit m, 'int4', Type::Integer
  register_class_with_limit m, 'int8', Type::Integer
  m.alias_type 'oid', 'int2'
  m.register_type 'float4', Type::Float.new
  m.alias_type 'float8', 'float4'
  m.register_type 'text', Type::Text.new
  register_class_with_limit m, 'varchar', Type::String
  m.alias_type 'char', 'varchar'
  m.alias_type 'name', 'varchar'
  m.alias_type 'bpchar', 'varchar'
  m.register_type 'bool', Type::Boolean.new
  m.alias_type 'timestamptz', 'timestamp'
  m.register_type 'date', Type::Date.new
  m.register_type 'time', Type::Time.new

  m.register_type 'timestamp' do |_, _, sql_type|
    precision = extract_precision(sql_type)
    OID::DateTime.new(precision: precision)
  end

  m.register_type 'numeric' do |_, fmod, sql_type|
    precision = extract_precision(sql_type)
    scale = extract_scale(sql_type)

    # The type for the numeric depends on the width of the field,
    # so we'll do something special here.
    #
    # When dealing with decimal columns:
    #
    # places after decimal  = fmod - 4 & 0xffff
    # places before decimal = (fmod - 4) >> 16 & 0xffff
    if fmod && (fmod - 4 & 0xffff) == 0
      # FIXME: Remove this class, and the second argument to
      # lookups on PG
      Type::DecimalWithoutScale.new(precision: precision)
    else
      OID::Decimal.new(precision: precision, scale: scale)
    end
  end
end

Instance Method Details

#active?Boolean

Is this connection alive and ready for queries?

Returns:

  • (Boolean)


209
210
211
212
213
214
# File 'lib/active_record/connection_adapters/redshift_adapter.rb', line 209

def active?
  @connection.query 'SELECT 1'
  true
rescue PG::Error
  false
end

#clear_cache!(new_connection: false) ⇒ Object

Clears the prepared statements cache.



200
201
202
# File 'lib/active_record/connection_adapters/redshift_adapter.rb', line 200

def clear_cache!(new_connection: false)
  @statements.clear
end

#column_name_for_operation(operation, _node) ⇒ Object

:nodoc:



324
325
326
# File 'lib/active_record/connection_adapters/redshift_adapter.rb', line 324

def column_name_for_operation(operation, _node) # :nodoc:
  OPERATION_ALIASES.fetch(operation) { operation.downcase }
end

#disable_extension(name) ⇒ Object



290
# File 'lib/active_record/connection_adapters/redshift_adapter.rb', line 290

def disable_extension(name); end

#disconnect!Object

Disconnects from the database if already connected. Otherwise, this method does nothing.



241
242
243
244
245
246
247
248
# File 'lib/active_record/connection_adapters/redshift_adapter.rb', line 241

def disconnect!
  super
  begin
    @connection.close
  rescue StandardError
    nil
  end
end

#enable_extension(name) ⇒ Object



288
# File 'lib/active_record/connection_adapters/redshift_adapter.rb', line 288

def enable_extension(name); end

#extension_enabled?(_name) ⇒ Boolean

Returns:

  • (Boolean)


292
293
294
# File 'lib/active_record/connection_adapters/redshift_adapter.rb', line 292

def extension_enabled?(_name)
  false
end

#index_algorithmsObject



135
136
137
# File 'lib/active_record/connection_adapters/redshift_adapter.rb', line 135

def index_algorithms
  { concurrently: 'CONCURRENTLY' }
end

#lookup_cast_type(sql_type) ⇒ Object

:nodoc:



319
320
321
322
# File 'lib/active_record/connection_adapters/redshift_adapter.rb', line 319

def lookup_cast_type(sql_type) # :nodoc:
  oid = execute("SELECT #{quote(sql_type)}::regtype::oid", 'SCHEMA').first['oid'].to_i
  super(oid)
end

#native_database_typesObject

:nodoc:



250
251
252
# File 'lib/active_record/connection_adapters/redshift_adapter.rb', line 250

def native_database_types # :nodoc:
  NATIVE_DATABASE_TYPES
end

#reconnect!Object

Close then reopen the connection.



222
223
224
225
226
227
228
229
230
# File 'lib/active_record/connection_adapters/redshift_adapter.rb', line 222

def reconnect!
  begin
    @connection&.reset
  rescue PG::ConnectionBad
    @connection = nil
  end

  connect unless @connection
end

#reload_type_mapObject



216
217
218
219
# File 'lib/active_record/connection_adapters/redshift_adapter.rb', line 216

def reload_type_map
  type_map.clear
  initialize_type_map
end

#reset!Object



232
233
234
235
236
237
# File 'lib/active_record/connection_adapters/redshift_adapter.rb', line 232

def reset!
  clear_cache!
  reset_transaction
  @connection.query 'ROLLBACK' unless @connection.transaction_status == ::PG::PQTRANS_IDLE
  configure_connection
end

#schema_creationObject

:nodoc:



103
104
105
# File 'lib/active_record/connection_adapters/redshift_adapter.rb', line 103

def schema_creation # :nodoc:
  Redshift::SchemaCreation.new self
end

#session_auth=(user) ⇒ Object

Set the authorized user for this session



302
303
304
305
# File 'lib/active_record/connection_adapters/redshift_adapter.rb', line 302

def session_auth=(user)
  clear_cache!
  exec_query "SET SESSION AUTHORIZATION #{user}"
end

#supports_ddl_transactions?Boolean

Returns:

  • (Boolean)


264
265
266
# File 'lib/active_record/connection_adapters/redshift_adapter.rb', line 264

def supports_ddl_transactions?
  true
end

#supports_deferrable_constraints?Boolean

Returns:

  • (Boolean)


123
124
125
# File 'lib/active_record/connection_adapters/redshift_adapter.rb', line 123

def supports_deferrable_constraints?
  false
end

#supports_explain?Boolean

Returns:

  • (Boolean)


268
269
270
# File 'lib/active_record/connection_adapters/redshift_adapter.rb', line 268

def supports_explain?
  true
end

#supports_extensions?Boolean

Returns:

  • (Boolean)


272
273
274
# File 'lib/active_record/connection_adapters/redshift_adapter.rb', line 272

def supports_extensions?
  false
end

#supports_foreign_keys?Boolean

Returns:

  • (Boolean)


119
120
121
# File 'lib/active_record/connection_adapters/redshift_adapter.rb', line 119

def supports_foreign_keys?
  true
end

#supports_import?Boolean

Returns:

  • (Boolean)


284
285
286
# File 'lib/active_record/connection_adapters/redshift_adapter.rb', line 284

def supports_import?
  true
end

#supports_index_sort_order?Boolean

Returns:

  • (Boolean)


107
108
109
# File 'lib/active_record/connection_adapters/redshift_adapter.rb', line 107

def supports_index_sort_order?
  false
end

#supports_materialized_views?Boolean

Returns:

  • (Boolean)


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

def supports_materialized_views?
  false
end

#supports_migrations?Boolean

Returns true, since this connection adapter supports migrations.

Returns:

  • (Boolean)


255
256
257
# File 'lib/active_record/connection_adapters/redshift_adapter.rb', line 255

def supports_migrations?
  true
end

#supports_partial_index?Boolean

Returns:

  • (Boolean)


111
112
113
# File 'lib/active_record/connection_adapters/redshift_adapter.rb', line 111

def supports_partial_index?
  false
end

#supports_primary_key?Boolean

Does PostgreSQL support finding primary key on non-Active Record tables?

Returns:

  • (Boolean)


260
261
262
# File 'lib/active_record/connection_adapters/redshift_adapter.rb', line 260

def supports_primary_key? # :nodoc:
  true
end

#supports_ranges?Boolean

Returns:

  • (Boolean)


276
277
278
# File 'lib/active_record/connection_adapters/redshift_adapter.rb', line 276

def supports_ranges?
  false
end

#supports_transaction_isolation?Boolean

Returns:

  • (Boolean)


115
116
117
# File 'lib/active_record/connection_adapters/redshift_adapter.rb', line 115

def supports_transaction_isolation?
  false
end

#supports_views?Boolean

Returns:

  • (Boolean)


127
128
129
# File 'lib/active_record/connection_adapters/redshift_adapter.rb', line 127

def supports_views?
  true
end

#supports_virtual_columns?Boolean

Returns:

  • (Boolean)


131
132
133
# File 'lib/active_record/connection_adapters/redshift_adapter.rb', line 131

def supports_virtual_columns?
  false
end

#table_alias_lengthObject

Returns the configured supported identifier length supported by PostgreSQL



297
298
299
# File 'lib/active_record/connection_adapters/redshift_adapter.rb', line 297

def table_alias_length
  @table_alias_length ||= query('SHOW max_identifier_length', 'SCHEMA')[0][0].to_i
end

#truncate(table_name, name = nil) ⇒ Object



204
205
206
# File 'lib/active_record/connection_adapters/redshift_adapter.rb', line 204

def truncate(table_name, name = nil)
  exec_query "TRUNCATE TABLE #{quote_table_name(table_name)}", name, []
end

#update_table_definition(table_name, base) ⇒ Object

:nodoc:



315
316
317
# File 'lib/active_record/connection_adapters/redshift_adapter.rb', line 315

def update_table_definition(table_name, base) # :nodoc:
  Redshift::Table.new(table_name, base)
end

#use_insert_returning?Boolean

Returns:

  • (Boolean)


307
308
309
# File 'lib/active_record/connection_adapters/redshift_adapter.rb', line 307

def use_insert_returning?
  false
end

#valid_type?(type) ⇒ Boolean

Returns:

  • (Boolean)


311
312
313
# File 'lib/active_record/connection_adapters/redshift_adapter.rb', line 311

def valid_type?(type)
  !native_database_types[type].nil?
end