sequel 3.21.0 → 3.31.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 (225) hide show
  1. data/CHANGELOG +485 -3
  2. data/README.rdoc +20 -6
  3. data/Rakefile +37 -19
  4. data/bin/sequel +1 -5
  5. data/doc/association_basics.rdoc +249 -43
  6. data/doc/dataset_basics.rdoc +4 -4
  7. data/doc/dataset_filtering.rdoc +8 -0
  8. data/doc/mass_assignment.rdoc +54 -0
  9. data/doc/migration.rdoc +15 -538
  10. data/doc/model_hooks.rdoc +72 -27
  11. data/doc/opening_databases.rdoc +89 -50
  12. data/doc/prepared_statements.rdoc +40 -13
  13. data/doc/reflection.rdoc +8 -2
  14. data/doc/release_notes/3.22.0.txt +39 -0
  15. data/doc/release_notes/3.23.0.txt +172 -0
  16. data/doc/release_notes/3.24.0.txt +420 -0
  17. data/doc/release_notes/3.25.0.txt +88 -0
  18. data/doc/release_notes/3.26.0.txt +88 -0
  19. data/doc/release_notes/3.27.0.txt +82 -0
  20. data/doc/release_notes/3.28.0.txt +304 -0
  21. data/doc/release_notes/3.29.0.txt +459 -0
  22. data/doc/release_notes/3.30.0.txt +135 -0
  23. data/doc/release_notes/3.31.0.txt +146 -0
  24. data/doc/schema_modification.rdoc +547 -0
  25. data/doc/sharding.rdoc +7 -1
  26. data/doc/testing.rdoc +129 -0
  27. data/doc/transactions.rdoc +137 -0
  28. data/doc/virtual_rows.rdoc +2 -2
  29. data/lib/sequel/adapters/ado/mssql.rb +18 -6
  30. data/lib/sequel/adapters/ado.rb +40 -18
  31. data/lib/sequel/adapters/amalgalite.rb +17 -9
  32. data/lib/sequel/adapters/db2.rb +175 -86
  33. data/lib/sequel/adapters/dbi.rb +15 -15
  34. data/lib/sequel/adapters/do/mysql.rb +5 -7
  35. data/lib/sequel/adapters/do/postgres.rb +0 -5
  36. data/lib/sequel/adapters/do/sqlite.rb +0 -5
  37. data/lib/sequel/adapters/do.rb +17 -36
  38. data/lib/sequel/adapters/firebird.rb +27 -208
  39. data/lib/sequel/adapters/ibmdb.rb +448 -0
  40. data/lib/sequel/adapters/informix.rb +6 -23
  41. data/lib/sequel/adapters/jdbc/as400.rb +16 -34
  42. data/lib/sequel/adapters/jdbc/db2.rb +45 -0
  43. data/lib/sequel/adapters/jdbc/derby.rb +247 -0
  44. data/lib/sequel/adapters/jdbc/firebird.rb +29 -0
  45. data/lib/sequel/adapters/jdbc/h2.rb +56 -29
  46. data/lib/sequel/adapters/jdbc/hsqldb.rb +170 -0
  47. data/lib/sequel/adapters/jdbc/informix.rb +26 -0
  48. data/lib/sequel/adapters/jdbc/jtds.rb +34 -0
  49. data/lib/sequel/adapters/jdbc/mssql.rb +3 -33
  50. data/lib/sequel/adapters/jdbc/mysql.rb +11 -11
  51. data/lib/sequel/adapters/jdbc/oracle.rb +81 -25
  52. data/lib/sequel/adapters/jdbc/postgresql.rb +9 -13
  53. data/lib/sequel/adapters/jdbc/sqlite.rb +2 -6
  54. data/lib/sequel/adapters/jdbc/sqlserver.rb +71 -0
  55. data/lib/sequel/adapters/jdbc/transactions.rb +83 -0
  56. data/lib/sequel/adapters/jdbc.rb +231 -78
  57. data/lib/sequel/adapters/mock.rb +335 -0
  58. data/lib/sequel/adapters/mysql.rb +82 -184
  59. data/lib/sequel/adapters/mysql2.rb +26 -25
  60. data/lib/sequel/adapters/odbc/db2.rb +17 -0
  61. data/lib/sequel/adapters/odbc/mssql.rb +1 -6
  62. data/lib/sequel/adapters/odbc.rb +28 -9
  63. data/lib/sequel/adapters/openbase.rb +3 -5
  64. data/lib/sequel/adapters/oracle.rb +351 -53
  65. data/lib/sequel/adapters/postgres.rb +194 -33
  66. data/lib/sequel/adapters/shared/access.rb +32 -9
  67. data/lib/sequel/adapters/shared/db2.rb +321 -0
  68. data/lib/sequel/adapters/shared/firebird.rb +221 -0
  69. data/lib/sequel/adapters/shared/informix.rb +53 -0
  70. data/lib/sequel/adapters/shared/mssql.rb +231 -106
  71. data/lib/sequel/adapters/shared/mysql.rb +181 -63
  72. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +149 -0
  73. data/lib/sequel/adapters/shared/oracle.rb +231 -41
  74. data/lib/sequel/adapters/shared/postgres.rb +214 -82
  75. data/lib/sequel/adapters/shared/progress.rb +4 -7
  76. data/lib/sequel/adapters/shared/sqlite.rb +201 -57
  77. data/lib/sequel/adapters/sqlite.rb +29 -21
  78. data/lib/sequel/adapters/swift/mysql.rb +12 -7
  79. data/lib/sequel/adapters/swift/postgres.rb +0 -5
  80. data/lib/sequel/adapters/swift/sqlite.rb +8 -6
  81. data/lib/sequel/adapters/swift.rb +5 -5
  82. data/lib/sequel/adapters/tinytds.rb +160 -19
  83. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +66 -0
  84. data/lib/sequel/adapters/utils/stored_procedures.rb +1 -11
  85. data/lib/sequel/ast_transformer.rb +190 -0
  86. data/lib/sequel/connection_pool/threaded.rb +3 -2
  87. data/lib/sequel/connection_pool.rb +1 -1
  88. data/lib/sequel/core.rb +46 -5
  89. data/lib/sequel/database/connecting.rb +5 -6
  90. data/lib/sequel/database/dataset.rb +4 -4
  91. data/lib/sequel/database/dataset_defaults.rb +59 -1
  92. data/lib/sequel/database/logging.rb +1 -1
  93. data/lib/sequel/database/misc.rb +104 -19
  94. data/lib/sequel/database/query.rb +153 -58
  95. data/lib/sequel/database/schema_generator.rb +17 -7
  96. data/lib/sequel/database/schema_methods.rb +59 -29
  97. data/lib/sequel/dataset/actions.rb +231 -76
  98. data/lib/sequel/dataset/features.rb +91 -8
  99. data/lib/sequel/dataset/graph.rb +38 -11
  100. data/lib/sequel/dataset/misc.rb +50 -23
  101. data/lib/sequel/dataset/mutation.rb +5 -6
  102. data/lib/sequel/dataset/prepared_statements.rb +48 -27
  103. data/lib/sequel/dataset/query.rb +236 -43
  104. data/lib/sequel/dataset/sql.rb +665 -253
  105. data/lib/sequel/dataset.rb +8 -0
  106. data/lib/sequel/exceptions.rb +4 -0
  107. data/lib/sequel/extensions/columns_introspection.rb +61 -0
  108. data/lib/sequel/extensions/migration.rb +6 -4
  109. data/lib/sequel/extensions/named_timezones.rb +5 -0
  110. data/lib/sequel/extensions/thread_local_timezones.rb +1 -1
  111. data/lib/sequel/extensions/to_dot.rb +95 -83
  112. data/lib/sequel/model/associations.rb +1020 -337
  113. data/lib/sequel/model/base.rb +414 -132
  114. data/lib/sequel/model/errors.rb +1 -1
  115. data/lib/sequel/model/exceptions.rb +5 -1
  116. data/lib/sequel/model.rb +15 -8
  117. data/lib/sequel/plugins/association_pks.rb +22 -4
  118. data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
  119. data/lib/sequel/plugins/dataset_associations.rb +100 -0
  120. data/lib/sequel/plugins/defaults_setter.rb +58 -0
  121. data/lib/sequel/plugins/force_encoding.rb +6 -6
  122. data/lib/sequel/plugins/identity_map.rb +114 -7
  123. data/lib/sequel/plugins/many_through_many.rb +65 -7
  124. data/lib/sequel/plugins/prepared_statements.rb +151 -0
  125. data/lib/sequel/plugins/prepared_statements_associations.rb +84 -0
  126. data/lib/sequel/plugins/prepared_statements_safe.rb +82 -0
  127. data/lib/sequel/plugins/prepared_statements_with_pk.rb +59 -0
  128. data/lib/sequel/plugins/rcte_tree.rb +29 -15
  129. data/lib/sequel/plugins/serialization.rb +88 -44
  130. data/lib/sequel/plugins/serialization_modification_detection.rb +51 -0
  131. data/lib/sequel/plugins/sharding.rb +21 -54
  132. data/lib/sequel/plugins/single_table_inheritance.rb +3 -1
  133. data/lib/sequel/plugins/typecast_on_load.rb +9 -12
  134. data/lib/sequel/plugins/update_primary_key.rb +2 -2
  135. data/lib/sequel/plugins/xml_serializer.rb +3 -3
  136. data/lib/sequel/sql.rb +109 -52
  137. data/lib/sequel/timezones.rb +57 -38
  138. data/lib/sequel/version.rb +1 -1
  139. data/spec/adapters/db2_spec.rb +146 -0
  140. data/spec/adapters/mssql_spec.rb +111 -29
  141. data/spec/adapters/mysql_spec.rb +135 -123
  142. data/spec/adapters/oracle_spec.rb +49 -77
  143. data/spec/adapters/postgres_spec.rb +267 -78
  144. data/spec/adapters/spec_helper.rb +6 -5
  145. data/spec/adapters/sqlite_spec.rb +35 -21
  146. data/spec/core/connection_pool_spec.rb +71 -92
  147. data/spec/core/core_sql_spec.rb +21 -30
  148. data/spec/core/database_spec.rb +788 -512
  149. data/spec/core/dataset_spec.rb +1073 -1053
  150. data/spec/core/expression_filters_spec.rb +159 -42
  151. data/spec/core/mock_adapter_spec.rb +419 -0
  152. data/spec/core/object_graph_spec.rb +86 -114
  153. data/spec/core/schema_generator_spec.rb +3 -3
  154. data/spec/core/schema_spec.rb +298 -38
  155. data/spec/core/spec_helper.rb +6 -48
  156. data/spec/extensions/association_autoreloading_spec.rb +1 -10
  157. data/spec/extensions/association_dependencies_spec.rb +2 -12
  158. data/spec/extensions/association_pks_spec.rb +66 -32
  159. data/spec/extensions/caching_spec.rb +23 -50
  160. data/spec/extensions/class_table_inheritance_spec.rb +31 -83
  161. data/spec/extensions/columns_introspection_spec.rb +91 -0
  162. data/spec/extensions/composition_spec.rb +18 -13
  163. data/spec/extensions/dataset_associations_spec.rb +199 -0
  164. data/spec/extensions/defaults_setter_spec.rb +64 -0
  165. data/spec/extensions/hook_class_methods_spec.rb +65 -91
  166. data/spec/extensions/identity_map_spec.rb +114 -22
  167. data/spec/extensions/instance_filters_spec.rb +11 -21
  168. data/spec/extensions/instance_hooks_spec.rb +53 -0
  169. data/spec/extensions/json_serializer_spec.rb +4 -5
  170. data/spec/extensions/lazy_attributes_spec.rb +16 -20
  171. data/spec/extensions/list_spec.rb +17 -39
  172. data/spec/extensions/many_through_many_spec.rb +283 -250
  173. data/spec/extensions/migration_spec.rb +35 -32
  174. data/spec/extensions/named_timezones_spec.rb +23 -3
  175. data/spec/extensions/nested_attributes_spec.rb +97 -88
  176. data/spec/extensions/optimistic_locking_spec.rb +9 -20
  177. data/spec/extensions/prepared_statements_associations_spec.rb +111 -0
  178. data/spec/extensions/prepared_statements_safe_spec.rb +61 -0
  179. data/spec/extensions/prepared_statements_spec.rb +53 -0
  180. data/spec/extensions/prepared_statements_with_pk_spec.rb +31 -0
  181. data/spec/extensions/pretty_table_spec.rb +1 -6
  182. data/spec/extensions/rcte_tree_spec.rb +41 -43
  183. data/spec/extensions/schema_dumper_spec.rb +5 -8
  184. data/spec/extensions/schema_spec.rb +13 -21
  185. data/spec/extensions/serialization_modification_detection_spec.rb +37 -0
  186. data/spec/extensions/serialization_spec.rb +72 -43
  187. data/spec/extensions/sharding_spec.rb +66 -140
  188. data/spec/extensions/single_table_inheritance_spec.rb +18 -29
  189. data/spec/extensions/spec_helper.rb +13 -61
  190. data/spec/extensions/sql_expr_spec.rb +20 -60
  191. data/spec/extensions/tactical_eager_loading_spec.rb +9 -19
  192. data/spec/extensions/thread_local_timezones_spec.rb +22 -2
  193. data/spec/extensions/timestamps_spec.rb +6 -6
  194. data/spec/extensions/to_dot_spec.rb +4 -7
  195. data/spec/extensions/touch_spec.rb +13 -14
  196. data/spec/extensions/tree_spec.rb +11 -26
  197. data/spec/extensions/typecast_on_load_spec.rb +1 -6
  198. data/spec/extensions/update_primary_key_spec.rb +30 -24
  199. data/spec/extensions/validation_class_methods_spec.rb +30 -51
  200. data/spec/extensions/validation_helpers_spec.rb +16 -35
  201. data/spec/extensions/xml_serializer_spec.rb +16 -4
  202. data/spec/integration/associations_test.rb +537 -21
  203. data/spec/integration/database_test.rb +4 -2
  204. data/spec/integration/dataset_test.rb +461 -65
  205. data/spec/integration/eager_loader_test.rb +19 -21
  206. data/spec/integration/model_test.rb +80 -1
  207. data/spec/integration/plugin_test.rb +304 -116
  208. data/spec/integration/prepared_statement_test.rb +212 -122
  209. data/spec/integration/schema_test.rb +161 -30
  210. data/spec/integration/spec_helper.rb +39 -30
  211. data/spec/integration/timezone_test.rb +38 -12
  212. data/spec/integration/transaction_test.rb +172 -5
  213. data/spec/integration/type_test.rb +17 -3
  214. data/spec/model/association_reflection_spec.rb +201 -7
  215. data/spec/model/associations_spec.rb +865 -662
  216. data/spec/model/base_spec.rb +275 -95
  217. data/spec/model/dataset_methods_spec.rb +7 -27
  218. data/spec/model/eager_loading_spec.rb +677 -676
  219. data/spec/model/hooks_spec.rb +309 -67
  220. data/spec/model/model_spec.rb +222 -168
  221. data/spec/model/plugins_spec.rb +24 -13
  222. data/spec/model/record_spec.rb +381 -218
  223. data/spec/model/spec_helper.rb +13 -71
  224. data/spec/model/validations_spec.rb +11 -0
  225. metadata +115 -73
