class ActiveRecord::ConnectionAdapters::SQLite3Adapter
The SQLite3
adapter works with the sqlite3-ruby drivers (available as gem from rubygems.org/gems/sqlite3).
Options:
-
:database
- Path to the database file.
Constants
- ADAPTER_NAME
- COLLATE_REGEX
- NATIVE_DATABASE_TYPES
Public Class Methods
database_exists?(config)
click to toggle source
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 91 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
new(connection, logger, connection_options, config)
click to toggle source
Calls superclass method
ActiveRecord::ConnectionAdapters::QueryCache::new
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 86 def initialize(connection, logger, connection_options, config) super(connection, logger, config) configure_connection end
Public Instance Methods
active?()
click to toggle source
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 156 def active? !@connection.closed? end
disconnect!()
click to toggle source
Disconnects from the database if already connected. Otherwise, this method does nothing.
Calls superclass method
ActiveRecord::ConnectionAdapters::AbstractAdapter#disconnect!
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 167 def disconnect! super @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 181 def encoding @connection.encoding.to_s end
foreign_keys(table_name)
click to toggle source
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 291 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
reconnect!()
click to toggle source
Calls superclass method
ActiveRecord::ConnectionAdapters::AbstractAdapter#reconnect!
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 160 def reconnect! super connect if @connection.closed? 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 228 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?()
click to toggle source
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 121 def requires_reloading? true end
supports_check_constraints?()
click to toggle source
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 129 def supports_check_constraints? true end
supports_common_table_expressions?()
click to toggle source
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 145 def supports_common_table_expressions? database_version >= "3.8.3" end
supports_datetime_with_precision?()
click to toggle source
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 137 def supports_datetime_with_precision? true end
supports_ddl_transactions?()
click to toggle source
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 101 def supports_ddl_transactions? true end
supports_explain?()
click to toggle source
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 185 def supports_explain? true end
supports_expression_index?()
click to toggle source
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 117 def supports_expression_index? database_version >= "3.9.0" end
supports_foreign_keys?()
click to toggle source
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 125 def supports_foreign_keys? true end
supports_index_sort_order?()
click to toggle source
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 172 def supports_index_sort_order? true end
supports_insert_on_conflict?()
click to toggle source
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 149 def supports_insert_on_conflict? database_version >= "3.24.0" end
supports_json?()
click to toggle source
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 141 def supports_json? true end
supports_lazy_transactions?()
click to toggle source
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 189 def supports_lazy_transactions? true end
supports_partial_index?()
click to toggle source
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 113 def supports_partial_index? true end
supports_savepoints?()
click to toggle source
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 105 def supports_savepoints? true end
supports_transaction_isolation?()
click to toggle source
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 109 def supports_transaction_isolation? true end
supports_views?()
click to toggle source
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 133 def supports_views? true end
Private Instance Methods
alter_table( table_name, foreign_keys = foreign_keys(table_name), check_constraints = check_constraints(table_name), **options ) { |definition| ... }
click to toggle source
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 358 def alter_table( table_name, foreign_keys = foreign_keys(table_name), check_constraints = check_constraints(table_name), **options ) altered_table_name = "a#{table_name}" caller = lambda do |definition| rename = options[:rename] || {} foreign_keys.each do |fk| if column = rename[fk.options[:column]] fk.options[:column] = column end to_table = strip_table_name_prefix_and_suffix(fk.to_table) definition.foreign_key(to_table, **fk.options) end check_constraints.each do |chk| definition.check_constraint(chk.expression, **chk.options) end yield definition if block_given? end transaction do disable_referential_integrity do move_table(table_name, altered_table_name, options.merge(temporary: true)) move_table(altered_table_name, table_name, &caller) end end end
arel_visitor()
click to toggle source
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 526 def arel_visitor Arel::Visitors::SQLite.new(self) end
bind_params_length()
click to toggle source
See www.sqlite.org/limits.html, the default value is 999 when not configured.
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 335 def bind_params_length 999 end
build_statement_pool()
click to toggle source
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 530 def build_statement_pool StatementPool.new(self.class.type_cast_config_to_integer(@config[:statement_limit])) end
configure_connection()
click to toggle source
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 542 def configure_connection @connection.busy_timeout(self.class.type_cast_config_to_integer(@config[:timeout])) if @config[:timeout] execute("PRAGMA foreign_keys = ON", "SCHEMA") end
connect()
click to toggle source
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 534 def connect @connection = ::SQLite3::Database.new( @config[:database].to_s, @config.merge(results_as_hash: true) ) configure_connection end
copy_table(from, to, options = {}) { |definition| ... }
click to toggle source
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 396 def copy_table(from, to, options = {}) from_primary_key = primary_key(from) options[:id] = false create_table(to, **options) do |definition| @definition = definition if from_primary_key.is_a?(Array) @definition.primary_keys from_primary_key end columns(from).each do |column| column_name = options[:rename] ? (options[:rename][column.name] || options[:rename][column.name.to_sym] || column.name) : column.name @definition.column(column_name, column.type, limit: column.limit, default: column.default, precision: column.precision, scale: column.scale, null: column.null, collation: column.collation, primary_key: column_name == from_primary_key ) end yield @definition if block_given? end copy_table_indexes(from, to, options[:rename] || {}) copy_table_contents(from, to, @definition.columns.map(&:name), options[:rename] || {}) end
copy_table_contents(from, to, columns, rename = {})
click to toggle source
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 454 def copy_table_contents(from, to, columns, rename = {}) column_mappings = Hash[columns.map { |name| [name, name] }] rename.each { |a| column_mappings[a.last] = a.first } from_columns = columns(from).collect(&:name) columns = columns.find_all { |col| from_columns.include?(column_mappings[col]) } from_columns_to_copy = columns.map { |col| column_mappings[col] } quoted_columns = columns.map { |col| quote_column_name(col) } * "," quoted_from_columns = from_columns_to_copy.map { |col| quote_column_name(col) } * "," exec_query("INSERT INTO #{quote_table_name(to)} (#{quoted_columns}) SELECT #{quoted_from_columns} FROM #{quote_table_name(from)}") end
copy_table_indexes(from, to, rename = {})
click to toggle source
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 427 def copy_table_indexes(from, to, rename = {}) indexes(from).each do |index| name = index.name if to == "a#{from}" name = "t#{name}" elsif from == "a#{to}" name = name[1..-1] end columns = index.columns if columns.is_a?(Array) to_column_names = columns(to).map(&:name) columns = columns.map { |c| rename[c] || c }.select do |column| to_column_names.include?(column) end end unless columns.empty? # index name can't be the same options = { name: name.gsub(/(^|_)(#{from})_/, "\\1#{to}_"), internal: true } options[:unique] = true if index.unique options[:where] = index.where if index.where add_index(to, columns, **options) end end end
initialize_type_map(m = type_map)
click to toggle source
Calls superclass method
ActiveRecord::ConnectionAdapters::AbstractAdapter#initialize_type_map
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 339 def initialize_type_map(m = type_map) super register_class_with_limit m, %r(int)i, SQLite3Integer end
invalid_alter_table_type?(type, options)
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 353 def invalid_alter_table_type?(type, options) type.to_sym == :primary_key || options[:primary_key] || options[:null] == false && options[:default].nil? end
move_table(from, to, options = {}, &block)
click to toggle source
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 391 def move_table(from, to, options = {}, &block) copy_table(from, to, options, &block) drop_table(from) end
table_structure(table_name)
click to toggle source
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 344 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
Also aliased as: column_definitions
table_structure_with_collation(table_name, basic_structure)
click to toggle source
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 487 def table_structure_with_collation(table_name, basic_structure) collation_hash = {} sql = <<~SQL SELECT sql FROM (SELECT * FROM sqlite_master UNION ALL SELECT * FROM sqlite_temp_master) WHERE type = 'table' AND name = #{quote(table_name)} SQL # Result will have following sample string # CREATE TABLE "users" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, # "password_digest" varchar COLLATE "NOCASE"); result = query_value(sql, "SCHEMA") if result # Splitting with left parentheses and discarding the first part will return all # columns separated with comma(,). columns_string = result.split("(", 2).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_a end end
translate_exception(exception, message:, sql:, binds:)
click to toggle source
Calls superclass method
ActiveRecord::ConnectionAdapters::AbstractAdapter#translate_exception
# File lib/active_record/connection_adapters/sqlite3_adapter.rb, line 467 def translate_exception(exception, message:, sql:, binds:) # 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 if exception.message.match?(/(column(s)? .* (is|are) not unique|UNIQUE constraint failed: .*)/i) RecordNotUnique.new(message, sql: sql, binds: binds) elsif exception.message.match?(/(.* may not be NULL|NOT NULL constraint failed: .*)/i) NotNullViolation.new(message, sql: sql, binds: binds) elsif exception.message.match?(/FOREIGN KEY constraint failed/i) InvalidForeignKey.new(message, sql: sql, binds: binds) elsif exception.message.match?(/called on a closed database/i) ConnectionNotEstablished.new(exception) else super end end