sequel 3.28.0 → 3.29.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (148) hide show
  1. data/CHANGELOG +119 -3
  2. data/Rakefile +5 -3
  3. data/bin/sequel +1 -5
  4. data/doc/model_hooks.rdoc +9 -1
  5. data/doc/opening_databases.rdoc +49 -40
  6. data/doc/prepared_statements.rdoc +27 -6
  7. data/doc/release_notes/3.28.0.txt +2 -2
  8. data/doc/release_notes/3.29.0.txt +459 -0
  9. data/doc/sharding.rdoc +7 -1
  10. data/doc/testing.rdoc +18 -9
  11. data/doc/transactions.rdoc +41 -1
  12. data/lib/sequel/adapters/ado.rb +28 -17
  13. data/lib/sequel/adapters/ado/mssql.rb +18 -6
  14. data/lib/sequel/adapters/amalgalite.rb +11 -7
  15. data/lib/sequel/adapters/db2.rb +122 -70
  16. data/lib/sequel/adapters/dbi.rb +15 -15
  17. data/lib/sequel/adapters/do.rb +5 -36
  18. data/lib/sequel/adapters/do/mysql.rb +0 -5
  19. data/lib/sequel/adapters/do/postgres.rb +0 -5
  20. data/lib/sequel/adapters/do/sqlite.rb +0 -5
  21. data/lib/sequel/adapters/firebird.rb +3 -6
  22. data/lib/sequel/adapters/ibmdb.rb +24 -16
  23. data/lib/sequel/adapters/informix.rb +2 -4
  24. data/lib/sequel/adapters/jdbc.rb +47 -11
  25. data/lib/sequel/adapters/jdbc/as400.rb +5 -24
  26. data/lib/sequel/adapters/jdbc/db2.rb +0 -5
  27. data/lib/sequel/adapters/jdbc/derby.rb +217 -0
  28. data/lib/sequel/adapters/jdbc/firebird.rb +0 -5
  29. data/lib/sequel/adapters/jdbc/h2.rb +10 -12
  30. data/lib/sequel/adapters/jdbc/hsqldb.rb +166 -0
  31. data/lib/sequel/adapters/jdbc/informix.rb +0 -5
  32. data/lib/sequel/adapters/jdbc/jtds.rb +0 -5
  33. data/lib/sequel/adapters/jdbc/mysql.rb +0 -10
  34. data/lib/sequel/adapters/jdbc/oracle.rb +70 -3
  35. data/lib/sequel/adapters/jdbc/postgresql.rb +0 -11
  36. data/lib/sequel/adapters/jdbc/sqlite.rb +0 -5
  37. data/lib/sequel/adapters/jdbc/sqlserver.rb +0 -5
  38. data/lib/sequel/adapters/jdbc/transactions.rb +56 -7
  39. data/lib/sequel/adapters/mock.rb +315 -0
  40. data/lib/sequel/adapters/mysql.rb +64 -51
  41. data/lib/sequel/adapters/mysql2.rb +15 -9
  42. data/lib/sequel/adapters/odbc.rb +13 -6
  43. data/lib/sequel/adapters/odbc/db2.rb +0 -4
  44. data/lib/sequel/adapters/odbc/mssql.rb +0 -5
  45. data/lib/sequel/adapters/openbase.rb +2 -4
  46. data/lib/sequel/adapters/oracle.rb +333 -51
  47. data/lib/sequel/adapters/postgres.rb +80 -27
  48. data/lib/sequel/adapters/shared/access.rb +0 -6
  49. data/lib/sequel/adapters/shared/db2.rb +13 -15
  50. data/lib/sequel/adapters/shared/firebird.rb +6 -6
  51. data/lib/sequel/adapters/shared/mssql.rb +23 -18
  52. data/lib/sequel/adapters/shared/mysql.rb +6 -6
  53. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +6 -0
  54. data/lib/sequel/adapters/shared/oracle.rb +185 -30
  55. data/lib/sequel/adapters/shared/postgres.rb +35 -18
  56. data/lib/sequel/adapters/shared/progress.rb +0 -6
  57. data/lib/sequel/adapters/shared/sqlite.rb +116 -37
  58. data/lib/sequel/adapters/sqlite.rb +16 -8
  59. data/lib/sequel/adapters/swift.rb +5 -5
  60. data/lib/sequel/adapters/swift/mysql.rb +0 -5
  61. data/lib/sequel/adapters/swift/postgres.rb +0 -5
  62. data/lib/sequel/adapters/swift/sqlite.rb +6 -4
  63. data/lib/sequel/adapters/tinytds.rb +13 -10
  64. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +8 -0
  65. data/lib/sequel/core.rb +40 -0
  66. data/lib/sequel/database/connecting.rb +1 -2
  67. data/lib/sequel/database/dataset.rb +3 -3
  68. data/lib/sequel/database/dataset_defaults.rb +58 -0
  69. data/lib/sequel/database/misc.rb +62 -2
  70. data/lib/sequel/database/query.rb +113 -49
  71. data/lib/sequel/database/schema_methods.rb +7 -2
  72. data/lib/sequel/dataset/actions.rb +37 -19
  73. data/lib/sequel/dataset/features.rb +24 -0
  74. data/lib/sequel/dataset/graph.rb +7 -6
  75. data/lib/sequel/dataset/misc.rb +11 -3
  76. data/lib/sequel/dataset/mutation.rb +2 -3
  77. data/lib/sequel/dataset/prepared_statements.rb +6 -4
  78. data/lib/sequel/dataset/query.rb +46 -15
  79. data/lib/sequel/dataset/sql.rb +28 -4
  80. data/lib/sequel/extensions/named_timezones.rb +5 -0
  81. data/lib/sequel/extensions/thread_local_timezones.rb +1 -1
  82. data/lib/sequel/model.rb +2 -1
  83. data/lib/sequel/model/associations.rb +115 -33
  84. data/lib/sequel/model/base.rb +91 -31
  85. data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
  86. data/lib/sequel/plugins/dataset_associations.rb +100 -0
  87. data/lib/sequel/plugins/force_encoding.rb +6 -6
  88. data/lib/sequel/plugins/identity_map.rb +1 -1
  89. data/lib/sequel/plugins/many_through_many.rb +6 -10
  90. data/lib/sequel/plugins/prepared_statements.rb +12 -1
  91. data/lib/sequel/plugins/prepared_statements_associations.rb +1 -1
  92. data/lib/sequel/plugins/rcte_tree.rb +29 -15
  93. data/lib/sequel/plugins/serialization.rb +6 -1
  94. data/lib/sequel/plugins/sharding.rb +0 -5
  95. data/lib/sequel/plugins/single_table_inheritance.rb +1 -1
  96. data/lib/sequel/plugins/typecast_on_load.rb +9 -12
  97. data/lib/sequel/plugins/update_primary_key.rb +1 -1
  98. data/lib/sequel/timezones.rb +42 -42
  99. data/lib/sequel/version.rb +1 -1
  100. data/spec/adapters/mssql_spec.rb +29 -29
  101. data/spec/adapters/mysql_spec.rb +86 -104
  102. data/spec/adapters/oracle_spec.rb +48 -76
  103. data/spec/adapters/postgres_spec.rb +98 -33
  104. data/spec/adapters/spec_helper.rb +0 -5
  105. data/spec/adapters/sqlite_spec.rb +24 -21
  106. data/spec/core/connection_pool_spec.rb +9 -15
  107. data/spec/core/core_sql_spec.rb +20 -31
  108. data/spec/core/database_spec.rb +491 -227
  109. data/spec/core/dataset_spec.rb +638 -1051
  110. data/spec/core/expression_filters_spec.rb +0 -1
  111. data/spec/core/mock_adapter_spec.rb +378 -0
  112. data/spec/core/object_graph_spec.rb +48 -114
  113. data/spec/core/schema_generator_spec.rb +3 -3
  114. data/spec/core/schema_spec.rb +51 -114
  115. data/spec/core/spec_helper.rb +3 -90
  116. data/spec/extensions/class_table_inheritance_spec.rb +1 -1
  117. data/spec/extensions/dataset_associations_spec.rb +199 -0
  118. data/spec/extensions/instance_hooks_spec.rb +71 -0
  119. data/spec/extensions/named_timezones_spec.rb +22 -2
  120. data/spec/extensions/nested_attributes_spec.rb +3 -0
  121. data/spec/extensions/schema_spec.rb +1 -1
  122. data/spec/extensions/serialization_modification_detection_spec.rb +1 -0
  123. data/spec/extensions/serialization_spec.rb +5 -8
  124. data/spec/extensions/spec_helper.rb +4 -0
  125. data/spec/extensions/thread_local_timezones_spec.rb +22 -2
  126. data/spec/extensions/typecast_on_load_spec.rb +1 -6
  127. data/spec/integration/associations_test.rb +123 -12
  128. data/spec/integration/dataset_test.rb +140 -47
  129. data/spec/integration/eager_loader_test.rb +19 -21
  130. data/spec/integration/model_test.rb +80 -1
  131. data/spec/integration/plugin_test.rb +179 -128
  132. data/spec/integration/prepared_statement_test.rb +92 -91
  133. data/spec/integration/schema_test.rb +42 -23
  134. data/spec/integration/spec_helper.rb +25 -31
  135. data/spec/integration/timezone_test.rb +38 -12
  136. data/spec/integration/transaction_test.rb +161 -34
  137. data/spec/integration/type_test.rb +3 -3
  138. data/spec/model/association_reflection_spec.rb +83 -7
  139. data/spec/model/associations_spec.rb +393 -676
  140. data/spec/model/base_spec.rb +186 -116
  141. data/spec/model/dataset_methods_spec.rb +7 -27
  142. data/spec/model/eager_loading_spec.rb +343 -867
  143. data/spec/model/hooks_spec.rb +160 -79
  144. data/spec/model/model_spec.rb +118 -165
  145. data/spec/model/plugins_spec.rb +7 -13
  146. data/spec/model/record_spec.rb +138 -207
  147. data/spec/model/spec_helper.rb +10 -73
  148. metadata +14 -8
