@@ -477,11 +477,7 @@ def bind_params_length
477
477
end
478
478
479
479
def table_structure ( table_name )
480
- structure = if supports_virtual_columns?
481
- internal_exec_query ( "PRAGMA table_xinfo(#{ quote_table_name ( table_name ) } )" , "SCHEMA" )
482
- else
483
- internal_exec_query ( "PRAGMA table_info(#{ quote_table_name ( table_name ) } )" , "SCHEMA" )
484
- end
480
+ structure = table_info ( table_name )
485
481
raise ActiveRecord ::StatementInvalid . new ( "Could not find table '#{ table_name } '" , connection_pool : @pool ) if structure . empty?
486
482
table_structure_with_collation ( table_name , structure )
487
483
end
@@ -684,7 +680,7 @@ def table_structure_with_collation(table_name, basic_structure)
684
680
auto_increments = { }
685
681
generated_columns = { }
686
682
687
- column_strings = table_structure_sql ( table_name )
683
+ column_strings = table_structure_sql ( table_name , basic_structure . map { | column | column [ "name" ] } )
688
684
689
685
if column_strings . any?
690
686
column_strings . each do |column_string |
@@ -719,7 +715,15 @@ def table_structure_with_collation(table_name, basic_structure)
719
715
end
720
716
end
721
717
722
- def table_structure_sql ( table_name )
718
+ UNQUOTED_OPEN_PARENS_REGEX = /\( (?![^'"]*['"][^'"]*$)/
719
+ FINAL_CLOSE_PARENS_REGEX = /\) ;*\z /
720
+
721
+ def table_structure_sql ( table_name , column_names = nil )
722
+ unless column_names
723
+ column_info = table_info ( table_name )
724
+ column_names = column_info . map { |column | column [ "name" ] }
725
+ end
726
+
723
727
sql = <<~SQL
724
728
SELECT sql FROM
725
729
(SELECT * FROM sqlite_master UNION ALL
@@ -729,16 +733,30 @@ def table_structure_sql(table_name)
729
733
730
734
# Result will have following sample string
731
735
# CREATE TABLE "users" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
732
- # "password_digest" varchar COLLATE "NOCASE");
736
+ # "password_digest" varchar COLLATE "NOCASE",
737
+ # "o_id" integer,
738
+ # CONSTRAINT "fk_rails_78146ddd2e" FOREIGN KEY ("o_id") REFERENCES "os" ("id"));
733
739
result = query_value ( sql , "SCHEMA" )
734
740
735
741
return [ ] unless result
736
742
737
743
# Splitting with left parentheses and discarding the first part will return all
738
744
# columns separated with comma(,).
739
- columns_string = result . split ( "(" , 2 ) . last
745
+ result . partition ( UNQUOTED_OPEN_PARENS_REGEX )
746
+ . last
747
+ . sub ( FINAL_CLOSE_PARENS_REGEX , "" )
748
+ # column definitions can have a comma in them, so split on commas followed
749
+ # by a space and a column name in quotes or followed by the keyword CONSTRAINT
750
+ . split ( /,(?=\s (?:CONSTRAINT|"(?:#{ Regexp . union ( column_names ) . source } )"))/i )
751
+ . map ( &:strip )
752
+ end
740
753
741
- columns_string . split ( "," ) . map ( &:strip )
754
+ def table_info ( table_name )
755
+ if supports_virtual_columns?
756
+ internal_exec_query ( "PRAGMA table_xinfo(#{ quote_table_name ( table_name ) } )" , "SCHEMA" )
757
+ else
758
+ internal_exec_query ( "PRAGMA table_info(#{ quote_table_name ( table_name ) } )" , "SCHEMA" )
759
+ end
742
760
end
743
761
744
762
def arel_visitor
0 commit comments