@@ -1,9 +1,13 @@
1
+ Sequel.require 'adapters/utils/emulate_offset_with_row_number'
2
+
1
3
  module Sequel
2
4
  module Oracle
3
5
  module DatabaseMethods
4
6
  TEMPORARY = 'GLOBAL TEMPORARY '.freeze
5
7
  AUTOINCREMENT = ''.freeze
6
8
 
9
+ attr_accessor :autosequence
10
+
7
11
  def create_sequence(name, opts={})
8
12
  self << create_sequence_sql(name, opts)
9
13
  end
@@ -12,6 +16,10 @@ module Sequel
12
16
  self << create_trigger_sql(*args)
13
17
  end
14
18
 
19
+ def current_user
20
+ @current_user ||= get{sys_context('USERENV', 'CURRENT_USER')}
21
+ end
22
+
15
23
  def drop_sequence(name)
16
24
  self << drop_sequence_sql(name)
17
25
  end
@@ -26,10 +34,6 @@ module Sequel
26
34
  ds.map{|r| ds.send(:output_identifier, r[:tname])}
27
35
  end
28
36
 
29
- def table_exists?(name)
30
- from(:tab).filter(:tname =>dataset.send(:input_identifier, name), :tabtype => 'TABLE').count > 0
31
- end
32
-
33
37
  def views(opts={})