@@ -39,6 +39,48 @@ module Sequel
39
39
  convert_output_timestamp(v, Sequel.database_timezone)
40
40
  end
41
41
 
42
+ # Converts the object to the given +output_timezone+.
43
+ def convert_output_timestamp(v, output_timezone)
44
+ if output_timezone
45
+ if v.is_a?(DateTime)
46
+ case output_timezone
47
+ when :utc
48
+ v.new_offset(0)
49
+ when :local
50
+ v.new_offset(local_offset_for_datetime(v))
51
+ else
52
+ convert_output_datetime_other(v, output_timezone)
53
+ end
54
+ else
55
+ v.send(output_timezone == :utc ? :getutc : :getlocal)
56
+ end
57
+ else
58
+ v
59
+ end
60
+ end
61
+
62
+ # Converts the given object from the given input timezone to the
63
+ # +application_timezone+ using +convert_input_timestamp+ and
64
+ # +convert_output_timestamp+.
65
+ def convert_timestamp(v, input_timezone)
66
+ begin
67
+ if v.is_a?(Date) && !v.is_a?(DateTime)
68
+ # Dates handled specially as they are assumed to already be in the application_timezone
69
+ if datetime_class == DateTime
70
+ DateTime.civil(v.year, v.month, v.day, 0, 0, 0, application_timezone == :local ? (defined?(Rational) ? Rational(Time.local(v.year, v.month, v.day).utc_offset, 86400) : Time.local(v.year, v.month, v.day).utc_offset/86400.0) : 0)
71
+ else
72
+ Time.send(application_timezone == :utc ? :utc : :local, v.year, v.month, v.day)
73
+ end
74
+ else
75
+ convert_output_timestamp(convert_input_timestamp(v, input_timezone), application_timezone)
76
+ end
77
+ rescue InvalidValue
78
+ raise
79
+ rescue => e
80
+ raise convert_exception_class(e, InvalidValue)
81
+ end
82
+ end
83
+
42
84
  # Convert the given object into an object of <tt>Sequel.datetime_class</tt> in the
43
85
  # +application_timezone+. Used when coverting datetime/timestamp columns
44
86
  # returned by the database.
@@ -135,48 +177,6 @@ module Sequel
135
177
  raise InvalidValue, "Invalid output_timezone: #{output_timezone.inspect}"
136
178
  end
137
179
 
138
- # Converts the object to the given +output_timezone+.
139
- def convert_output_timestamp(v, output_timezone)
140
- if output_timezone
141
- if v.is_a?(DateTime)
142
- case output_timezone
143
- when :utc
144
- v.new_offset(0)
145
- when :local
146
- v.new_offset(local_offset_for_datetime(v))
147
- else
148
- convert_output_datetime_other(v, output_timezone)
149
- end
150
- else
151
- v.send(output_timezone == :utc ? :getutc : :getlocal)
152
- end
153
- else
154
- v
155
- end
156
- end
157
-
158
- # Converts the given object from the given input timezone to the
159
- # +application_timezone+ using +convert_input_timestamp+ and
160
- # +convert_output_timestamp+.
161
- def convert_timestamp(v, input_timezone)
162
- begin
163
- if v.is_a?(Date) && !v.is_a?(DateTime)
164
- # Dates handled specially as they are assumed to already be in the application_timezone
165
- if datetime_class == DateTime
166
- DateTime.civil(v.year, v.month, v.day, 0, 0, 0, application_timezone == :local ? (defined?(Rational) ? Rational(Time.local(v.year, v.month, v.day).utc_offset, 86400) : Time.local(v.year, v.month, v.day).utc_offset/86400.0) : 0)
167
- else
168
- Time.send(application_timezone == :utc ? :utc : :local, v.year, v.month, v.day)
169
- end
170
- else
171
- convert_output_timestamp(convert_input_timestamp(v, input_timezone), application_timezone)
172
- end
173
- rescue InvalidValue
174
- raise
175
- rescue => e
176
- raise convert_exception_class(e, InvalidValue)
177
- end
178
- end
179
-
180
180
  # Convert the timezone setter argument. Returns argument given by default,
181
181
  # exists for easier overriding in extensions.
182
182
  def convert_timezone_setter_arg(tz)
@@ -3,7 +3,7 @@ module Sequel
3
3
  MAJOR = 3
4
4
  # The minor version of Sequel. Bumped for every non-patch level
5
5
  # release, generally around once a month.
6
- MINOR = 28
6
+ MINOR = 29
7
7
  # The tiny version of Sequel. Usually 0, only bumped for bugfix
8
8
  # releases that fix regressions from previous versions.
9
9
  TINY = 0
@@ -63,12 +63,12 @@ end
63
63
  describe "MSSQL Dataset#join_table" do
64
64
  specify "should emulate the USING clause with ON" do
65
65
  MSSQL_DB[:items].join(:categories, [:id]).sql.should ==
66
- 'SELECT * FROM ITEMS INNER JOIN CATEGORIES ON (CATEGORIES.ID = ITEMS.ID)'
67
- ['SELECT * FROM ITEMS INNER JOIN CATEGORIES ON ((CATEGORIES.ID1 = ITEMS.ID1) AND (CATEGORIES.ID2 = ITEMS.ID2))',
68
- 'SELECT * FROM ITEMS INNER JOIN CATEGORIES ON ((CATEGORIES.ID2 = ITEMS.ID2) AND (CATEGORIES.ID1 = ITEMS.ID1))'].
66
+ 'SELECT * FROM [ITEMS] INNER JOIN [CATEGORIES] ON ([CATEGORIES].[ID] = [ITEMS].[ID])'
67
+ ['SELECT * FROM [ITEMS] INNER JOIN [CATEGORIES] ON (([CATEGORIES].[ID1] = [ITEMS].[ID1]) AND ([CATEGORIES].[ID2] = [ITEMS].[ID2]))',
68
+ 'SELECT * FROM [ITEMS] INNER JOIN [CATEGORIES] ON (([CATEGORIES].[ID2] = [ITEMS].[ID2]) AND ([CATEGORIES].[ID1] = [ITEMS].[ID1]))'].
69
69
  should include(MSSQL_DB[:items].join(:categories, [:id1, :id2]).sql)
70
70
  MSSQL_DB[:items___i].join(:categories___c, [:id]).sql.should ==
71
- 'SELECT * FROM ITEMS AS I INNER JOIN CATEGORIES AS C ON (C.ID = I.ID)'
71
+ 'SELECT * FROM [ITEMS] AS [I] INNER JOIN [CATEGORIES] AS [C] ON ([C].[ID] = [I].[ID])'
72
72
  end
73
73
  end
74
74
 
@@ -86,44 +86,44 @@ describe "MSSQL Dataset#output" do
86
86
 
87
87
  specify "should format OUTPUT clauses without INTO for DELETE statements" do
88
88
  @ds.output(nil, [:deleted__name, :deleted__value]).delete_sql.should =~
89
- /DELETE FROM ITEMS OUTPUT DELETED.(NAME|VALUE), DELETED.(NAME|VALUE)/
89
+ /DELETE FROM \[ITEMS\] OUTPUT \[DELETED\].\[(NAME|VALUE)\], \[DELETED\].\[(NAME|VALUE)\]/
90
90
  @ds.output(nil, [:deleted.*]).delete_sql.should =~
