Class: ActiveRecord::ConnectionAdapters::SQLite3Adapter

Inherits:
AbstractAdapter show all
Includes:
ActiveRecord::ConnectionAdapters::SQLite3::DatabaseStatements, ActiveRecord::ConnectionAdapters::SQLite3::Quoting, ActiveRecord::ConnectionAdapters::SQLite3::SchemaStatements
Defined in:
activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb

Overview

The SQLite3 adapter works with the sqlite3-ruby drivers (available as gem from rubygems.org/gems/sqlite3).

Options:

  • :database - Path to the database file.

Defined Under Namespace

Classes: SQLite3Integer, StatementPool

Constant Summary collapse

ADAPTER_NAME =
"SQLite"
NATIVE_DATABASE_TYPES =
{
  primary_key:  "integer PRIMARY KEY AUTOINCREMENT NOT NULL",
  string:       { name: "varchar" },
  text:         { name: "text" },
  integer:      { name: "integer" },
  float:        { name: "float" },
  decimal:      { name: "decimal" },
  datetime:     { name: "datetime" },
  time:         { name: "time" },
  date:         { name: "date" },
  binary:       { name: "blob" },
  boolean:      { name: "boolean" },
  json:         { name: "json" },
}
TYPE_MAP =
Type::TypeMap.new.tap { |m| initialize_type_map(m) }
EXTENDED_TYPE_MAPS =
Concurrent::Map.new

Constants inherited from AbstractAdapter

AbstractAdapter::COMMENT_REGEX, AbstractAdapter::SIMPLE_INT

Constants included from ActiveSupport::Callbacks

ActiveSupport::Callbacks::CALLBACK_FILTER_TYPES

Instance Attribute Summary

Attributes inherited from AbstractAdapter

#lock, #logger, #owner, #pool, #visitor

Attributes included from QueryCache

#query_cache, #query_cache_enabled

Attributes included from DatabaseStatements

#transaction_manager

Class Method Summary collapse

Instance Method Summary collapse

Methods included from ActiveRecord::ConnectionAdapters::SQLite3::DatabaseStatements

#begin_db_transaction, #begin_isolated_db_transaction, #commit_db_transaction, #exec_delete, #exec_query, #exec_rollback_db_transaction, #execute, #explain, #high_precision_current_timestamp, #write_query?

Methods included from ActiveRecord::ConnectionAdapters::SQLite3::SchemaStatements

#add_check_constraint, #add_foreign_key, #check_constraints, #create_schema_dumper, #indexes, #remove_check_constraint, #remove_foreign_key

Methods included from ActiveRecord::ConnectionAdapters::SQLite3::Quoting

#column_name_matcher, #column_name_with_order_matcher, #quote_column_name, #quote_default_expression, #quote_string, #quote_table_name, #quote_table_name_for_assignment, #quoted_binary, #quoted_false, #quoted_time, #quoted_true, #type_cast, #unquoted_false, #unquoted_true

Methods inherited from AbstractAdapter

#adapter_name, #advisory_locks_enabled?, #async_enabled?, build_read_query_regexp, #case_insensitive_comparison, #case_sensitive_comparison, #check_if_write_query, #clear_cache!, #close, #connection_class, #create_enum, #database_version, #default_index_type?, #default_timezone, #default_uniqueness_comparison, #disable_extension, #discard!, #enable_extension, #expire, extended_type_map, #extensions, #field_ordered_value, #get_advisory_lock, #index_algorithms, #lease, #migration_context, #migrations_paths, #prefetch_primary_key?, #prepared_statements?, #prepared_statements_disabled_cache, #preventing_writes?, quoted_column_names, quoted_table_names, #raw_connection, register_class_with_precision, #release_advisory_lock, #replica?, #role, #savepoint_errors_invalidate_transactions?, #schema_cache, #schema_cache=, #schema_migration, #schema_version, #seconds_idle, #shard, #steal!, #supports_advisory_locks?, #supports_bulk_alter?, #supports_comments?, #supports_comments_in_create?, #supports_deferrable_constraints?, #supports_extensions?, #supports_foreign_tables?, #supports_indexes_in_create?, #supports_insert_returning?, #supports_materialized_views?, #supports_optimizer_hints?, #supports_partitioned_indexes?, #supports_restart_db_transaction?, #supports_validate_constraints?, #supports_virtual_columns?, #throw_away!, type_cast_config_to_boolean, type_cast_config_to_integer, #unprepared_statement, #use_metadata_table?, #valid_type?, validate_default_timezone, #verify!, #with_instrumenter

Methods included from Savepoints

#create_savepoint, #current_savepoint_name, #exec_rollback_to_savepoint, #release_savepoint