34
38
  ds = from(:tab).server(opts[:server]).select(:tname).filter(:tabtype => 'VIEW')
35
39
  ds.map{|r| ds.send(:output_identifier, r[:tname])}
@@ -41,13 +45,37 @@ module Sequel
41
45
 
42
46
  private
43
47
 
44
- def auto_increment_sql
45
- AUTOINCREMENT
48
+ # Handle Oracle specific ALTER TABLE SQL
49
+ def alter_table_sql(table, op)
50
+ case op[:op]
51
+ when :add_column
52
+ if op[:primary_key]
53
+ sqls = []
54
+ sqls << alter_table_sql(table, op.merge(:primary_key=>nil))
55
+ if op[:auto_increment]
56
+ seq_name = default_sequence_name(table, op[:name])
57
+ sqls << drop_sequence_sql(seq_name)
58
+ sqls << create_sequence_sql(seq_name, op)
59
+ sqls << "UPDATE #{quote_schema_table(table)} SET #{quote_identifier(op[:name])} = #{seq_name}.nextval"
60
+ end
61
+ sqls << "ALTER TABLE #{quote_schema_table(table)} ADD PRIMARY KEY (#{quote_identifier(op[:name])})"
62
+ sqls
63
+ else
64
+ "ALTER TABLE #{quote_schema_table(table)} ADD #{column_definition_sql(op)}"
65
+ end
66
+ when :set_column_null
67
+ "ALTER TABLE #{quote_schema_table(table)} MODIFY #{quote_identifier(op[:name])} #{op[:null] ? 'NULL' : 'NOT NULL'}"
68
+ when :set_column_type
69
+ "ALTER TABLE #{quote_schema_table(table)} MODIFY #{quote_identifier(op[:name])} #{type_literal(op)}"
70
+ when :set_column_default
71
+ "ALTER TABLE #{quote_schema_table(table)} MODIFY #{quote_identifier(op[:name])} DEFAULT #{literal(op[:default])}"
72
+ else
73
+ super(table, op)
74
+ end
46
75
  end
