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)


95
96
97
# File 'lib/arjdbc/sqlite3/adapter.rb', line 95

def self.database_exists?(config)
  @config[:database] == ":memory:" || File.exist?(@config[:database].to_s)
end

Instance Method Details

#active?Boolean

Returns:

  • (Boolean)


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

def active?
  @raw_connection && !@raw_connection.closed?
end

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

:nodoc:



257
258
259
260
261
262
263
264
265
# File 'lib/arjdbc/sqlite3/adapter.rb', line 257

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:



328
329
330
# File 'lib/arjdbc/sqlite3/adapter.rb', line 328

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

#add_timestamps(table_name, **options) ⇒ Object



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

def add_timestamps(table_name, **options)
  options[:null] = false if options[:null].nil?

  if !options.key?(:precision)
    options[:precision] = 6
  end

  alter_table(table_name) do |definition|
    definition.column :created_at, :datetime, **options
    definition.column :updated_at, :datetime, **options
  end
end

#build_insert_sql(insert) ⇒ Object

:nodoc:



356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
# File 'lib/arjdbc/sqlite3/adapter.rb', line 356

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 << " RETURNING #{insert.returning}" if insert.returning
  sql
end

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

:nodoc:



303
304
305
306
307
# File 'lib/arjdbc/sqlite3/adapter.rb', line 303

def change_column(table_name, column_name, type, **options) #:nodoc:
  alter_table(table_name) do |definition|
    definition.change_column(column_name, type, **options)
  end
end

#change_column_default(table_name, column_name, default_or_changes) ⇒ Object

:nodoc:



284
285
286
287
288
289
290
# File 'lib/arjdbc/sqlite3/adapter.rb', line 284

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:



292
293
294
295
296
297
298
299
300
301
# File 'lib/arjdbc/sqlite3/adapter.rb', line 292

def change_column_null(table_name, column_name, null, default = nil) #:nodoc:
  validate_change_column_null_argument!(null)

  unless null || default.nil?
    internal_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_all_foreign_keys_valid!Object

:nodoc:



219
220
221
222
223
224
225
226
227
# File 'lib/arjdbc/sqlite3/adapter.rb', line 219

def check_all_foreign_keys_valid! # :nodoc:
  sql = "PRAGMA foreign_key_check"
  result = execute(sql)

  unless result.blank?
    tables = result.map { |row| row["table"] }
    raise ActiveRecord::StatementInvalid.new("Foreign key violations found: #{tables.join(", ")}", sql: sql)
  end
end

#check_versionObject



387
388
389
390
391
# File 'lib/arjdbc/sqlite3/adapter.rb', line 387

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



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

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.



175
176
177
178
179
180
# File 'lib/arjdbc/sqlite3/adapter.rb', line 175

def disconnect!
  super

  @raw_connection&.close rescue nil
  @raw_connection = nil
end

#encodingObject

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



191
192
193
# File 'lib/arjdbc/sqlite3/adapter.rb', line 191

def encoding
  any_raw_connection.encoding.to_s
end

#foreign_keys(table_name) ⇒ Object



333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
# File 'lib/arjdbc/sqlite3/adapter.rb', line 333

def foreign_keys(table_name)
  # SQLite returns 1 row for each column of composite foreign keys.
  fk_info = internal_exec_query("PRAGMA foreign_key_list(#{quote(table_name)})", "SCHEMA")
  grouped_fk = fk_info.group_by { |row| row["id"] }.values.each { |group| group.sort_by! { |row| row["seq"] } }
  grouped_fk.map do |group|
    row = group.first
    options = {
      on_delete: extract_foreign_key_action(row["on_delete"]),
      on_update: extract_foreign_key_action(row["on_update"])
    }

    if group.one?
      options[:column] = row["from"]
      options[:primary_key] = row["to"]
    else
      options[:column] = group.map { |row| row["from"] }
      options[:primary_key] = group.map { |row| row["to"] }
    end
    # DIFFERENCE: FQN
    ::ActiveRecord::ConnectionAdapters::ForeignKeyDefinition.new(table_name, row["table"], options)
  end
end

#get_database_versionObject

:nodoc:



383
384
385
# File 'lib/arjdbc/sqlite3/adapter.rb', line 383

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

#native_database_typesObject

:nodoc:



186
187
188
# File 'lib/arjdbc/sqlite3/adapter.rb', line 186

def native_database_types #:nodoc:
  NATIVE_DATABASE_TYPES
end

#new_column_from_field(table_name, field, definitions) ⇒ Object

DIFFERENCE: here to



394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
# File 'lib/arjdbc/sqlite3/adapter.rb', line 394