91
- /DELETE FROM ITEMS OUTPUT DELETED.*/
91
+ /DELETE FROM \[ITEMS\] OUTPUT \[DELETED\].*/
92
92
  end
93
93
 
94
94
  specify "should format OUTPUT clauses with INTO for DELETE statements" do
95
95
  @ds.output(:out, [:deleted__name, :deleted__value]).delete_sql.should =~
96
- /DELETE FROM ITEMS OUTPUT DELETED.(NAME|VALUE), DELETED.(NAME|VALUE) INTO OUT/
96
+ /DELETE FROM \[ITEMS\] OUTPUT \[DELETED\].\[(NAME|VALUE)\], \[DELETED\].\[(NAME|VALUE)\] INTO \[OUT\]/
97
97
  @ds.output(:out, {:name => :deleted__name, :value => :deleted__value}).delete_sql.should =~
98
- /DELETE FROM ITEMS OUTPUT DELETED.(NAME|VALUE), DELETED.(NAME|VALUE) INTO OUT \((NAME|VALUE), (NAME|VALUE)\)/
98
+ /DELETE FROM \[ITEMS\] OUTPUT \[DELETED\].\[(NAME|VALUE)\], \[DELETED\].\[(NAME|VALUE)\] INTO \[OUT\] \(\[(NAME|VALUE)\], \[(NAME|VALUE)\]\)/
99
99
  end
100
100
 
101
101
  specify "should format OUTPUT clauses without INTO for INSERT statements" do
102
102
  @ds.output(nil, [:inserted__name, :inserted__value]).insert_sql(:name => "name", :value => 1).should =~
103
- /INSERT INTO ITEMS \((NAME|VALUE), (NAME|VALUE)\) OUTPUT INSERTED.(NAME|VALUE), INSERTED.(NAME|VALUE) VALUES \((N'name'|1), (N'name'|1)\)/
103
+ /INSERT INTO \[ITEMS\] \(\[(NAME|VALUE)\], \[(NAME|VALUE)\]\) OUTPUT \[INSERTED\].\[(NAME|VALUE)\], \[INSERTED\].\[(NAME|VALUE)\] VALUES \((N'name'|1), (N'name'|1)\)/
104
104
  @ds.output(nil, [:inserted.*]).insert_sql(:name => "name", :value => 1).should =~
105
- /INSERT INTO ITEMS \((NAME|VALUE), (NAME|VALUE)\) OUTPUT INSERTED.* VALUES \((N'name'|1), (N'name'|1)\)/
105
+ /INSERT INTO \[ITEMS\] \(\[(NAME|VALUE)\], \[(NAME|VALUE)\]\) OUTPUT \[INSERTED\].* VALUES \((N'name'|1), (N'name'|1)\)/
106
106
  end
107
107
 
108
108
  specify "should format OUTPUT clauses with INTO for INSERT statements" do
109
109
  @ds.output(:out, [:inserted__name, :inserted__value]).insert_sql(:name => "name", :value => 1).should =~
110
- /INSERT INTO ITEMS \((NAME|VALUE), (NAME|VALUE)\) OUTPUT INSERTED.(NAME|VALUE), INSERTED.(NAME|VALUE) INTO OUT VALUES \((N'name'|1), (N'name'|1)\)/
110
+ /INSERT INTO \[ITEMS\] \((\[NAME\]|\[VALUE\]), (\[NAME\]|\[VALUE\])\) OUTPUT \[INSERTED\].\[(NAME|VALUE)\], \[INSERTED\].\[(NAME|VALUE)\] INTO \[OUT\] VALUES \((N'name'|1), (N'name'|1)\)/
111
111
  @ds.output(:out, {:name => :inserted__name, :value => :inserted__value}).insert_sql(:name => "name", :value => 1).should =~
112
- /INSERT INTO ITEMS \((NAME|VALUE), (NAME|VALUE)\) OUTPUT INSERTED.(NAME|VALUE), INSERTED.(NAME|VALUE) INTO OUT \((NAME|VALUE), (NAME|VALUE)\) VALUES \((N'name'|1), (N'name'|1)\)/
112
+ /INSERT INTO \[ITEMS\] \(\[(NAME|VALUE)\], \[(NAME|VALUE)\]\) OUTPUT \[INSERTED\].\[(NAME|VALUE)\], \[INSERTED\].\[(NAME|VALUE)\] INTO \[OUT\] \(\[(NAME|VALUE)\], \[(NAME|VALUE)\]\) VALUES \((N'name'|1), (N'name'|1)\)/
113
113
  end
114
114
 
115
115
  specify "should format OUTPUT clauses without INTO for UPDATE statements" do
116
116
  @ds.output(nil, [:inserted__name, :deleted__value]).update_sql(:value => 2).should =~
117
- /UPDATE ITEMS SET VALUE = 2 OUTPUT (INSERTED.NAME|DELETED.VALUE), (INSERTED.NAME|DELETED.VALUE)/
117
+ /UPDATE \[ITEMS\] SET \[VALUE\] = 2 OUTPUT \[(INSERTED\].\[NAME|DELETED\].\[VALUE)\], \[(INSERTED\].\[NAME|DELETED\].\[VALUE)\]/
118
118
  @ds.output(nil, [:inserted.*]).update_sql(:value => 2).should =~
119
- /UPDATE ITEMS SET VALUE = 2 OUTPUT INSERTED.*/
119
+ /UPDATE \[ITEMS\] SET \[VALUE\] = 2 OUTPUT \[INSERTED\].*/
120
120
  end
121
121
 
122
122
  specify "should format OUTPUT clauses with INTO for UPDATE statements" do
123
123
  @ds.output(:out, [:inserted__name, :deleted__value]).update_sql(:value => 2).should =~
124
- /UPDATE ITEMS SET VALUE = 2 OUTPUT (INSERTED.NAME|DELETED.VALUE), (INSERTED.NAME|DELETED.VALUE) INTO OUT/
124
+ /UPDATE \[ITEMS\] SET \[VALUE\] = 2 OUTPUT \[(INSERTED\].\[NAME|DELETED\].\[VALUE)\], \[(INSERTED\].\[NAME|DELETED\].\[VALUE)\] INTO \[OUT\]/
125
125
  @ds.output(:out, {:name => :inserted__name, :value => :deleted__value}).update_sql(:value => 2).should =~
126
- /UPDATE ITEMS SET VALUE = 2 OUTPUT (INSERTED.NAME|DELETED.VALUE), (INSERTED.NAME|DELETED.VALUE) INTO OUT \((NAME|VALUE), (NAME|VALUE)\)/
126
+ /UPDATE \[ITEMS\] SET \[VALUE\] = 2 OUTPUT \[(INSERTED\].\[NAME|DELETED\].\[VALUE)\], \[(INSERTED\].\[NAME|DELETED\].\[VALUE)\] INTO \[OUT\] \(\[(NAME|VALUE)\], \[(NAME|VALUE)\]\)/
127
127
  end
128
128
 
129
129
  specify "should execute OUTPUT clauses in DELETE statements" do
@@ -164,23 +164,23 @@ describe "MSSQL dataset" do
164
164
  end
165
165
 
166
166
  specify "should prepend UPDATE statements with WITH clause" do
167
- @ds1.update_sql(:x => :y).should == 'WITH T AS (SELECT * FROM X) UPDATE T SET X = Y'
168
- @ds2.update_sql(:x => :y).should == 'WITH T AS (SELECT * FROM X UNION ALL SELECT * FROM T) UPDATE T SET X = Y'
167
+ @ds1.update_sql(:x => :y).should == 'WITH [T] AS (SELECT * FROM [X]) UPDATE [T] SET [X] = [Y]'
168
+ @ds2.update_sql(:x => :y).should == 'WITH [T] AS (SELECT * FROM [X] UNION ALL SELECT * FROM [T]) UPDATE [T] SET [X] = [Y]'
169
169
  end
170
170
 
171
171
  specify "should prepend DELETE statements with WITH clause" do
172
- @ds1.filter(:y => 1).delete_sql.should == 'WITH T AS (SELECT * FROM X) DELETE FROM T WHERE (Y = 1)'
173
- @ds2.filter(:y => 1).delete_sql.should == 'WITH T AS (SELECT * FROM X UNION ALL SELECT * FROM T) DELETE FROM T WHERE (Y = 1)'
172
+ @ds1.filter(:y => 1).delete_sql.should == 'WITH [T] AS (SELECT * FROM [X]) DELETE FROM [T] WHERE ([Y] = 1)'
173
+ @ds2.filter(:y => 1).delete_sql.should == 'WITH [T] AS (SELECT * FROM [X] UNION ALL SELECT * FROM [T]) DELETE FROM [T] WHERE ([Y] = 1)'
174
174
  end