47
76
 
48
- # SQL fragment for showing a table is temporary
49
- def temporary_table_sql
50
- TEMPORARY
77
+ def auto_increment_sql
78
+ AUTOINCREMENT
51
79
  end
52
80
 
53
81
  def create_sequence_sql(name, opts={})
@@ -65,7 +93,7 @@ module Sequel
65
93
  drop_seq_statement = nil
66
94
  generator.columns.each do |c|
67
95
  if c[:auto_increment]
68
- c[:sequence_name] ||= "seq_#{name}_#{c[:name]}"
96
+ c[:sequence_name] ||= default_sequence_name(name, c[:name])
69
97
  unless c[:create_sequence] == false
70
98
  drop_seq_statement = drop_sequence_sql(c[:sequence_name])
71
99
  statements << create_sequence_sql(c[:sequence_name], c)
@@ -97,13 +125,120 @@ module Sequel
97
125
  sql
98
126
  end
99
127
 
128
+ def default_sequence_name(table, column)
129
+ "seq_#{table}_#{column}"
130
+ end
131
+
100
132
  def drop_sequence_sql(name)
101
133
  "DROP SEQUENCE #{quote_identifier(name)}"
102
134
  end
135
+
136
+ def remove_cached_schema(table)
137
+ @primary_key_sequences.delete(table)
138
+ super
139
+ end
140
+
141
+ def sequence_for_table(table)
142
+ return nil unless autosequence
143
+ @primary_key_sequences.fetch(table) do |key|
144
+ pk = schema(table).select{|k, v| v[:primary_key]}
145
+ @primary_key_sequences[table] = if pk.length == 1
146
+ seq = "seq_#{table}_#{pk.first.first}"
147
+ seq.to_sym unless from(:user_sequences).filter(:sequence_name=>input_identifier_meth.call(seq)).empty?
148
+ end
149
+ end
150
+ end
151
+
152
+ # Oracle's integer/:number type handles larger values than
153
+ # most other databases's bigint types, so it should be
154
+ # safe to use for Bignum.
155
+ def type_literal_generic_bignum(column)
156
+ :integer
157
+ end
158
+
159
+ # Oracle doesn't have a time type, so use timestamp for all
160
+ # time columns.
161
+ def type_literal_generic_time(column)
162
+ :timestamp
163
+ end
164
+
165
+ # Oracle doesn't have a boolean type or even a reasonable
166
+ # facsimile. Using a char(1) seems to be the recommended way.
167
+ def type_literal_generic_trueclass(column)
168
+ :'char(1)'
169
+ end
170
+
171
+ # SQL fragment for showing a table is temporary
172
+ def temporary_table_sql
173
+ TEMPORARY
174
+ end
103
175
  end
