Module: ArJdbc::SQLite3

Includes:
ActiveRecord::ConnectionAdapters::SQLite3::DatabaseStatements, ActiveRecord::ConnectionAdapters::SQLite3::Quoting, ActiveRecord::ConnectionAdapters::SQLite3::SchemaStatements
Included in:
ActiveRecord::ConnectionAdapters::SQLite3Adapter
Defined in:
lib/arjdbc/sqlite3/adapter.rb

Overview

All the code in this module is a copy of ConnectionAdapters::SQLite3Adapter from active_record 5. The constants at the front of this file are to allow the rest of the file to remain with no modifications from its original source. If you hack on this file try not to modify this module and instead try and put those overrides in SQL3Adapter below. We try and keep a copy of the Rails this adapter supports with the current goal of being able to diff changes easily over time and to also eventually remove this module from ARJDBC altogether.

Defined Under Namespace

Classes: StatementPool

Constant Summary collapse

ConnectionAdapters =

DIFFERENCE: Some common constant names to reduce differences in rest of this module from AR5 version

::ActiveRecord::ConnectionAdapters
IndexDefinition =
::ActiveRecord::ConnectionAdapters::IndexDefinition
Quoting =
::ActiveRecord::ConnectionAdapters::SQLite3::Quoting
RecordNotUnique =
::ActiveRecord::RecordNotUnique
SchemaCreation =
ConnectionAdapters::SQLite3::SchemaCreation
SQLite3Adapter =
ConnectionAdapters::AbstractAdapter
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" },
}

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.database_exists?(config) ⇒ Boolean

Returns:

  • (Boolean)


98
99
100
101
102
103
104
105
106
# File 'lib/arjdbc/sqlite3/adapter.rb', line 98

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)


168
169
170
# File 'lib/arjdbc/sqlite3/adapter.rb', line 168

def active?
  !@raw_connection.closed?
end

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

:nodoc:



252
253
254
255
256
257
258
259
260
# File 'lib/arjdbc/sqlite3/adapter.rb', line 252

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:



311
312
313
# File 'lib/arjdbc/sqlite3/adapter.rb', line 311

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)


221
222
223
# File 'lib/arjdbc/sqlite3/adapter.rb', line 221

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 'lib/arjdbc/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:



296
297
298
299
300
301
302
303
# File 'lib/arjdbc/sqlite3/adapter.rb', line 296

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:



279
280
281
282
283
284
285
# File 'lib/arjdbc/sqlite3/adapter.rb', line 279

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:



287
288
289
290
291
292
293
294
# File 'lib/arjdbc/sqlite3/adapter.rb', line 287

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



356
357
358
359
360
# File 'lib/arjdbc/sqlite3/adapter.rb', line 356

def check_version
  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 ====================================



207
208
209
210
211
212
213
214
215
216
217
218
219
# File 'lib/arjdbc/sqlite3/adapter.rb', line 207

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.



179
180
181
182
# File 'lib/arjdbc/sqlite3/adapter.rb', line 179

def disconnect!
  super
  @connection.close rescue nil
end

#encodingObject

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



193
194
195
# File 'lib/arjdbc/sqlite3/adapter.rb', line 193

def encoding
  @connection.encoding.to_s
end

#foreign_keys(table_name) ⇒ Object



316
317
318
319
320
321
322
323
324
325
326
327
328
# File 'lib/arjdbc/sqlite3/adapter.rb', line 316

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"])
    }
    # DIFFERENCE: FQN
    ::ActiveRecord::ConnectionAdapters::ForeignKeyDefinition.new(table_name, row["table"], options)
  end
end

#get_database_versionObject

:nodoc:



352
353
354
# File 'lib/arjdbc/sqlite3/adapter.rb', line 352

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

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



92
93
94
95
96
# File 'lib/arjdbc/sqlite3/adapter.rb', line 92

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

#native_database_typesObject

:nodoc:



188
189
190
# File 'lib/arjdbc/sqlite3/adapter.rb', line 188

def native_database_types #:nodoc:
  NATIVE_DATABASE_TYPES
end

#primary_keys(table_name) ⇒ Object

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



227
228
229
230
# File 'lib/arjdbc/sqlite3/adapter.rb', line 227

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!Object



