Skip to content

Commit 379ea1e

Browse files
committed
Copy over some of the changes to the AR sqlite adapter
1 parent 1531e42 commit 379ea1e

File tree

1 file changed

+66
-19
lines changed

1 file changed

+66
-19
lines changed

lib/arjdbc/sqlite3/adapter.rb

Lines changed: 66 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,10 @@ def supports_common_table_expressions?
153153
database_version >= "3.8.3"
154154
end
155155

156+
def supports_insert_returning?
157+
database_version >= "3.35.0"
158+
end
159+
156160
def supports_insert_on_conflict?
157161
database_version >= "3.24.0"
158162
end
@@ -169,6 +173,10 @@ def active?
169173
@raw_connection && !@raw_connection.closed?
170174
end
171175

176+
def return_value_after_insert?(column) # :nodoc:
177+
column.auto_populated?
178+
end
179+
172180
def reconnect
173181
if active?
174182
@raw_connection.rollback rescue nil
@@ -194,7 +202,7 @@ def native_database_types #:nodoc:
194202

195203
# Returns the current database encoding format as a string, eg: 'UTF-8'
196204
def encoding
197-
@connection.encoding.to_s
205+
any_raw_connection.encoding.to_s
198206
end
199207

200208
def supports_explain?
@@ -304,7 +312,7 @@ def change_column_default(table_name, column_name, default_or_changes) #:nodoc:
304312

