sequel 3.29.0 → 3.30.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 (106) hide show
  1. data/CHANGELOG +35 -3
  2. data/Rakefile +2 -1
  3. data/doc/association_basics.rdoc +11 -0
  4. data/doc/opening_databases.rdoc +2 -0
  5. data/doc/release_notes/3.30.0.txt +135 -0
  6. data/doc/testing.rdoc +17 -3
  7. data/lib/sequel/adapters/amalgalite.rb +2 -2
  8. data/lib/sequel/adapters/do/mysql.rb +5 -2
  9. data/lib/sequel/adapters/ibmdb.rb +2 -2
  10. data/lib/sequel/adapters/jdbc.rb +126 -43
  11. data/lib/sequel/adapters/jdbc/as400.rb +11 -3
  12. data/lib/sequel/adapters/jdbc/db2.rb +2 -1
  13. data/lib/sequel/adapters/jdbc/derby.rb +44 -19
  14. data/lib/sequel/adapters/jdbc/h2.rb +32 -19
  15. data/lib/sequel/adapters/jdbc/hsqldb.rb +21 -17
  16. data/lib/sequel/adapters/jdbc/jtds.rb +9 -4
  17. data/lib/sequel/adapters/jdbc/mssql.rb +3 -1
  18. data/lib/sequel/adapters/jdbc/mysql.rb +2 -1
  19. data/lib/sequel/adapters/jdbc/oracle.rb +21 -7
  20. data/lib/sequel/adapters/jdbc/postgresql.rb +3 -2
  21. data/lib/sequel/adapters/jdbc/sqlite.rb +2 -1
  22. data/lib/sequel/adapters/jdbc/sqlserver.rb +48 -18
  23. data/lib/sequel/adapters/mock.rb +2 -1
  24. data/lib/sequel/adapters/mysql.rb +4 -2
  25. data/lib/sequel/adapters/mysql2.rb +2 -2
  26. data/lib/sequel/adapters/odbc/mssql.rb +1 -1
  27. data/lib/sequel/adapters/openbase.rb +1 -1
  28. data/lib/sequel/adapters/oracle.rb +6 -6
  29. data/lib/sequel/adapters/postgres.rb +25 -12
  30. data/lib/sequel/adapters/shared/access.rb +14 -6
  31. data/lib/sequel/adapters/shared/db2.rb +36 -13
  32. data/lib/sequel/adapters/shared/firebird.rb +12 -5
  33. data/lib/sequel/adapters/shared/informix.rb +11 -3
  34. data/lib/sequel/adapters/shared/mssql.rb +94 -47
  35. data/lib/sequel/adapters/shared/mysql.rb +107 -49
  36. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +2 -2
  37. data/lib/sequel/adapters/shared/oracle.rb +54 -27
  38. data/lib/sequel/adapters/shared/postgres.rb +65 -26
  39. data/lib/sequel/adapters/shared/progress.rb +4 -1
  40. data/lib/sequel/adapters/shared/sqlite.rb +36 -20
  41. data/lib/sequel/adapters/sqlite.rb +2 -3
  42. data/lib/sequel/adapters/swift/mysql.rb +3 -2
  43. data/lib/sequel/adapters/swift/sqlite.rb +2 -2
  44. data/lib/sequel/adapters/tinytds.rb +14 -8
  45. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +7 -4
  46. data/lib/sequel/database/misc.rb +6 -2
  47. data/lib/sequel/dataset/graph.rb +33 -7
  48. data/lib/sequel/dataset/prepared_statements.rb +19 -5
  49. data/lib/sequel/dataset/sql.rb +611 -201
  50. data/lib/sequel/model/associations.rb +12 -5
  51. data/lib/sequel/model/base.rb +20 -5
  52. data/lib/sequel/plugins/sharding.rb +9 -29
  53. data/lib/sequel/sql.rb +2 -1
  54. data/lib/sequel/timezones.rb +14 -4
  55. data/lib/sequel/version.rb +1 -1
  56. data/spec/adapters/mysql_spec.rb +10 -0
  57. data/spec/adapters/oracle_spec.rb +1 -1
  58. data/spec/core/core_sql_spec.rb +3 -1
  59. data/spec/core/database_spec.rb +42 -0
  60. data/spec/core/dataset_spec.rb +10 -3
  61. data/spec/core/mock_adapter_spec.rb +4 -0
  62. data/spec/core/object_graph_spec.rb +38 -0
  63. data/spec/extensions/association_autoreloading_spec.rb +1 -10
  64. data/spec/extensions/association_dependencies_spec.rb +2 -12
  65. data/spec/extensions/association_pks_spec.rb +35 -39
  66. data/spec/extensions/caching_spec.rb +23 -50
  67. data/spec/extensions/class_table_inheritance_spec.rb +30 -82
  68. data/spec/extensions/composition_spec.rb +18 -13
  69. data/spec/extensions/hook_class_methods_spec.rb +65 -91
  70. data/spec/extensions/identity_map_spec.rb +33 -103
  71. data/spec/extensions/instance_filters_spec.rb +10 -21
  72. data/spec/extensions/instance_hooks_spec.rb +6 -24
  73. data/spec/extensions/json_serializer_spec.rb +4 -5
  74. data/spec/extensions/lazy_attributes_spec.rb +16 -20
  75. data/spec/extensions/list_spec.rb +17 -39
  76. data/spec/extensions/many_through_many_spec.rb +135 -277
  77. data/spec/extensions/migration_spec.rb +18 -15
  78. data/spec/extensions/named_timezones_spec.rb +1 -1
  79. data/spec/extensions/nested_attributes_spec.rb +97 -92
  80. data/spec/extensions/optimistic_locking_spec.rb +9 -20
  81. data/spec/extensions/prepared_statements_associations_spec.rb +22 -37
  82. data/spec/extensions/prepared_statements_safe_spec.rb +9 -27
  83. data/spec/extensions/prepared_statements_spec.rb +11 -30
  84. data/spec/extensions/prepared_statements_with_pk_spec.rb +6 -13
  85. data/spec/extensions/pretty_table_spec.rb +1 -6
  86. data/spec/extensions/rcte_tree_spec.rb +41 -43
  87. data/spec/extensions/schema_dumper_spec.rb +3 -6
  88. data/spec/extensions/serialization_spec.rb +20 -32
  89. data/spec/extensions/sharding_spec.rb +66 -140
  90. data/spec/extensions/single_table_inheritance_spec.rb +14 -36
  91. data/spec/extensions/spec_helper.rb +10 -64
  92. data/spec/extensions/sql_expr_spec.rb +20 -60
  93. data/spec/extensions/tactical_eager_loading_spec.rb +9 -19
  94. data/spec/extensions/timestamps_spec.rb +6 -6
  95. data/spec/extensions/to_dot_spec.rb +1 -2
  96. data/spec/extensions/touch_spec.rb +13 -14
  97. data/spec/extensions/tree_spec.rb +11 -26
  98. data/spec/extensions/update_primary_key_spec.rb +30 -24
  99. data/spec/extensions/validation_class_methods_spec.rb +30 -51
  100. data/spec/extensions/validation_helpers_spec.rb +16 -35
  101. data/spec/integration/dataset_test.rb +16 -4
  102. data/spec/integration/prepared_statement_test.rb +4 -2
  103. data/spec/model/eager_loading_spec.rb +16 -0
  104. data/spec/model/model_spec.rb +15 -1
  105. data/spec/model/record_spec.rb +60 -0
  106. metadata +23 -40
