colincasey-sequel 2.10.1 → 2.10.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. data/CHANGELOG +10 -0
  2. data/lib/sequel_core/adapters/ado.rb +3 -0
  3. data/lib/sequel_core/adapters/db2.rb +0 -11
  4. data/lib/sequel_core/adapters/dbi.rb +0 -11
  5. data/lib/sequel_core/adapters/do.rb +0 -12
  6. data/lib/sequel_core/adapters/firebird.rb +19 -14
  7. data/lib/sequel_core/adapters/informix.rb +1 -11
  8. data/lib/sequel_core/adapters/jdbc/h2.rb +3 -11
  9. data/lib/sequel_core/adapters/jdbc/mysql.rb +0 -10
  10. data/lib/sequel_core/adapters/jdbc/postgresql.rb +3 -15
  11. data/lib/sequel_core/adapters/jdbc.rb +1 -13
  12. data/lib/sequel_core/adapters/mysql.rb +6 -13
  13. data/lib/sequel_core/adapters/odbc.rb +34 -28
  14. data/lib/sequel_core/adapters/openbase.rb +0 -11
  15. data/lib/sequel_core/adapters/oracle.rb +11 -9
  16. data/lib/sequel_core/adapters/postgres.rb +13 -16
  17. data/lib/sequel_core/adapters/shared/ms_access.rb +8 -2
  18. data/lib/sequel_core/adapters/shared/mssql.rb +6 -15
  19. data/lib/sequel_core/adapters/shared/mysql.rb +23 -14
  20. data/lib/sequel_core/adapters/shared/oracle.rb +4 -0
  21. data/lib/sequel_core/adapters/shared/postgres.rb +27 -25
  22. data/lib/sequel_core/adapters/shared/progress.rb +4 -0
  23. data/lib/sequel_core/adapters/shared/sqlite.rb +9 -16
  24. data/lib/sequel_core/adapters/sqlite.rb +5 -14
  25. data/lib/sequel_core/core_sql.rb +7 -3
  26. data/lib/sequel_core/dataset/convenience.rb +1 -1
  27. data/lib/sequel_core/dataset/prepared_statements.rb +1 -1
  28. data/lib/sequel_core/dataset/sql.rb +116 -30
  29. data/lib/sequel_core/dataset.rb +2 -2
  30. data/lib/sequel_core/sql.rb +2 -31
  31. data/lib/sequel_model/base.rb +23 -7
  32. data/spec/integration/dataset_test.rb +2 -2
  33. data/spec/sequel_core/core_sql_spec.rb +9 -0
  34. data/spec/sequel_core/dataset_spec.rb +27 -31
  35. data/spec/sequel_model/base_spec.rb +66 -0
  36. data/spec/sequel_model/spec_helper.rb +3 -0
  37. metadata +1 -1
  38. data/lib/sequel_core/dataset/stored_procedures.rb +0 -75
  39. data/lib/sequel_core/dataset/unsupported.rb +0 -43
data/CHANGELOG CHANGED
@@ -1,5 +1,15 @@
1
1
  === HEAD
2
2
 
3
+ * Optimize Model.[] by using static sql when possible, for a 30-40% speed increase (jeremyevans)
4
+
5
+ * Add Dataset#with_sql, which returns a clone of the datatset with static SQL (jeremyevans)
6
+
7
+ * Refactor Dataset#literal so it doesn't need to be overridden in subadapters, for a 20-25% performance increase (jeremyevans)
8
+
9
+ * Remove SQL::IrregularFunction, no longer used internally (jeremyevans)
10
+
11
+ * Allow String#lit to take arguments and return a SQL::PlaceholderLiteralString (jeremyevans)
12
+
3
13
  * Add Model#set_associated_object, used by the many_to_one setter method, for easier overriding (jeremyevans)
4
14
 
5
15
  * Allow use of database independent types when casting (jeremyevans)
@@ -1,3 +1,4 @@
1
+ require 'sequel_core/adapters/utils/date_format'
1
2
  require 'win32ole'
2
3
 
3
4
  module Sequel
@@ -61,6 +62,8 @@ module Sequel
61
62
  end
62
63
 
63
64
  class Dataset < Sequel::Dataset
65
+ include Dataset::SQLStandardDateFormat
66
+
64
67
  def fetch_rows(sql)
65
68
  execute(sql) do |s|
