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