@@ -39,6 +39,9 @@ module Sequel
39
39
  # Dataset class for AS400 datasets accessed via JDBC.
40
40
  class Dataset < JDBC::Dataset
41
41
  WILDCARD = Sequel::LiteralString.new('*').freeze
42
+ FETCH_FIRST_ROW_ONLY = " FETCH FIRST ROW ONLY".freeze
43
+ FETCH_FIRST = " FETCH FIRST ".freeze
44
+ ROWS_ONLY = " ROWS ONLY".freeze
42
45
 
43
46
  # AS400 needs to use a couple of subselects for queries with offsets.
44
47
  def select_sql
@@ -60,9 +63,14 @@ module Sequel
60
63
 
61
64
  # Modify the sql to limit the number of rows returned
62
65
  def select_limit_sql(sql)
63
- if @opts[:limit]
64
- sql << " FETCH FIRST ROW ONLY" if @opts[:limit] == 1
65
- sql << " FETCH FIRST #{@opts[:limit]} ROWS ONLY" if @opts[:limit] > 1
66
+ if l = @opts[:limit]
67
+ if l == 1
68
+ sql << FETCH_FIRST_ROW_ONLY
69
+ elsif l > 1
70
+ sql << FETCH_FIRST
71
+ literal_append(sql, l)
72
+ sql << ROWS_ONLY
73
+ end
66
74
  end