Methods included from QueryCache

#cache, #clear_query_cache, dirties_query_cache, #disable_query_cache!, #enable_query_cache!, included, #select_all, #uncached

Methods included from DatabaseLimits

#index_name_length, #max_identifier_length, #table_alias_length

Methods included from Quoting

#column_name_matcher, #column_name_with_order_matcher, #lookup_cast_type_from_column, #quote, #quote_bound_value, #quote_column_name, #quote_default_expression, #quote_string, #quote_table_name, #quote_table_name_for_assignment, #quoted_binary, #quoted_date, #quoted_false, #quoted_time, #quoted_true, #sanitize_as_sql_comment, #type_cast, #unquoted_false, #unquoted_true

Methods included from DatabaseStatements

#add_transaction_record, #begin_db_transaction, #begin_isolated_db_transaction, #cacheable_query, #commit_db_transaction, #default_sequence_name, #delete, #empty_insert_statement_value, #exec_delete, #exec_insert, #exec_insert_all, #exec_query, #exec_restart_db_transaction, #exec_rollback_db_transaction, #exec_update, #execute, #explain, #high_precision_current_timestamp, #insert, #insert_fixture, #insert_fixtures_set, #mark_transaction_written_if_write, #query, #query_value, #query_values, #reset_sequence!, #reset_transaction, #restart_db_transaction, #rollback_db_transaction, #rollback_to_savepoint, #sanitize_limit, #select_all, #select_one, #select_rows, #select_value, #select_values, #to_sql, #transaction, #transaction_isolation_levels, #transaction_open?, #truncate, #truncate_tables, #update, #with_yaml_fallback, #write_query?

Methods included from SchemaStatements

#add_check_constraint, #add_columns, #add_foreign_key, #add_index, #add_index_options, #add_timestamps, #assume_migrated_upto_version, #change_column_comment, #change_table, #change_table_comment, #check_constraint_options, #check_constraints, #column_exists?, #columns, #columns_for_distinct, #create_join_table, #create_schema_dumper, #create_table, #data_source_exists?, #data_sources, #distinct_relation_for_primary_key, #drop_join_table, #drop_table, #dump_schema_information, #foreign_key_column_for, #foreign_key_exists?, #foreign_key_options, #index_algorithm, #index_exists?, #index_name, #index_name_exists?, #indexes, #internal_string_options_for_primary_key, #options_include_default?, #primary_key, #quoted_columns_for_index, #remove_check_constraint, #remove_foreign_key, #remove_reference, #remove_timestamps, #rename_index, #table_alias_for, #table_comment, #table_exists?, #table_options, #tables, #type_to_sql, #update_table_definition, #view_exists?, #views

Methods included from ActiveSupport::Callbacks

#run_callbacks

Methods included from ActiveSupport::Concern

#append_features, #class_methods, extended, #included, #prepend_features, #prepended

Constructor Details

#initialize(connection, logger, connection_options, config) ⇒ SQLite3Adapter

Returns a new instance of SQLite3Adapter.


88
89
90
91
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 88

def initialize(connection, logger, connection_options, config)
  @memory_database = config[:database] == ":memory:"
  super(connection, logger, config)
end

Class Method Details

.database_exists?(config) ⇒ Boolean

Returns:

  • (Boolean)

93
94
95
96
97
98
99
100
101
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 93

def self.database_exists?(config)
  config = config.symbolize_keys
  if config[:database] == ":memory:"
    true
  else
    database_file = defined?(Rails.root) ? File.expand_path(config[:database], Rails.root) : config[:database]
    File.exist?(database_file)
  end
end

Instance Method Details

#active?Boolean

Returns:

  • (Boolean)

162
163
164
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 162

def active?
  !@raw_connection.closed?
end

#add_column(table_name, column_name, type, **options) ⇒ Object

:nodoc:


253
254
255
256
257
258
259
260
261
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 253

def add_column(table_name, column_name, type, **options) # :nodoc:
  if invalid_alter_table_type?(type, options)
    alter_table(table_name) do |definition|
      definition.column(column_name, type, **options)
    end
  else
    super
  end
end

#add_reference(table_name, ref_name, **options) ⇒ Object Also known as: add_belongs_to

:nodoc:


312
313
314
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 312

def add_reference(table_name, ref_name, **options) # :nodoc:
  super(table_name, ref_name, type: :integer, **options)
end

#all_foreign_keys_valid?Boolean

:nodoc:

Returns:

  • (Boolean)

223
224
225
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 223

def all_foreign_keys_valid? # :nodoc:
  execute("PRAGMA foreign_key_check").blank?
end

#build_insert_sql(insert) ⇒ Object

:nodoc:


330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 330