66
69
  @columns = s.Fields.extend(Enumerable).map do |column|
@@ -75,17 +75,6 @@ module Sequel
75
75
  class Dataset < Sequel::Dataset
76
76
  MAX_COL_SIZE = 256
77
77
 
78
- def literal(v)
79
- case v
80
- when Time
81
- literal(v.iso8601)
82
- when Date, DateTime
83
- literal(v.to_s)
84
- else
85
- super
86
- end
87
- end
88
-
89
78
  def fetch_rows(sql)
90
79
  execute(sql) do |sth|
91
80
  @column_info = get_column_info(sth)
@@ -76,17 +76,6 @@ module Sequel
76
76
  end
77
77
 
78
78
  class Dataset < Sequel::Dataset
79
- def literal(v)
80
- case v
81
- when Time
82
- literal(v.iso8601)
83
- when Date, DateTime
84
- literal(v.to_s)
85
- else
86
- super
87
- end
88
- end
89
-
90
79
  def fetch_rows(sql, &block)
91
80
  execute(sql) do |s|
92
81
  begin
@@ -175,18 +175,6 @@ module Sequel
175
175
 
176
176
  # Dataset class for Sequel::DataObjects::Database objects.
177
177
  class Dataset < Sequel::Dataset
178
- # Handle the usual time class overrides.
179
- def literal(v)
180
- case v
181
- when Time
182
- literal(v.iso8601)
183
- when Date, DateTime
184
- literal(v.to_s)
185
- else
186
- super
187
- end
188
- end
189
-
190
178
  # Execute the SQL on the database and yield the rows as hashes
191
179
  # with symbol keys.
192
180
  def fetch_rows(sql)
@@ -1,4 +1,5 @@
1
1
  require 'fb'
2
+ require 'sequel_core/adapters/utils/unsupported'
2
3
 
3
4
  module Sequel
4
5
  # The Sequel Firebird adapter requires the ruby fb driver located at
@@ -214,6 +215,7 @@ module Sequel
214
215
 
215
216
  BOOL_TRUE = '1'.freeze
216
217
  BOOL_FALSE = '0'.freeze
218
+ NULL = LiteralString.new('NULL').freeze
217
219
  COMMA_SEPARATOR = ', '.freeze
218
220
  FIREBIRD_TIMESTAMP_FORMAT = "TIMESTAMP '%Y-%m-%d %H:%M:%S".freeze
219
221
  SELECT_CLAUSE_ORDER = %w'distinct limit columns from join where group having compounds order'.freeze
@@ -249,7 +251,7 @@ module Sequel
249
251
  # Use the RETURNING clause to return the primary key of the inserted record, if it exists
250
252
  def insert_returning_pk_sql(*values)
251
253
  pk = db.primary_key(opts[:from].first)
252
- insert_returning_sql(pk ? Sequel::SQL::Identifier.new(pk) : 'NULL'.lit, *values)
254
+ insert_returning_sql(pk ? Sequel::SQL::Identifier.new(pk) : NULL, *values)
253
255
  end
254
256
 
255
257
  # Use the RETURNING clause to return the columns listed in returning.
@@ -262,19 +264,6 @@ module Sequel
262
264
  single_record(default_server_opts(:naked=>true, :sql=>insert_returning_sql(nil, *values)))
263
265
  end
264
266
 
265
- def literal(v)
266
- case v
267
- when Time, DateTime
268
- "#{v.strftime(FIREBIRD_TIMESTAMP_FORMAT)}.#{sprintf("%04d",v.usec / 100)}'"
269
- when TrueClass
270
- BOOL_TRUE
271
- when FalseClass
272
- BOOL_FALSE
273
- else
274
- super
275
- end
276
- end
277
-
278
267
  # The order of clauses in the SELECT SQL statement
279
268
  def select_clause_order
280
269
  SELECT_CLAUSE_ORDER
@@ -293,6 +282,22 @@ module Sequel
293
282
  m
294
283
  end
295
284
  end
285
+
286
+ def literal_datetime(v)
287
+ "#{v.strftime(FIREBIRD_TIMESTAMP_FORMAT)}.#{sprintf("%04d",(v.sec_fraction * 864000000))}'"
288
+ end
289
+
290
+ def literal_false
291
+ BOOL_FALSE
292
+ end
293
+
294
+ def literal_time(v)
295
+ "#{v.strftime(FIREBIRD_TIMESTAMP_FORMAT)}.#{sprintf("%04d",v.usec / 100)}'"
296
+ end
297
+
298
+ def literal_true
299
+ BOOL_TRUE
300
+ end
296
301
  end
