class ActiveRecord::ConnectionAdapters::SQLite3Adapter

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

Options:

Constants

ADAPTER_NAME
COLLATE_REGEX
NATIVE_DATABASE_TYPES

Public Class Methods

new(connection, logger, connection_options, config) click to toggle source
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 86
def initialize(connection, logger, connection_options, config)
  super(connection, logger, config)

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

Public Instance Methods

active?() click to toggle source
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 136
def active?
  @active != false
end
allowed_index_name_length() click to toggle source

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

# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 164
def allowed_index_name_length
  index_name_length - 2
end
clear_cache!() click to toggle source

Clears the prepared statements cache.

# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 149
def clear_cache!
  @statements.clear
end
data_source_exists?(table_name) click to toggle source
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 279
def data_source_exists?(table_name)
  return false unless table_name.present?

  sql = "SELECT name FROM sqlite_master WHERE type IN ('table','view') AND name <> 'sqlite_sequence'"
  sql << " AND name = #{quote(table_name)}"

  select_values(sql, 'SCHEMA').any?
end
data_sources() click to toggle source
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 265
def data_sources
  select_values("SELECT name FROM sqlite_master WHERE type IN ('table','view') AND name <> 'sqlite_sequence'", 'SCHEMA')
end
disconnect!() click to toggle source

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

# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 142
def disconnect!
  super
  @active = false
  @connection.close rescue nil
end
encoding() click to toggle source

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

# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 173
def encoding
  @connection.encoding.to_s
end
exec_delete(sql, name = 'SQL', binds = []) click to toggle source
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 221
def exec_delete(sql, name = 'SQL', binds = [])
  exec_query(sql, name, binds)
  @connection.changes
end
Also aliased as: exec_update
exec_query(sql, name = nil, binds = [], prepare: false) click to toggle source
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 190
def exec_query(sql, name = nil, binds = [], prepare: false)
  type_casted_binds = binds.map { |attr| type_cast(attr.value_for_database) }

  log(sql, name, binds) 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
      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)
    end

    ActiveRecord::Result.new(cols, stmt.to_a)
  end
end
exec_update(sql, name = 'SQL', binds = [])
Alias for: exec_delete
explain(arel, binds = []) click to toggle source
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 185
def explain(arel, binds = [])
  sql = "EXPLAIN QUERY PLAN #{to_sql(arel, binds)}"
  SQLite3::ExplainPrettyPrinter.new.pp(exec_query(sql, 'EXPLAIN', []))
end
last_inserted_id(result) click to toggle source
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 227
def last_inserted_id(result)
  @connection.last_insert_row_id
end
rename_table(table_name, new_name) click to toggle source

Renames a table.

Example:

rename_table('octopuses', 'octopi')
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 360
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
requires_reloading?() click to toggle source
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 120
def requires_reloading?
  true
end
supports_datetime_with_precision?() click to toggle source
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 128
def supports_datetime_with_precision?
  true
end
supports_ddl_transactions?() click to toggle source
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 93
def supports_ddl_transactions?
  true
end
supports_explain?() click to toggle source
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 177
def supports_explain?
  true
end
supports_index_sort_order?() click to toggle source
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 153
def supports_index_sort_order?
  true
end
supports_multi_insert?() click to toggle source
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 132
def supports_multi_insert?
  sqlite_version >= '3.7.11'
end
supports_partial_index?() click to toggle source
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 101
def supports_partial_index?
  sqlite_version >= '3.8.0'
end
supports_savepoints?() click to toggle source
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 97
def supports_savepoints?
  true
end
supports_statement_cache?() click to toggle source

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

# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 107
def supports_statement_cache?
  true
end
supports_views?() click to toggle source
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 124
def supports_views?
  true
end
table_exists?(table_name) click to toggle source
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 269
      def table_exists?(table_name)
        ActiveSupport::Deprecation.warn("          #table_exists? currently checks both tables and views.
          This behavior is deprecated and will be changed with Rails 5.1 to only check tables.
          Use #data_source_exists? instead.
".squish)

        data_source_exists?(table_name)
      end
valid_alter_table_type?(type) click to toggle source

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

# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 367
def valid_alter_table_type?(type)
  type.to_sym != :primary_key
end
valid_type?(type) click to toggle source
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 157
def valid_type?(type)
  true
end

Protected Instance Methods

sqlite_version() click to toggle source
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 511
def sqlite_version
  @sqlite_version ||= SQLite3Adapter::Version.new(select_value('select sqlite_version(*)'))
end
table_structure(table_name) click to toggle source
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 427
def table_structure(table_name)
  structure = exec_query("PRAGMA table_info(#{quote_table_name(table_name)})", 'SCHEMA')
  raise(ActiveRecord::StatementInvalid, "Could not find table '#{table_name}'") if structure.empty?
  table_structure_with_collation(table_name, structure)
end
translate_exception(exception, message) click to toggle source
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 515
def translate_exception(exception, message)
  case exception.message
  # SQLite 3.8.2 returns a newly formatted error message:
  #   UNIQUE constraint failed: *table_name*.*column_name*
  # Older versions of SQLite return:
  #   column *column_name* is not unique
  when /column(s)? .* (is|are) not unique/, /UNIQUE constraint failed: .*/
    RecordNotUnique.new(message)
  else
    super
  end
end

Private Instance Methods

table_structure_with_collation(table_name, basic_structure) click to toggle source
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 531
def table_structure_with_collation(table_name, basic_structure)
  collation_hash = {}
  sql            = "SELECT sql FROM
                      (SELECT * FROM sqlite_master UNION ALL
                       SELECT * FROM sqlite_temp_master)
                    WHERE type='table' and name='#{ table_name }' \;"

  # Result will have following sample string
  # CREATE TABLE "users" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
  #                       "password_digest" varchar COLLATE "NOCASE");
  result = exec_query(sql, 'SCHEMA').first

  if result
    # Splitting with left parentheses and picking up last will return all
    # columns separated with comma(,).
    columns_string = result["sql"].split('(').last

    columns_string.split(',').each do |column_string|
      # This regex will match the column name and collation type and will save
      # the value in $1 and $2 respectively.
      collation_hash[$1] = $2 if (COLLATE_REGEX =~ column_string)
    end

    basic_structure.map! do |column|
      column_name = column['name']

      if collation_hash.has_key? column_name
        column['collation'] = collation_hash[column_name]
      end

      column
    end
  else
    basic_structure.to_hash
  end
end