def new_column_from_field(table_name, field, definitions)
  default = field["dflt_value"]

   = (field["type"])
  default_value = extract_value_from_default(default)
  default_function = extract_default_function(default_value, default)
  rowid = is_column_the_rowid?(field, definitions)

  ActiveRecord::ConnectionAdapters::SQLite3Column.new(
    field["name"],
    default_value,
    ,
    field["notnull"].to_i == 0,
    default_function,
    collation: field["collation"],
    auto_increment: field["auto_increment"],
    rowid: rowid
  )
end

#primary_keys(table_name) ⇒ Object

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



231
232
233
234
# File 'lib/arjdbc/sqlite3/adapter.rb', line 231

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:



267
268
269
270
271
272
# File 'lib/arjdbc/sqlite3/adapter.rb', line 267

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:



274
275
276
277
278
279
280
281
282
# File 'lib/arjdbc/sqlite3/adapter.rb', line 274

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:



236
237
238
239
240
241
242
# File 'lib/arjdbc/sqlite3/adapter.rb', line 236

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)

  internal_exec_query "DROP INDEX #{quote_column_name(index_name)}"
end

#rename_column(table_name, column_name, new_column_name) ⇒ Object

:nodoc:



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

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, **options) ⇒ Object

Renames a table.

Example: rename_table('octopuses', 'octopi')



249
250
251
252
253
254
255
# File 'lib/arjdbc/sqlite3/adapter.rb', line 249

def rename_table(table_name, new_name, **options)
  validate_table_length!(new_name) unless options[:_uses_legacy_table_name]      
  schema_cache.clear_data_source_cache!(table_name.to_s)
  schema_cache.clear_data_source_cache!(new_name.to_s)
  internal_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)


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

def requires_reloading?
  true
end

#return_value_after_insert?(column) ⇒ Boolean

:nodoc:

Returns:

  • (Boolean)


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

def return_value_after_insert?(column) # :nodoc:
  column.auto_populated?
end

#shared_cache?Boolean

:nodoc:

Returns:

  • (Boolean)


375
376
377
# File 'lib/arjdbc/sqlite3/adapter.rb', line 375

def shared_cache? # :nodoc:
  @config.fetch(:flags, 0).anybits?(::SQLite3::Constants::Open::SHAREDCACHE)
end

#supports_check_constraints?Boolean

Returns:

  • (Boolean)


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

def supports_check_constraints?
  true
end

#supports_common_table_expressions?Boolean

Returns:

  • (Boolean)


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

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)


159
160
161
# File 'lib/arjdbc/sqlite3/adapter.rb', line 159

def supports_concurrent_connections?
  !@memory_database
end

#supports_datetime_with_precision?Boolean

Returns:

  • (Boolean)


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

def supports_datetime_with_precision?
  true
end

#supports_ddl_transactions?Boolean

Returns:

  • (Boolean)


99
100
101
# File 'lib/arjdbc/sqlite3/adapter.rb', line 99

def supports_ddl_transactions?
  true
end

#supports_explain?Boolean

Returns:

  • (Boolean)


195
196
197
# File 'lib/arjdbc/sqlite3/adapter.rb', line 195

def supports_explain?
  true
end

#supports_expression_index?Boolean

Returns:

  • (Boolean)


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

def supports_expression_index?
  database_version >= "3.9.0"
end

#supports_foreign_keys?Boolean

Returns:

  • (Boolean)


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

def supports_foreign_keys?
  true
end

#supports_index_sort_order?Boolean

Returns:

  • (Boolean)


182
183
184
# File 'lib/arjdbc/sqlite3/adapter.rb', line 182

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)


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

def supports_insert_on_conflict?
  database_version >= "3.24.0"
end

#supports_insert_returning?Boolean

Returns:

  • (Boolean)


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

def supports_insert_returning?
  database_version >= "3.35.0"
end

#supports_json?Boolean

Returns:

  • (Boolean)


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

def supports_json?
  true
end

#supports_lazy_transactions?Boolean

Returns:

  • (Boolean)


199
200
201
# File 'lib/arjdbc/sqlite3/adapter.rb', line 199

def supports_lazy_transactions?
  true
end

#supports_partial_index?Boolean

Returns:

  • (Boolean)


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

def supports_partial_index?
  true
end

#supports_savepoints?Boolean

Returns:

  • (Boolean)


103
104
105
# File 'lib/arjdbc/sqlite3/adapter.rb', line 103

def supports_savepoints?
  true
end

#supports_transaction_isolation?Boolean

Returns:

  • (Boolean)


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

def supports_transaction_isolation?
  true
end

#supports_views?Boolean

Returns:

  • (Boolean)


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

def supports_views?
  true
end

#use_insert_returning?Boolean

Returns:

  • (Boolean)


379
380
381
# File 'lib/arjdbc/sqlite3/adapter.rb', line 379

def use_insert_returning?
  @use_insert_returning
end