67
75
  end
68
76
 
@@ -18,6 +18,7 @@ module Sequel
18
18
  module DatabaseMethods
19
19
  include Sequel::DB2::DatabaseMethods
20
20
  include Sequel::JDBC::Transactions
21
+ IDENTITY_VAL_LOCAL = "SELECT IDENTITY_VAL_LOCAL() FROM SYSIBM.SYSDUMMY1".freeze
21
22
 
22
23
  %w'schema_parse_table tables views indexes'.each do |s|
23
24
  class_eval("def #{s}(*a) jdbc_#{s}(*a) end", __FILE__, __LINE__)
@@ -27,7 +28,7 @@ module Sequel
27
28
 
28
29
  def last_insert_id(conn, opts={})
29
30
  statement(conn) do |stmt|
30
- sql = "SELECT IDENTITY_VAL_LOCAL() FROM SYSIBM.SYSDUMMY1"
31
+ sql = IDENTITY_VAL_LOCAL
31
32
  rs = log_yield(sql){stmt.executeQuery(sql)}
32
33
  rs.next
33
34
  rs.getInt(1)
@@ -104,17 +104,31 @@ module Sequel
104
104
 
105
105
  # Dataset class for Derby datasets accessed via JDBC.
106
106
  class Dataset < JDBC::Dataset
107
+ PAREN_CLOSE = Dataset::PAREN_CLOSE
108
+ PAREN_OPEN = Dataset::PAREN_OPEN
109
+ OFFSET = Dataset::OFFSET
110
+ CAST_STRING_OPEN = "RTRIM(".freeze
111
+ BITCOMP_OPEN = "((0 - ".freeze
112
+ BITCOMP_CLOSE = ") - 1)".freeze
113
+ BLOB_OPEN = "CAST(X'".freeze
114
+ BLOB_CLOSE = "' AS BLOB)".freeze
115
+ HSTAR = "H*".freeze
116
+ TIME_FORMAT = "'%H:%M:%S'".freeze
117
+ DEFAULT_FROM = " FROM sysibm.sysdummy1".freeze
118
+ ROWS = " ROWS".freeze
119
+ FETCH_FIRST = " FETCH FIRST ".freeze
120
+ ROWS_ONLY = " ROWS ONLY".freeze
107
121
  BOOL_TRUE = '(1 = 1)'.freeze
108
122
  BOOL_FALSE = '(1 = 0)'.freeze
109
- SELECT_CLAUSE_METHODS = clause_methods(:select, %w'distinct columns from join where group having compounds order limit lock')
123
+ SELECT_CLAUSE_METHODS = clause_methods(:select, %w'select distinct columns from join where group having compounds order limit lock')
110
124
 
111
125
  # Derby doesn't support an expression between CASE and WHEN,
112
126
  # so emulate it by using an equality statement for all of the
113
127
  # conditions.
114
- def case_expression_sql(ce)
128
+ def case_expression_sql_append(sql, ce)
115
129
  if ce.expression?
116
130
  e = ce.expression
