@@ -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,11 @@ 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+ defp drop_mode ( :restrict ) , do: [ ]
582+
638583 ##
639584 ## Query generation
640585 ##
@@ -1736,6 +1681,22 @@ defmodule Ecto.Adapters.SQLite3.Connection do
17361681 defp pk_expr ( true , _ ) , do: " PRIMARY KEY"
17371682 defp pk_expr ( _ , _ ) , do: [ ]
17381683
1684+ defp modifiers_expr ( nil ) , do: [ ]
1685+
1686+ defp modifiers_expr ( modifiers ) when is_binary ( modifiers ) do
1687+ if temporary? ( modifiers ) do
1688+ [ modifiers , ?\s ]
1689+ else
1690+ raise ArgumentError ,
1691+ ~s| SQLite3 adapter expects :modifiers to be one of [nil, "TEMP", "TEMPORARY"], got #{ inspect ( modifiers ) } |
1692+ end
1693+ end
1694+
1695+ defp modifiers_expr ( other ) do
1696+ raise ArgumentError ,
1697+ "SQLite3 adapter expects :modifiers to be a string or nil, got #{ inspect ( other ) } "
1698+ end
1699+
17391700 defp options_expr ( nil ) , do: [ ]
17401701
17411702 defp options_expr ( options ) when is_list ( options ) do
@@ -1748,7 +1709,7 @@ defmodule Ecto.Adapters.SQLite3.Connection do
17481709 defp reference_expr ( % Reference { with: [ _ ] } , _table , _name ) , do: [ ]
17491710
17501711 defp reference_expr ( % Reference { } = ref , table , name ) do
1751- assert_same_database ( table . prefix , ref . prefix )
1712+ assert_same_database ( table , ref )
17521713
17531714 [
17541715 " CONSTRAINT " ,
@@ -1859,7 +1820,7 @@ defmodule Ecto.Adapters.SQLite3.Connection do
18591820 end
18601821
18611822 defp composite_fk_definition ( table , { _op , name , ref , _opts } ) do
1862- assert_same_database ( table . prefix , ref . prefix )
1823+ assert_same_database ( table , ref )
18631824
18641825 { current_columns , reference_columns } = Enum . unzip ( [ { name , ref . column } | ref . with ] )
18651826
@@ -1950,8 +1911,6 @@ defmodule Ecto.Adapters.SQLite3.Connection do
19501911 # We know this holds since exqlite does not export sqlite3_db_config from Sqlite3NIF,
19511912 # thus nobody can call sqlite3_db_config(db, SQLITE_DBCONFIG_MAINDBNAME, ...)
19521913 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;}`
19551914 "main"
19561915 end
19571916
@@ -1963,10 +1922,34 @@ defmodule Ecto.Adapters.SQLite3.Connection do
19631922 String . downcase ( name , :ascii )
19641923 end
19651924
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
1925+ defp temporary? ( nil ) , do: false
1926+
1927+ defp temporary? ( modifiers ) when is_binary ( modifiers ) ,
1928+ do:
1929+ ( modifiers
1930+ |> String . trim ( )
1931+ |> String . upcase ( :ascii ) ) in [ "TEMP" , "TEMPORARY" ]
1932+
1933+ defp temporary? ( _ ) , do: false
1934+
1935+ defp table_database ( % Table { } = table ) do
1936+ if temporary? ( table . modifiers ) ,
1937+ do: "temp" ,
1938+ else: normalize_database_name ( table . prefix )
1939+ end
1940+
1941+ defp assert_same_database ( % Table { } = table , % Reference { } = ref ) do
1942+ table_db = table_database ( table )
1943+ ref_db = if ref . prefix , do: normalize_database_name ( ref . prefix ) , else: table_db
1944+
1945+ if ref_db != table_db do
19691946 raise ArgumentError , "SQLite3 does not support cross-database foreign keys"
19701947 end
19711948 end
1949+
1950+ defp assert_unqual_name ( modifiers , prefix ) do
1951+ if modifiers != [ ] and prefix != nil do
1952+ raise ArgumentError , "SQLite3 does not support a prefix on a temporary table"
1953+ end
1954+ end
19721955end
0 commit comments