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.
- data/CHANGELOG +35 -3
- data/Rakefile +2 -1
- data/doc/association_basics.rdoc +11 -0
- data/doc/opening_databases.rdoc +2 -0
- data/doc/release_notes/3.30.0.txt +135 -0
- data/doc/testing.rdoc +17 -3
- data/lib/sequel/adapters/amalgalite.rb +2 -2
- data/lib/sequel/adapters/do/mysql.rb +5 -2
- data/lib/sequel/adapters/ibmdb.rb +2 -2
- data/lib/sequel/adapters/jdbc.rb +126 -43
- data/lib/sequel/adapters/jdbc/as400.rb +11 -3
- data/lib/sequel/adapters/jdbc/db2.rb +2 -1
- data/lib/sequel/adapters/jdbc/derby.rb +44 -19
- data/lib/sequel/adapters/jdbc/h2.rb +32 -19
- data/lib/sequel/adapters/jdbc/hsqldb.rb +21 -17
- data/lib/sequel/adapters/jdbc/jtds.rb +9 -4
- data/lib/sequel/adapters/jdbc/mssql.rb +3 -1
- data/lib/sequel/adapters/jdbc/mysql.rb +2 -1
- data/lib/sequel/adapters/jdbc/oracle.rb +21 -7
- data/lib/sequel/adapters/jdbc/postgresql.rb +3 -2
- data/lib/sequel/adapters/jdbc/sqlite.rb +2 -1
- data/lib/sequel/adapters/jdbc/sqlserver.rb +48 -18
- data/lib/sequel/adapters/mock.rb +2 -1
- data/lib/sequel/adapters/mysql.rb +4 -2
- data/lib/sequel/adapters/mysql2.rb +2 -2
- data/lib/sequel/adapters/odbc/mssql.rb +1 -1
- data/lib/sequel/adapters/openbase.rb +1 -1
- data/lib/sequel/adapters/oracle.rb +6 -6
- data/lib/sequel/adapters/postgres.rb +25 -12
- data/lib/sequel/adapters/shared/access.rb +14 -6
- data/lib/sequel/adapters/shared/db2.rb +36 -13
- data/lib/sequel/adapters/shared/firebird.rb +12 -5
- data/lib/sequel/adapters/shared/informix.rb +11 -3
- data/lib/sequel/adapters/shared/mssql.rb +94 -47
- data/lib/sequel/adapters/shared/mysql.rb +107 -49
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +2 -2
- data/lib/sequel/adapters/shared/oracle.rb +54 -27
- data/lib/sequel/adapters/shared/postgres.rb +65 -26
- data/lib/sequel/adapters/shared/progress.rb +4 -1
- data/lib/sequel/adapters/shared/sqlite.rb +36 -20
- data/lib/sequel/adapters/sqlite.rb +2 -3
- data/lib/sequel/adapters/swift/mysql.rb +3 -2
- data/lib/sequel/adapters/swift/sqlite.rb +2 -2
- data/lib/sequel/adapters/tinytds.rb +14 -8
- data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +7 -4
- data/lib/sequel/database/misc.rb +6 -2
- data/lib/sequel/dataset/graph.rb +33 -7
- data/lib/sequel/dataset/prepared_statements.rb +19 -5
- data/lib/sequel/dataset/sql.rb +611 -201
- data/lib/sequel/model/associations.rb +12 -5
- data/lib/sequel/model/base.rb +20 -5
- data/lib/sequel/plugins/sharding.rb +9 -29
- data/lib/sequel/sql.rb +2 -1
- data/lib/sequel/timezones.rb +14 -4
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/mysql_spec.rb +10 -0
- data/spec/adapters/oracle_spec.rb +1 -1
- data/spec/core/core_sql_spec.rb +3 -1
- data/spec/core/database_spec.rb +42 -0
- data/spec/core/dataset_spec.rb +10 -3
- data/spec/core/mock_adapter_spec.rb +4 -0
- data/spec/core/object_graph_spec.rb +38 -0
- data/spec/extensions/association_autoreloading_spec.rb +1 -10
- data/spec/extensions/association_dependencies_spec.rb +2 -12
- data/spec/extensions/association_pks_spec.rb +35 -39
- data/spec/extensions/caching_spec.rb +23 -50
- data/spec/extensions/class_table_inheritance_spec.rb +30 -82
- data/spec/extensions/composition_spec.rb +18 -13
- data/spec/extensions/hook_class_methods_spec.rb +65 -91
- data/spec/extensions/identity_map_spec.rb +33 -103
- data/spec/extensions/instance_filters_spec.rb +10 -21
- data/spec/extensions/instance_hooks_spec.rb +6 -24
- data/spec/extensions/json_serializer_spec.rb +4 -5
- data/spec/extensions/lazy_attributes_spec.rb +16 -20
- data/spec/extensions/list_spec.rb +17 -39
- data/spec/extensions/many_through_many_spec.rb +135 -277
- data/spec/extensions/migration_spec.rb +18 -15
- data/spec/extensions/named_timezones_spec.rb +1 -1
- data/spec/extensions/nested_attributes_spec.rb +97 -92
- data/spec/extensions/optimistic_locking_spec.rb +9 -20
- data/spec/extensions/prepared_statements_associations_spec.rb +22 -37
- data/spec/extensions/prepared_statements_safe_spec.rb +9 -27
- data/spec/extensions/prepared_statements_spec.rb +11 -30
- data/spec/extensions/prepared_statements_with_pk_spec.rb +6 -13
- data/spec/extensions/pretty_table_spec.rb +1 -6
- data/spec/extensions/rcte_tree_spec.rb +41 -43
- data/spec/extensions/schema_dumper_spec.rb +3 -6
- data/spec/extensions/serialization_spec.rb +20 -32
- data/spec/extensions/sharding_spec.rb +66 -140
- data/spec/extensions/single_table_inheritance_spec.rb +14 -36
- data/spec/extensions/spec_helper.rb +10 -64
- data/spec/extensions/sql_expr_spec.rb +20 -60
- data/spec/extensions/tactical_eager_loading_spec.rb +9 -19
- data/spec/extensions/timestamps_spec.rb +6 -6
- data/spec/extensions/to_dot_spec.rb +1 -2
- data/spec/extensions/touch_spec.rb +13 -14
- data/spec/extensions/tree_spec.rb +11 -26
- data/spec/extensions/update_primary_key_spec.rb +30 -24
- data/spec/extensions/validation_class_methods_spec.rb +30 -51
- data/spec/extensions/validation_helpers_spec.rb +16 -35
- data/spec/integration/dataset_test.rb +16 -4
- data/spec/integration/prepared_statement_test.rb +4 -2
- data/spec/model/eager_loading_spec.rb +16 -0
- data/spec/model/model_spec.rb +15 -1
- data/spec/model/record_spec.rb +60 -0
- 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
|
-
|
|
65
|
-
|
|
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 =
|
|
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
|
|
128
|
+
def case_expression_sql_append(sql, ce)
|
|
115
129
|
if ce.expression?
|
|
116
130
|
e = ce.expression
|
|
117
|
-
|
|
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
|
|
140
|
+
def cast_sql_append(sql, expr, type)
|
|
127
141
|
if type == String
|
|
128
|
-
|
|
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
|
|
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
|
-
|
|
160
|
+
sql << BITCOMP_OPEN
|
|
161
|
+
literal_append(sql, args.at(0))
|
|
162
|
+
sql << BITCOMP_CLOSE
|
|
145
163
|
when :extract
|
|
146
|
-
|
|
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
|
|
166
|
-
|
|
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(
|
|
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 <<
|
|
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
|
-
|
|
212
|
-
|
|
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
|
|
117
|
+
def complex_expression_sql_append(sql, op, args)
|
|
112
118
|
case op
|
|
113
|
-
when :ILIKE
|
|
114
|
-
super(:LIKE, [SQL::PlaceholderLiteralString.new(
|
|
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
|
-
|
|
128
|
+
sql << BITCOMP_OPEN
|
|
129
|
+
literal_append(sql, args.at(0))
|
|
130
|
+
sql << BITCOMP_CLOSE
|
|
125
131
|
else
|
|
126
|
-
super
|
|
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
|
|
154
|
-
|
|
155
|
-
|
|
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
|
|
171
|
+
super
|
|
159
172
|
end
|
|
160
173
|
end
|
|
161
174
|
|
|
162
175
|
# H2 expects hexadecimal strings for blob values
|
|
163
|
-
def
|
|
164
|
-
|
|
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(
|
|
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
|
|
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
|
-
|
|
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
|
|
124
|
-
|
|
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(
|
|
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 <<
|
|
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
|
|
19
|
-
|
|
20
|
-
|
|
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] ?
|
|
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(
|
|
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
|
-
|
|
71
|
-
|
|
72
|
-
|
|
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(
|
|
76
|
+
if v.equals(JAVA_BIG_DECIMAL.new(i))
|
|
76
77
|
i
|
|
77
78
|
else
|
|
78
|
-
|
|
79
|
+
decimal(v)
|
|
79
80
|
end
|
|
80
81
|
else
|
|
81
|
-
|
|
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
|
-
|
|
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
|
|
86
|
-
db.synchronize{|c|
|
|
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(
|
|
17
|
+
rs = stmt.executeQuery(LAST_INSERT_ROWID)
|
|
17
18
|
rs.next
|
|
18
19
|
rs.getInt(1)
|
|
19
20
|
end
|