175
175
 
176
176
  specify "should prepend INSERT statements with WITH clause" do
177
- @ds1.insert_sql(@db[:t]).should == 'WITH T AS (SELECT * FROM X) INSERT INTO T SELECT * FROM T'
178
- @ds2.insert_sql(@db[:t]).should == 'WITH T AS (SELECT * FROM X UNION ALL SELECT * FROM T) INSERT INTO T SELECT * FROM T'
177
+ @ds1.insert_sql(@db[:t]).should == 'WITH [T] AS (SELECT * FROM [X]) INSERT INTO [T] SELECT * FROM [T]'
178
+ @ds2.insert_sql(@db[:t]).should == 'WITH [T] AS (SELECT * FROM [X] UNION ALL SELECT * FROM [T]) INSERT INTO [T] SELECT * FROM [T]'
179
179
  end
180
180
 
181
181
  specify "should move WITH clause on joined dataset to top level" do
182
- @db[:s].inner_join(@ds1).sql.should == "WITH T AS (SELECT * FROM X) SELECT * FROM S INNER JOIN (SELECT * FROM T) AS T1"
183
- @ds1.inner_join(@db[:s].with(:s, @db[:y])).sql.should == "WITH T AS (SELECT * FROM X), S AS (SELECT * FROM Y) SELECT * FROM T INNER JOIN (SELECT * FROM S) AS T1"
182
+ @db[:s].inner_join(@ds1).sql.should == "WITH [T] AS (SELECT * FROM [X]) SELECT * FROM [S] INNER JOIN (SELECT * FROM [T]) AS [T1]"
183
+ @ds1.inner_join(@db[:s].with(:s, @db[:y])).sql.should == "WITH [T] AS (SELECT * FROM [X]), [S] AS (SELECT * FROM [Y]) SELECT * FROM [T] INNER JOIN (SELECT * FROM [S]) AS [T1]"
184
184
  end
185
185
 
186
186
  describe "on #import" do
@@ -208,10 +208,10 @@ describe "MSSQL dataset" do
208
208
  @db[:items].with(:items, @db[:inventory].group(:type)).import([:x, :y], [[1, 2], [3, 4], [5, 6]], :slice => 2)
209
209
  @db.import_sqls.should == [
210
210
  'BEGIN',
211
- "WITH ITEMS AS (SELECT * FROM INVENTORY GROUP BY TYPE) INSERT INTO ITEMS (X, Y) SELECT 1, 2 UNION ALL SELECT 3, 4",
211
+ "WITH [ITEMS] AS (SELECT * FROM [INVENTORY] GROUP BY [TYPE]) INSERT INTO [ITEMS] ([X], [Y]) SELECT 1, 2 UNION ALL SELECT 3, 4",
212
212
  'COMMIT',
213
213
  'BEGIN',
214
- "WITH ITEMS AS (SELECT * FROM INVENTORY GROUP BY TYPE) INSERT INTO ITEMS (X, Y) SELECT 5, 6",
214
+ "WITH [ITEMS] AS (SELECT * FROM [INVENTORY] GROUP BY [TYPE]) INSERT INTO [ITEMS] ([X], [Y]) SELECT 5, 6",
215
215
  'COMMIT'
216
216
  ]
217
217
  end
@@ -226,12 +226,12 @@ describe "MSSQL joined datasets" do
226
226
 
227
227
  specify "should format DELETE statements" do
228
228
  @db[:t1].inner_join(:t2, :t1__pk => :t2__pk).delete_sql.should ==
229
- "DELETE FROM T1 FROM T1 INNER JOIN T2 ON (T1.PK = T2.PK)"
229
+ "DELETE FROM [T1] FROM [T1] INNER JOIN [T2] ON ([T1].[PK] = [T2].[PK])"
230
230
  end
231
231
 
232
232
  specify "should format UPDATE statements" do
233
233
  @db[:t1].inner_join(:t2, :t1__pk => :t2__pk).update_sql(:pk => :t2__pk).should ==
234
- "UPDATE T1 SET PK = T2.PK FROM T1 INNER JOIN T2 ON (T1.PK = T2.PK)"
234
+ "UPDATE [T1] SET [PK] = [T2].[PK] FROM [T1] INNER JOIN [T2] ON ([T1].[PK] = [T2].[PK])"
235
235
  end
236
236
  end
237
237
 
@@ -370,7 +370,7 @@ describe "MSSSQL::Dataset#into" do
370
370
  end
371
371
 
372
372
  specify "should format SELECT statement" do
373
- @db[:t].into(:new).select_sql.should == "SELECT * INTO NEW FROM T"
373
+ @db[:t].into(:new).select_sql.should == "SELECT * INTO [NEW] FROM [T]"
374
374
  end
375
375
 
376
376
  specify "should select rows into a new table" do
@@ -45,22 +45,22 @@ describe "MySQL", '#create_table' do
45
45
 
46
46
  specify "should allow to specify options for MySQL" do
47
47
  @db.create_table(:dolls, :engine => 'MyISAM', :charset => 'latin2'){text :name}
48
- @db.sqls.should == ["CREATE TABLE dolls (name text) ENGINE=MyISAM DEFAULT CHARSET=latin2"]
48
+ @db.sqls.should == ["CREATE TABLE `dolls` (`name` text) ENGINE=MyISAM DEFAULT CHARSET=latin2"]
49
49
  end
50
50
 
51
51
  specify "should create a temporary table" do
52
52
  @db.create_table(:tmp_dolls, :temp => true, :engine => 'MyISAM', :charset => 'latin2'){text :name}
53
- @db.sqls.should == ["CREATE TEMPORARY TABLE tmp_dolls (name text) ENGINE=MyISAM DEFAULT CHARSET=latin2"]
53
+ @db.sqls.should == ["CREATE TEMPORARY TABLE `tmp_dolls` (`name` text) ENGINE=MyISAM DEFAULT CHARSET=latin2"]
54
54
  end
55
55
 
56
56
  specify "should not use a default for a String :text=>true type" do
57
57
  @db.create_table(:dolls){String :name, :text=>true, :default=>'blah'}
58
- @db.sqls.should == ["CREATE TABLE dolls (name text)"]
58
+ @db.sqls.should == ["CREATE TABLE `dolls` (`name` text)"]
59
59
  end
60
60
 
61
61
  specify "should not use a default for a File type" do
62
62
  @db.create_table(:dolls){File :name, :default=>'blah'}
63
- @db.sqls.should == ["CREATE TABLE dolls (name blob)"]
63
+ @db.sqls.should == ["CREATE TABLE `dolls` (`name` blob)"]
64
64
  end
65
65
 
66
66
  specify "should respect the size option for File type" do
@@ -112,18 +112,18 @@ if MYSQL_DB.adapter_scheme == :mysql
112
112
  @ds = @db[:booltest]
113
113
  end
114
114
  after do
115
- Sequel::MySQL.convert_tinyint_to_bool = true
115
+ @db.convert_tinyint_to_bool = true
116
116
  @db.drop_table(:booltest)
117
117
  end
118
118
 
119
119
  specify "should consider tinyint(1) datatypes as boolean if set, but not larger tinyints" do
120
120
  @db.schema(:booltest, :reload=>true).should == [[:b, {:type=>:boolean, :allow_null=>true, :primary_key=>false, :default=>nil, :ruby_default=>nil, :db_type=>"tinyint(1)"}, ], [:i, {:type=>:integer, :allow_null=>true, :primary_key=>false, :default=>nil, :ruby_default=>nil, :db_type=>"tinyint(4)"}, ]]
121
- Sequel::MySQL.convert_tinyint_to_bool = false
121
+ @db.convert_tinyint_to_bool = false
122
122
  @db.schema(:booltest, :reload=>true).should == [[:b, {:type=>:integer, :allow_null=>true, :primary_key=>false, :default=>nil, :ruby_default=>nil, :db_type=>"tinyint(1)"}, ], [:i, {:type=>:integer, :allow_null=>true, :primary_key=>false, :default=>nil, :ruby_default=>nil, :db_type=>"tinyint(4)"}, ]]
123
123
  end
124
124
 
125
125
  specify "should return tinyint(1)s as bools and tinyint(4)s as integers when set" do
126
- Sequel::MySQL.convert_tinyint_to_bool = true
126
+ @db.convert_tinyint_to_bool = true
127
127
  @ds.delete