305313
def change_column_null(table_name, column_name, null, default = nil) #:nodoc:
306314
unless null || default.nil?
307-
exec_query("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
315+
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")
308316
end
309317
alter_table(table_name) do |definition|
310318
definition[column_name].null = null
@@ -326,13 +334,26 @@ def rename_column(table_name, column_name, new_column_name) #:nodoc:
326334
rename_column_indexes(table_name, column.name, new_column_name)
327335
end
328336

337+
def add_timestamps(table_name, **options)
338+
options[:null] = false if options[:null].nil?
339+
340+
if !options.key?(:precision)
341+
options[:precision] = 6
342+
end
343+
344+
alter_table(table_name) do |definition|
345+
definition.column :created_at, :datetime, **options
346+
definition.column :updated_at, :datetime, **options
347+
end
348+
end
349+
329350
def add_reference(table_name, ref_name, **options) # :nodoc:
330351
super(table_name, ref_name, type: :integer, **options)
331352
end
332353
alias :add_belongs_to :add_reference
333354

334355
def foreign_keys(table_name)
335-
fk_info = exec_query("PRAGMA foreign_key_list(#{quote(table_name)})", "SCHEMA")
356+
fk_info = internal_exec_query("PRAGMA foreign_key_list(#{quote(table_name)})", "SCHEMA")
336357
fk_info.map do |row|
337358
options = {
338359
column: row["from"],
@@ -360,13 +381,18 @@ def build_insert_sql(insert) # :nodoc:
360381
end
361382
end
362383

384+
sql << " RETURNING #{insert.returning}" if insert.returning
363385
sql
364386
end
365387

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

392+
def use_insert_returning?
393+
@use_insert_returning
394+
end
395+
370396
def get_database_version # :nodoc:
371397
SQLite3Adapter::Version.new(query_value("SELECT sqlite_version(*)", "SCHEMA"))
372398
end
@@ -395,15 +421,18 @@ def extract_value_from_default(default)
395421
case default
396422
when /^null$/i
397423
nil
398-
# Quoted types
399-
when /^'(.*)'$/m
424+
# Quoted types
425+
when /^'([^|]*)'$/m
400426
$1.gsub("''", "'")
401-
# Quoted types
402-
when /^"(.*)"$/m
427+
# Quoted types
428+
when /^"([^|]*)"$/m
403429
$1.gsub('""', '"')
404-
# Numeric types
430+
# Numeric types
405431
when /\A-?\d+(\.\d*)?\z/
406432
$&
433+
# Binary columns
434+
when /x'(.*)'/
435+
[ $1 ].pack("H*")
407436
else
408437
# Anything else is blank or some function
409438
# and we can't know the value of that, so return nil.
@@ -482,14 +511,25 @@ def copy_table(from, to, options = {})
482511
if column.has_default?
483512
type = lookup_cast_type_from_column(column)
484513
default = type.deserialize(column.default)
514+
default = -> { column.default_function } if default.nil?
485515
end
486516

487-
@definition.column(column_name, column.type,
488-
limit: column.limit, default: default,
489-
precision: column.precision, scale: column.scale,
490-
null: column.null, collation: column.collation,
517+
column_options = {
518+
limit: column.limit,
519+
precision: column.precision,
520+
scale: column.scale,
521+
null: column.null,
522+
collation: column.collation,
491523
primary_key: column_name == from_primary_key
492-
)
524+
}
525+
526+
# FIXME: This requires changes to the Column class
527+
# unless column.auto_increment?
528+
# column_options[:default] = default
529+
# end
530+
531+
column_type = column.bigint? ? :bigint : column.type
532+
@definition.column(column_name, column_type, **column_options)
493533
end
494534

495535
yield @definition if block_given?
@@ -537,8 +577,8 @@ def copy_table_contents(from, to, columns, rename = {})
537577
quoted_columns = columns.map { |col| quote_column_name(col) } * ","
538578
quoted_from_columns = from_columns_to_copy.map { |col| quote_column_name(col) } * ","
539579

540-
exec_query("INSERT INTO #{quote_table_name(to)} (#{quoted_columns})
541-
SELECT #{quoted_from_columns} FROM #{quote_table_name(from)}")
580+
internal_exec_query("INSERT INTO #{quote_table_name(to)} (#{quoted_columns})
581+
SELECT #{quoted_from_columns} FROM #{quote_table_name(from)}")
542582
end
543583

544584
def translate_exception(exception, message:, sql:, binds:)
@@ -548,25 +588,27 @@ def translate_exception(exception, message:, sql:, binds:)
548588
# column *column_name* is not unique
549589
if exception.message.match?(/(column(s)? .* (is|are) not unique|UNIQUE constraint failed: .*)/i)
550590
# DIFFERENCE: FQN
551-
::ActiveRecord::RecordNotUnique.new(message, sql: sql, binds: binds)
591+
::ActiveRecord::RecordNotUnique.new(message, sql: sql, binds: binds, connection_pool: @pool)
552592
elsif exception.message.match?(/(.* may not be NULL|NOT NULL constraint failed: .*)/i)
553593
# DIFFERENCE: FQN
554-
::ActiveRecord::NotNullViolation.new(message, sql: sql, binds: binds)
594+
::ActiveRecord::NotNullViolation.new(message, sql: sql, binds: binds, connection_pool: @pool)
555595
elsif exception.message.match?(/FOREIGN KEY constraint failed/i)
556596
# DIFFERENCE: FQN
557-
::ActiveRecord::InvalidForeignKey.new(message, sql: sql, binds: binds)
597+
::ActiveRecord::InvalidForeignKey.new(message, sql: sql, binds: binds, connection_pool: @pool)
558598
elsif exception.message.match?(/called on a closed database/i)
559599
# DIFFERENCE: FQN
560-
::ActiveRecord::ConnectionNotEstablished.new(exception)
600+
::ActiveRecord::ConnectionNotEstablished.new(exception, connection_pool: @pool)
561601
else
562602
super
563603
end
564604
end
565605

566606
COLLATE_REGEX = /.*\"(\w+)\".*collate\s+\"(\w+)\".*/i.freeze
607+
PRIMARY_KEY_AUTOINCREMENT_REGEX = /.*\"(\w+)\".+PRIMARY KEY AUTOINCREMENT/i
567608

568609
def table_structure_with_collation(table_name, basic_structure)
569610
collation_hash = {}
611+
auto_increments = {}
570612
sql = <<~SQL
571613
SELECT sql FROM
572614
(SELECT * FROM sqlite_master UNION ALL
@@ -588,6 +630,7 @@ def table_structure_with_collation(table_name, basic_structure)
588630
# This regex will match the column name and collation type and will save
589631
# the value in $1 and $2 respectively.
590632
collation_hash[$1] = $2 if COLLATE_REGEX =~ column_string
633+
auto_increments[$1] = true if PRIMARY_KEY_AUTOINCREMENT_REGEX =~ column_string
591634
end
592635

593636
basic_structure.map do |column|
@@ -597,6 +640,10 @@ def table_structure_with_collation(table_name, basic_structure)
597640
column["collation"] = collation_hash[column_name]
598641
end
599642

643+
if auto_increments.has_key?(column_name)
644+
column["auto_increment"] = true
645+
end
646+
600647
column
601648
end
602649
else

0 commit comments

Comments
 (0)