def build_insert_sql(insert) # :nodoc:
  sql = +"INSERT #{insert.into} #{insert.values_list}"

  if insert.skip_duplicates?
    sql << " ON CONFLICT #{insert.conflict_target} DO NOTHING"
  elsif insert.update_duplicates?
    sql << " ON CONFLICT #{insert.conflict_target} DO UPDATE SET "
    if insert.raw_update_sql?
      sql << insert.raw_update_sql
    else
      sql << insert.touch_model_timestamps_unless { |column| "#{column} IS excluded.#{column}" }
      sql << insert.updatable_columns.map { |column| "#{column}=excluded.#{column}" }.join(",")
    end
  end

  sql
end

#change_column(table_name, column_name, type, **options) ⇒ Object

:nodoc:


297
298
299
300
301
302
303
304
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 297

def change_column(table_name, column_name, type, **options) # :nodoc:
  alter_table(table_name) do |definition|
    definition[column_name].instance_eval do
      self.type = aliased_types(type.to_s, type)
      self.options.merge!(options)
    end
  end
end

#change_column_default(table_name, column_name, default_or_changes) ⇒ Object

:nodoc:


280
281
282
283
284
285
286
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 280

def change_column_default(table_name, column_name, default_or_changes) # :nodoc:
  default = extract_new_default_value(default_or_changes)

  alter_table(table_name) do |definition|
    definition[column_name].default = default
  end
end

#change_column_null(table_name, column_name, null, default = nil) ⇒ Object

:nodoc:


288
289
290
291
292
293
294
295
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 288

