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_7_0_adapter.rb,
lib/active_record/connection_adapters/redshift_7_1_adapter.rb,
lib/active_record/connection_adapters/redshift_7_2_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
RS_VALID_CONN_PARAMS =
%i[host hostaddr port dbname user password connect_timeout
client_encoding options application_name fallback_application_name
keepalives keepalives_idle keepalives_interval keepalives_count
tty sslmode requiressl sslcompression sslcert sslkey
sslrootcert sslcrl requirepeer krbsrvname gsslib service].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

Constants included from ActiveRecord::ConnectionAdapters::Redshift::Quoting

ActiveRecord::ConnectionAdapters::Redshift::Quoting::QUOTED_COLUMN_NAMES, ActiveRecord::ConnectionAdapters::Redshift::Quoting::QUOTED_TABLE_NAMES

Class Method Summary collapse

Instance Method Summary collapse

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

#begin_db_transaction, #begin_isolated_db_transaction, #build_explain_clause, #commit_db_transaction, #exec_delete, #exec_insert, #exec_query, #exec_restart_db_transaction, #exec_rollback_db_transaction, #execute, #explain, #high_precision_current_timestamp, #query, #raw_execute, #result_as_array, #select_rows, #select_value, #select_values, #sql_for_insert, #write_query?

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

#column_name_matcher, #column_name_with_order_matcher, #escape_bytea, #lookup_cast_type_from_column, #quote, #quote_column_name, #quote_default_expression, #quote_default_value, #quote_schema_name, #quote_string, #quote_table_name, #quote_table_name_for_assignment, #quoted_binary, #quoted_date, #type_cast, #unescape_bytea

Constructor Details

#initializeRedshiftAdapter

Initializes and connects a PostgreSQL adapter.



167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# File 'lib/active_record/connection_adapters/redshift_7_0_adapter.rb', line 167

def initialize(connection, logger, connection_parameters, config)
  super(connection, logger, config)

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

  @connection_parameters = connection_parameters

  # @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(config[: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:



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
379
380
381
382
383
384
385
# File 'lib/active_record/connection_adapters/redshift_7_0_adapter.rb', line 344

def initialize_type_map(m) # :nodoc:
  m.register_type 'int2', Type::Integer.new(limit: 2)
  m.register_type 'int4', Type::Integer.new(limit: 4)
  m.register_type 'int8', Type::Integer.new(limit: 8)
  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

.new_client(conn_params) ⇒ Object



155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
# File 'lib/active_record/connection_adapters/redshift_7_1_adapter.rb', line 155

def new_client(conn_params)
  PG.connect(**conn_params)
rescue ::PG::Error => error
  if conn_params && conn_params[:dbname] == "postgres"
    raise ActiveRecord::ConnectionNotEstablished, error.message
  elsif conn_params && conn_params[:dbname] && error.message.include?(conn_params[:dbname])
    raise ActiveRecord::NoDatabaseError.db_error(conn_params[:dbname])
  elsif conn_params && conn_params[:user] && error.message.include?(conn_params[:user])
    raise ActiveRecord::DatabaseConnectionError.username_error(conn_params[:user])
  elsif conn_params && conn_params[:host] && error.message.include?(conn_params[:host])
    raise ActiveRecord::DatabaseConnectionError.hostname_error(conn_params[:host])
  else
    raise ActiveRecord::ConnectionNotEstablished, error.message
  end
end

Instance Method Details

#active?Boolean

Is this connection alive and ready for queries?

Returns:

  • (Boolean)


200
201
202
203
204
205
# File 'lib/active_record/connection_adapters/redshift_7_0_adapter.rb', line 200

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

#clear_cache!(new_connection: false) ⇒ Object

Clears the prepared statements cache.



191
192
193
# File 'lib/active_record/connection_adapters/redshift_7_0_adapter.rb', line 191

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

#column_name_for_operation(operation, _node) ⇒ Object

:nodoc:



313
314
315
# File 'lib/active_record/connection_adapters/redshift_7_0_adapter.rb', line 313

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

#disable_extension(name) ⇒ Object



279
# File 'lib/active_record/connection_adapters/redshift_7_0_adapter.rb', line 279

def disable_extension(name); end

#discard!Object

:nodoc:



245
246
247
248
249
# File 'lib/active_record/connection_adapters/redshift_7_1_adapter.rb', line 245

def discard! # :nodoc:
  super
  @raw_connection&.socket_io&.reopen(IO::NULL) rescue nil
  @raw_connection = nil
end

#disconnect!Object

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



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

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

#enable_extension(name) ⇒ Object



277
# File 'lib/active_record/connection_adapters/redshift_7_0_adapter.rb', line 277

def enable_extension(name); end

#extension_enabled?(_name) ⇒ Boolean

Returns:

  • (Boolean)


281
282
283
# File 'lib/active_record/connection_adapters/redshift_7_0_adapter.rb', line 281

def extension_enabled?(_name)
  false
end

#index_algorithmsObject



133
134
135
# File 'lib/active_record/connection_adapters/redshift_7_0_adapter.rb', line 133

def index_algorithms
  { concurrently: 'CONCURRENTLY' }
end

#lookup_cast_type(sql_type) ⇒ Object

:nodoc:



308
309
310
311
# File 'lib/active_record/connection_adapters/redshift_7_0_adapter.rb', line 308

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:



239
240
241
# File 'lib/active_record/connection_adapters/redshift_7_0_adapter.rb', line 239