128
128
  @ds << {:b=>true, :i=>10}
129
129
  @ds.all.should == [{:b=>true, :i=>10}]
@@ -136,7 +136,7 @@ if MYSQL_DB.adapter_scheme == :mysql
136
136
  end
137
137
 
138
138
  specify "should return all tinyints as integers when unset" do
139
- Sequel::MySQL.convert_tinyint_to_bool = false
139
+ @db.convert_tinyint_to_bool = false
140
140
  @ds.delete
141
141
  @ds << {:b=>true, :i=>10}
142
142
  @ds.all.should == [{:b=>1, :i=>10}]
@@ -226,12 +226,12 @@ describe "A MySQL dataset" do
226
226
 
227
227
  specify "should support ORDER clause in UPDATE statements" do
228
228
  @d.order(:name).update_sql(:value => 1).should == \
229
- 'UPDATE items SET value = 1 ORDER BY name'
229
+ 'UPDATE `items` SET `value` = 1 ORDER BY `name`'
230
230
  end
231
231
 
232
232
  specify "should support LIMIT clause in UPDATE statements" do
233
233
  @d.limit(10).update_sql(:value => 1).should == \
234
- 'UPDATE items SET value = 1 LIMIT 10'
234
+ 'UPDATE `items` SET `value` = 1 LIMIT 10'
235
235
  end
236
236
 
237
237
  specify "should support regexps" do
@@ -299,43 +299,43 @@ describe "MySQL join expressions" do
299
299
  end
300
300
  specify "should support natural left joins" do
301
301
  @ds.join_table(:natural_left, :nodes).sql.should == \
302
- 'SELECT * FROM nodes NATURAL LEFT JOIN nodes'
302
+ 'SELECT * FROM `nodes` NATURAL LEFT JOIN `nodes`'
303
303
  end
304
304
  specify "should support natural right joins" do
305
305
  @ds.join_table(:natural_right, :nodes).sql.should == \
306
- 'SELECT * FROM nodes NATURAL RIGHT JOIN nodes'
306
+ 'SELECT * FROM `nodes` NATURAL RIGHT JOIN `nodes`'
307
307
  end
308
308
  specify "should support natural left outer joins" do
309
309
  @ds.join_table(:natural_left_outer, :nodes).sql.should == \
310
- 'SELECT * FROM nodes NATURAL LEFT OUTER JOIN nodes'
310
+ 'SELECT * FROM `nodes` NATURAL LEFT OUTER JOIN `nodes`'
311
311
  end
312
312
  specify "should support natural right outer joins" do
313
313
  @ds.join_table(:natural_right_outer, :nodes).sql.should == \
314
- 'SELECT * FROM nodes NATURAL RIGHT OUTER JOIN nodes'
314
+ 'SELECT * FROM `nodes` NATURAL RIGHT OUTER JOIN `nodes`'
315
315
  end
316
316
  specify "should support natural inner joins" do
317
317
  @ds.join_table(:natural_inner, :nodes).sql.should == \
318
- 'SELECT * FROM nodes NATURAL LEFT JOIN nodes'
318
+ 'SELECT * FROM `nodes` NATURAL LEFT JOIN `nodes`'
319
319
  end
320
320
  specify "should support cross joins" do
321
321
  @ds.join_table(:cross, :nodes).sql.should == \
322
- 'SELECT * FROM nodes CROSS JOIN nodes'
322
+ 'SELECT * FROM `nodes` CROSS JOIN `nodes`'
323
323
  end
324
324
  specify "should support cross joins as inner joins if conditions are used" do
325
325
  @ds.join_table(:cross, :nodes, :id=>:id).sql.should == \
326
- 'SELECT * FROM nodes INNER JOIN nodes ON (nodes.id = nodes.id)'
326
+ 'SELECT * FROM `nodes` INNER JOIN `nodes` ON (`nodes`.`id` = `nodes`.`id`)'
327
327
  end
328
328
  specify "should support straight joins (force left table to be read before right)" do
329
329
  @ds.join_table(:straight, :nodes).sql.should == \
330
- 'SELECT * FROM nodes STRAIGHT_JOIN nodes'
330
+ 'SELECT * FROM `nodes` STRAIGHT_JOIN `nodes`'
331
331
  end
332
332
  specify "should support natural joins on multiple tables." do
333
333
  @ds.join_table(:natural_left_outer, [:nodes, :branches]).sql.should == \
334
- 'SELECT * FROM nodes NATURAL LEFT OUTER JOIN (nodes, branches)'
334
+ 'SELECT * FROM `nodes` NATURAL LEFT OUTER JOIN (`nodes`, `branches`)'
335
335
  end
336
336
  specify "should support straight joins on multiple tables." do
337
337
  @ds.join_table(:straight, [:nodes,:branches]).sql.should == \
338
- 'SELECT * FROM nodes STRAIGHT_JOIN (nodes, branches)'
338
+ 'SELECT * FROM `nodes` STRAIGHT_JOIN (`nodes`, `branches`)'
339
339
  end
340
340
  end
341
341
 
@@ -354,12 +354,12 @@ describe "Joined MySQL dataset" do
354
354
  proc {@ds.having('blah')}.should_not raise_error
355
355
 
356
356
  @ds.having('blah').sql.should == \
357
- "SELECT * FROM nodes HAVING (blah)"
357
+ "SELECT * FROM `nodes` HAVING (blah)"
358
358
  end
359
359
 
360
360
  specify "should put a having clause before an order by clause" do
361
361
  @ds.order(:aaa).having(:bbb => :ccc).sql.should == \
362
- "SELECT * FROM nodes HAVING (bbb = ccc) ORDER BY aaa"
362
+ "SELECT * FROM `nodes` HAVING (`bbb` = `ccc`) ORDER BY `aaa`"
363
363
  end
364
364
  end
365
365
 
@@ -453,17 +453,17 @@ describe "A MySQL database with table options" do
453
453
 
454
454
  specify "should allow to pass custom options (engine, charset, collate) for table creation" do
455
455
  @db.create_table(:items, @options){Integer :size; text :name}
456
- @db.sqls.should == ["CREATE TABLE items (size integer, name text) ENGINE=MyISAM DEFAULT CHARSET=latin1 DEFAULT COLLATE=latin1_swedish_ci"]
456
+ @db.sqls.should == ["CREATE TABLE `items` (`size` integer, `name` text) ENGINE=MyISAM DEFAULT CHARSET=latin1 DEFAULT COLLATE=latin1_swedish_ci"]
457
457
  end
458
458
 
459
459
  specify "should use default options if specified (engine, charset, collate) for table creation" do
460
460
  @db.create_table(:items){Integer :size; text :name}
461
- @db.sqls.should == ["CREATE TABLE items (size integer, name text) ENGINE=InnoDB DEFAULT CHARSET=utf8 DEFAULT COLLATE=utf8_general_ci"]
461
+ @db.sqls.should == ["CREATE TABLE `items` (`size` integer, `name` text) ENGINE=InnoDB DEFAULT CHARSET=utf8 DEFAULT COLLATE=utf8_general_ci"]
462
462
  end
463
463
 
464
464
  specify "should not use default if option has a nil value" do
465
465
  @db.create_table(:items, :engine=>nil, :charset=>nil, :collate=>nil){Integer :size; text :name}
466
- @db.sqls.should == ["CREATE TABLE items (size integer, name text)"]
466
+ @db.sqls.should == ["CREATE TABLE `items` (`size` integer, `name` text)"]
467
467
  end
468
468
  end
469
469
 
@@ -479,24 +479,24 @@ describe "A MySQL database" do
479
479
 
480
480
  specify "should support defaults for boolean columns" do
481
481
  @db.create_table(:items){TrueClass :active1, :default=>true; FalseClass :active2, :default => false}
482
- @db.sqls.should == ["CREATE TABLE items (active1 tinyint(1) DEFAULT 1, active2 tinyint(1) DEFAULT 0)"]
482
+ @db.sqls.should == ["CREATE TABLE `items` (`active1` tinyint(1) DEFAULT 1, `active2` tinyint(1) DEFAULT 0)"]
483
483
  end
484
484
 
485
485
  specify "should correctly format CREATE TABLE statements with foreign keys" do
486
486
  @db.create_table(:items){Integer :id; foreign_key :p_id, :items, :key => :id, :null => false, :on_delete => :cascade}