104
176
 
105
177
  module DatasetMethods
106
- SELECT_CLAUSE_METHODS = Dataset.clause_methods(:select, %w'with distinct columns from join where group having compounds order limit lock')
178
+ include EmulateOffsetWithRowNumber
179
+
180
+ SELECT_CLAUSE_METHODS = Dataset.clause_methods(:select, %w'with select distinct columns from join where group having compounds order lock')
181
+ ROW_NUMBER_EXPRESSION = 'ROWNUM'.lit.freeze
182
+ SPACE = Dataset::SPACE
183
+ APOS = Dataset::APOS
184
+ APOS_RE = Dataset::APOS_RE
185
+ DOUBLE_APOS = Dataset::DOUBLE_APOS
186
+ FROM = Dataset::FROM
187
+ BITCOMP_OPEN = "((0 - ".freeze
188
+ BITCOMP_CLOSE = ") - 1)".freeze
189
+ ILIKE_0 = "(UPPER(".freeze
190
+ ILIKE_1 = ") ".freeze
191
+ ILIKE_2 = ' UPPER('.freeze
192
+ ILIKE_3 = "))".freeze
193
+ LIKE = 'LIKE'.freeze
194
+ NOT_LIKE = 'NOT LIKE'.freeze
195
+ TIMESTAMP_FORMAT = "TIMESTAMP '%Y-%m-%d %H:%M:%S%N %z'".freeze
196
+ TIMESTAMP_OFFSET_FORMAT = "%+03i:%02i".freeze
197
+ BOOL_FALSE = "'N'".freeze
198
+ BOOL_TRUE = "'Y'".freeze
199
+ HSTAR = "H*".freeze
200
+ DUAL = ['DUAL'.freeze].freeze
201
+
202
+ # Oracle needs to emulate bitwise operators and ILIKE/NOT ILIKE operators.
203
+ def complex_expression_sql_append(sql, op, args)
204
+ case op
205
+ when :&
206
+ sql << complex_expression_arg_pairs(args){|a, b| "CAST(BITAND(#{literal(a)}, #{literal(b)}) AS INTEGER)"}
207
+ when :|
208
+ sql << complex_expression_arg_pairs(args){|a, b| "(#{literal(a)} - #{complex_expression_sql(:&, [a, b])} + #{literal(b)})"}
209
+ when :^
210
+ sql << complex_expression_arg_pairs(args){|*x| "(#{complex_expression_sql(:|, x)} - #{complex_expression_sql(:&, x)})"}
211
+ when :'B~'
212
+ sql << BITCOMP_OPEN
213
+ literal_append(sql, args.at(0))
214
+ sql << BITCOMP_CLOSE
215
+ when :<<
216
+ sql << complex_expression_arg_pairs(args){|a, b| "(#{literal(a)} * power(2, #{literal b}))"}
217
+ when :>>
218
+ sql << complex_expression_arg_pairs(args){|a, b| "(#{literal(a)} / power(2, #{literal b}))"}
219
+ when :ILIKE, :'NOT ILIKE'
220
+ sql << ILIKE_0
221
+ literal_append(sql, args.at(0))
222
+ sql << ILIKE_1
223
+ sql << (op == :ILIKE ? LIKE : NOT_LIKE)
224
+ sql<< ILIKE_2
225
+ literal_append(sql, args.at(1))
226
+ sql << ILIKE_3
227
+ else
228
+ super
229
+ end
230
+ end
231
+
232
+ # Oracle doesn't support CURRENT_TIME, as it doesn't have
233
+ # a type for storing just time values without a date, so
234
+ # use CURRENT_TIMESTAMP in its place.
235
+ def constant_sql_append(sql, c)
236
+ if c == :CURRENT_TIME
237
+ super(sql, :CURRENT_TIMESTAMP)
238
+ else
239
+ super
240
+ end
241
+ end
107
242
 
