@@ -390,38 +390,30 @@ defmodule Ecto.Adapters.SQLite3.Connection do
390390 ## DDL
391391 ##
392392
393+ @ creates [ :create , :create_if_not_exists ]
394+ @ drops [ :drop , :drop_if_exists ]
395+
393396 @ impl true
394397 def execute_ddl ( { _command , % Table { options: options } , _ } ) when is_list ( options ) do
395398 raise ArgumentError , "SQLite3 adapter does not support keyword lists in :options"
396399 end
397400
398- def execute_ddl ( { :create , % Table { } = table , columns } ) do
401+ def execute_ddl ( { command , % Table { } = table , columns } ) when command in @ creates do
399402 { table , composite_pk_def } = composite_pk_definition ( table , columns )
400403 composite_fk_defs = composite_fk_definitions ( table , columns )
401404
402- [
403- [
404- "CREATE TABLE " ,
405- quote_name ( table . prefix , table . name ) ,
406- ?\s ,
407- ?( ,
408- column_definitions ( table , columns ) ,
409- composite_pk_def ,
410- composite_fk_defs ,
411- ?) ,
412- options_expr ( table . options )
413- ]
414- ]
415- end
405+ table_name = quote_name ( table . prefix , table . name )
416406
417- def execute_ddl ( { :create_if_not_exists , % Table { } = table , columns } ) do
418- { table , composite_pk_def } = composite_pk_definition ( table , columns )
419- composite_fk_defs = composite_fk_definitions ( table , columns )
407+ modifiers = modifiers_expr ( table . modifiers )
408+ assert_unqual_name ( modifiers , table . prefix )
420409
421410 [
422411 [
423- "CREATE TABLE IF NOT EXISTS " ,
424- quote_name ( table . prefix , table . name ) ,
412+ "CREATE " ,
413+ modifiers ,
414+ "TABLE " ,
415+ if_do ( command == :create_if_not_exists , "IF NOT EXISTS " ) ,
416+ table_name ,
425417 ?\s ,
426418 ?( ,
427419 column_definitions ( table , columns ) ,
@@ -433,32 +425,17 @@ defmodule Ecto.Adapters.SQLite3.Connection do
433425 ]
434426 end
435427
436- def execute_ddl ( { :drop , % Table { } = table } ) do
428+ def execute_ddl ( { command , % Table { } = table , mode } ) when command in @ drops do
437429 [
438430 [
439431 "DROP TABLE " ,
440- quote_name ( table . prefix , table . name )
441- ]
442- ]
443- end
444-
445- def execute_ddl ( { :drop , % Table { } = table , _mode } ) do
446- execute_ddl ( { :drop , table } )
447- end
448-
449- def execute_ddl ( { :drop_if_exists , % Table { } = table } ) do
450- [
451- [
452- "DROP TABLE IF EXISTS " ,
453- quote_name ( table . prefix , table . name )
432+ if_do ( command == :drop_if_exists , "IF EXISTS " ) ,
433+ quote_name ( table . prefix , table . name ) ,
434+ drop_mode ( mode )
454435 ]
455436 ]
456437 end
457438
458- def execute_ddl ( { :drop_if_exists , % Table { } = table , _mode } ) do
459- execute_ddl ( { :drop_if_exists , table } )
460- end
461-
462439 def execute_ddl ( { :alter , % Table { } = table , changes } ) do
463440 Enum . map ( changes , fn change ->
464441 [
@@ -490,14 +467,15 @@ defmodule Ecto.Adapters.SQLite3.Connection do
490467 raise ArgumentError , "`nulls_distinct` is not supported with SQLite3"
491468 end
492469
493- def execute_ddl ( { :create , % Index { } = index } ) do
470+ def execute_ddl ( { command , % Index { } = index } ) when command in @ creates do
494471 fields = Enum . map_intersperse ( index . columns , ", " , & index_expr / 1 )
495472
496473 [
497474 [
498475 "CREATE " ,
499476 if_do ( index . unique , "UNIQUE " ) ,
500477 "INDEX " ,
478+ if_do ( command == :create_if_not_exists , "IF NOT EXISTS " ) ,
501479 quote_name ( index . prefix , index . name ) ,
502480 " ON " ,
503481 quote_name ( index . table ) ,
@@ -509,51 +487,17 @@ defmodule Ecto.Adapters.SQLite3.Connection do
509487 ]
510488 end
511489
512- def execute_ddl ( { :create_if_not_exists , % Index { } = index } ) do
513- fields = Enum . map_intersperse ( index . columns , ", " , & index_expr / 1 )
514-
515- [
516- [
517- "CREATE " ,
518- if_do ( index . unique , "UNIQUE " ) ,
519- "INDEX IF NOT EXISTS " ,
520- quote_name ( index . prefix , index . name ) ,
521- " ON " ,
522- quote_name ( index . table ) ,
523- " (" ,
524- fields ,
525- ?) ,
526- if_do ( index . where , [ " WHERE " , to_string ( index . where ) ] )
527- ]
528- ]
529- end
530-
531- def execute_ddl ( { :drop , % Index { } = index } ) do
490+ def execute_ddl ( { command , % Index { } = index , mode } ) when command in @ drops do
532491 [
533492 [
534493 "DROP INDEX " ,
535- quote_name ( index . prefix , index . name )
536- ]
537- ]
538- end
539-
540- def execute_ddl ( { :drop , % Index { } = index , _mode } ) do
541- execute_ddl ( { :drop , index } )
542- end
543-
544- def execute_ddl ( { :drop_if_exists , % Index { } = index } ) do
545- [
546- [
547- "DROP INDEX IF EXISTS " ,
548- quote_name ( index . prefix , index . name )
494+ if_do ( command == :drop_if_exists , "IF EXISTS " ) ,
495+ quote_name ( index . prefix , index . name ) ,
496+ drop_mode ( mode )
549497 ]
550498 ]
551499 end
552500
553- def execute_ddl ( { :drop_if_exists , % Index { } = index , _mode } ) do
554- execute_ddl ( { :drop_if_exists , index } )
555- end
556-
557501 def execute_ddl ( { :rename , % Table { } = current_table , % Table { } = new_table } ) do
558502 [
559503 [
@@ -600,18 +544,14 @@ defmodule Ecto.Adapters.SQLite3.Connection do
600544 raise ArgumentError , "SQLite3 does not support exclusion constraints"
601545 end
602546
603- def execute_ddl ( { :drop , % Constraint { } , :cascade } ) do
604- raise ArgumentError ,
605- "SQLite3 does not support `CASCADE` in `DROP CONSTRAINT` commands"
606- end
607-
608- def execute_ddl ( { :drop , % Constraint { } = constraint , _mode } ) do
547+ def execute_ddl ( { :drop , % Constraint { } = constraint , mode } ) do
609548 [
610549 [
611550 "ALTER TABLE " ,
612551 quote_name ( constraint . prefix , constraint . table ) ,
613552 " DROP CONSTRAINT " ,
614- quote_name ( constraint . name )
553+ quote_name ( constraint . name ) ,
554+ drop_mode ( mode )
615555 ]
616556 ]
617557 end
@@ -622,7 +562,7 @@ defmodule Ecto.Adapters.SQLite3.Connection do
622562
623563 def execute_ddl ( { :rename , % Index { } = index , new_index } ) do
624564 [
625- execute_ddl ( { :drop , index } ) ,
565+ execute_ddl ( { :drop , index , :restrict } ) ,
626566 execute_ddl ( { :create , % Index { index | name: new_index } } )
627567 ]
628568 end
@@ -635,6 +575,12 @@ defmodule Ecto.Adapters.SQLite3.Connection do
635575 { "SELECT name FROM sqlite_master WHERE type='table' AND name=? LIMIT 1" , [ table ] }
636576 end
637577
578+ defp drop_mode ( :cascade ) do
579+ raise ArgumentError , "SQLite3 does not support `CASCADE` in this command"
580+ end
581+
582+ defp drop_mode ( :restrict ) , do: [ ]
583+
638584 ##
639585 ## Query generation
640586 ##
@@ -1736,6 +1682,22 @@ defmodule Ecto.Adapters.SQLite3.Connection do
17361682 defp pk_expr ( true , _ ) , do: " PRIMARY KEY"
17371683 defp pk_expr ( _ , _ ) , do: [ ]
17381684
1685+ defp modifiers_expr ( nil ) , do: [ ]
1686+
1687+ defp modifiers_expr ( modifiers ) when is_binary ( modifiers ) do
1688+ if temporary? ( modifiers ) do
1689+ [ modifiers , ?\s ]
1690+ else
1691+ raise ArgumentError ,
1692+ ~s| SQLite3 adapter expects :modifiers to be one of [nil, "TEMP", "TEMPORARY"], got #{ inspect ( modifiers ) } |
1693+ end
1694+ end
1695+
1696+ defp modifiers_expr ( other ) do
1697+ raise ArgumentError ,
1698+ "SQLite3 adapter expects :modifiers to be a string or nil, got #{ inspect ( other ) } "
1699+ end
1700+
17391701 defp options_expr ( nil ) , do: [ ]
17401702
17411703 defp options_expr ( options ) when is_list ( options ) do
@@ -1748,7 +1710,7 @@ defmodule Ecto.Adapters.SQLite3.Connection do
17481710 defp reference_expr ( % Reference { with: [ _ ] } , _table , _name ) , do: [ ]
17491711
17501712 defp reference_expr ( % Reference { } = ref , table , name ) do
1751- assert_same_database ( table . prefix , ref . prefix )
1713+ assert_same_database ( table , ref )
17521714
17531715 [
17541716 " CONSTRAINT " ,
@@ -1859,7 +1821,7 @@ defmodule Ecto.Adapters.SQLite3.Connection do
18591821 end
18601822
18611823 defp composite_fk_definition ( table , { _op , name , ref , _opts } ) do
1862- assert_same_database ( table . prefix , ref . prefix )
1824+ assert_same_database ( table , ref )
18631825
18641826 { current_columns , reference_columns } = Enum . unzip ( [ { name , ref . column } | ref . with ] )
18651827
@@ -1950,8 +1912,6 @@ defmodule Ecto.Adapters.SQLite3.Connection do
19501912 # We know this holds since exqlite does not export sqlite3_db_config from Sqlite3NIF,
19511913 # thus nobody can call sqlite3_db_config(db, SQLITE_DBCONFIG_MAINDBNAME, ...)
19521914 defp normalize_database_name ( nil ) do
1953- # TODO: handle modifier-selected temp database somehow?
1954- # src/parse.y: `temp(A) ::= TEMP. {A = pParse->db->init.busy==0;}`
19551915 "main"
19561916 end
19571917
@@ -1963,10 +1923,34 @@ defmodule Ecto.Adapters.SQLite3.Connection do
19631923 String . downcase ( name , :ascii )
19641924 end
19651925
1966- defp assert_same_database ( table_prefix , ref_prefix ) do
1967- if normalize_database_name ( ref_prefix || table_prefix ) !=
1968- normalize_database_name ( table_prefix ) do
1926+ defp temporary? ( nil ) , do: false
1927+
1928+ defp temporary? ( modifiers ) when is_binary ( modifiers ) ,
1929+ do:
1930+ ( modifiers
1931+ |> String . trim ( )
1932+ |> String . upcase ( :ascii ) ) in [ "TEMP" , "TEMPORARY" ]
1933+
1934+ defp temporary? ( _ ) , do: false
1935+
1936+ defp table_database ( % Table { } = table ) do
1937+ if temporary? ( table . modifiers ) ,
1938+ do: "temp" ,
1939+ else: normalize_database_name ( table . prefix )
1940+ end
1941+
1942+ defp assert_same_database ( % Table { } = table , % Reference { } = ref ) do
1943+ table_db = table_database ( table )
1944+ ref_db = if ref . prefix , do: normalize_database_name ( ref . prefix ) , else: table_db
1945+
1946+ if ref_db != table_db do
19691947 raise ArgumentError , "SQLite3 does not support cross-database foreign keys"
19701948 end
19711949 end
1950+
1951+ defp assert_unqual_name ( modifiers , prefix ) do
1952+ if modifiers != [ ] and prefix != nil do
1953+ raise ArgumentError , "SQLite3 does not support a prefix on a temporary table"
1954+ end
1955+ end
19721956end
0 commit comments