297
302
  end
298
303
  end
@@ -1,3 +1,4 @@
1
+ require 'sequel_core/adapters/utils/unsupported'
1
2
  require 'informix'
2
3
 
3
4
  module Sequel
@@ -39,17 +40,6 @@ module Sequel
39
40
 
40
41
  SELECT_CLAUSE_ORDER = %w'limit distinct columns from join where having group compounds order'.freeze
41
42
 
42
- def literal(v)
43
- case v
44
- when Time
45
- literal(v.iso8601)
46
- when Date, DateTime
47
- literal(v.to_s)
48
- else
49
- super
50
- end
51
- end
52
-
53
43
  def fetch_rows(sql, &block)
54
44
  execute(sql) do |cursor|
55
45
  begin
@@ -1,3 +1,5 @@
1
+ require 'sequel_core/adapters/utils/date_format'
2
+
1
3
  module Sequel
2
4
  module JDBC
3
5
  # Database and Dataset support for H2 databases accessed via JDBC.
@@ -52,17 +54,7 @@ module Sequel
52
54
 
53
55
  # Dataset class for H2 datasets accessed via JDBC.
54
56
  class Dataset < JDBC::Dataset
55
- # Use H2 syntax for Date, DateTime, and Time types.
56
- def literal(v)
57
- case v
58
- when Date
59
- v.strftime("DATE '%Y-%m-%d'")
60
- when DateTime, Time
61
- v.strftime("TIMESTAMP '%Y-%m-%d %H:%M:%S'")
62
- else
63
- super
64
- end
65
- end
57
+ include Dataset::SQLStandardDateFormat
66
58
  end
67
59
  end
68
60
  end
@@ -46,16 +46,6 @@ module Sequel
46
46
  execute_insert(insert_sql(*values))
47
47
  end
48
48
 
49
- # Handle time types correctly
50
- def literal(v)
51
- case v
52
- when Time, DateTime
53
- v.strftime("'%Y-%m-%d %H:%M:%S'")
54
- else
55
- super
56
- end
57
- end
58
-
59
49
  # Use execute_insert to execute the replace_sql.
60
50
  def replace(*args)
61
51
  execute_insert(replace_sql(*args))
@@ -91,21 +91,9 @@ module Sequel
91
91
  ps
92
92
  end
93
93
 
94
- # Convert Java::JavaSql::Timestamps correctly, and handle Strings
95
- # similar to the native postgres adapter.
96
- def literal(v)
97
- case v
98
- when LiteralString
99
- v
100
- when SQL::Blob
101
- super
102
- when String
103
- db.synchronize{|c| "'#{c.escape_string(v)}'"}
104
- when Java::JavaSql::Timestamp
105
- "TIMESTAMP #{literal(v.to_s)}"
106
- else
107
- super
108
- end
94
+ # Literalize strings similar to the native postgres adapter
95
+ def literal_string(v)
96
+ db.synchronize{|c| "'#{c.escape_string(v)}'"}
109
97
  end
110
98
  end
111
99
  end
@@ -1,5 +1,5 @@
1
1
  require 'java'
2
- require 'sequel_core/dataset/stored_procedures'
2
+ require 'sequel_core/adapters/utils/stored_procedures'
3
3
 
4
4
  module Sequel
5
5
  # Houses Sequel's JDBC support when running on JRuby.
@@ -414,18 +414,6 @@ module Sequel
414
414
  self
415
415
  end
416
416
 
417
- # Use the ISO values for dates and times.
418
- def literal(v)
419
- case v
420
- when Time
421
- literal(v.iso8601)
422
- when Date, DateTime, Java::JavaSql::Timestamp, Java::JavaSql::Date
423
- literal(v.to_s)
424
- else
425
- super
426
- end
427
- end
428
-
429
417
  # Create a named prepared statement that is stored in the
430
418
  # database (and connection) for reuse.
431
419
  def prepare(type, name=nil, values=nil)
@@ -1,6 +1,6 @@
1
1
  require 'mysql'
2
2
  require 'sequel_core/adapters/shared/mysql'