108
243
  # Oracle uses MINUS instead of EXCEPT, and doesn't support EXCEPT ALL
109
244
  def except(dataset, opts={})
@@ -112,19 +247,10 @@ module Sequel
112
247
  compound_clone(:minus, dataset, opts)
113
248
  end
114
249
 
250
+ # Use a custom expression with EXISTS to determine whether a dataset
251
+ # is empty.
115
252
  def empty?
116
- db[:dual].where(exists).get(1) == nil
117
- end
118
-
119
- # If this dataset is associated with a sequence, return the most recently
120
- # inserted sequence value.
121
- def insert(*args)
122
- r = super
123
- if s = opts[:sequence]
124
- with_sql("SELECT #{literal(s)}.currval FROM dual").single_value.to_i
125
- else
126
- r
127
- end
253
+ db[:dual].where(@opts[:offset] ? exists : unordered.exists).get(1) == nil
128
254
  end
129
255
 
130
256
  # Oracle requires SQL standard datetimes
@@ -139,16 +265,61 @@ module Sequel
139
265
  clone(:sequence=>s)
140
266
  end
141
267
 
268
+ # Handle LIMIT by using a unlimited subselect filtered with ROWNUM.
269
+ def select_sql
270
+ if (limit = @opts[:limit]) && !@opts[:sql]
271
+ ds = clone(:limit=>nil)
272
+ # Lock doesn't work in subselects, so don't use a subselect when locking.
273
+ # Don't use a subselect if custom SQL is used, as it breaks somethings.
274
+ ds = ds.from_self unless @opts[:lock]
275
+ sql = @opts[:append_sql] || ''
276
+ subselect_sql_append(sql, ds.where(SQL::ComplexExpression.new(:<=, ROW_NUMBER_EXPRESSION, limit)))
277
+ sql
278
+ else
279
+ super
280
+ end
281
+ end
282
+
283
+ # Oracle requires recursive CTEs to have column aliases.
284
+ def recursive_cte_requires_column_aliases?
285
+ true
286
+ end
287
+
288
+ # Oracle supports GROUP BY CUBE
289
+ def supports_group_cube?
290
+ true
291
+ end
292
+
293
+ # Oracle supports GROUP BY ROLLUP
294
+ def supports_group_rollup?
295
+ true
296
+ end
297
+
142
298
  # Oracle does not support INTERSECT ALL or EXCEPT ALL