117
- literal(::Sequel::SQL::CaseExpression.new(ce.conditions.map{|c, r| [::Sequel::SQL::BooleanExpression.new(:'=', e, c), r]}, ce.default))
131
+ case_expression_sql_append(sql, ::Sequel::SQL::CaseExpression.new(ce.conditions.map{|c, r| [::Sequel::SQL::BooleanExpression.new(:'=', e, c), r]}, ce.default))
118
132
  else
119
133
  super
120
134
  end
@@ -123,27 +137,33 @@ module Sequel
123
137
  # If the type is String, trim the extra spaces since CHAR is used instead
124
138
  # of varchar. This can cause problems if you are casting a char/varchar to
125
139
  # a string and the ending whitespace is important.
126
- def cast_sql(expr, type)
140
+ def cast_sql_append(sql, expr, type)
127
141
  if type == String
128
- "RTRIM(#{super})"
142
+ sql << CAST_STRING_OPEN
143
+ super
144
+ sql << PAREN_CLOSE
129
145
  else
130
146
  super
131
147
  end
132
148
  end
133
149
 
134
150
  # Handle Derby specific LIKE, extract, and some bitwise compliment support.
135
- def complex_expression_sql(op, args)
151
+ def complex_expression_sql_append(sql, op, args)
136
152
  case op
137
153
  when :ILIKE
138
- super(:LIKE, [SQL::Function.new(:upper, args.at(0)), SQL::Function.new(:upper, args.at(1)) ])
154
+ super(sql, :LIKE, [SQL::Function.new(:upper, args.at(0)), SQL::Function.new(:upper, args.at(1))])
139
155
  when :"NOT ILIKE"
140
- super(:"NOT LIKE", [SQL::Function.new(:upper, args.at(0)), SQL::Function.new(:upper, args.at(1)) ])
156
+ super(sql, :"NOT LIKE", [SQL::Function.new(:upper, args.at(0)), SQL::Function.new(:upper, args.at(1))])
141
157
  when :&, :|, :^, :<<, :>>
142
158
  raise Error, "Derby doesn't support the #{op} operator"
143
159
  when :'B~'
144
- "((0 - #{literal(args.at(0))}) - 1)"
160
+ sql << BITCOMP_OPEN
161
+ literal_append(sql, args.at(0))
162
+ sql << BITCOMP_CLOSE
145
163
  when :extract
146
- "#{args.at(0)}(#{literal(args.at(1))})"
164
+ sql << args.at(0).to_s << PAREN_OPEN
165
+ literal_append(sql, args.at(1))
166
+ sql << PAREN_CLOSE
147
167
  else
148
168
  super
149
169
  end
@@ -162,11 +182,8 @@ module Sequel
162
182
  private
163
183
 
164
184
  # Derby needs a hex string casted to BLOB for blobs.
165
- def literal_blob(v)
166
- blob = "CAST(X'"
167
- v.each_byte{|x| blob << sprintf('%02x', x)}
168
- blob << "' AS BLOB)"
169
- blob
185
+ def literal_blob_append(sql, v)
186
+ sql << BLOB_OPEN << v.unpack(HSTAR).first << BLOB_CLOSE
170
187
  end
171
188
 
172
189
  # Derby needs the standard workaround to insert all default values into
@@ -183,7 +200,7 @@ module Sequel
183
200
 
184
201
  # Derby handles fractional seconds in timestamps, but not in times
185
202
  def literal_sqltime(v)
186
- v.strftime("'%H:%M:%S'")
203
+ v.strftime(TIME_FORMAT)
187
204
  end
188
205
 
189
206
  # Derby uses an expression yielding true for true values.
@@ -202,14 +219,22 @@ module Sequel
202
219
  if @opts[:from]
203
220
  super
204
221
  else
205
- sql << " FROM sysibm.sysdummy1"
222
+ sql << DEFAULT_FROM
206
223
  end
207
224
  end
208
225
 
209
226
  # Offset comes before limit in Derby
210
227
  def select_limit_sql(sql)