3
- require 'sequel_core/dataset/stored_procedures'
3
+ require 'sequel_core/adapters/utils/stored_procedures'
4
4
 
5
5
  module Sequel
6
6
  # Module for holding all MySQL-related classes and modules for Sequel.
@@ -299,18 +299,6 @@ module Sequel
299
299
  execute_dui(insert_sql(*values)){|c| c.insert_id}
300
300
  end
301
301
 
302
- # Handle correct quoting of strings using ::MySQL.quote.
303
- def literal(v)
304
- case v
305
- when LiteralString
306
- v
307
- when String
308
- "'#{::Mysql.quote(v)}'"
309
- else
310
- super
311
- end
312
- end
313
-
314
302
  # Store the given type of prepared statement in the associated database
315
303
  # with the given name.
316
304
  def prepare(type, name=nil, values=nil)
@@ -360,6 +348,11 @@ module Sequel
360
348
  super(sql, {:type=>:dui}.merge(opts), &block)
361
349
  end
362
350
 
351
+ # Handle correct quoting of strings using ::MySQL.quote.
352
+ def literal_string(v)
353
+ "'#{::Mysql.quote(v)}'"
354
+ end
355
+
363
356
  # Extend the dataset with the MySQL stored procedure methods.
364
357
  def prepare_extend_sproc(ds)
365
358
  ds.extend(StoredProcedureMethods)
@@ -100,25 +100,6 @@ module Sequel
100
100
  ODBC_TIMESTAMP_AFTER_SECONDS =
101
101
  ODBC_TIMESTAMP_FORMAT.index( '%S' ).succ - ODBC_TIMESTAMP_FORMAT.length
102
102
  ODBC_DATE_FORMAT = "{d '%Y-%m-%d'}".freeze
103
-
104
- def literal(v)
105
- case v
106
- when true
107
- BOOL_TRUE
108
- when false
109
- BOOL_FALSE
110
- when Time, DateTime
111
- formatted = v.strftime(ODBC_TIMESTAMP_FORMAT)
112
- usec = (Time === v ? v.usec : (v.sec_fraction * 86400000000))
113
- formatted.insert(ODBC_TIMESTAMP_AFTER_SECONDS, ".#{(usec.to_f/1000).round}") if usec >= 1000
114
- formatted
115
- when Date
116
- v.strftime(ODBC_DATE_FORMAT)
117
- else
118
- super
119
- end
120
- end
121
-
122
103
  UNTITLED_COLUMN = 'untitled_%d'.freeze
123
104
 
124
105
  def fetch_rows(sql, &block)
@@ -141,15 +122,7 @@ module Sequel
141
122
  end
142
123
 
143
124
  private
144
-
145
- def hash_row(row)
146
- hash = {}
147
- row.each_with_index do |v, idx|
148
- hash[@columns[idx]] = convert_odbc_value(v)
149
- end
150
- hash
151
- end
152
-
125
+
153
126
  def convert_odbc_value(v)
154
127
  # When fetching a result set, the Ruby ODBC driver converts all ODBC
155
128
  # SQL types to an equivalent Ruby type; with the exception of
@@ -169,6 +142,39 @@ module Sequel
169
142
  v
170
143
  end
171
144
  end
145
+
146
+ def hash_row(row)
147
+ hash = {}
148
+ row.each_with_index do |v, idx|
149
+ hash[@columns[idx]] = convert_odbc_value(v)
150
+ end
151
+ hash
152
+ end
153
+
154
+ def literal_date(v)
155
+ v.strftime(ODBC_DATE_FORMAT)
156
+ end
157
+
158
+ def literal_datetime(v)
159
+ formatted = v.strftime(ODBC_TIMESTAMP_FORMAT)
160
+ usec = v.sec_fraction * 86400000000
161
+ formatted.insert(ODBC_TIMESTAMP_AFTER_SECONDS, ".#{(usec.to_f/1000).round}") if usec >= 1000
162
+ formatted
163
+ end
164
+
165
+ def literal_false
166
+ BOOL_FALSE
167
+ end
168
+
169
+ def literal_true
170
+ BOOL_TRUE
171
+ end
172
+
173
+ def literal_time(v)
174
+ formatted = v.strftime(ODBC_TIMESTAMP_FORMAT)
175
+ formatted.insert(ODBC_TIMESTAMP_AFTER_SECONDS, ".#{(v.usec.to_f/1000).round}") if usec >= 1000
176
+ formatted
177
+ end
172
178
  end