487
- @db.sqls.should == ["CREATE TABLE items (id integer, p_id integer NOT NULL, FOREIGN KEY (p_id) REFERENCES items(id) ON DELETE CASCADE)"]
487
+ @db.sqls.should == ["CREATE TABLE `items` (`id` integer, `p_id` integer NOT NULL, FOREIGN KEY (`p_id`) REFERENCES `items`(`id`) ON DELETE CASCADE)"]
488
488
  end
489
489
 
490
490
  specify "should correctly format ALTER TABLE statements with foreign keys" do
491
491
  @db.create_table(:items){Integer :id}
492
492
  @db.alter_table(:items){add_foreign_key :p_id, :users, :key => :id, :null => false, :on_delete => :cascade}
493
- @db.sqls.should == ["CREATE TABLE items (id integer)", "ALTER TABLE items ADD COLUMN p_id integer NOT NULL", "ALTER TABLE items ADD FOREIGN KEY (p_id) REFERENCES users(id) ON DELETE CASCADE"]
493
+ @db.sqls.should == ["CREATE TABLE `items` (`id` integer)", "ALTER TABLE `items` ADD COLUMN `p_id` integer NOT NULL", "ALTER TABLE `items` ADD FOREIGN KEY (`p_id`) REFERENCES `users`(`id`) ON DELETE CASCADE"]
494
494
  end
495
495
 
496
496
  specify "should have rename_column support keep existing options" do
497
497
  @db.create_table(:items){String :id, :null=>false, :default=>'blah'}
498
498
  @db.alter_table(:items){rename_column :id, :nid}
499
- @db.sqls.should == ["CREATE TABLE items (id varchar(255) NOT NULL DEFAULT 'blah')", "DESCRIBE items", "ALTER TABLE items CHANGE COLUMN id nid varchar(255) NOT NULL DEFAULT 'blah'"]
499
+ @db.sqls.should == ["CREATE TABLE `items` (`id` varchar(255) NOT NULL DEFAULT 'blah')", "DESCRIBE `items`", "ALTER TABLE `items` CHANGE COLUMN `id` `nid` varchar(255) NOT NULL DEFAULT 'blah'"]
500
500
  @db[:items].insert
501
501
  @db[:items].all.should == [{:nid=>'blah'}]
502
502
  proc{@db[:items].insert(:nid=>nil)}.should raise_error(Sequel::DatabaseError)
@@ -505,7 +505,7 @@ describe "A MySQL database" do
505
505
  specify "should have set_column_type support keep existing options" do
506
506
  @db.create_table(:items){Integer :id, :null=>false, :default=>5}
507
507
  @db.alter_table(:items){set_column_type :id, Bignum}
508
- @db.sqls.should == ["CREATE TABLE items (id integer NOT NULL DEFAULT 5)", "DESCRIBE items", "ALTER TABLE items CHANGE COLUMN id id bigint NOT NULL DEFAULT 5"]
508
+ @db.sqls.should == ["CREATE TABLE `items` (`id` integer NOT NULL DEFAULT 5)", "DESCRIBE `items`", "ALTER TABLE `items` CHANGE COLUMN `id` `id` bigint NOT NULL DEFAULT 5"]
509
509
  @db[:items].insert
510
510
  @db[:items].all.should == [{:id=>5}]
511
511
  proc{@db[:items].insert(:id=>nil)}.should raise_error(Sequel::DatabaseError)
@@ -517,13 +517,13 @@ describe "A MySQL database" do
517
517
  specify "should have set_column_type pass through options" do
518
518
  @db.create_table(:items){integer :id; enum :list, :elements=>%w[one]}
519
519
  @db.alter_table(:items){set_column_type :id, :int, :unsigned=>true, :size=>8; set_column_type :list, :enum, :elements=>%w[two]}
520
- @db.sqls.should == ["CREATE TABLE items (id integer, list enum('one'))", "DESCRIBE items", "ALTER TABLE items CHANGE COLUMN id id int(8) UNSIGNED NULL", "ALTER TABLE items CHANGE COLUMN list list enum('two') NULL"]
520
+ @db.sqls.should == ["CREATE TABLE `items` (`id` integer, `list` enum('one'))", "DESCRIBE `items`", "ALTER TABLE `items` CHANGE COLUMN `id` `id` int(8) UNSIGNED NULL", "ALTER TABLE `items` CHANGE COLUMN `list` `list` enum('two') NULL"]
521
521
  end
522
522
 
523
523
  specify "should have set_column_default support keep existing options" do
524
524
  @db.create_table(:items){Integer :id, :null=>false, :default=>5}
525
525
  @db.alter_table(:items){set_column_default :id, 6}
526
- @db.sqls.should == ["CREATE TABLE items (id integer NOT NULL DEFAULT 5)", "DESCRIBE items", "ALTER TABLE items CHANGE COLUMN id id int(11) NOT NULL DEFAULT 6"]
526
+ @db.sqls.should == ["CREATE TABLE `items` (`id` integer NOT NULL DEFAULT 5)", "DESCRIBE `items`", "ALTER TABLE `items` CHANGE COLUMN `id` `id` int(11) NOT NULL DEFAULT 6"]
527
527
  @db[:items].insert
528
528
  @db[:items].all.should == [{:id=>6}]
529
529
  proc{@db[:items].insert(:id=>nil)}.should raise_error(Sequel::DatabaseError)
@@ -532,7 +532,7 @@ describe "A MySQL database" do
532
532
  specify "should have set_column_allow_null support keep existing options" do
533
533
  @db.create_table(:items){Integer :id, :null=>false, :default=>5}
534
534
  @db.alter_table(:items){set_column_allow_null :id, true}
535
- @db.sqls.should == ["CREATE TABLE items (id integer NOT NULL DEFAULT 5)", "DESCRIBE items", "ALTER TABLE items CHANGE COLUMN id id int(11) NULL DEFAULT 5"]
535
+ @db.sqls.should == ["CREATE TABLE `items` (`id` integer NOT NULL DEFAULT 5)", "DESCRIBE `items`", "ALTER TABLE `items` CHANGE COLUMN `id` `id` int(11) NULL DEFAULT 5"]
536
536
  @db[:items].insert
537
537
  @db[:items].all.should == [{:id=>5}]
538
538
  proc{@db[:items].insert(:id=>nil)}.should_not
@@ -618,9 +618,9 @@ describe "A MySQL database" do
618
618
  specify "should support fulltext indexes and full_text_search" do
619
619
  @db.create_table(:posts){text :title; text :body; full_text_index :title; full_text_index [:title, :body]}
620
620
  @db.sqls.should == [
621
- "CREATE TABLE posts (title text, body text)",
622
- "CREATE FULLTEXT INDEX posts_title_index ON posts (title)",
623
- "CREATE FULLTEXT INDEX posts_title_body_index ON posts (title, body)"
621
+ "CREATE TABLE `posts` (`title` text, `body` text)",
622
+ "CREATE FULLTEXT INDEX `posts_title_index` ON `posts` (`title`)",
623
+ "CREATE FULLTEXT INDEX `posts_title_body_index` ON `posts` (`title`, `body`)"
624
624
  ]
625
625
 
626
626
  @db[:posts].insert(:title=>'ruby rails', :body=>'y')
@@ -632,32 +632,32 @@ describe "A MySQL database" do
632
632
  @db[:posts].full_text_search([:title, :body], ['sequel', 'ruby']).all.should == [{:title=>'sequel', :body=>'ruby'}]
633
633
  @db[:posts].full_text_search(:title, '+ruby -rails', :boolean => true).all.should == [{:title=>'ruby scooby', :body=>'x'}]
634
634
  @db.sqls.should == [
635
- "SELECT * FROM posts WHERE (MATCH (title) AGAINST ('rails'))",
636
- "SELECT * FROM posts WHERE (MATCH (title, body) AGAINST ('sequel ruby'))",
637
- "SELECT * FROM posts WHERE (MATCH (title) AGAINST ('+ruby -rails' IN BOOLEAN MODE))"]
635
+ "SELECT * FROM `posts` WHERE (MATCH (`title`) AGAINST ('rails'))",
636
+ "SELECT * FROM `posts` WHERE (MATCH (`title`, `body`) AGAINST ('sequel ruby'))",
637
+ "SELECT * FROM `posts` WHERE (MATCH (`title`) AGAINST ('+ruby -rails' IN BOOLEAN MODE))"]
638
638
  end
639
639
 
640
640
  specify "should support spatial indexes" do
641
641
  @db.create_table(:posts){point :geom, :null=>false; spatial_index [:geom]}
642
642
  @db.sqls.should == [
643
- "CREATE TABLE posts (geom point NOT NULL)",
644
- "CREATE SPATIAL INDEX posts_geom_index ON posts (geom)"
643
+ "CREATE TABLE `posts` (`geom` point NOT NULL)",
644
+ "CREATE SPATIAL INDEX `posts_geom_index` ON `posts` (`geom`)"
645
645
  ]