def native_database_types # :nodoc:
  NATIVE_DATABASE_TYPES
end

#reconnect!Object

Close then reopen the connection.



213
214
215
216
217
218
# File 'lib/active_record/connection_adapters/redshift_7_0_adapter.rb', line 213

def reconnect!
  super
  @connection.reset
  configure_connection
  reload_type_map
end

#reload_type_mapObject

:nodoc:



211
212
213
214
# File 'lib/active_record/connection_adapters/redshift_7_1_adapter.rb', line 211

def reload_type_map
  type_map.clear
  initialize_type_map
end

#reset!Object



220
221
222
223
224
225
226
# File 'lib/active_record/connection_adapters/redshift_7_0_adapter.rb', line 220

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

#schema_creationObject

:nodoc:



101
102
103
# File 'lib/active_record/connection_adapters/redshift_7_0_adapter.rb', line 101

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

#session_auth=(user) ⇒ Object

Set the authorized user for this session



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

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

#supports_common_table_expressions?Boolean

Returns:

  • (Boolean)


301
302
303
# File 'lib/active_record/connection_adapters/redshift_7_1_adapter.rb', line 301

def supports_common_table_expressions?
  true
end

#supports_ddl_transactions?Boolean

Returns:

  • (Boolean)


253
254
255
# File 'lib/active_record/connection_adapters/redshift_7_0_adapter.rb', line 253

def supports_ddl_transactions?
  true
end

#supports_deferrable_constraints?Boolean

Returns:

  • (Boolean)


121
122
123
# File 'lib/active_record/connection_adapters/redshift_7_0_adapter.rb', line 121

def supports_deferrable_constraints?
  false
end

#supports_explain?Boolean

Returns:

  • (Boolean)


257
258
259
# File 'lib/active_record/connection_adapters/redshift_7_0_adapter.rb', line 257

def supports_explain?
  true
end

#supports_extensions?Boolean

Returns:

  • (Boolean)


261
262
263
# File 'lib/active_record/connection_adapters/redshift_7_0_adapter.rb', line 261

def supports_extensions?
  false
end

#supports_foreign_keys?Boolean

Returns:

  • (Boolean)


117
118
119
# File 'lib/active_record/connection_adapters/redshift_7_0_adapter.rb', line 117

def supports_foreign_keys?
  true
end

#supports_import?Boolean

Returns:

  • (Boolean)


273
274
275
# File 'lib/active_record/connection_adapters/redshift_7_0_adapter.rb', line 273

def supports_import?
  true
end

#supports_index_sort_order?Boolean

Returns:

  • (Boolean)


105
106
107
# File 'lib/active_record/connection_adapters/redshift_7_0_adapter.rb', line 105

def supports_index_sort_order?
  false
end

#supports_materialized_views?Boolean

Returns:

  • (Boolean)


269
270
271
# File 'lib/active_record/connection_adapters/redshift_7_0_adapter.rb', line 269

def supports_materialized_views?
  false
end

#supports_migrations?Boolean

Returns true, since this connection adapter supports migrations.

Returns:

  • (Boolean)


244
245
246
# File 'lib/active_record/connection_adapters/redshift_7_0_adapter.rb', line 244

def supports_migrations?
  true
end

#supports_partial_index?Boolean

Returns:

  • (Boolean)


109
110
111
# File 'lib/active_record/connection_adapters/redshift_7_0_adapter.rb', line 109

def supports_partial_index?
  false
end

#supports_primary_key?Boolean

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

Returns:

  • (Boolean)


249
250
251
# File 'lib/active_record/connection_adapters/redshift_7_0_adapter.rb', line 249

def supports_primary_key? # :nodoc:
  true
end

#supports_ranges?Boolean

Returns:

  • (Boolean)


265
266
267
# File 'lib/active_record/connection_adapters/redshift_7_0_adapter.rb', line 265

def supports_ranges?
  false
end

#supports_transaction_isolation?Boolean

Returns:

  • (Boolean)


113
114
115
# File 'lib/active_record/connection_adapters/redshift_7_0_adapter.rb', line 113

def supports_transaction_isolation?
  false
end

#supports_views?Boolean

Returns:

  • (Boolean)


125
126
127
# File 'lib/active_record/connection_adapters/redshift_7_0_adapter.rb', line 125

def supports_views?
  true
end

#supports_virtual_columns?Boolean

Returns:

  • (Boolean)


129
130
131
# File 'lib/active_record/connection_adapters/redshift_7_0_adapter.rb', line 129

def supports_virtual_columns?
  false
end

#table_alias_lengthObject

Returns the configured supported identifier length supported by PostgreSQL



286
287
288
# File 'lib/active_record/connection_adapters/redshift_7_0_adapter.rb', line 286

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

#truncate(table_name, name = nil) ⇒ Object



195
196
197
# File 'lib/active_record/connection_adapters/redshift_7_0_adapter.rb', line 195

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:



304
305
306
# File 'lib/active_record/connection_adapters/redshift_7_0_adapter.rb', line 304

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

#use_insert_returning?Boolean

Returns:

  • (Boolean)


296
297
298
# File 'lib/active_record/connection_adapters/redshift_7_0_adapter.rb', line 296

def use_insert_returning?
  false
end

#valid_type?(type) ⇒ Boolean

Returns:

  • (Boolean)


300
301
302
# File 'lib/active_record/connection_adapters/redshift_7_0_adapter.rb', line 300

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