211
- sql << " OFFSET #{literal(@opts[:offset])} ROWS" if @opts[:offset]
212
- sql << " FETCH FIRST #{literal(@opts[:limit])} ROWS ONLY" if @opts[:limit]
228
+ if o = @opts[:offset]
229
+ sql << OFFSET
230
+ literal_append(sql, o)
231
+ sql << ROWS
232
+ end
233
+ if l = @opts[:limit]
234
+ sql << FETCH_FIRST
235
+ literal_append(sql, l)
236
+ sql << ROWS_ONLY
237
+ end
213
238
  end
214
239
  end
215
240
  end
@@ -104,26 +104,32 @@ module Sequel
104
104
 
105
105
  # Dataset class for H2 datasets accessed via JDBC.
106
106
  class Dataset < JDBC::Dataset
107
- SELECT_CLAUSE_METHODS = clause_methods(:select, %w'distinct columns from join where group having compounds order limit')
107
+ SELECT_CLAUSE_METHODS = clause_methods(:select, %w'select distinct columns from join where group having compounds order limit')
108
108
  BITWISE_METHOD_MAP = {:& =>:BITAND, :| => :BITOR, :^ => :BITXOR}
109
+ APOS = Dataset::APOS
110
+ HSTAR = "H*".freeze
111
+ BITCOMP_OPEN = "((0 - ".freeze
112
+ BITCOMP_CLOSE = ") - 1)".freeze
113
+ ILIKE_PLACEHOLDER = "CAST(? AS VARCHAR_IGNORECASE)".freeze
114
+ TIME_FORMAT = "'%H:%M:%S'".freeze
109
115
 
110
116
  # Emulate the case insensitive LIKE operator and the bitwise operators.
111
- def complex_expression_sql(op, args)
117
+ def complex_expression_sql_append(sql, op, args)
112
118
  case op
113
- when :ILIKE
114
- super(:LIKE, [SQL::PlaceholderLiteralString.new("CAST(? AS VARCHAR_IGNORECASE)", [args.at(0)]), args.at(1)])
115
- when :"NOT ILIKE"
116
- super(:"NOT LIKE", [SQL::PlaceholderLiteralString.new("CAST(? AS VARCHAR_IGNORECASE)", [args.at(0)]), args.at(1)])
119
+ when :ILIKE, :"NOT ILIKE"
120
+ super(sql, (op == :ILIKE ? :LIKE : :"NOT LIKE"), [SQL::PlaceholderLiteralString.new(ILIKE_PLACEHOLDER, [args.at(0)]), args.at(1)])
117
121
  when :&, :|, :^
118
- complex_expression_arg_pairs(args){|a, b| literal(SQL::Function.new(BITWISE_METHOD_MAP[op], a, b))}
122
+ sql << complex_expression_arg_pairs(args){|a, b| literal(SQL::Function.new(BITWISE_METHOD_MAP[op], a, b))}
119
123
  when :<<
120
- complex_expression_arg_pairs(args){|a, b| "(#{literal(a)} * POWER(2, #{literal(b)}))"}
124
+ sql << complex_expression_arg_pairs(args){|a, b| "(#{literal(a)} * POWER(2, #{literal(b)}))"}
121
125
  when :>>
122
- complex_expression_arg_pairs(args){|a, b| "(#{literal(a)} / POWER(2, #{literal(b)}))"}
126
+ sql << complex_expression_arg_pairs(args){|a, b| "(#{literal(a)} / POWER(2, #{literal(b)}))"}
123
127
  when :'B~'
124
- "((0 - #{literal(args.at(0))}) - 1)"
128
+ sql << BITCOMP_OPEN
129
+ literal_append(sql, args.at(0))
130
+ sql << BITCOMP_CLOSE
125
131
  else
126
- super(op, args)
132
+ super
127
133
  end
128
134
  end
129
135
 
@@ -148,25 +154,32 @@ module Sequel
148
154
  end
149
155
 
150
156
  private