def change_column_null(table_name, column_name, null, default = nil) # :nodoc:
  unless null || default.nil?
    exec_query("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
  end
  alter_table(table_name) do |definition|
    definition[column_name].null = null
  end
end

#check_versionObject

:nodoc:


356
357
358
359
360
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 356

def check_version # :nodoc:
  if database_version < "3.8.0"
    raise "Your version of SQLite (#{database_version}) is too old. Active Record supports SQLite >= 3.8."
  end
end

#disable_referential_integrityObject

REFERENTIAL INTEGRITY ====================================


209
210
211
212
213
214
215
216
217
218
219
220
221
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 209

def disable_referential_integrity # :nodoc:
  old_foreign_keys = query_value("PRAGMA foreign_keys")
  old_defer_foreign_keys = query_value("PRAGMA defer_foreign_keys")

  begin
    execute("PRAGMA defer_foreign_keys = ON")
    execute("PRAGMA foreign_keys = OFF")
    yield
  ensure
    execute("PRAGMA defer_foreign_keys = #{old_defer_foreign_keys}")
    execute("PRAGMA foreign_keys = #{old_foreign_keys}")
  end
end

#disconnect!Object

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


181
182
183
184
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 181

def disconnect!
  super
  @raw_connection.close rescue nil
end

#encodingObject

Returns the current database encoding format as a string, e.g. 'UTF-8'


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

def encoding
  @raw_connection.encoding.to_s
end

#foreign_keys(table_name) ⇒ Object


317
318
319
320
321
322
323
324
325
326
327
328
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 317

def foreign_keys(table_name)
  fk_info = exec_query("PRAGMA foreign_key_list(#{quote(table_name)})", "SCHEMA")
  fk_info.map do |row|
    options = {
      column: row["from"],
      primary_key: row["to"],
      on_delete: extract_foreign_key_action(row["on_delete"]),
      on_update: extract_foreign_key_action(row["on_update"])
    }
    ForeignKeyDefinition.new(table_name, row["table"], options)
  end
end

#get_database_versionObject

:nodoc:


352
353
354
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 352

def get_database_version # :nodoc:
  SQLite3Adapter::Version.new(query_value("SELECT sqlite_version(*)"))
end

#native_database_typesObject

:nodoc:


190
191
192
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 190

def native_database_types # :nodoc:
  NATIVE_DATABASE_TYPES
end

#primary_keys(table_name) ⇒ Object

SCHEMA STATEMENTS ========================================


229
230
231
232
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 229

def primary_keys(table_name) # :nodoc:
  pks = table_structure(table_name).select { |f| f["pk"] > 0 }
  pks.sort_by { |f| f["pk"] }.map { |f| f["name"] }
end

#reconnect!(restore_transactions: false) ⇒ Object Also known as: reset!


166
167
168
169
170
171
172
173
174
175
176
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 166

def reconnect!(restore_transactions: false)
  @lock.synchronize do
    if active?
      @raw_connection.rollback rescue nil
    else
      connect
    end

    super
  end
end

#remove_column(table_name, column_name, type = nil, **options) ⇒ Object

:nodoc:


263
264
265
266
267
268
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 263

def remove_column(table_name, column_name, type = nil, **options) # :nodoc:
  alter_table(table_name) do |definition|
    definition.remove_column column_name
    definition.foreign_keys.delete_if { |fk| fk.column == column_name.to_s }
  end
end

#remove_columns(table_name, *column_names, type: nil, **options) ⇒ Object

:nodoc:


270
271
272
273
274
275
276
277
278
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 270

def remove_columns(table_name, *column_names, type: nil, **options) # :nodoc:
  alter_table(table_name) do |definition|
    column_names.each do |column_name|
      definition.remove_column column_name
    end
    column_names = column_names.map(&:to_s)
    definition.foreign_keys.delete_if { |fk| column_names.include?(fk.column) }
  end
end

#remove_index(table_name, column_name = nil, **options) ⇒ Object

:nodoc:


234
235
236
237
238
239
240
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 234

def remove_index(table_name, column_name = nil, **options) # :nodoc:
  return if options[:if_exists] && !index_exists?(table_name, column_name, **options)

  index_name = index_name_for_remove(table_name, column_name, options)

  exec_query "DROP INDEX #{quote_column_name(index_name)}"
end

#rename_column(table_name, column_name, new_column_name) ⇒ Object

:nodoc:


306
307
308
309
310
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 306

def rename_column(table_name, column_name, new_column_name) # :nodoc:
  column = column_for(table_name, column_name)
  alter_table(table_name, rename: { column.name => new_column_name.to_s })
  rename_column_indexes(table_name, column.name, new_column_name)
end

#rename_table(table_name, new_name) ⇒ Object

Renames a table.

Example:

rename_table('octopuses', 'octopi')

246
247
248
249
250
251
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 246

def rename_table(table_name, new_name)
  schema_cache.clear_data_source_cache!(table_name.to_s)
  schema_cache.clear_data_source_cache!(new_name.to_s)
  exec_query "ALTER TABLE #{quote_table_name(table_name)} RENAME TO #{quote_table_name(new_name)}"
  rename_table_indexes(table_name, new_name)
end

#requires_reloading?Boolean

Returns:

  • (Boolean)

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

def requires_reloading?
  true
end

#shared_cache?Boolean

:nodoc:

Returns:

  • (Boolean)

348
349
350
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 348

def shared_cache? # :nodoc:
  @config.fetch(:flags, 0).anybits?(::SQLite3::Constants::Open::SHAREDCACHE)
end

#supports_check_constraints?Boolean

Returns:

  • (Boolean)

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

def supports_check_constraints?
  true
end

#supports_common_table_expressions?Boolean

Returns:

  • (Boolean)

147
148
149
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 147

def supports_common_table_expressions?
  database_version >= "3.8.3"
end

#supports_concurrent_connections?Boolean

Returns:

  • (Boolean)

158
159
160
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 158

def supports_concurrent_connections?
  !@memory_database
end

#supports_datetime_with_precision?Boolean

Returns:

  • (Boolean)

139
140
141
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 139

def supports_datetime_with_precision?
  true
end

#supports_ddl_transactions?Boolean

Returns:

  • (Boolean)

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

def supports_ddl_transactions?
  true
end

#supports_explain?Boolean

Returns:

  • (Boolean)

199
200
201
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 199

def supports_explain?
  true
end

#supports_expression_index?Boolean

Returns:

  • (Boolean)

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

def supports_expression_index?
  database_version >= "3.9.0"
end

#supports_foreign_keys?Boolean

Returns:

  • (Boolean)

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

def supports_foreign_keys?
  true
end

#supports_index_sort_order?Boolean

Returns:

  • (Boolean)

186
187
188
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 186

def supports_index_sort_order?
  true
end

#supports_insert_on_conflict?Boolean Also known as: supports_insert_on_duplicate_skip?, supports_insert_on_duplicate_update?, supports_insert_conflict_target?

Returns:

  • (Boolean)

151
152
153
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 151

def supports_insert_on_conflict?
  database_version >= "3.24.0"
end

#supports_json?Boolean

Returns:

  • (Boolean)

143
144
145
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 143

def supports_json?
  true
end

#supports_lazy_transactions?Boolean

Returns:

  • (Boolean)

203
204
205
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 203

def supports_lazy_transactions?
  true
end

#supports_partial_index?Boolean

Returns:

  • (Boolean)

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

def supports_partial_index?
  true
end

#supports_savepoints?Boolean

Returns:

  • (Boolean)

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

def supports_savepoints?
  true
end

#supports_transaction_isolation?Boolean

Returns:

  • (Boolean)

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

def supports_transaction_isolation?
  true
end

#supports_views?Boolean

Returns:

  • (Boolean)

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

def supports_views?
  true
end