646
646
  end
647
647
 
648
648
  specify "should support indexes with index type" do
649
649
  @db.create_table(:posts){Integer :id; index :id, :type => :btree}
650
650
  @db.sqls.should == [
651
- "CREATE TABLE posts (id integer)",
652
- "CREATE INDEX posts_id_index USING btree ON posts (id)"
651
+ "CREATE TABLE `posts` (`id` integer)",
652
+ "CREATE INDEX `posts_id_index` USING btree ON `posts` (`id`)"
653
653
  ]
654
654
  end
655
655
 
656
656
  specify "should support unique indexes with index type" do
657
657
  @db.create_table(:posts){Integer :id; index :id, :type => :btree, :unique => true}
658
658
  @db.sqls.should == [
659
- "CREATE TABLE posts (id integer)",
660
- "CREATE UNIQUE INDEX posts_id_index USING btree ON posts (id)"
659
+ "CREATE TABLE `posts` (`id` integer)",
660
+ "CREATE UNIQUE INDEX `posts_id_index` USING btree ON `posts` (`id`)"
661
661
  ]
662
662
  end
663
663
 
@@ -686,38 +686,20 @@ describe "MySQL::Dataset#insert and related methods" do
686
686
 
687
687
  specify "#insert should insert record with default values when no arguments given" do
688
688
  @d.insert
689
-
690
- MYSQL_DB.sqls.should == [
691
- "INSERT INTO items () VALUES ()"
692
- ]
693
-
694
- @d.all.should == [
695
- {:name => nil, :value => nil}
696
- ]
689
+ MYSQL_DB.sqls.should == ["INSERT INTO `items` () VALUES ()"]
690
+ @d.all.should == [{:name => nil, :value => nil}]
697
691
  end
698
692
 
699
693
  specify "#insert should insert record with default values when empty hash given" do
700
694
  @d.insert({})
701
-
702
- MYSQL_DB.sqls.should == [
703
- "INSERT INTO items () VALUES ()"
704
- ]
705
-
706
- @d.all.should == [
707
- {:name => nil, :value => nil}
708
- ]
695
+ MYSQL_DB.sqls.should == ["INSERT INTO `items` () VALUES ()"]
696
+ @d.all.should == [{:name => nil, :value => nil}]
709
697
  end
710
698
 
711
699
  specify "#insert should insert record with default values when empty array given" do
712
700
  @d.insert []
713
-
714
- MYSQL_DB.sqls.should == [
715
- "INSERT INTO items () VALUES ()"
716
- ]
717
-
718
- @d.all.should == [
719
- {:name => nil, :value => nil}
720
- ]
701
+ MYSQL_DB.sqls.should == ["INSERT INTO `items` () VALUES ()"]
702
+ @d.all.should == [{:name => nil, :value => nil}]
721
703
  end
722
704
 
723
705
  specify "#on_duplicate_key_update should work with regular inserts" do
@@ -728,9 +710,9 @@ describe "MySQL::Dataset#insert and related methods" do
728
710
  @d.on_duplicate_key_update(:name, :value => 6).insert(:name => 'def', :value => 2)
729
711
 
730
712
  MYSQL_DB.sqls.length.should == 3
731
- MYSQL_DB.sqls[0].should =~ /\AINSERT INTO items \((name|value), (name|value)\) VALUES \(('abc'|1), (1|'abc')\)\z/
732
- MYSQL_DB.sqls[1].should =~ /\AINSERT INTO items \((name|value), (name|value)\) VALUES \(('abc'|1), (1|'abc')\) ON DUPLICATE KEY UPDATE name=VALUES\(name\), value=6\z/
733
- MYSQL_DB.sqls[2].should =~ /\AINSERT INTO items \((name|value), (name|value)\) VALUES \(('def'|2), (2|'def')\) ON DUPLICATE KEY UPDATE name=VALUES\(name\), value=6\z/
713
+ MYSQL_DB.sqls[0].should =~ /\AINSERT INTO `items` \(`(name|value)`, `(name|value)`\) VALUES \(('abc'|1), (1|'abc')\)\z/
714
+ MYSQL_DB.sqls[1].should =~ /\AINSERT INTO `items` \(`(name|value)`, `(name|value)`\) VALUES \(('abc'|1), (1|'abc')\) ON DUPLICATE KEY UPDATE `name`=VALUES\(`name`\), `value`=6\z/
715
+ MYSQL_DB.sqls[2].should =~ /\AINSERT INTO `items` \(`(name|value)`, `(name|value)`\) VALUES \(('def'|2), (2|'def')\) ON DUPLICATE KEY UPDATE `name`=VALUES\(`name`\), `value`=6\z/
734
716
 
735
717
  @d.all.should == [{:name => 'abc', :value => 6}, {:name => 'def', :value => 2}]
736
718
  end
@@ -740,7 +722,7 @@ describe "MySQL::Dataset#insert and related methods" do
740
722
 
741
723
  MYSQL_DB.sqls.should == [
742
724
  SQL_BEGIN,
743
- "INSERT INTO items (name) VALUES ('abc'), ('def')",
725
+ "INSERT INTO `items` (`name`) VALUES ('abc'), ('def')",
744
726
  SQL_COMMIT
745
727
  ]
746
728
 
@@ -755,10 +737,10 @@ describe "MySQL::Dataset#insert and related methods" do
755
737
 
756
738
  MYSQL_DB.sqls.should == [
757
739
  SQL_BEGIN,
758
- "INSERT INTO items (value) VALUES (1), (2)",
740
+ "INSERT INTO `items` (`value`) VALUES (1), (2)",
759
741
  SQL_COMMIT,
760
742
  SQL_BEGIN,
761
- "INSERT INTO items (value) VALUES (3), (4)",
743
+ "INSERT INTO `items` (`value`) VALUES (3), (4)",
762
744
  SQL_COMMIT
763
745
  ]
764
746
 
@@ -776,10 +758,10 @@ describe "MySQL::Dataset#insert and related methods" do
776
758
 
777
759
  MYSQL_DB.sqls.should == [
778
760
  SQL_BEGIN,
779
- "INSERT INTO items (value) VALUES (1), (2)",
761
+ "INSERT INTO `items` (`value`) VALUES (1), (2)",
780
762
  SQL_COMMIT,
781
763
  SQL_BEGIN,
782
- "INSERT INTO items (value) VALUES (3), (4)",
764
+ "INSERT INTO `items` (`value`) VALUES (3), (4)",
783
765
  SQL_COMMIT
784
766
  ]
785
767
 
@@ -796,7 +778,7 @@ describe "MySQL::Dataset#insert and related methods" do
796
778
 
797
779
  MYSQL_DB.sqls.should == [
798
780
  SQL_BEGIN,
799
- "INSERT INTO items (name, value) VALUES ('abc', 1), ('def', 2)",
781
+ "INSERT INTO `items` (`name`, `value`) VALUES ('abc', 1), ('def', 2)",
800
782
  SQL_COMMIT
801
783
  ]
802
784
 
@@ -811,7 +793,7 @@ describe "MySQL::Dataset#insert and related methods" do
811
793
 
812
794
  MYSQL_DB.sqls.should == [
813
795
  SQL_BEGIN,
814
- "INSERT IGNORE INTO items (name) VALUES ('abc'), ('def')",
796
+ "INSERT IGNORE INTO `items` (`name`) VALUES ('abc'), ('def')",
815
797
  SQL_COMMIT
816
798
  ]
817
799
 
@@ -822,7 +804,7 @@ describe "MySQL::Dataset#insert and related methods" do
822
804
 
823
805
  specify "#insert_ignore should add the IGNORE keyword for single inserts" do
824
806
  @d.insert_ignore.insert(:name => 'ghi')
825
- MYSQL_DB.sqls.should == ["INSERT IGNORE INTO items (name) VALUES ('ghi')"]
807
+ MYSQL_DB.sqls.should == ["INSERT IGNORE INTO `items` (`name`) VALUES ('ghi')"]
826
808
  @d.all.should == [{:name => 'ghi', :value => nil}]
827
809
  end
828
810
 
@@ -830,9 +812,9 @@ describe "MySQL::Dataset#insert and related methods" do
830
812
  @d.on_duplicate_key_update.import([:name,:value], [['abc', 1], ['def',2]])
831
813
 