157
+
158
+ #JAVA_H2_CLOB = Java::OrgH2Jdbc::JdbcClob
159
+
160
+ class ::Sequel::JDBC::Dataset::TYPE_TRANSLATOR
161
+ def h2_clob(v) Sequel::SQL::Blob.new(v.getSubString(1, v.length)) end
162
+ end
163
+
164
+ H2_CLOB_METHOD = TYPE_TRANSLATOR_INSTANCE.method(:h2_clob)
151
165
 
152
166
  # Handle H2 specific clobs as strings.
153
- def convert_type(v)
154
- case v
155
- when Java::OrgH2Jdbc::JdbcClob
156
- convert_type(v.getSubString(1, v.length))
167
+ def convert_type_proc(v)
168
+ if v.is_a?(Java::OrgH2Jdbc::JdbcClob)
169
+ H2_CLOB_METHOD
157
170
  else
158
- super(v)
171
+ super
159
172
  end
160
173
  end
161
174
 
162
175
  # H2 expects hexadecimal strings for blob values
163
- def literal_blob(v)
164
- literal_string v.unpack("H*").first
176
+ def literal_blob_append(sql, v)
177
+ sql << APOS << v.unpack(HSTAR).first << APOS
165
178
  end
166
179
 
167
180
  # H2 handles fractional seconds in timestamps, but not in times
168
181
  def literal_sqltime(v)
169
- v.strftime("'%H:%M:%S'")
182
+ v.strftime(TIME_FORMAT)
170
183
  end
171
184
 
172
185
  def select_clause_methods
@@ -83,25 +83,32 @@ module Sequel
83
83
  # CTEs in earlier queries might take precedence over CTEs with the same name in later queries.
84
84
  # Also, if any CTE is recursive, all CTEs must be recursive.
85
85
  # If you want to use CTEs with HSQLDB, you'll have to manually modify the dataset to allow it.
86
- SELECT_CLAUSE_METHODS = clause_methods(:select, %w'distinct columns from join where group having compounds order limit lock')
86
+ SELECT_CLAUSE_METHODS = clause_methods(:select, %w'select distinct columns from join where group having compounds order limit lock')
87
87
  SQL_WITH_RECURSIVE = "WITH RECURSIVE ".freeze
88
+ APOS = Dataset::APOS
89
+ HSTAR = "H*".freeze
90
+ BLOB_OPEN = "X'".freeze
91
+ BITCOMP_OPEN = "((0 - ".freeze
92
+ BITCOMP_CLOSE = ") - 1)".freeze
93
+ DEFAULT_FROM = " FROM (VALUES (0))".freeze
94
+ TIME_FORMAT = "'%H:%M:%S'".freeze
88
95
 
89
96
  # Handle HSQLDB specific case insensitive LIKE and bitwise operator support.
90
- def complex_expression_sql(op, args)
97
+ def complex_expression_sql_append(sql, op, args)
91
98
  case op
92
- when :ILIKE
93
- super(:LIKE, [SQL::Function.new(:ucase, args.at(0)), SQL::Function.new(:ucase, args.at(1)) ])
94
- when :"NOT ILIKE"
95
- super(:"NOT LIKE", [SQL::Function.new(:ucase, args.at(0)), SQL::Function.new(:ucase, args.at(1)) ])
99
+ when :ILIKE, :"NOT ILIKE"
100
+ super(sql, (op == :ILIKE ? :LIKE : :"NOT LIKE"), [SQL::Function.new(:ucase, args.at(0)), SQL::Function.new(:ucase, args.at(1)) ])
96
101
  when :&, :|, :^
97
102
  op = BITWISE_METHOD_MAP[op]
98
- complex_expression_arg_pairs(args){|a, b| literal(SQL::Function.new(op, a, b))}
103
+ sql << complex_expression_arg_pairs(args){|a, b| literal(SQL::Function.new(op, a, b))}
99
104
  when :<<
100
- complex_expression_arg_pairs(args){|a, b| "(#{literal(a)} * POWER(2, #{literal(b)}))"}
105
+ sql << complex_expression_arg_pairs(args){|a, b| "(#{literal(a)} * POWER(2, #{literal(b)}))"}
101
106
  when :>>
