@@ -153,6 +153,10 @@ def supports_common_table_expressions?
153
153
database_version >= "3.8.3"
154
154
end
155
155
156
+ def supports_insert_returning?
157
+ database_version >= "3.35.0"
158
+ end
159
+
156
160
def supports_insert_on_conflict?
157
161
database_version >= "3.24.0"
158
162
end
@@ -169,6 +173,10 @@ def active?
169
173
@raw_connection && !@raw_connection . closed?
170
174
end
171
175
176
+ def return_value_after_insert? ( column ) # :nodoc:
177
+ column . auto_populated?
178
+ end
179
+
172
180
def reconnect
173
181
if active?
174
182
@raw_connection . rollback rescue nil
@@ -194,7 +202,7 @@ def native_database_types #:nodoc:
194
202
195
203
# Returns the current database encoding format as a string, eg: 'UTF-8'
196
204
def encoding
197
- @connection . encoding . to_s
205
+ any_raw_connection . encoding . to_s
198
206
end
199
207
200
208
def supports_explain?
@@ -304,7 +312,7 @@ def change_column_default(table_name, column_name, default_or_changes) #:nodoc:
304
312
305
313
def change_column_null ( table_name , column_name , null , default = nil ) #:nodoc:
306
314
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" )
308
316
end
309
317
alter_table ( table_name ) do |definition |
310
318
definition [ column_name ] . null = null
@@ -326,13 +334,26 @@ def rename_column(table_name, column_name, new_column_name) #:nodoc:
326
334
rename_column_indexes ( table_name , column . name , new_column_name )
327
335
end
328
336
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
+
329
350
def add_reference ( table_name , ref_name , **options ) # :nodoc:
330
351
super ( table_name , ref_name , type : :integer , **options )
331
352
end
332
353
alias :add_belongs_to :add_reference
333
354
334
355
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" )
336
357
fk_info . map do |row |
337
358
options = {
338
359
column : row [ "from" ] ,
@@ -360,13 +381,18 @@ def build_insert_sql(insert) # :nodoc:
360
381
end
361
382
end
362
383
384
+ sql << " RETURNING #{ insert . returning } " if insert . returning
363
385
sql
364
386
end
365
387
366
388
def shared_cache? # :nodoc:
367
389
@config . fetch ( :flags , 0 ) . anybits? ( ::SQLite3 ::Constants ::Open ::SHAREDCACHE )
368
390
end
369
391
392
+ def use_insert_returning?
393
+ @use_insert_returning
394
+ end
395
+
370
396
def get_database_version # :nodoc:
371
397
SQLite3Adapter ::Version . new ( query_value ( "SELECT sqlite_version(*)" , "SCHEMA" ) )
372
398
end
@@ -395,15 +421,18 @@ def extract_value_from_default(default)
395
421
case default
396
422
when /^null$/i
397
423
nil
398
- # Quoted types
399
- when /^'(. *)'$/m
424
+ # Quoted types
425
+ when /^'([^|] *)'$/m
400
426
$1. gsub ( "''" , "'" )
401
- # Quoted types
402
- when /^"(. *)"$/m
427
+ # Quoted types
428
+ when /^"([^|] *)"$/m
403
429
$1. gsub ( '""' , '"' )
404
- # Numeric types
430
+ # Numeric types
405
431
when /\A -?\d +(\. \d *)?\z /
406
432
$&
433
+ # Binary columns
434
+ when /x'(.*)'/
435
+ [ $1 ] . pack ( "H*" )
407
436
else
408
437
# Anything else is blank or some function
409
438
# and we can't know the value of that, so return nil.
@@ -482,14 +511,25 @@ def copy_table(from, to, options = {})
482
511
if column . has_default?
483
512
type = lookup_cast_type_from_column ( column )
484
513
default = type . deserialize ( column . default )
514
+ default = -> { column . default_function } if default . nil?
485
515
end
486
516
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 ,
491
523
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 )
493
533
end
494
534
495
535
yield @definition if block_given?
@@ -537,8 +577,8 @@ def copy_table_contents(from, to, columns, rename = {})
537
577
quoted_columns = columns . map { |col | quote_column_name ( col ) } * ","
538
578
quoted_from_columns = from_columns_to_copy . map { |col | quote_column_name ( col ) } * ","
539
579
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 ) } " )
542
582
end
543
583
544
584
def translate_exception ( exception , message :, sql :, binds :)
@@ -548,25 +588,27 @@ def translate_exception(exception, message:, sql:, binds:)
548
588
# column *column_name* is not unique
549
589
if exception . message . match? ( /(column(s)? .* (is|are) not unique|UNIQUE constraint failed: .*)/i )
550
590
# DIFFERENCE: FQN
551
- ::ActiveRecord ::RecordNotUnique . new ( message , sql : sql , binds : binds )
591
+ ::ActiveRecord ::RecordNotUnique . new ( message , sql : sql , binds : binds , connection_pool : @pool )
552
592
elsif exception . message . match? ( /(.* may not be NULL|NOT NULL constraint failed: .*)/i )
553
593
# DIFFERENCE: FQN
554
- ::ActiveRecord ::NotNullViolation . new ( message , sql : sql , binds : binds )
594
+ ::ActiveRecord ::NotNullViolation . new ( message , sql : sql , binds : binds , connection_pool : @pool )
555
595
elsif exception . message . match? ( /FOREIGN KEY constraint failed/i )
556
596
# DIFFERENCE: FQN
557
- ::ActiveRecord ::InvalidForeignKey . new ( message , sql : sql , binds : binds )
597
+ ::ActiveRecord ::InvalidForeignKey . new ( message , sql : sql , binds : binds , connection_pool : @pool )
558
598
elsif exception . message . match? ( /called on a closed database/i )
559
599
# DIFFERENCE: FQN
560
- ::ActiveRecord ::ConnectionNotEstablished . new ( exception )
600
+ ::ActiveRecord ::ConnectionNotEstablished . new ( exception , connection_pool : @pool )
561
601
else
562
602
super
563
603
end
564
604
end
565
605
566
606
COLLATE_REGEX = /.*\" (\w +)\" .*collate\s +\" (\w +)\" .*/i . freeze
607
+ PRIMARY_KEY_AUTOINCREMENT_REGEX = /.*\" (\w +)\" .+PRIMARY KEY AUTOINCREMENT/i
567
608
568
609
def table_structure_with_collation ( table_name , basic_structure )
569
610
collation_hash = { }
611
+ auto_increments = { }
570
612
sql = <<~SQL
571
613
SELECT sql FROM
572
614
(SELECT * FROM sqlite_master UNION ALL
@@ -588,6 +630,7 @@ def table_structure_with_collation(table_name, basic_structure)
588
630
# This regex will match the column name and collation type and will save
589
631
# the value in $1 and $2 respectively.
590
632
collation_hash [ $1] = $2 if COLLATE_REGEX =~ column_string
633
+ auto_increments [ $1] = true if PRIMARY_KEY_AUTOINCREMENT_REGEX =~ column_string
591
634
end
592
635
593
636
basic_structure . map do |column |
@@ -597,6 +640,10 @@ def table_structure_with_collation(table_name, basic_structure)
597
640
column [ "collation" ] = collation_hash [ column_name ]
598
641
end
599
642
643
+ if auto_increments . has_key? ( column_name )
644
+ column [ "auto_increment" ] = true
645
+ end
646
+
600
647
column
601
648
end
602
649
else
0 commit comments