173
179
  end
174
180
  end
@@ -37,17 +37,6 @@ module Sequel
37
37
  end
38
38
 
39
39
  class Dataset < Sequel::Dataset
40
- def literal(v)
41
- case v
42
- when Time
43
- literal(v.iso8601)
44
- when Date, DateTime
45
- literal(v.to_s)
46
- else
47
- super
48
- end
49
- end
50
-
51
40
  def fetch_rows(sql)
52
41
  execute(sql) do |result|
53
42
  begin
@@ -78,15 +78,6 @@ module Sequel
78
78
  class Dataset < Sequel::Dataset
79
79
  include DatasetMethods
80
80
 
81
- def literal(v)
82
- case v
83
- when OraDate
84
- literal(Time.local(*v.to_a))
85
- else
86
- super
87
- end
88
- end
89
-
90
81
  def fetch_rows(sql, &block)
91
82
  execute(sql) do |cursor|
92
83
  begin
@@ -102,6 +93,17 @@ module Sequel
102
93
  end
103
94
  self
104
95
  end
96
+
97
+ private
98
+
99
+ def literal_other(v)
100
+ case v
101
+ when OraDate
102
+ literal_time(Time.local(*v.to_a))
103
+ else
104
+ super
105
+ end
106
+ end
105
107
  end
106
108
  end
107
109
  end
@@ -326,23 +326,9 @@ module Sequel
326
326
  end
327
327
  end
328
328
 
329
- # Literalize strings and blobs using code from the native adapter.
330
- def literal(v)
331
- case v
332
- when LiteralString
333
- v
334
- when SQL::Blob
335
- db.synchronize{|c| "'#{c.escape_bytea(v)}'"}
336
- when String
337
- db.synchronize{|c| "'#{c.escape_string(v)}'"}
338
- else
339
- super
340
- end
341
- end
342
-
343
329
  if SEQUEL_POSTGRES_USES_PG
344
330
 
345
- PREPARED_ARG_PLACEHOLDER = '$'.lit.freeze
331
+ PREPARED_ARG_PLACEHOLDER = LiteralString.new('$').freeze
346
332
 
347
333
  # PostgreSQL specific argument mapper used for mapping the named
348
334
  # argument hash to a array with numbered arguments. Only used with
@@ -373,7 +359,7 @@ module Sequel
373
359
  @prepared_args << y
374
360
  i = @prepared_args.length
375
361
  end
