Class: ActiveRecord::ConnectionAdapters::SQLite3Adapter

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

Overview

The SQLite3 adapter works SQLite 3.6.16 or newer 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".freeze
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" },
}

Constants inherited from AbstractAdapter

AbstractAdapter::SIMPLE_INT

Instance Attribute Summary

Attributes inherited from AbstractAdapter

#lock, #logger, #owner, #pool, #prepared_statements, #schema_cache, #visitor

Attributes included from QueryCache

#query_cache, #query_cache_enabled

Attributes included from DatabaseStatements

#transaction_manager

Instance Method Summary collapse

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

#create_schema_dumper, #indexes

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

#quote_column_name, #quote_string, #quote_table_name_for_assignment, #quoted_binary, #quoted_false, #quoted_time, #quoted_true, #unquoted_false, #unquoted_true

Methods inherited from AbstractAdapter

#adapter_name, #case_insensitive_comparison, #case_sensitive_comparison, #close, #column_name_for_operation, #column_name_from_arel_node, #default_index_type?, #disable_extension, #discard!, #enable_extension, #expire, #extensions, #get_advisory_lock, #index_algorithms, #lease, #migration_context, #migrations_paths, #prefetch_primary_key?, #raw_connection, #reconnect!, #release_advisory_lock, #reset!, #seconds_idle, #steal!, #supports_advisory_locks?, #supports_bulk_alter?, #supports_comments?, #supports_comments_in_create?, #supports_expression_index?, #supports_extensions?, #supports_foreign_keys?, #supports_foreign_tables?, #supports_transaction_isolation?, #supports_validate_constraints?, #supports_virtual_columns?, type_cast_config_to_boolean, type_cast_config_to_integer, #unprepared_statement, #valid_type?, #verify!

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

#column_name_length, #columns_per_multicolumn_index, #columns_per_table, #in_clause_length, #index_name_length, #indexes_per_table, #joins_per_query, #sql_query_length, #table_alias_length, #table_name_length

Methods included from Quoting

#lookup_cast_type_from_column, #quote, #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, #type_cast, #type_cast_from_column, #type_casted_binds, #unquoted_false, #unquoted_true

Methods included from DatabaseStatements

#add_transaction_record, #begin_isolated_db_transaction, #cacheable_query, #default_sequence_name, #delete, #empty_insert_statement_value, #exec_insert, #insert, #insert_fixture, #join_to_update, #query, #query_value, #query_values, #reset_sequence!, #reset_transaction, #rollback_db_transaction, #rollback_to_savepoint, #sanitize_limit, #select_all, #select_one, #select_rows, #select_value, #select_values, #supports_statement_cache?, #to_sql, #transaction, #transaction_isolation_levels, #transaction_open?, #transaction_state, #truncate, #update

Methods included from SchemaStatements

#add_foreign_key, #add_index, #add_index_options, #add_timestamps, #assume_migrated_upto_version, #change_column_comment, #change_table, #change_table_comment, #column_exists?, #columns, #columns_for_distinct, #create_join_table, #create_schema_dumper, #create_table, #data_source_exists?, #data_sources, #drop_join_table, #drop_table, #dump_schema_information, #foreign_key_column_for, #foreign_key_exists?, #foreign_key_options, #index_exists?, #index_name, #index_name_exists?, #indexes, #internal_string_options_for_primary_key, #options_include_default?, #primary_key, #remove_columns, #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

Constructor Details

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

Returns a new instance of SQLite3Adapter.



101
102
103
104
105
106
107
108
# File 'lib/active_record/connection_adapters/sqlite3_adapter.rb', line 101

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

  @active     = true
  @statements = StatementPool.new(self.class.type_cast_config_to_integer(config[:statement_limit]))

  configure_connection
end

Instance Method Details

#active?Boolean

Returns:

  • (Boolean)


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

def active?
  @active
end

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

:nodoc:



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

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:



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

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

#allowed_index_name_lengthObject

Returns 62. SQLite supports index names up to 64 characters. The rest is used by Rails internally to perform temporary rename operations



170
171
172
# File 'lib/active_record/connection_adapters/sqlite3_adapter.rb', line 170

def allowed_index_name_length
  index_name_length - 2
end

#begin_db_transactionObject

:nodoc:



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

def begin_db_transaction #:nodoc:
  log("begin transaction", nil) { @connection.transaction }
end

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

:nodoc:



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

def change_column(table_name, column_name, type, options = {}) #:nodoc:
  alter_table(table_name) do |definition|
    definition[column_name].instance_eval do
      self.type    = type
      self.limit   = options[:limit] if options.include?(:limit)
      self.default = options[:default] if options.include?(:default)
      self.null    = options[:null] if options.include?(:null)
      self.precision = options[:precision] if options.include?(:precision)
      self.scale = options[:scale] if options.include?(:scale)
      self.collation = options[:collation] if options.include?(:collation)
    end
  end
