Class: ActiveRecord::ConnectionAdapters::SQLite3Adapter

Inherits:
AbstractAdapter show all
Includes:
Savepoints
Defined in:
activerecord/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: ExplainPrettyPrinter, StatementPool, Version

Constant Summary

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" },
  timestamp:    { name: "datetime" },
  time:         { name: "time" },
  date:         { name: "date" },
  binary:       { name: "blob" },
  boolean:      { name: "boolean" }
}

Constants inherited from AbstractAdapter

AbstractAdapter::SIMPLE_INT

Constants included from ActiveSupport::Callbacks

ActiveSupport::Callbacks::CALLBACK_FILTER_TYPES

Instance Attribute Summary

Attributes inherited from AbstractAdapter

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

Attributes included from QueryCache

#query_cache, #query_cache_enabled

Instance Method Summary (collapse)

Methods included from Savepoints

#create_savepoint, #release_savepoint, #rollback_to_savepoint

Methods inherited from AbstractAdapter

#case_insensitive_comparison, #case_sensitive_comparison, #case_sensitive_modifier, #close, #collector, #create_savepoint, #current_savepoint_name, #disable_extension, #disable_referential_integrity, #enable_extension, #expire, #extensions, #index_algorithms, #lease, #open_transactions, #prefetch_primary_key?, #raw_connection, #reconnect!, #release_savepoint, #reset!, #rollback_to_savepoint, #schema_creation, #substitute_at, #supports_bulk_alter?, #supports_extensions?, #supports_indexes_in_create?, #supports_transaction_isolation?, type_cast_config_to_boolean, type_cast_config_to_integer, #unprepared_statement, #valid_type?, #verify!

Methods included from ColumnDumper

#column_spec, #migration_keys, #prepare_column_options

Methods included from ActiveSupport::Callbacks

#run_callbacks

Methods included from ActiveSupport::Concern

#append_features, #class_methods, extended, #included

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

#quote_table_name, #quoted_false, #quoted_true

Methods included from DatabaseStatements

#add_transaction_record, #begin_isolated_db_transaction, #begin_transaction, #cacheable_query, #commit_transaction, #current_transaction, #default_sequence_name, #delete, #empty_insert_statement_value, #exec_insert, #insert, #insert_fixture, #join_to_delete, #join_to_update, #limited_update_conditions, #reset_sequence!, #reset_transaction, #rollback_transaction, #sanitize_limit, #select_all, #select_one, #select_value, #select_values, #to_sql, #transaction, #transaction_isolation_levels, #transaction_open?, #update, #within_new_transaction

Methods included from SchemaStatements

#add_index, #add_index_options, #add_reference, #add_timestamps, #assume_migrated_upto_version, #change_table, #column_exists?, #columns_for_distinct, #create_join_table, #create_table, #drop_join_table, #drop_table, #dump_schema_information, #index_exists?, #index_name, #index_name_exists?, #initialize_schema_migrations_table, #remove_columns, #remove_index, #remove_reference, #remove_timestamps, #rename_index, #table_alias_for, #type_to_sql, #update_table_definition

Constructor Details

- (SQLite3Adapter) initialize(connection, logger, connection_options, config)

Returns a new instance of SQLite3Adapter



126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 126

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

  @active     = nil
  @statements = StatementPool.new(@connection,
                                  self.class.type_cast_config_to_integer(config.fetch(:statement_limit) { 1000 }))
  @config = config

  @visitor = Arel::Visitors::SQLite.new self

  if self.class.type_cast_config_to_boolean(config.fetch(:prepared_statements) { true })
    @prepared_statements = true
  else
    @prepared_statements = false
  end
end

Instance Method Details

- (Boolean) active?

Returns:

  • (Boolean)


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

def active?
  @active != false
end

- (Object) adapter_name

:nodoc:



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

def adapter_name #:nodoc:
  'SQLite'
end

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

:nodoc:



449
450
451
452
453
454
455
456
457
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 449

def add_column(table_name, column_name, type, options = {}) #:nodoc:
  if supports_add_column? && valid_alter_table_options( type, options )
    super(table_name, column_name, type, options)
  else
    alter_table(table_name) do |definition|
      definition.column(column_name, type, options)
    end
  end
end

- (Object) allowed_index_name_length

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



206
207
208
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 206

def allowed_index_name_length
  index_name_length - 2
end

- (Object) begin_db_transaction

:nodoc:



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

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

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

:nodoc:



480
481
482
483
484
485
486
487
488
489
490
491
492
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 480

def change_column(table_name, column_name, type, options = {}) #:nodoc:
  alter_table(table_name) do |definition|
    include_default = options_include_default?(options)
    definition[column_name].instance_eval do
      self.type    = type
      self.limit   = options[:limit] if options.include?(:limit)
      self.default = options[:default] if 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)
    end
  end