143
299
  def supports_intersect_except_all?
144
300
  false
145
301
  end
302
+
303
+ # Oracle does not support IS TRUE.
304
+ def supports_is_true?
305
+ false
306
+ end
307
+
308
+ # Oracle does not support SELECT *, column
309
+ def supports_select_all_and_column?
310
+ false
311
+ end
146
312
 
147
313
  # Oracle supports timezones in literal timestamps.
148
314
  def supports_timestamp_timezones?
149
315
  true
150
316
  end
151
317
 
318
+ # Oracle does not support WHERE 'Y' for WHERE TRUE.
319
+ def supports_where_true?
320
+ false
321
+ end
322
+
152
323
  # Oracle supports window functions
153
324
  def supports_window_functions?
154
325
  true
@@ -158,25 +329,54 @@ module Sequel
158
329
 
159
330
  # Oracle doesn't support the use of AS when aliasing a dataset. It doesn't require
160
331
  # the use of AS anywhere, so this disables it in all cases.
161
- def as_sql(expression, aliaz)
162
- "#{expression} #{quote_identifier(aliaz)}"
332
+ def as_sql_append(sql, aliaz)
333
+ sql << SPACE
334
+ quote_identifier_append(sql, aliaz)
163
335
  end
164
336
 
165
337
  # The strftime format to use when literalizing the time.