end

#change_column_default(table_name, column_name, default_or_changes) ⇒ Object

:nodoc:



314
315
316
317
318
319
320
# File 'lib/active_record/connection_adapters/sqlite3_adapter.rb', line 314

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:



322
323
324
325
326
327
328
329
# File 'lib/active_record/connection_adapters/sqlite3_adapter.rb', line 322

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

#clear_cache!Object

Clears the prepared statements cache.



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

def clear_cache!
  @statements.clear
end

#commit_db_transactionObject

:nodoc:



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

def commit_db_transaction #:nodoc:
  log("commit transaction", nil) { @connection.commit }
end

#disable_referential_integrityObject

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



189
190
191
192
193
194
195
196
197
198
# File 'lib/active_record/connection_adapters/sqlite3_adapter.rb', line 189

def disable_referential_integrity # :nodoc:
  old = query_value("PRAGMA foreign_keys")

  begin
    execute("PRAGMA foreign_keys = OFF")
    yield
  ensure
    execute("PRAGMA foreign_keys = #{old}")
  end
end

#disconnect!Object

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



152
153
154
155
156
# File 'lib/active_record/connection_adapters/sqlite3_adapter.rb', line 152

def disconnect!
  super
  @active = false
  @connection.close rescue nil
end

#encodingObject

Returns the current database encoding format as a string, eg: ‘UTF-8’



179
180
181
# File 'lib/active_record/connection_adapters/sqlite3_adapter.rb', line 179

def encoding
  @connection.encoding.to_s
end

#exec_delete(sql, name = "SQL", binds = []) ⇒ Object Also known as: exec_update



242
243
244
245
# File 'lib/active_record/connection_adapters/sqlite3_adapter.rb', line 242

def exec_delete(sql, name = "SQL", binds = [])
  exec_query(sql, name, binds)
  @connection.changes
end

#exec_query(sql, name = nil, binds = [], prepare: false) ⇒ Object



209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
# File 'lib/active_record/connection_adapters/sqlite3_adapter.rb', line 209

def exec_query(sql, name = nil, binds = [], prepare: false)
  type_casted_binds = type_casted_binds(binds)

  log(sql, name, binds, type_casted_binds) do
    ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
      # Don't cache statements if they are not prepared
      unless prepare
        stmt = @connection.prepare(sql)
        begin
          cols = stmt.columns
          unless without_prepared_statement?(binds)
            stmt.bind_params(type_casted_binds)
          end
          records = stmt.to_a
        ensure
          stmt.close
        end
      else
        cache = @statements[sql] ||= {
          stmt: @connection.prepare(sql)
        }
        stmt = cache[:stmt]
        cols = cache[:cols] ||= stmt.columns
        stmt.reset!
        stmt.bind_params(type_casted_binds)
        records = stmt.to_a
      end

      ActiveRecord::Result.new(cols, records)
    end
  end
end

#exec_rollback_db_transactionObject

:nodoc:



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

def exec_rollback_db_transaction #:nodoc:
  log("rollback transaction", nil) { @connection.rollback }
end

#execute(sql, name = nil) ⇒ Object

:nodoc:



252
253
254
255
256
257
258
# File 'lib/active_record/connection_adapters/sqlite3_adapter.rb', line 252

def execute(sql, name = nil) #:nodoc:
  log(sql, name) do
    ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
      @connection.execute(sql)
    end
  end
end

#explain(arel, binds = []) ⇒ Object

– DATABASE STATEMENTS ====================================== ++



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

def explain(arel, binds = [])
  sql = "EXPLAIN QUERY PLAN #{to_sql(arel, binds)}"
  SQLite3::ExplainPrettyPrinter.new.pp(exec_query(sql, "EXPLAIN", []))
end

#foreign_keys(table_name) ⇒ Object



356
357
358
359
360
361
362
363
364
365
366
367
# File 'lib/active_record/connection_adapters/sqlite3_adapter.rb', line 356

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

#insert_fixtures(rows, table_name) ⇒ Object



369
370
371
372
373
374
375
# File 'lib/active_record/connection_adapters/sqlite3_adapter.rb', line 369

def insert_fixtures(rows, table_name)
  ActiveSupport::Deprecation.warn(<<-MSG.squish)
    `insert_fixtures` is deprecated and will be removed in the next version of Rails.
    Consider using `insert_fixtures_set` for performance improvement.
  MSG
  insert_fixtures_set(table_name => rows)
end

#insert_fixtures_set(fixture_set, tables_to_delete = []) ⇒ Object