172
173
174
175
# File 'lib/arjdbc/sqlite3/adapter.rb', line 172

def reconnect!
  super
  connect if @connection.closed?
end

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

:nodoc:



262
263
264
265
266
267
# File 'lib/arjdbc/sqlite3/adapter.rb', line 262

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:



269
270
271
272
273
274
275
276
277
# File 'lib/arjdbc/sqlite3/adapter.rb', line 269

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:



232
233
234
235
236
237
238
# File 'lib/arjdbc/sqlite3/adapter.rb', line 232

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:



305
306
307
308
309
# File 'lib/arjdbc/sqlite3/adapter.rb', line 305

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



245
246
247
248
249
250
# File 'lib/arjdbc/sqlite3/adapter.rb', line 245

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)


128
129
130
# File 'lib/arjdbc/sqlite3/adapter.rb', line 128

def requires_reloading?
  true
end

#shared_cache?Boolean

:nodoc:

Returns:

  • (Boolean)


348
349
350
# File 'lib/arjdbc/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)


136
137
138
# File 'lib/arjdbc/sqlite3/adapter.rb', line 136

def supports_check_constraints?
  true
end

#supports_common_table_expressions?Boolean

Returns:

  • (Boolean)


152
153
154
# File 'lib/arjdbc/sqlite3/adapter.rb', line 152

def supports_common_table_expressions?
  database_version >= "3.8.3"
end

#supports_concurrent_connections?Boolean

DIFFERENCE: active?, reconnect!, disconnect! handles by arjdbc core

Returns:

  • (Boolean)


164
165
166
# File 'lib/arjdbc/sqlite3/adapter.rb', line 164

def supports_concurrent_connections?
  !@memory_database
end

#supports_datetime_with_precision?Boolean

Returns:

  • (Boolean)


144
145
146
# File 'lib/arjdbc/sqlite3/adapter.rb', line 144

def supports_datetime_with_precision?
  true
end

#supports_ddl_transactions?Boolean

Returns:

  • (Boolean)


108
109
110
# File 'lib/arjdbc/sqlite3/adapter.rb', line 108

def supports_ddl_transactions?
  true
end

#supports_explain?Boolean

Returns:

  • (Boolean)


197
198
199
# File 'lib/arjdbc/sqlite3/adapter.rb', line 197

def supports_explain?
  true
end

#supports_expression_index?Boolean

Returns:

  • (Boolean)


124
125
126
# File 'lib/arjdbc/sqlite3/adapter.rb', line 124

def supports_expression_index?
  database_version >= "3.9.0"
end

#supports_foreign_keys?Boolean

Returns:

  • (Boolean)


132
133
134
# File 'lib/arjdbc/sqlite3/adapter.rb', line 132

def supports_foreign_keys?
  true
end

#supports_index_sort_order?Boolean

Returns:

  • (Boolean)


184
185
186
# File 'lib/arjdbc/sqlite3/adapter.rb', line 184

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)


156
157
158
# File 'lib/arjdbc/sqlite3/adapter.rb', line 156

def supports_insert_on_conflict?
  database_version >= "3.24.0"
end

#supports_json?Boolean

Returns:

  • (Boolean)


148
149
150
# File 'lib/arjdbc/sqlite3/adapter.rb', line 148

def supports_json?
  true
end

#supports_lazy_transactions?Boolean

Returns:

  • (Boolean)


201
202
203
# File 'lib/arjdbc/sqlite3/adapter.rb', line 201

def supports_lazy_transactions?
  true
end

#supports_partial_index?Boolean

Returns:

  • (Boolean)


120
121
122
# File 'lib/arjdbc/sqlite3/adapter.rb', line 120

def supports_partial_index?
  true
end

#supports_savepoints?Boolean

Returns:

  • (Boolean)


112
113
114
# File 'lib/arjdbc/sqlite3/adapter.rb', line 112

def supports_savepoints?
  true
end

#supports_transaction_isolation?Boolean

Returns:

  • (Boolean)


116
117
118
# File 'lib/arjdbc/sqlite3/adapter.rb', line 116

def supports_transaction_isolation?
  true
end

#supports_views?Boolean

Returns:

  • (Boolean)


140
141
142
# File 'lib/arjdbc/sqlite3/adapter.rb', line 140

def supports_views?
  true
end