166
338
  def default_timestamp_format
167
- "TIMESTAMP '%Y-%m-%d %H:%M:%S%N %z'".freeze
339
+ TIMESTAMP_FORMAT
340
+ end
341
+
342
+ # If this dataset is associated with a sequence, return the most recently
343
+ # inserted sequence value.
344
+ def execute_insert(sql, opts={})
345
+ f = @opts[:from]
346
+ super(sql, {:table=>(f.first if f), :sequence=>@opts[:sequence]}.merge(opts))
168
347
  end
169
348
 
170
349
  # Use a colon for the timestamp offset, since Oracle appears to require it.
171
350
  def format_timestamp_offset(hour, minute)
172
- sprintf("%+03i:%02i", hour, minute)
351
+ sprintf(TIMESTAMP_OFFSET_FORMAT, hour, minute)
352
+ end
353
+
354
+ # Oracle doesn't support empty values when inserting.
355
+ def insert_supports_empty_values?
356
+ false
357
+ end
358
+
359
+ # Use string in hex format for blob data.
360
+ def literal_blob_append(sql, v)
361
+ sql << APOS << v.unpack(HSTAR).first << APOS
362
+ end
363
+
364
+ # Oracle uses 'N' for false values.
365
+ def literal_false
366
+ BOOL_FALSE
173
367
  end
174
368
 
175
369
  # Oracle uses the SQL standard of only doubling ' inside strings.
176
- def literal_string(v)
177
- "'#{v.gsub("'", "''")}'"
370
+ def literal_string_append(sql, v)
371
+ sql << APOS << v.gsub(APOS_RE, DOUBLE_APOS) << APOS
372
+ end
373
+
374
+ # Oracle uses 'Y' for true values.
375
+ def literal_true
376
+ BOOL_TRUE
178
377
  end
179
378
 
379
+ # Use the Oracle-specific SQL clauses (no limit, since it is emulated).
180
380
  def select_clause_methods
181
381
  SELECT_CLAUSE_METHODS
182
382
  end
@@ -186,18 +386,8 @@ module Sequel
186
386
  # so add the dummy DUAL table if the dataset doesn't select
187
387
  # from a table.
188
388
  def select_from_sql(sql)
189
- sql << " FROM #{source_list(@opts[:from] || ['DUAL'])}"
190
- end
191
-
192
- # Oracle requires a subselect to do limit and offset
193
- def select_limit_sql(sql)
194
- if limit = @opts[:limit]
195
- if (offset = @opts[:offset]) && (offset > 0)
196
- sql.replace("SELECT * FROM (SELECT raw_sql_.*, ROWNUM raw_rnum_ FROM(#{sql}) raw_sql_ WHERE ROWNUM <= #{limit + offset}) WHERE raw_rnum_ > #{offset}")
197
- else
198
- sql.replace("SELECT * FROM (#{sql}) WHERE ROWNUM <= #{limit}")
199
- end
200
- end
389
+ sql << FROM
390
+ source_list_append(sql, @opts[:from] || DUAL)
201
391
  end
202
392
  end
203
393
  end