832
814
  MYSQL_DB.sqls.should == [
833
- "SELECT * FROM items LIMIT 1",
815
+ "SELECT * FROM `items` LIMIT 1",
834
816
  SQL_BEGIN,
835
- "INSERT INTO items (name, value) VALUES ('abc', 1), ('def', 2) ON DUPLICATE KEY UPDATE name=VALUES(name), value=VALUES(value)",
817
+ "INSERT INTO `items` (`name`, `value`) VALUES ('abc', 1), ('def', 2) ON DUPLICATE KEY UPDATE `name`=VALUES(`name`), `value`=VALUES(`value`)",
836
818
  SQL_COMMIT
837
819
  ]
838
820
 
@@ -848,7 +830,7 @@ describe "MySQL::Dataset#insert and related methods" do
848
830
 
849
831
  MYSQL_DB.sqls.should == [
850
832
  SQL_BEGIN,
851
- "INSERT INTO items (name, value) VALUES ('abc', 1), ('def', 2) ON DUPLICATE KEY UPDATE value=VALUES(value)",
833
+ "INSERT INTO `items` (`name`, `value`) VALUES ('abc', 1), ('def', 2) ON DUPLICATE KEY UPDATE `value`=VALUES(`value`)",
852
834
  SQL_COMMIT
853
835
  ]
854
836
 
@@ -907,25 +889,25 @@ describe "MySQL::Dataset#complex_expression_sql" do
907
889
  end
908
890
 
909
891
  specify "should handle pattern matches correctly" do
910
- @d.literal(:x.like('a')).should == "(x LIKE BINARY 'a')"
911
- @d.literal(~:x.like('a')).should == "(x NOT LIKE BINARY 'a')"
912
- @d.literal(:x.ilike('a')).should == "(x LIKE 'a')"
913
- @d.literal(~:x.ilike('a')).should == "(x NOT LIKE 'a')"
914
- @d.literal(:x.like(/a/)).should == "(x REGEXP BINARY 'a')"
915
- @d.literal(~:x.like(/a/)).should == "(x NOT REGEXP BINARY 'a')"
916
- @d.literal(:x.like(/a/i)).should == "(x REGEXP 'a')"
917
- @d.literal(~:x.like(/a/i)).should == "(x NOT REGEXP 'a')"
892
+ @d.literal(:x.like('a')).should == "(`x` LIKE BINARY 'a')"
893
+ @d.literal(~:x.like('a')).should == "(`x` NOT LIKE BINARY 'a')"
894
+ @d.literal(:x.ilike('a')).should == "(`x` LIKE 'a')"
895
+ @d.literal(~:x.ilike('a')).should == "(`x` NOT LIKE 'a')"
896
+ @d.literal(:x.like(/a/)).should == "(`x` REGEXP BINARY 'a')"
897
+ @d.literal(~:x.like(/a/)).should == "(`x` NOT REGEXP BINARY 'a')"
898
+ @d.literal(:x.like(/a/i)).should == "(`x` REGEXP 'a')"
899
+ @d.literal(~:x.like(/a/i)).should == "(`x` NOT REGEXP 'a')"
918
900
  end
919
901
 
920
902
  specify "should handle string concatenation with CONCAT if more than one record" do
921
- @d.literal([:x, :y].sql_string_join).should == "CONCAT(x, y)"
922
- @d.literal([:x, :y].sql_string_join(' ')).should == "CONCAT(x, ' ', y)"
923
- @d.literal([:x.sql_function(:y), 1, 'z'.lit].sql_string_join(:y.sql_subscript(1))).should == "CONCAT(x(y), y[1], '1', y[1], z)"
903
+ @d.literal([:x, :y].sql_string_join).should == "CONCAT(`x`, `y`)"
904
+ @d.literal([:x, :y].sql_string_join(' ')).should == "CONCAT(`x`, ' ', `y`)"
905
+ @d.literal([:x.sql_function(:y), 1, 'z'.lit].sql_string_join(:y.sql_subscript(1))).should == "CONCAT(x(`y`), `y`[1], '1', `y`[1], z)"
924
906
  end
925
907
 
926
908
  specify "should handle string concatenation as simple string if just one record" do
927
- @d.literal([:x].sql_string_join).should == "x"
928
- @d.literal([:x].sql_string_join(' ')).should == "x"
909
+ @d.literal([:x].sql_string_join).should == "`x`"
910
+ @d.literal([:x].sql_string_join(' ')).should == "`x`"
929
911
  end
930
912
  end
931
913
 
@@ -939,7 +921,7 @@ describe "MySQL::Dataset#calc_found_rows" do
939
921
 
940
922
  specify "should add the SQL_CALC_FOUND_ROWS keyword when selecting" do
941
923
  MYSQL_DB[:items].select(:a).calc_found_rows.limit(1).sql.should == \
942
- 'SELECT SQL_CALC_FOUND_ROWS a FROM items LIMIT 1'
924
+ 'SELECT SQL_CALC_FOUND_ROWS `a` FROM `items` LIMIT 1'
943
925
  end
944
926
 
945
927
  specify "should count matching rows disregarding LIMIT clause" do
@@ -950,8 +932,8 @@ describe "MySQL::Dataset#calc_found_rows" do
950
932
  MYSQL_DB.dataset.select(:FOUND_ROWS.sql_function.as(:rows)).all.should == [{:rows => 2 }]
951
933
 
952
934
  MYSQL_DB.sqls.should == [
953
- 'SELECT SQL_CALC_FOUND_ROWS * FROM items WHERE (a = 1) LIMIT 1',
954
- 'SELECT FOUND_ROWS() AS rows',
935
+ 'SELECT SQL_CALC_FOUND_ROWS * FROM `items` WHERE (`a` = 1) LIMIT 1',
936
+ 'SELECT FOUND_ROWS() AS `rows`',
955
937
  ]
956
938
  end
957
939
  end
@@ -1015,29 +997,29 @@ end
1015
997
  if MYSQL_DB.adapter_scheme == :mysql
1016
998
  describe "MySQL bad date/time conversions" do
1017
999
  after do
1018
- Sequel::MySQL.convert_invalid_date_time = false
1000
+ MYSQL_DB.convert_invalid_date_time = false
1019
1001
  end
1020
1002
 
1021
1003
  specify "should raise an exception when a bad date/time is used and convert_invalid_date_time is false" do
1022
- Sequel::MySQL.convert_invalid_date_time = false
1004
+ MYSQL_DB.convert_invalid_date_time = false
1023
1005
  proc{MYSQL_DB["SELECT CAST('0000-00-00' AS date)"].single_value}.should raise_error(Sequel::InvalidValue)
1024
1006
  proc{MYSQL_DB["SELECT CAST('0000-00-00 00:00:00' AS datetime)"].single_value}.should raise_error(Sequel::InvalidValue)
1025
1007
  proc{MYSQL_DB["SELECT CAST('25:00:00' AS time)"].single_value}.should raise_error(Sequel::InvalidValue)
1026
1008
  end
1027
1009
 
1028
1010
  specify "should not use a nil value bad date/time is used and convert_invalid_date_time is nil or :nil" do
1029
- Sequel::MySQL.convert_invalid_date_time = nil
1011
+ MYSQL_DB.convert_invalid_date_time = nil
1030
1012
  MYSQL_DB["SELECT CAST('0000-00-00' AS date)"].single_value.should == nil
1031
1013
  MYSQL_DB["SELECT CAST('0000-00-00 00:00:00' AS datetime)"].single_value.should == nil
1032
1014
  MYSQL_DB["SELECT CAST('25:00:00' AS time)"].single_value.should == nil
1033
- Sequel::MySQL.convert_invalid_date_time = :nil
1015
+ MYSQL_DB.convert_invalid_date_time = :nil
1034
1016
  MYSQL_DB["SELECT CAST('0000-00-00' AS date)"].single_value.should == nil
1035
1017
  MYSQL_DB["SELECT CAST('0000-00-00 00:00:00' AS datetime)"].single_value.should == nil
1036
1018
  MYSQL_DB["SELECT CAST('25:00:00' AS time)"].single_value.should == nil
1037
1019
  end
1038
1020
 
1039
1021
  specify "should not use a nil value bad date/time is used and convert_invalid_date_time is :string" do
1040
- Sequel::MySQL.convert_invalid_date_time = :string
1022
+ MYSQL_DB.convert_invalid_date_time = :string
1041
1023
  MYSQL_DB["SELECT CAST('0000-00-00' AS date)"].single_value.should == '0000-00-00'
1042
1024
  MYSQL_DB["SELECT CAST('0000-00-00 00:00:00' AS datetime)"].single_value.should == '0000-00-00 00:00:00'
1043
1025
  MYSQL_DB["SELECT CAST('25:00:00' AS time)"].single_value.should == '25:00:00'