end

- (Object) change_column_default(table_name, column_name, default)

:nodoc:



465
466
467
468
469
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 465

def change_column_default(table_name, column_name, default) #:nodoc:
  alter_table(table_name) do |definition|
    definition[column_name].default = default
  end
end

- (Object) change_column_null(table_name, column_name, null, default = nil)



471
472
473
474
475
476
477
478
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 471

def change_column_null(table_name, column_name, null, default = nil)
  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

- (Object) clear_cache!

Clears the prepared statements cache.



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

def clear_cache!
  @statements.clear
end

- (Object) columns(table_name)

Returns an array of SQLite3Column objects for the table specified by table_name.



383
384
385
386
387
388
389
390
391
392
393
394
395
396
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 383

def columns(table_name) #:nodoc:
  table_structure(table_name).map do |field|
    case field["dflt_value"]
    when /^null$/i
      field["dflt_value"] = nil
    when /^'(.*)'$/m
      field["dflt_value"] = $1.gsub("''", "'")
    when /^"(.*)"$/m
      field["dflt_value"] = $1.gsub('""', '"')
    end

    SQLite3Column.new(field['name'], field['dflt_value'], field['type'], field['notnull'].to_i == 0)
  end
end

- (Object) commit_db_transaction

:nodoc:



355
356
357
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 355

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

- (Object) delete_sql(sql, name = nil)

:nodoc:



336
337
338
339
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 336

def delete_sql(sql, name = nil) #:nodoc:
  sql += " WHERE 1=1" unless sql =~ /WHERE/i
  super sql, name
end

- (Object) disconnect!

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



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

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

- (Object) encoding

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



215
216
217
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 215

def encoding
  @connection.encoding.to_s
end

- (Object) exec_delete(sql, name = 'SQL', binds = []) Also known as: exec_update



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

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

- (Object) exec_query(sql, name = nil, binds = [])



290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 290

def exec_query(sql, name = nil, binds = [])
  type_casted_binds = binds.map { |col, val|
    [col, type_cast(val, col)]
  }

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

    ActiveRecord::Result.new(cols, stmt.to_a)
  end
end

- (Object) execute(sql, name = nil)

:nodoc:



327
328
329
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 327

def execute(sql, name = nil) #:nodoc:
  log(sql, name) { @connection.execute(sql) }
end

- (Object) explain(arel, binds = [])

DATABASE STATEMENTS ======================================



271
272
273
274
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 271

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

- (Object) indexes(table_name, name = nil)

Returns an array of indexes for the given table.



399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 399

def indexes(table_name, name = nil) #:nodoc:
  exec_query("PRAGMA index_list(#{quote_table_name(table_name)})", 'SCHEMA').map do |row|
    sql = <<-SQL
      SELECT sql
      FROM sqlite_master
      WHERE name=#{quote(row['name'])} AND type='index'
      UNION ALL
      SELECT sql
      FROM sqlite_temp_master
      WHERE name=#{quote(row['name'])} AND type='index'
    SQL
    index_sql = exec_query(sql).first['sql']
    match = /\sWHERE\s+(.+)$/i.match(index_sql)
    where = match[1] if match
    IndexDefinition.new(
      table_name,
      row['name'],
      row['unique'] != 0,
      exec_query("PRAGMA index_info('#{row['name']}')", "SCHEMA").map { |col|
        col['name']
      }, nil, nil, where)
  end
end

- (Object) insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) Also known as: create

:nodoc:



341
342
343
344
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 341

def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) #:nodoc:
  super
  id_value || @connection.last_insert_row_id
end

- (Object) last_inserted_id(result)



323
324
325
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 323

def last_inserted_id(result)
  @connection.last_insert_row_id
end

- (Object) native_database_types

:nodoc:



210
211
212
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 210

def native_database_types #:nodoc:
  NATIVE_DATABASE_TYPES
end

- (Object) primary_key(table_name)

:nodoc:



423
424
425
426
427
428
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 423

def primary_key(table_name) #:nodoc:
  column = table_structure(table_name).find { |field|
    field['pk'] == 1
  }
  column && column['name']
end

- (Object) quote(value, column = nil)

QUOTING ==================================================



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

def quote(value, column = nil)
  if value.kind_of?(String) && column && column.type == :binary
    s = value.unpack("H*")[0]
    "x'#{s}'"
  else
    super
  end
end

- (Object) quote_column_name(name)

:nodoc:



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