377
378
379
380
381
382
383
384
385
386
387
# File 'lib/active_record/connection_adapters/sqlite3_adapter.rb', line 377

def insert_fixtures_set(fixture_set, tables_to_delete = [])
  disable_referential_integrity do
    transaction(requires_new: true) do
      tables_to_delete.each { |table| delete "DELETE FROM #{quote_table_name(table)}", "Fixture Delete" }

      fixture_set.each do |table_name, rows|
        rows.each { |row| insert_fixture(row, table_name) }
      end
    end
  end
end

#last_inserted_id(result) ⇒ Object



248
249
250
# File 'lib/active_record/connection_adapters/sqlite3_adapter.rb', line 248

def last_inserted_id(result)
  @connection.last_insert_row_id
end

#native_database_typesObject

:nodoc:



174
175
176
# File 'lib/active_record/connection_adapters/sqlite3_adapter.rb', line 174

def native_database_types #:nodoc:
  NATIVE_DATABASE_TYPES
end

#primary_keys(table_name) ⇒ Object

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



274
275
276
277
# File 'lib/active_record/connection_adapters/sqlite3_adapter.rb', line 274

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

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

:nodoc:



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

def remove_column(table_name, column_name, type = nil, options = {}) #:nodoc:
  alter_table(table_name) do |definition|
    definition.remove_column column_name
  end
end

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

:nodoc:



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

def remove_index(table_name, options = {}) #:nodoc:
  index_name = index_name_for_remove(table_name, options)
  exec_query "DROP INDEX #{quote_column_name(index_name)}"
end

#rename_column(table_name, column_name, new_column_name) ⇒ Object

:nodoc:



345
346
347
348
349
# File 'lib/active_record/connection_adapters/sqlite3_adapter.rb', line 345

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')


288
289
290
291
# File 'lib/active_record/connection_adapters/sqlite3_adapter.rb', line 288

def rename_table(table_name, new_name)
  exec_query "ALTER TABLE #{quote_table_name(table_name)} RENAME TO #{quote_table_name(new_name)}"
  rename_table_indexes(table_name, new_name)
end

#represent_boolean_as_integerObject

:singleton-method: Indicates whether boolean values are stored in sqlite3 databases as 1 and 0 or ‘t’ and ‘f’. Leaving ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer set to false is deprecated. SQLite databases have used ‘t’ and ‘f’ to serialize boolean values and must have old data converted to 1 and 0 (its native boolean serialization) before setting this flag to true. Conversion can be accomplished by setting up a rake task which runs

ExampleModel.where("boolean_column = 't'").update_all(boolean_column: 1)
ExampleModel.where("boolean_column = 'f'").update_all(boolean_column: 0)

for all models and all boolean columns, after which the flag must be set to true by adding the following to your application.rb file:

Rails.application.config.active_record.sqlite3.represent_boolean_as_integer = true


92
# File 'lib/active_record/connection_adapters/sqlite3_adapter.rb', line 92

class_attribute :represent_boolean_as_integer, default: false

#requires_reloading?Boolean

Returns:

  • (Boolean)


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

def requires_reloading?
  true
end

#supports_datetime_with_precision?Boolean

Returns:

  • (Boolean)


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

def supports_datetime_with_precision?
  true
end

#supports_ddl_transactions?Boolean

Returns:

  • (Boolean)


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

def supports_ddl_transactions?
  true
end

#supports_explain?Boolean

Returns:

  • (Boolean)


183
184
185
# File 'lib/active_record/connection_adapters/sqlite3_adapter.rb', line 183

def supports_explain?
  true
end

#supports_foreign_keys_in_create?Boolean

Returns:

  • (Boolean)


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

def supports_foreign_keys_in_create?
  sqlite_version >= "3.6.19"
end

#supports_index_sort_order?Boolean

Returns:

  • (Boolean)


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

def supports_index_sort_order?
  true
end

#supports_json?Boolean

Returns:

  • (Boolean)


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

def supports_json?
  true
end

#supports_multi_insert?Boolean

Returns:

  • (Boolean)


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

def supports_multi_insert?
  sqlite_version >= "3.7.11"
end

#supports_partial_index?Boolean

Returns:

  • (Boolean)


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

def supports_partial_index?
  sqlite_version >= "3.8.0"
end

#supports_savepoints?Boolean

Returns:

  • (Boolean)


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

def supports_savepoints?
  true
end

#supports_views?Boolean

Returns:

  • (Boolean)


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

def supports_views?
  true
end

#valid_alter_table_type?(type, options = {}) ⇒ Boolean

Returns:

  • (Boolean)


293
294
295
# File 'lib/active_record/connection_adapters/sqlite3_adapter.rb', line 293

def valid_alter_table_type?(type, options = {})
  !invalid_alter_table_type?(type, options)
end