102
- complex_expression_arg_pairs(args){|a, b| "(#{literal(a)} / POWER(2, #{literal(b)}))"}
107
+ sql << complex_expression_arg_pairs(args){|a, b| "(#{literal(a)} / POWER(2, #{literal(b)}))"}
103
108
  when :'B~'
104
- "((0 - #{literal(args.at(0))}) - 1)"
109
+ sql << BITCOMP_OPEN
110
+ literal_append(sql, args.at(0))
111
+ sql << BITCOMP_CLOSE
105
112
  else
106
113
  super
107
114
  end
@@ -120,11 +127,8 @@ module Sequel
120
127
  private
121
128
 
122
129
  # Use string in hex format for blob data.
123
- def literal_blob(v)
124
- blob = "X'"
125
- v.each_byte{|x| blob << sprintf('%02x', x)}
126
- blob << "'"
127
- blob
130
+ def literal_blob_append(sql, v)
131
+ sql << BLOB_OPEN << v.unpack(HSTAR).first << APOS
128
132
  end
129
133
 
130
134
  # HSQLDB uses FALSE for false values.
@@ -134,7 +138,7 @@ module Sequel
134
138
 
135
139
  # HSQLDB handles fractional seconds in timestamps, but not in times
136
140
  def literal_sqltime(v)
137
- v.strftime("'%H:%M:%S'")
141
+ v.strftime(TIME_FORMAT)
138
142
  end
139
143
 
140
144
  # HSQLDB uses TRUE for true values.
@@ -152,7 +156,7 @@ module Sequel
152
156
  if @opts[:from]
153
157
  super
154
158
  else
155
- sql << " FROM (VALUES (0))"
159
+ sql << DEFAULT_FROM
156
160
  end
157
161
  end
158
162
 
@@ -14,11 +14,16 @@ module Sequel
14
14
  class Dataset < JDBC::Dataset
15
15
  include Sequel::MSSQL::DatasetMethods
16
16
 
17
+ class ::Sequel::JDBC::Dataset::TYPE_TRANSLATOR
18
+ def jtds_clob(v) Sequel::SQL::Blob.new(v.getSubString(1, v.length)) end
19
+ end
20
+
21
+ JTDS_CLOB_METHOD = TYPE_TRANSLATOR_INSTANCE.method(:jtds_clob)
22
+
17
23
  # Handle CLOB types retrieved via JTDS.
18
- def convert_type(v)
19
- case v
20
- when Java::NetSourceforgeJtdsJdbc::ClobImpl
21
- convert_type(v.getSubString(1, v.length))
24
+ def convert_type_proc(v)
25
+ if v.is_a?(Java::NetSourceforgeJtdsJdbc::ClobImpl)
26
+ JTDS_CLOB_METHOD
22
27
  else
23
28
  super
24
29
  end
@@ -13,6 +13,8 @@ module Sequel
13
13
  # Database instance methods for MSSQL databases accessed via JDBC.
14
14
  module DatabaseMethods
15
15
  PRIMARY_KEY_INDEX_RE = /\Apk__/i.freeze
16
+ ATAT_IDENTITY = 'SELECT @@IDENTITY'.freeze
17
+ SCOPE_IDENTITY = 'SELECT SCOPE_IDENTITY()'.freeze
16
18
 
17
19
  include Sequel::MSSQL::DatabaseMethods
18
20
 
@@ -21,7 +23,7 @@ module Sequel
21
23
  # Get the last inserted id using SCOPE_IDENTITY().
22
24
  def last_insert_id(conn, opts={})
23
25
  statement(conn) do |stmt|
24
- sql = opts[:prepared] ? 'SELECT @@IDENTITY' : 'SELECT SCOPE_IDENTITY()'
26
+ sql = opts[:prepared] ? ATAT_IDENTITY : SCOPE_IDENTITY
25
27
  rs = log_yield(sql){stmt.executeQuery(sql)}
26
28
  rs.next
