epugh-sequel 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (134) hide show
  1. data/README.rdoc +652 -0
  2. data/VERSION.yml +4 -0
  3. data/bin/sequel +104 -0
  4. data/lib/sequel.rb +1 -0
  5. data/lib/sequel/adapters/ado.rb +85 -0
  6. data/lib/sequel/adapters/db2.rb +132 -0
  7. data/lib/sequel/adapters/dbi.rb +101 -0
  8. data/lib/sequel/adapters/do.rb +197 -0
  9. data/lib/sequel/adapters/do/mysql.rb +38 -0
  10. data/lib/sequel/adapters/do/postgres.rb +92 -0
  11. data/lib/sequel/adapters/do/sqlite.rb +31 -0
  12. data/lib/sequel/adapters/firebird.rb +307 -0
  13. data/lib/sequel/adapters/informix.rb +75 -0
  14. data/lib/sequel/adapters/jdbc.rb +485 -0
  15. data/lib/sequel/adapters/jdbc/h2.rb +62 -0
  16. data/lib/sequel/adapters/jdbc/mysql.rb +56 -0
  17. data/lib/sequel/adapters/jdbc/oracle.rb +23 -0
  18. data/lib/sequel/adapters/jdbc/postgresql.rb +101 -0
  19. data/lib/sequel/adapters/jdbc/sqlite.rb +43 -0
  20. data/lib/sequel/adapters/mysql.rb +370 -0
  21. data/lib/sequel/adapters/odbc.rb +184 -0
  22. data/lib/sequel/adapters/openbase.rb +57 -0
  23. data/lib/sequel/adapters/oracle.rb +140 -0
  24. data/lib/sequel/adapters/postgres.rb +453 -0
  25. data/lib/sequel/adapters/shared/mssql.rb +93 -0
  26. data/lib/sequel/adapters/shared/mysql.rb +341 -0
  27. data/lib/sequel/adapters/shared/oracle.rb +62 -0
  28. data/lib/sequel/adapters/shared/postgres.rb +743 -0
  29. data/lib/sequel/adapters/shared/progress.rb +34 -0
  30. data/lib/sequel/adapters/shared/sqlite.rb +263 -0
  31. data/lib/sequel/adapters/sqlite.rb +243 -0
  32. data/lib/sequel/adapters/utils/date_format.rb +21 -0
  33. data/lib/sequel/adapters/utils/stored_procedures.rb +75 -0
  34. data/lib/sequel/adapters/utils/unsupported.rb +62 -0
  35. data/lib/sequel/connection_pool.rb +258 -0
  36. data/lib/sequel/core.rb +204 -0
  37. data/lib/sequel/core_sql.rb +185 -0
  38. data/lib/sequel/database.rb +687 -0
  39. data/lib/sequel/database/schema_generator.rb +324 -0
  40. data/lib/sequel/database/schema_methods.rb +164 -0
  41. data/lib/sequel/database/schema_sql.rb +324 -0
  42. data/lib/sequel/dataset.rb +422 -0
  43. data/lib/sequel/dataset/convenience.rb +237 -0
  44. data/lib/sequel/dataset/prepared_statements.rb +220 -0
  45. data/lib/sequel/dataset/sql.rb +1105 -0
  46. data/lib/sequel/deprecated.rb +529 -0
  47. data/lib/sequel/exceptions.rb +44 -0
  48. data/lib/sequel/extensions/blank.rb +42 -0
  49. data/lib/sequel/extensions/inflector.rb +288 -0
  50. data/lib/sequel/extensions/pagination.rb +96 -0
  51. data/lib/sequel/extensions/pretty_table.rb +78 -0
  52. data/lib/sequel/extensions/query.rb +48 -0
  53. data/lib/sequel/extensions/string_date_time.rb +47 -0
  54. data/lib/sequel/metaprogramming.rb +44 -0
  55. data/lib/sequel/migration.rb +212 -0
  56. data/lib/sequel/model.rb +142 -0
  57. data/lib/sequel/model/association_reflection.rb +263 -0
  58. data/lib/sequel/model/associations.rb +1024 -0
  59. data/lib/sequel/model/base.rb +911 -0
  60. data/lib/sequel/model/deprecated.rb +188 -0
  61. data/lib/sequel/model/deprecated_hooks.rb +103 -0
  62. data/lib/sequel/model/deprecated_inflector.rb +335 -0
  63. data/lib/sequel/model/deprecated_validations.rb +384 -0
  64. data/lib/sequel/model/errors.rb +37 -0
  65. data/lib/sequel/model/exceptions.rb +7 -0
  66. data/lib/sequel/model/inflections.rb +230 -0
  67. data/lib/sequel/model/plugins.rb +74 -0
  68. data/lib/sequel/object_graph.rb +230 -0
  69. data/lib/sequel/plugins/caching.rb +122 -0
  70. data/lib/sequel/plugins/hook_class_methods.rb +122 -0
  71. data/lib/sequel/plugins/schema.rb +53 -0
  72. data/lib/sequel/plugins/single_table_inheritance.rb +63 -0
  73. data/lib/sequel/plugins/validation_class_methods.rb +373 -0
  74. data/lib/sequel/sql.rb +854 -0
  75. data/lib/sequel/version.rb +11 -0
  76. data/lib/sequel_core.rb +1 -0
  77. data/lib/sequel_model.rb +1 -0
  78. data/spec/adapters/ado_spec.rb +46 -0
  79. data/spec/adapters/firebird_spec.rb +376 -0
  80. data/spec/adapters/informix_spec.rb +96 -0
  81. data/spec/adapters/mysql_spec.rb +875 -0
  82. data/spec/adapters/oracle_spec.rb +272 -0
  83. data/spec/adapters/postgres_spec.rb +692 -0
  84. data/spec/adapters/spec_helper.rb +10 -0
  85. data/spec/adapters/sqlite_spec.rb +550 -0
  86. data/spec/core/connection_pool_spec.rb +526 -0
  87. data/spec/core/core_ext_spec.rb +156 -0
  88. data/spec/core/core_sql_spec.rb +528 -0
  89. data/spec/core/database_spec.rb +1214 -0
  90. data/spec/core/dataset_spec.rb +3513 -0
  91. data/spec/core/expression_filters_spec.rb +363 -0
  92. data/spec/core/migration_spec.rb +261 -0
  93. data/spec/core/object_graph_spec.rb +280 -0
  94. data/spec/core/pretty_table_spec.rb +58 -0
  95. data/spec/core/schema_generator_spec.rb +167 -0
  96. data/spec/core/schema_spec.rb +778 -0
  97. data/spec/core/spec_helper.rb +82 -0
  98. data/spec/core/version_spec.rb +7 -0
  99. data/spec/extensions/blank_spec.rb +67 -0
  100. data/spec/extensions/caching_spec.rb +201 -0
  101. data/spec/extensions/hook_class_methods_spec.rb +470 -0
  102. data/spec/extensions/inflector_spec.rb +122 -0
  103. data/spec/extensions/pagination_spec.rb +99 -0
  104. data/spec/extensions/pretty_table_spec.rb +91 -0
  105. data/spec/extensions/query_spec.rb +85 -0
  106. data/spec/extensions/schema_spec.rb +111 -0
  107. data/spec/extensions/single_table_inheritance_spec.rb +53 -0
  108. data/spec/extensions/spec_helper.rb +90 -0
  109. data/spec/extensions/string_date_time_spec.rb +93 -0
  110. data/spec/extensions/validation_class_methods_spec.rb +1054 -0
  111. data/spec/integration/dataset_test.rb +160 -0
  112. data/spec/integration/eager_loader_test.rb +683 -0
  113. data/spec/integration/prepared_statement_test.rb +130 -0
  114. data/spec/integration/schema_test.rb +183 -0
  115. data/spec/integration/spec_helper.rb +75 -0
  116. data/spec/integration/type_test.rb +96 -0
  117. data/spec/model/association_reflection_spec.rb +93 -0
  118. data/spec/model/associations_spec.rb +1780 -0
  119. data/spec/model/base_spec.rb +494 -0
  120. data/spec/model/caching_spec.rb +217 -0
  121. data/spec/model/dataset_methods_spec.rb +78 -0
  122. data/spec/model/eager_loading_spec.rb +1165 -0
  123. data/spec/model/hooks_spec.rb +472 -0
  124. data/spec/model/inflector_spec.rb +126 -0
  125. data/spec/model/model_spec.rb +588 -0
  126. data/spec/model/plugins_spec.rb +142 -0
  127. data/spec/model/record_spec.rb +1243 -0
  128. data/spec/model/schema_spec.rb +92 -0
  129. data/spec/model/spec_helper.rb +124 -0
  130. data/spec/model/validations_spec.rb +1080 -0
  131. data/spec/rcov.opts +6 -0
  132. data/spec/spec.opts +0 -0
  133. data/spec/spec_config.rb.example +10 -0
  134. metadata +202 -0