376
- "#{prepared_arg_placeholder}#{i}#{"::#{type}" if type}".lit
362
+ LiteralString.new("#{prepared_arg_placeholder}#{i}#{"::#{type}" if type}")
377
363
  end
378
364
  end
379
365
 
@@ -451,6 +437,17 @@ module Sequel
451
437
  PREPARED_ARG_PLACEHOLDER
452
438
  end
453
439
  end
440
+
441
+ private
442
+
443
+ def literal_blob(v)
444
+ db.synchronize{|c| "'#{c.escape_bytea(v)}'"}
445
+ end
446
+
447
+ def literal_string(v)
448
+ db.synchronize{|c| "'#{c.escape_string(v)}'"}
449
+ end
450
+
454
451
  end
455
452
  end
456
453
  end
@@ -24,8 +24,11 @@ module Sequel
24
24
  false
25
25
  end
26
26
 
27
- private
27
+ def identifier_output_method
28
+ nil
29
+ end
28
30
 
31
+ private
29
32
  # SQL to BEGIN a transaction.
30
33
  def begin_transaction_sql
31
34
  SQL_BEGIN
@@ -90,7 +93,6 @@ module Sequel
90
93
  end
91
94
 
92
95
  private
93
-
94
96
  def select_clause_order
95
97
  SELECT_CLAUSE_ORDER
96
98
  end
@@ -105,6 +107,10 @@ module Sequel
105
107
  def select_with_sql(sql, opts)
106
108
  sql << " WITH #{opts[:with]}" if opts[:with]
107
109
  end
110
+
111
+ def select_union_sql(sql, opts)
112
+ sql << " UNION #{opts[:union]}" if opts[:union]
113
+ end
108
114
  end
109
115
  end
110
116
  end
@@ -1,3 +1,5 @@
1
+ require 'sequel_core/adapters/utils/unsupported'
2
+
1
3
  module Sequel
2
4
  module MSSQL
3
5
  module DatabaseMethods
@@ -52,21 +54,6 @@ module Sequel
52
54
  filter("CONTAINS (#{literal(cols)}, #{literal(terms)})")
53
55
  end
54
56
 
55
- def literal(v)
56
- case v
57
- when LiteralString
58
- v
59
- when String
60
- "N#{super}"
61
- when Time
62
- literal(v.iso8601)
63
- when Date, DateTime
64
- literal(v.to_s)
65
- else
66
- super
67
- end
68
- end
69
-
70
57
  def multi_insert_sql(columns, values)
71
58
  values = values.map {|r| "SELECT #{expression_list(r)}" }.join(" UNION ALL ")
72
59
  ["INSERT INTO #{source_list(@opts[:from])} (#{identifier_list(columns)}) #{values}"]
@@ -83,6 +70,10 @@ module Sequel
83
70
 
84
71
  private
85
72
 
73
+ def literal_string(v)
74
+ "N#{super}"
75
+ end
76
+
86
77
  def select_clause_order
87
78
  SELECT_CLAUSE_ORDER
88
79
  end
@@ -1,3 +1,5 @@
1
+ require 'sequel_core/adapters/utils/unsupported'
2
+
1
3
  module Sequel
2
4
  module Schema
3
5
  module SQL
@@ -147,6 +149,7 @@ module Sequel
147
149
  BOOL_TRUE = '1'.freeze
148
150
  BOOL_FALSE = '0'.freeze
149
151
  CAST_TYPES = {String=>:CHAR, Integer=>:SIGNED, Time=>:DATETIME, DateTime=>:DATETIME, Numeric=>:DECIMAL, BigDecimal=>:DECIMAL, File=>:BINARY}
152
+ TIMESTAMP_FORMAT = "'%Y-%m-%d %H:%M:%S'".freeze
150
153
  COMMA_SEPARATOR = ', '.freeze
151
154
 
152
155
  # MySQL can't use the varchar type in a cast.
@@ -230,20 +233,6 @@ module Sequel
230
233
  end
231
234
  end
232
235
 
233
- # Override the default boolean values.
234
- def literal(v)
235
- case v
236
- when true
237
- BOOL_TRUE
238
- when false
239
- BOOL_FALSE
240
- when DateTime, Time
241
- v.strftime("'%Y-%m-%d %H:%M:%S'")
242
- else
243
- super
244
- end
245
- end
246
-
247
236
  # MySQL specific syntax for inserting multiple values at once.
248
237
  def multi_insert_sql(columns, values)
249
238
  values = values.map {|r| literal(Array(r))}.join(COMMA_SEPARATOR)
@@ -313,6 +302,26 @@ module Sequel
313
302
 
314
303
  private
315
304
 
305
+ # Use MySQL Timestamp format
306
+ def literal_datetime(v)
307
+ v.strftime(TIMESTAMP_FORMAT)
308
+ end
309
+
310
+ # Use 0 for false on MySQL
311
+ def literal_false
312
+ BOOL_FALSE
313
+ end
314
+
315
+ # Use MySQL Timestamp format
316
+ def literal_time(v)
317
+ v.strftime(TIMESTAMP_FORMAT)
318
+ end
319
+
320
+ # Use 1 for true on MySQL
321
+ def literal_true
322
+ BOOL_TRUE
323
+ end
324
+
316
325
  # MySQL doesn't support DISTINCT ON
317
326
  def select_distinct_sql(sql, opts)
318
327
  if opts[:distinct]
@@ -1,3 +1,6 @@
1
+ require 'sequel_core/adapters/utils/date_format'
2
+ require 'sequel_core/adapters/utils/unsupported'
3
+
1
4
  module Sequel
2
5
  module Oracle
3
6
  module DatabaseMethods
@@ -13,6 +16,7 @@ module Sequel
13
16
 
14
17
  module DatasetMethods
15
18
  include Dataset::UnsupportedIntersectExceptAll
19
+ include Dataset::SQLStandardDateFormat
16
20
 
17
21
  SELECT_CLAUSE_ORDER = %w'distinct columns from join where group having compounds order limit'.freeze
18
22