27
29
  rs.getInt(1)
@@ -8,6 +8,7 @@ module Sequel
8
8
  # Database instance methods for MySQL databases accessed via JDBC.
9
9
  module DatabaseMethods
10
10
  include Sequel::MySQL::DatabaseMethods
11
+ LAST_INSERT_ID = 'SELECT LAST_INSERT_ID()'.freeze
11
12
 
12
13
  private
13
14
 
@@ -34,7 +35,7 @@ module Sequel
34
35
  end
35
36
  else
36
37
  statement(conn) do |stmt|
37
- rs = stmt.executeQuery('SELECT LAST_INSERT_ID()')
38
+ rs = stmt.executeQuery(LAST_INSERT_ID)
38
39
  rs.next
39
40
  rs.getInt(1)
40
41
  end
@@ -67,21 +67,35 @@ module Sequel
67
67
 
68
68
  private
69
69
 
70
- def convert_type(v)
71
- case v
72
- when Java::JavaMath::BigDecimal
70
+ JAVA_BIG_DECIMAL = ::Sequel::JDBC::Dataset::JAVA_BIG_DECIMAL
71
+
72
+ class ::Sequel::JDBC::Dataset::TYPE_TRANSLATOR
73
+ def oracle_decimal(v)
73
74
  if v.scale == 0
74
75
  i = v.long_value
75
- if v.equals(Java::JavaMath::BigDecimal.new(i))
76
+ if v.equals(JAVA_BIG_DECIMAL.new(i))
76
77
  i
77
78
  else
78
- super
79
+ decimal(v)
79
80
  end
80
81
  else
81
- super
82
+ decimal(v)
82
83
  end
84
+ end
85
+ end
86
+
87
+ ORACLE_DECIMAL_METHOD = TYPE_TRANSLATOR_INSTANCE.method(:oracle_decimal)
88
+
89
+ def convert_type_oracle_timestamp(v)
90
+ db.to_application_timestamp(v.to_string)
91
+ end
92
+
93
+ def convert_type_proc(v)
94
+ case v
95
+ when JAVA_BIG_DECIMAL
96
+ ORACLE_DECIMAL_METHOD
83
97
  when Java::OracleSql::TIMESTAMP
84
- db.to_application_timestamp(v.to_string)
98
+ method(:convert_type_oracle_timestamp)
85
99
  else
86
100
  super
87
101
  end
@@ -73,6 +73,7 @@ module Sequel
73
73
  # Dataset subclass used for datasets that connect to PostgreSQL via JDBC.
74
74
  class Dataset < JDBC::Dataset
75
75
  include Sequel::Postgres::DatasetMethods
76
+ APOS = Dataset::APOS
76
77
 
77
78
  # Add the shared PostgreSQL prepared statement methods
78
79
  def prepare(*args)
@@ -82,8 +83,8 @@ module Sequel
82
83
  end
83
84
 
84
85
  # Literalize strings similar to the native postgres adapter
85
- def literal_string(v)
86
- db.synchronize{|c| "'#{c.escape_string(v)}'"}
86
+ def literal_string_append(sql, v)
87
+ sql << APOS << db.synchronize{|c| c.escape_string(v)} << APOS
87
88
  end
88
89
  end
89
90
  end
@@ -7,13 +7,14 @@ module Sequel
7
7
  # Instance methods for SQLite Database objects accessed via JDBC.
8
8
  module DatabaseMethods
9
9
  include Sequel::SQLite::DatabaseMethods
10
+ LAST_INSERT_ROWID = 'SELECT last_insert_rowid()'.freeze
10
11
 
11
12
  private
12
13
 
13
14
  # Use last_insert_rowid() to get the last inserted id.
14
15
  def last_insert_id(conn, opts={})
15
16
  statement(conn) do |stmt|
16
- rs = stmt.executeQuery('SELECT last_insert_rowid()')
17
+ rs = stmt.executeQuery(LAST_INSERT_ROWID)
17
18
  rs.next
18
19
  rs.getInt(1)
19
20
  end