@@ -0,0 +1,93 @@
1
+ Sequel.require 'adapters/utils/unsupported'
2
+
3
+ module Sequel
4
+ module MSSQL
5
+ module DatabaseMethods
6
+ AUTO_INCREMENT = 'IDENTITY(1,1)'.freeze
7
+ SQL_BEGIN = "BEGIN TRANSACTION".freeze
8
+ SQL_COMMIT = "COMMIT TRANSACTION".freeze
9
+ SQL_ROLLBACK = "ROLLBACK TRANSACTION".freeze
10
+
11
+ def auto_increment_sql
12
+ AUTO_INCREMENT
13
+ end
14
+
15
+ def dataset(opts = nil)
16
+ ds = super
17
+ ds.extend(DatasetMethods)
18
+ ds
19
+ end
20
+
21
+ private
22
+
23
+ # SQL to BEGIN a transaction.
24
+ def begin_transaction_sql
25
+ SQL_BEGIN
26
+ end
27
+
28
+ # SQL to COMMIT a transaction.
29
+ def commit_transaction_sql
30
+ SQL_COMMIT
31
+ end
32
+
33
+ # SQL to ROLLBACK a transaction.
34
+ def rollback_transaction_sql
35
+ SQL_ROLLBACK
36
+ end
37
+ end
38
+
39
+ module DatasetMethods
40
+ include Dataset::UnsupportedIntersectExcept
41
+
42
+ SELECT_CLAUSE_ORDER = %w'limit distinct columns from with join where group order having compounds'.freeze
43
+
44
+ def complex_expression_sql(op, args)
45
+ case op
46
+ when :'||'
47
+ super(:+, args)
48
+ else
49
+ super(op, args)
50
+ end
51
+ end
52
+
53
+ def full_text_search(cols, terms, opts = {})
54
+ filter("CONTAINS (#{literal(cols)}, #{literal(terms)})")
55
+ end
56
+
57
+ def multi_insert_sql(columns, values)
58
+ values = values.map {|r| "SELECT #{expression_list(r)}" }.join(" UNION ALL ")
59
+ ["INSERT INTO #{source_list(@opts[:from])} (#{identifier_list(columns)}) #{values}"]
60
+ end
61
+
62
+ # Allows you to do .nolock on a query
63
+ def nolock
64
+ clone(:with => "(NOLOCK)")
65
+ end
66
+
67
+ def quoted_identifier(name)
68
+ "[#{name}]"
69
+ end
70
+
71
+ private
72
+
73
+ def literal_string(v)
74
+ "N#{super}"
75
+ end
76
+
77
+ def select_clause_order
78
+ SELECT_CLAUSE_ORDER
79
+ end
80
+
81
+ # MSSQL uses TOP for limit, with no offset support
82
+ def select_limit_sql(sql, opts)
83
+ raise(Error, "OFFSET not supported") if opts[:offset]
84
+ sql << " TOP #{opts[:limit]}" if opts[:limit]
85
+ end
86
+
87
+ # MSSQL uses the WITH statement to lock tables
88
+ def select_with_sql(sql, opts)
89
+ sql << " WITH #{opts[:with]}" if opts[:with]
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,341 @@
1
+ Sequel.require 'adapters/utils/unsupported'
2
+
3
+ module Sequel
4
+ class Database
5
+ # Keep default column_references_sql for add_foreign_key support
6
+ alias default_column_references_sql column_references_sql
7
+ end
8
+ module MySQL
9
+ class << self
10
+ # Set the default options used for CREATE TABLE
11
+ attr_accessor :default_charset, :default_collate, :default_engine
12
+ end
13
+
14
+ # Methods shared by Database instances that connect to MySQL,
15
+ # currently supported by the native and JDBC adapters.
16
+ module DatabaseMethods
17
+ AUTO_INCREMENT = 'AUTO_INCREMENT'.freeze
18
+ NOT_NULL = Sequel::Database::NOT_NULL
19
+ NULL = Sequel::Database::NULL
20
+ PRIMARY_KEY = Sequel::Database::PRIMARY_KEY
21
+ TYPES = Sequel::Database::TYPES.merge(DateTime=>'datetime', \
22
+ TrueClass=>'tinyint', FalseClass=>'tinyint')
23
+ UNIQUE = Sequel::Database::UNIQUE
24
+ UNSIGNED = Sequel::Database::UNSIGNED
25
+
26
+ # Use MySQL specific syntax for rename column, set column type, and
27
+ # drop index cases.
28
+ def alter_table_sql(table, op)
29
+ case op[:op]
30
+ when :add_column
31
+ if related = op.delete(:table)
32
+ sql = super(table, op)
33
+ op[:table] = related
34
+ [sql, "ALTER TABLE #{quote_schema_table(table)} ADD FOREIGN KEY (#{quote_identifier(op[:name])})#{default_column_references_sql(op)}"]
35
+ else
36
+ super(table, op)
37
+ end
38
+ when :rename_column
39
+ "ALTER TABLE #{quote_schema_table(table)} CHANGE COLUMN #{quote_identifier(op[:name])} #{quote_identifier(op[:new_name])} #{type_literal(op)}"
40
+ when :set_column_type
41
+ "ALTER TABLE #{quote_schema_table(table)} CHANGE COLUMN #{quote_identifier(op[:name])} #{quote_identifier(op[:name])} #{type_literal(op)}"
42
+ when :drop_index
43
+ "#{drop_index_sql(table, op)} ON #{quote_schema_table(table)}"
44
+ else
45
+ super(table, op)
46
+ end
47
+ end
48
+
49
+ # Use MySQL specific AUTO_INCREMENT text.
50
+ def auto_increment_sql
51
+ AUTO_INCREMENT
52
+ end
53
+
54
+ # Handle MySQL specific syntax for column references
55
+ def column_references_sql(column)
56
+ "#{", FOREIGN KEY (#{quote_identifier(column[:name])})" unless column[:type] == :check}#{super(column)}"
57
+ end
58
+
59
+ # Use MySQL specific syntax for engine type and character encoding
60
+ def create_table_sql_list(name, columns, indexes = nil, options = {})
61
+ options[:engine] = Sequel::MySQL.default_engine unless options.include?(:engine)
62
+ options[:charset] = Sequel::MySQL.default_charset unless options.include?(:charset)
63
+ options[:collate] = Sequel::MySQL.default_collate unless options.include?(:collate)
64
+ sql = ["CREATE TABLE #{quote_schema_table(name)} (#{column_list_sql(columns)})#{" ENGINE=#{options[:engine]}" if options[:engine]}#{" DEFAULT CHARSET=#{options[:charset]}" if options[:charset]}#{" DEFAULT COLLATE=#{options[:collate]}" if options[:collate]}"]
65
+ sql.concat(index_list_sql_list(name, indexes)) if indexes && !indexes.empty?
66
+ sql
67
+ end
68
+
69
+ # Handle MySQL specific index SQL syntax
70
+ def index_definition_sql(table_name, index)
71
+ index_name = quote_identifier(index[:name] || default_index_name(table_name, index[:columns]))
72
+ index_type = case index[:type]
73
+ when :full_text
74
+ "FULLTEXT "
75
+ when :spatial
76
+ "SPATIAL "
77
+ else
78
+ using = " USING #{index[:type]}" unless index[:type] == nil
79
+ "UNIQUE " if index[:unique]
80
+ end
81
+ "CREATE #{index_type}INDEX #{index_name} ON #{quote_schema_table(table_name)} #{literal(index[:columns])}#{using}"
82
+ end
83
+
84
+ # Get version of MySQL server, used for determined capabilities.
85
+ def server_version
86
+ m = /(\d+)\.(\d+)\.(\d+)/.match(get(SQL::Function.new(:version)))
87
+ @server_version ||= (m[1].to_i * 10000) + (m[2].to_i * 100) + m[3].to_i
88
+ end
89
+
90
+ # Return an array of symbols specifying table names in the current database.
91
+ #
92
+ # Options:
93
+ # * :server - Set the server to use
94
+ def tables(opts={})
95
+ ds = self['SHOW TABLES'].server(opts[:server])
96
+ ds.identifier_output_method = nil
97
+ ds2 = dataset
98
+ ds.map{|r| ds2.send(:output_identifier, r.values.first)}
99
+ end
100
+
101
+ # Changes the database in use by issuing a USE statement. I would be
102
+ # very careful if I used this.
103
+ def use(db_name)
104
+ disconnect
105
+ @opts[:database] = db_name if self << "USE #{db_name}"
106
+ @schemas = nil
107
+ self
108
+ end
109
+
110
+ private
111
+
112
+ # MySQL folds unquoted identifiers to lowercase, so it shouldn't need to upcase identifiers on input.
113
+ def identifier_input_method_default
114
+ nil
115
+ end
116
+
117
+ # MySQL folds unquoted identifiers to lowercase, so it shouldn't need to upcase identifiers on output.
118
+ def identifier_output_method_default
119
+ nil
120
+ end
121
+
122
+ # Use the MySQL specific DESCRIBE syntax to get a table description.
123
+ def schema_parse_table(table_name, opts)
124
+ ds = self["DESCRIBE ?", SQL::Identifier.new(table_name)]
125
+ ds.identifier_output_method = nil
126
+ ds2 = dataset
127
+ ds.map do |row|
128
+ row.delete(:Extra)
129
+ row[:allow_null] = row.delete(:Null) == 'YES'
130
+ row[:default] = row.delete(:Default)
131
+ row[:primary_key] = row.delete(:Key) == 'PRI'
132
+ row[:default] = nil if blank_object?(row[:default])
133
+ row[:db_type] = row.delete(:Type)
134
+ row[:type] = schema_column_type(row[:db_type])
135
+ [ds2.send(:output_identifier, row.delete(:Field)), row]
136
+ end
137
+ end
138
+
139
+ # Override the standard type conversions with MySQL specific ones
140
+ def type_literal_base(column)
141
+ TYPES[column[:type]]
142
+ end
143
+ end
144
+
145
+ # Dataset methods shared by datasets that use MySQL databases.
146
+ module DatasetMethods
147
+ include Dataset::UnsupportedIntersectExcept
148
+
149
+ BOOL_TRUE = '1'.freeze
150
+ BOOL_FALSE = '0'.freeze
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
153
+ COMMA_SEPARATOR = ', '.freeze
154
+
155
+ # MySQL can't use the varchar type in a cast.
156
+ def cast_sql(expr, type)
157
+ "CAST(#{literal(expr)} AS #{CAST_TYPES[type] || db.send(:type_literal_base, :type=>type)})"
158
+ end
159
+
160
+ # MySQL specific syntax for LIKE/REGEXP searches, as well as
161
+ # string concatenation.
162
+ def complex_expression_sql(op, args)
163
+ case op
164
+ when :~, :'!~', :'~*', :'!~*', :LIKE, :'NOT LIKE', :ILIKE, :'NOT ILIKE'
165
+ "(#{literal(args.at(0))} #{'NOT ' if [:'NOT LIKE', :'NOT ILIKE', :'!~', :'!~*'].include?(op)}#{[:~, :'!~', :'~*', :'!~*'].include?(op) ? 'REGEXP' : 'LIKE'} #{'BINARY ' if [:~, :'!~', :LIKE, :'NOT LIKE'].include?(op)}#{literal(args.at(1))})"
166
+ when :'||'
167
+ if args.length > 1
168
+ "CONCAT(#{args.collect{|a| literal(a)}.join(', ')})"
169
+ else
170
+ literal(args.at(0))
171
+ end
172
+ else
173
+ super(op, args)
174
+ end
175
+ end
176
+
177
+ # MySQL supports ORDER and LIMIT clauses in DELETE statements.
178
+ def delete_sql(opts = (defarg=true;nil))
179
+ if defarg
180
+ sql = super()
181
+ opts = @opts
182
+ else
183
+ sql = super
184
+ opts = opts ? @opts.merge(opts) : @opts
185
+ end
186
+
187
+ if order = opts[:order]
188
+ sql << " ORDER BY #{expression_list(order)}"
189
+ end
190
+ if limit = opts[:limit]
191
+ sql << " LIMIT #{limit}"
192
+ end
193
+
194
+ sql
195
+ end
196
+
197
+ # MySQL doesn't support DISTINCT ON
198
+ def distinct(*columns)
199
+ raise(Error, "DISTINCT ON not supported by MySQL") unless columns.empty?
200
+ super
201
+ end
202
+
203
+ # MySQL specific full text search syntax.
204
+ def full_text_search(cols, terms, opts = {})
205
+ mode = opts[:boolean] ? " IN BOOLEAN MODE" : ""
206
+ s = if Array === terms
207
+ if mode.empty?
208
+ "MATCH #{literal(Array(cols))} AGAINST #{literal(terms)}"
209
+ else
210
+ "MATCH #{literal(Array(cols))} AGAINST (#{literal(terms)[1...-1]}#{mode})"
211
+ end
212
+ else
213
+ "MATCH #{literal(Array(cols))} AGAINST (#{literal(terms)}#{mode})"
214
+ end
215
+ filter(s)
216
+ end
217
+
218
+ # MySQL allows HAVING clause on ungrouped datasets.
219
+ def having(*cond, &block)
220
+ _filter(:having, *cond, &block)
221
+ end
222
+
223
+ # MySQL doesn't use the SQL standard DEFAULT VALUES.
224
+ def insert_default_values_sql
225
+ "INSERT INTO #{source_list(@opts[:from])} () VALUES ()"
226
+ end
227
+
228
+ # Transforms an CROSS JOIN to an INNER JOIN if the expr is not nil.
229
+ # Raises an error on use of :full_outer type, since MySQL doesn't support it.
230
+ def join_table(type, table, expr=nil, table_alias={})
231
+ type = :inner if (type == :cross) && !expr.nil?
232
+ raise(Sequel::Error, "MySQL doesn't support FULL OUTER JOIN") if type == :full_outer
233
+ super(type, table, expr, table_alias)
234
+ end
235
+
236
+ # Transforms :natural_inner to NATURAL LEFT JOIN and straight to
237
+ # STRAIGHT_JOIN.
238
+ def join_type_sql(join_type)
239
+ case join_type
240
+ when :straight then 'STRAIGHT_JOIN'
241
+ when :natural_inner then 'NATURAL LEFT JOIN'
242
+ else super
243
+ end
244
+ end
245
+
246
+ # MySQL specific syntax for inserting multiple values at once.
247
+ def multi_insert_sql(columns, values)
248
+ values = values.map {|r| literal(Array(r))}.join(COMMA_SEPARATOR)
249
+ ["INSERT INTO #{source_list(@opts[:from])} (#{identifier_list(columns)}) VALUES #{values}"]
250
+ end
251
+
252
+ # MySQL uses the nonstandard ` (backtick) for quoting identifiers.
253
+ def quoted_identifier(c)
254
+ "`#{c}`"
255
+ end
256
+
257
+ # MySQL specific syntax for REPLACE (aka UPSERT, or update if exists,
258
+ # insert if it doesn't).
259
+ def replace_sql(*values)
260
+ from = source_list(@opts[:from])
261
+ if values.empty?
262
+ "REPLACE INTO #{from} DEFAULT VALUES"
263
+ else
264
+ values = values[0] if values.size == 1
265
+
266
+ # if hash or array with keys we need to transform the values
267
+ if @transform && (values.is_a?(Hash) || (values.is_a?(Array) && values.keys))
268
+ values = transform_save(values)
269
+ end
270
+
271
+ case values
272
+ when Array
273
+ if values.empty?
274
+ "REPLACE INTO #{from} DEFAULT VALUES"
275
+ else
276
+ "REPLACE INTO #{from} VALUES #{literal(values)}"
277
+ end
278
+ when Hash
279
+ if values.empty?
280
+ "REPLACE INTO #{from} DEFAULT VALUES"
281
+ else
282
+ fl, vl = [], []
283
+ values.each {|k, v| fl << literal(k.is_a?(String) ? k.to_sym : k); vl << literal(v)}
284
+ "REPLACE INTO #{from} (#{fl.join(COMMA_SEPARATOR)}) VALUES (#{vl.join(COMMA_SEPARATOR)})"
285
+ end
286
+ when Dataset
287
+ "REPLACE INTO #{from} #{literal(values)}"
288
+ else
289
+ if values.respond_to?(:values)
290
+ replace_sql(values.values)
291
+ else
292
+ "REPLACE INTO #{from} VALUES (#{literal(values)})"
293
+ end
294
+ end
295
+ end
296
+ end
297
+
298
+ # MySQL supports ORDER and LIMIT clauses in UPDATE statements.
299
+ def update_sql(values, opts = (defarg=true;nil))
300
+ if defarg
301
+ sql = super(values)
302
+ opts = @opts
303
+ else
304
+ sql = super
305
+ opts = opts ? @opts.merge(opts) : @opts
306
+ end
307
+
308
+ if order = opts[:order]
309
+ sql << " ORDER BY #{expression_list(order)}"
310
+ end
311
+ if limit = opts[:limit]
312
+ sql << " LIMIT #{limit}"
313
+ end
314
+
315
+ sql
316
+ end
317
+
318
+ private
319
+
320
+ # Use MySQL Timestamp format
321
+ def literal_datetime(v)
322
+ v.strftime(TIMESTAMP_FORMAT)
323
+ end
324
+
325
+ # Use 0 for false on MySQL
326
+ def literal_false
327
+ BOOL_FALSE
328
+ end
329
+
330
+ # Use MySQL Timestamp format
331
+ def literal_time(v)
332
+ v.strftime(TIMESTAMP_FORMAT)
333
+ end
334
+
335
+ # Use 1 for true on MySQL
336
+ def literal_true
337
+ BOOL_TRUE
338
+ end
339
+ end
340
+ end
341
+ end
@@ -0,0 +1,62 @@
1
+ Sequel.require %w'date_format unsupported', 'adapters/utils'
2
+
3
+ module Sequel
4
+ module Oracle
5
+ module DatabaseMethods
6
+ def tables(opts={})
7
+ ds = from(:tab).server(opts[:server]).select(:tname).filter(:tabtype => 'TABLE')
8
+ ds.map{|r| ds.send(:output_identifier, r[:tname])}
9
+ end
10
+
11
+ def table_exists?(name)
12
+ from(:tab).filter(:tname =>dataset.send(:input_identifier, name), :tabtype => 'TABLE').count > 0
13
+ end
14
+ end
15
+
16
+ module DatasetMethods
17
+ include Dataset::UnsupportedIntersectExceptAll
18
+ include Dataset::SQLStandardDateFormat
19
+
20
+ SELECT_CLAUSE_ORDER = %w'distinct columns from join where group having compounds order limit'.freeze
21
+
22
+ # Oracle doesn't support DISTINCT ON
23
+ def distinct(*columns)
24
+ raise(Error, "DISTINCT ON not supported by Oracle") unless columns.empty?
25
+ super
26
+ end
27
+
28
+ # Oracle uses MINUS instead of EXCEPT, and doesn't support EXCEPT ALL
29
+ def except(dataset, all = false)
30
+ raise(Sequel::Error, "EXCEPT ALL not supported") if all
31
+ compound_clone(:minus, dataset, all)
32
+ end
33
+
34
+ def empty?
35
+ db[:dual].where(exists).get(1) == nil
36
+ end
37
+
38
+ private
39
+
40
+ # Oracle doesn't support the use of AS when aliasing a dataset. It doesn't require
41
+ # the use of AS anywhere, so this disables it in all cases.
42
+ def as_sql(expression, aliaz)
43
+ "#{expression} #{quote_identifier(aliaz)}"
44
+ end
45
+
46
+ def select_clause_order
47
+ SELECT_CLAUSE_ORDER
48
+ end
49
+
50
+ # Oracle requires a subselect to do limit and offset
51
+ def select_limit_sql(sql, opts)
52
+ if limit = opts[:limit]
53
+ if (offset = opts[:offset]) && (offset > 0)
54
+ sql.replace("SELECT * FROM (SELECT raw_sql_.*, ROWNUM raw_rnum_ FROM(#{sql}) raw_sql_ WHERE ROWNUM <= #{limit + offset}) WHERE raw_rnum_ > #{offset}")
55
+ else
56
+ sql.replace("SELECT * FROM (#{sql}) WHERE ROWNUM <= #{limit}")
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end