def quote_column_name(name) #:nodoc:
  %Q("#{name.to_s.gsub('"', '""')}")
end

- (Object) quote_string(s)

:nodoc:



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

def quote_string(s) #:nodoc:
  @connection.class.quote(s)
end

- (Object) quote_table_name_for_assignment(table, attr)



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

def quote_table_name_for_assignment(table, attr)
  quote_column_name(attr)
end

- (Object) quoted_date(value)

Quote date/time values for use in SQL input. Includes microseconds if the value is a Time responding to usec.



248
249
250
251
252
253
254
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 248

def quoted_date(value) #:nodoc:
  if value.respond_to?(:usec)
    "#{super}.#{sprintf("%06d", value.usec)}"
  else
    super
  end
end

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

:nodoc:



459
460
461
462
463
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 459

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

- (Object) remove_index!(table_name, index_name)

:nodoc:



430
431
432
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 430

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

- (Object) rename_column(table_name, column_name, new_column_name)

:nodoc:



494
495
496
497
498
499
500
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 494

def rename_column(table_name, column_name, new_column_name) #:nodoc:
  unless columns(table_name).detect{|c| c.name == column_name.to_s }
    raise ActiveRecord::ActiveRecordError, "Missing column #{table_name}.#{column_name}"
  end
  alter_table(table_name, :rename => {column_name.to_s => new_column_name.to_s})
  rename_column_indexes(table_name, column_name, new_column_name)
end

- (Object) rename_table(table_name, new_name)

Renames a table.

Example:

rename_table('octopuses', 'octopi')


438
439
440
441
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 438

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

- (Boolean) requires_reloading?

Returns:

  • (Boolean)


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

def requires_reloading?
  true
end

- (Object) rollback_db_transaction

:nodoc:



359
360
361
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 359

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

- (Object) select_rows(sql, name = nil, binds = [])



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

def select_rows(sql, name = nil, binds = [])
  exec_query(sql, name, binds).rows
end

- (Boolean) supports_add_column?

Returns:

  • (Boolean)


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

def supports_add_column?
  true
end

- (Boolean) supports_ddl_transactions?

Returns:

  • (Boolean)


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

def supports_ddl_transactions?
  true
end

- (Boolean) supports_explain?

Returns:

  • (Boolean)


219
220
221
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 219

def supports_explain?
  true
end

- (Boolean) supports_index_sort_order?

Returns:

  • (Boolean)


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

def supports_index_sort_order?
  true
end

- (Boolean) supports_migrations?

Returns true, since this connection adapter supports migrations.

Returns:

  • (Boolean)


166
167
168
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 166

def supports_migrations? #:nodoc:
  true
end

- (Boolean) supports_partial_index?

Returns:

  • (Boolean)


155
156
157
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 155

def supports_partial_index?
  sqlite_version >= '3.8.0'
end

- (Boolean) supports_primary_key?

:nodoc:

Returns:

  • (Boolean)


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

def supports_primary_key? #:nodoc:
  true
end

- (Boolean) supports_savepoints?

Returns:

  • (Boolean)


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

def supports_savepoints?
  true
end

- (Boolean) supports_statement_cache?

Returns true, since this connection adapter supports prepared statement caching.

Returns:

  • (Boolean)


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

def supports_statement_cache?
  true
end

- (Boolean) table_exists?(table_name)

Returns:

  • (Boolean)


378
379
380
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 378

def table_exists?(table_name)
  table_name && tables(nil, table_name).any?
end

- (Object) tables(name = nil, table_name = nil)

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



365
366
367
368
369
370
371
372
373
374
375
376
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 365

def tables(name = nil, table_name = nil) #:nodoc:
  sql = <<-SQL
    SELECT name
    FROM sqlite_master
    WHERE type = 'table' AND NOT name = 'sqlite_sequence'
  SQL
  sql << " AND name = #{quote_table_name(table_name)}" if table_name

  exec_query(sql, 'SCHEMA').map do |row|
    row['name']
  end
end

- (Object) type_cast(value, column)

:nodoc:



256
257
258
259
260
261
262
263
264
265
266
267
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 256

def type_cast(value, column) # :nodoc:
  return value.to_f if BigDecimal === value
  return super unless String === value
  return super unless column && value

  value = super
  if column.type == :string && value.encoding == Encoding::ASCII_8BIT
    logger.error "Binary data inserted for `string` type on column `#{column.name}`" if logger
    value = value.encode Encoding::UTF_8
  end
  value
end

- (Object) update_sql(sql, name = nil)

:nodoc:



331
332
333
334
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 331

def update_sql(sql, name = nil) #:nodoc:
  super
  @connection.changes
end

- (Object) valid_alter_table_options(type, options)

See: www.sqlite.org/lang_altertable.html SQLite has an additional restriction on the ALTER TABLE statement



445
446
447
# File 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb', line 445

def valid_alter_table_options( type, options)
  type.to_sym != :primary_key
end