sequel 3.21.0 → 3.32.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 +539 -3
- data/MIT-LICENSE +1 -1
- data/README.rdoc +20 -6
- data/Rakefile +37 -19
- data/bin/sequel +1 -5
- data/doc/advanced_associations.rdoc +17 -0
- data/doc/association_basics.rdoc +293 -43
- data/doc/dataset_basics.rdoc +4 -4
- data/doc/dataset_filtering.rdoc +8 -0
- data/doc/mass_assignment.rdoc +54 -0
- data/doc/migration.rdoc +15 -538
- data/doc/model_hooks.rdoc +72 -27
- data/doc/opening_databases.rdoc +89 -50
- data/doc/prepared_statements.rdoc +40 -13
- data/doc/reflection.rdoc +8 -2
- data/doc/release_notes/3.22.0.txt +39 -0
- data/doc/release_notes/3.23.0.txt +172 -0
- data/doc/release_notes/3.24.0.txt +420 -0
- data/doc/release_notes/3.25.0.txt +88 -0
- data/doc/release_notes/3.26.0.txt +88 -0
- data/doc/release_notes/3.27.0.txt +82 -0
- data/doc/release_notes/3.28.0.txt +304 -0
- data/doc/release_notes/3.29.0.txt +459 -0
- data/doc/release_notes/3.30.0.txt +135 -0
- data/doc/release_notes/3.31.0.txt +146 -0
- data/doc/release_notes/3.32.0.txt +202 -0
- data/doc/schema_modification.rdoc +547 -0
- data/doc/sharding.rdoc +7 -1
- data/doc/testing.rdoc +129 -0
- data/doc/transactions.rdoc +137 -0
- data/doc/virtual_rows.rdoc +2 -2
- data/lib/sequel/adapters/ado/mssql.rb +18 -6
- data/lib/sequel/adapters/ado.rb +40 -18
- data/lib/sequel/adapters/amalgalite.rb +17 -9
- data/lib/sequel/adapters/db2.rb +175 -86
- data/lib/sequel/adapters/dbi.rb +15 -15
- data/lib/sequel/adapters/do/mysql.rb +5 -7
- data/lib/sequel/adapters/do/postgres.rb +0 -5
- data/lib/sequel/adapters/do/sqlite.rb +0 -5
- data/lib/sequel/adapters/do.rb +17 -36
- data/lib/sequel/adapters/firebird.rb +27 -208
- data/lib/sequel/adapters/ibmdb.rb +448 -0
- data/lib/sequel/adapters/informix.rb +6 -23
- data/lib/sequel/adapters/jdbc/as400.rb +16 -34
- data/lib/sequel/adapters/jdbc/db2.rb +52 -0
- data/lib/sequel/adapters/jdbc/derby.rb +260 -0
- data/lib/sequel/adapters/jdbc/firebird.rb +29 -0
- data/lib/sequel/adapters/jdbc/h2.rb +66 -30
- data/lib/sequel/adapters/jdbc/hsqldb.rb +177 -0
- data/lib/sequel/adapters/jdbc/informix.rb +26 -0
- data/lib/sequel/adapters/jdbc/jtds.rb +34 -0
- data/lib/sequel/adapters/jdbc/mssql.rb +3 -33
- data/lib/sequel/adapters/jdbc/mysql.rb +11 -11
- data/lib/sequel/adapters/jdbc/oracle.rb +88 -25
- data/lib/sequel/adapters/jdbc/postgresql.rb +9 -13
- data/lib/sequel/adapters/jdbc/sqlite.rb +2 -6
- data/lib/sequel/adapters/jdbc/sqlserver.rb +71 -0
- data/lib/sequel/adapters/jdbc/transactions.rb +83 -0
- data/lib/sequel/adapters/jdbc.rb +231 -78
- data/lib/sequel/adapters/mock.rb +339 -0
- data/lib/sequel/adapters/mysql.rb +85 -184
- data/lib/sequel/adapters/mysql2.rb +26 -25
- data/lib/sequel/adapters/odbc/db2.rb +17 -0
- data/lib/sequel/adapters/odbc/mssql.rb +1 -6
- data/lib/sequel/adapters/odbc.rb +28 -9
- data/lib/sequel/adapters/openbase.rb +3 -5
- data/lib/sequel/adapters/oracle.rb +355 -53
- data/lib/sequel/adapters/postgres.rb +194 -33
- data/lib/sequel/adapters/shared/access.rb +32 -9
- data/lib/sequel/adapters/shared/db2.rb +328 -0
- data/lib/sequel/adapters/shared/firebird.rb +221 -0
- data/lib/sequel/adapters/shared/informix.rb +53 -0
- data/lib/sequel/adapters/shared/mssql.rb +278 -107
- data/lib/sequel/adapters/shared/mysql.rb +203 -65
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +149 -0
- data/lib/sequel/adapters/shared/oracle.rb +237 -46
- data/lib/sequel/adapters/shared/postgres.rb +214 -82
- data/lib/sequel/adapters/shared/progress.rb +5 -8
- data/lib/sequel/adapters/shared/sqlite.rb +200 -50
- data/lib/sequel/adapters/sqlite.rb +29 -21
- data/lib/sequel/adapters/swift/mysql.rb +12 -7
- data/lib/sequel/adapters/swift/postgres.rb +0 -5
- data/lib/sequel/adapters/swift/sqlite.rb +8 -6
- data/lib/sequel/adapters/swift.rb +5 -5
- data/lib/sequel/adapters/tinytds.rb +160 -19
- data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +66 -0
- data/lib/sequel/adapters/utils/stored_procedures.rb +1 -11
- data/lib/sequel/ast_transformer.rb +190 -0
- data/lib/sequel/connection_pool/threaded.rb +3 -2
- data/lib/sequel/connection_pool.rb +1 -1
- data/lib/sequel/core.rb +68 -5
- data/lib/sequel/database/connecting.rb +5 -6
- data/lib/sequel/database/dataset.rb +4 -4
- data/lib/sequel/database/dataset_defaults.rb +59 -1
- data/lib/sequel/database/logging.rb +1 -1
- data/lib/sequel/database/misc.rb +104 -19
- data/lib/sequel/database/query.rb +163 -59
- data/lib/sequel/database/schema_generator.rb +17 -7
- data/lib/sequel/database/schema_methods.rb +59 -29
- data/lib/sequel/dataset/actions.rb +240 -76
- data/lib/sequel/dataset/features.rb +91 -8
- data/lib/sequel/dataset/graph.rb +38 -11
- data/lib/sequel/dataset/misc.rb +50 -23
- data/lib/sequel/dataset/mutation.rb +12 -7
- data/lib/sequel/dataset/prepared_statements.rb +59 -27
- data/lib/sequel/dataset/query.rb +236 -43
- data/lib/sequel/dataset/sql.rb +676 -267
- data/lib/sequel/dataset.rb +8 -0
- data/lib/sequel/exceptions.rb +4 -0
- data/lib/sequel/extensions/columns_introspection.rb +61 -0
- data/lib/sequel/extensions/migration.rb +6 -4
- data/lib/sequel/extensions/named_timezones.rb +5 -0
- data/lib/sequel/extensions/query.rb +1 -1
- data/lib/sequel/extensions/thread_local_timezones.rb +1 -1
- data/lib/sequel/extensions/to_dot.rb +95 -83
- data/lib/sequel/model/associations.rb +1081 -344
- data/lib/sequel/model/base.rb +420 -133
- data/lib/sequel/model/errors.rb +1 -1
- data/lib/sequel/model/exceptions.rb +5 -1
- data/lib/sequel/model.rb +20 -10
- data/lib/sequel/plugins/active_model.rb +13 -1
- data/lib/sequel/plugins/association_pks.rb +22 -4
- data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
- data/lib/sequel/plugins/composition.rb +43 -10
- data/lib/sequel/plugins/dataset_associations.rb +100 -0
- data/lib/sequel/plugins/defaults_setter.rb +58 -0
- data/lib/sequel/plugins/force_encoding.rb +6 -6
- data/lib/sequel/plugins/identity_map.rb +114 -7
- data/lib/sequel/plugins/many_through_many.rb +68 -7
- data/lib/sequel/plugins/nested_attributes.rb +65 -10
- data/lib/sequel/plugins/prepared_statements.rb +151 -0
- data/lib/sequel/plugins/prepared_statements_associations.rb +84 -0
- data/lib/sequel/plugins/prepared_statements_safe.rb +82 -0
- data/lib/sequel/plugins/prepared_statements_with_pk.rb +59 -0
- data/lib/sequel/plugins/rcte_tree.rb +29 -15
- data/lib/sequel/plugins/serialization.rb +98 -49
- data/lib/sequel/plugins/serialization_modification_detection.rb +63 -0
- data/lib/sequel/plugins/sharding.rb +21 -54
- data/lib/sequel/plugins/single_table_inheritance.rb +3 -1
- data/lib/sequel/plugins/typecast_on_load.rb +9 -12
- data/lib/sequel/plugins/update_primary_key.rb +2 -2
- data/lib/sequel/plugins/xml_serializer.rb +3 -3
- data/lib/sequel/sql.rb +109 -52
- data/lib/sequel/timezones.rb +57 -38
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/db2_spec.rb +146 -0
- data/spec/adapters/mssql_spec.rb +135 -30
- data/spec/adapters/mysql_spec.rb +244 -212
- data/spec/adapters/oracle_spec.rb +67 -77
- data/spec/adapters/postgres_spec.rb +267 -78
- data/spec/adapters/spec_helper.rb +6 -5
- data/spec/adapters/sqlite_spec.rb +35 -21
- data/spec/core/connection_pool_spec.rb +71 -92
- data/spec/core/core_sql_spec.rb +21 -30
- data/spec/core/database_spec.rb +789 -512
- data/spec/core/dataset_spec.rb +1176 -1061
- data/spec/core/expression_filters_spec.rb +159 -42
- data/spec/core/mock_adapter_spec.rb +419 -0
- data/spec/core/object_graph_spec.rb +86 -114
- data/spec/core/schema_generator_spec.rb +3 -3
- data/spec/core/schema_spec.rb +298 -38
- data/spec/core/spec_helper.rb +6 -48
- data/spec/extensions/active_model_spec.rb +13 -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 +66 -32
- data/spec/extensions/caching_spec.rb +23 -50
- data/spec/extensions/class_table_inheritance_spec.rb +31 -83
- data/spec/extensions/columns_introspection_spec.rb +91 -0
- data/spec/extensions/composition_spec.rb +18 -13
- data/spec/extensions/dataset_associations_spec.rb +199 -0
- data/spec/extensions/defaults_setter_spec.rb +64 -0
- data/spec/extensions/hook_class_methods_spec.rb +65 -91
- data/spec/extensions/identity_map_spec.rb +114 -22
- data/spec/extensions/instance_filters_spec.rb +11 -21
- data/spec/extensions/instance_hooks_spec.rb +53 -0
- 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 +283 -250
- data/spec/extensions/migration_spec.rb +35 -32
- data/spec/extensions/named_timezones_spec.rb +23 -3
- data/spec/extensions/nested_attributes_spec.rb +97 -88
- data/spec/extensions/optimistic_locking_spec.rb +9 -20
- data/spec/extensions/prepared_statements_associations_spec.rb +111 -0
- data/spec/extensions/prepared_statements_safe_spec.rb +61 -0
- data/spec/extensions/prepared_statements_spec.rb +53 -0
- data/spec/extensions/prepared_statements_with_pk_spec.rb +31 -0
- data/spec/extensions/pretty_table_spec.rb +1 -6
- data/spec/extensions/query_spec.rb +6 -0
- data/spec/extensions/rcte_tree_spec.rb +41 -43
- data/spec/extensions/schema_dumper_spec.rb +5 -8
- data/spec/extensions/schema_spec.rb +13 -21
- data/spec/extensions/serialization_modification_detection_spec.rb +72 -0
- data/spec/extensions/serialization_spec.rb +81 -43
- data/spec/extensions/sharding_spec.rb +66 -140
- data/spec/extensions/single_table_inheritance_spec.rb +18 -29
- data/spec/extensions/spec_helper.rb +13 -61
- data/spec/extensions/sql_expr_spec.rb +20 -60
- data/spec/extensions/tactical_eager_loading_spec.rb +9 -19
- data/spec/extensions/thread_local_timezones_spec.rb +22 -2
- data/spec/extensions/timestamps_spec.rb +6 -6
- data/spec/extensions/to_dot_spec.rb +4 -7
- data/spec/extensions/touch_spec.rb +13 -14
- data/spec/extensions/tree_spec.rb +11 -26
- data/spec/extensions/typecast_on_load_spec.rb +1 -6
- 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/extensions/xml_serializer_spec.rb +16 -4
- data/spec/integration/associations_test.rb +661 -21
- data/spec/integration/database_test.rb +4 -2
- data/spec/integration/dataset_test.rb +500 -67
- data/spec/integration/eager_loader_test.rb +19 -21
- data/spec/integration/model_test.rb +80 -1
- data/spec/integration/plugin_test.rb +367 -119
- data/spec/integration/prepared_statement_test.rb +222 -125
- data/spec/integration/schema_test.rb +217 -39
- data/spec/integration/spec_helper.rb +39 -30
- data/spec/integration/timezone_test.rb +38 -12
- data/spec/integration/transaction_test.rb +182 -5
- data/spec/integration/type_test.rb +17 -3
- data/spec/model/association_reflection_spec.rb +201 -7
- data/spec/model/associations_spec.rb +955 -662
- data/spec/model/base_spec.rb +275 -95
- data/spec/model/dataset_methods_spec.rb +7 -27
- data/spec/model/eager_loading_spec.rb +677 -676
- data/spec/model/hooks_spec.rb +349 -67
- data/spec/model/model_spec.rb +222 -168
- data/spec/model/plugins_spec.rb +24 -13
- data/spec/model/record_spec.rb +381 -218
- data/spec/model/spec_helper.rb +13 -71
- data/spec/model/validations_spec.rb +11 -0
- metadata +117 -73
|
@@ -11,16 +11,11 @@ module Sequel
|
|
|
11
11
|
# :dataserver and :username options.
|
|
12
12
|
def connect(server)
|
|
13
13
|
opts = server_opts(server)
|
|
14
|
-
opts[:dataserver] = opts[:host]
|
|
15
14
|
opts[:username] = opts[:user]
|
|
15
|
+
set_mssql_unicode_strings
|
|
16
16
|
TinyTds::Client.new(opts)
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
-
# Return instance of Sequel::TinyTDS::Dataset with the given options.
|
|
20
|
-
def dataset(opts = nil)
|
|
21
|
-
TinyTDS::Dataset.new(self, opts)
|
|
22
|
-
end
|
|
23
|
-
|
|
24
19
|
# Execute the given +sql+ on the server. If the :return option
|
|
25
20
|
# is present, its value should be a method symbol that is called
|
|
26
21
|
# on the TinyTds::Result object returned from executing the
|
|
@@ -32,13 +27,36 @@ module Sequel
|
|
|
32
27
|
begin
|
|
33
28
|
m = opts[:return]
|
|
34
29
|
r = nil
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
30
|
+
if (args = opts[:arguments]) && !args.empty?
|
|
31
|
+
types = []
|
|
32
|
+
values = []
|
|
33
|
+
args.each_with_index do |(k, v), i|
|
|
34
|
+
v, type = ps_arg_type(v)
|
|
35
|
+
types << "@#{k} #{type}"
|
|
36
|
+
values << "@#{k} = #{v}"
|
|
37
|
+
end
|
|
38
|
+
case m
|
|
39
|
+
when :do
|
|
40
|
+
sql = "#{sql}; SELECT @@ROWCOUNT AS AffectedRows"
|
|
41
|
+
single_value = true
|
|
42
|
+
when :insert
|
|
43
|
+
sql = "#{sql}; SELECT CAST(SCOPE_IDENTITY() AS bigint) AS Ident"
|
|
44
|
+
single_value = true
|
|
45
|
+
end
|
|
46
|
+
sql = "EXEC sp_executesql N'#{c.escape(sql)}', N'#{c.escape(types.join(', '))}', #{values.join(', ')}"
|
|
47
|
+
log_yield(sql) do
|
|
48
|
+
r = c.execute(sql)
|
|
49
|
+
r.each{|row| return row.values.first} if single_value
|
|
50
|
+
end
|
|
51
|
+
else
|
|
52
|
+
log_yield(sql) do
|
|
53
|
+
r = c.execute(sql)
|
|
54
|
+
return r.send(m) if m
|
|
55
|
+
end
|
|
38
56
|
end
|
|
39
57
|
yield(r) if block_given?
|
|
40
58
|
rescue TinyTds::Error => e
|
|
41
|
-
raise_error(e)
|
|
59
|
+
raise_error(e, :disconnect=>!c.active?)
|
|
42
60
|
ensure
|
|
43
61
|
r.cancel if r && c.sqlsent?
|
|
44
62
|
end
|
|
@@ -74,51 +92,174 @@ module Sequel
|
|
|
74
92
|
super
|
|
75
93
|
end
|
|
76
94
|
|
|
95
|
+
# tiny_tds uses TinyTds::Error as the base error class.
|
|
96
|
+
def database_error_classes
|
|
97
|
+
[TinyTds::Error]
|
|
98
|
+
end
|
|
99
|
+
|
|
77
100
|
# Close the TinyTds::Client object.
|
|
78
101
|
def disconnect_connection(c)
|
|
79
102
|
c.close
|
|
80
103
|
end
|
|
104
|
+
|
|
105
|
+
# Return true if the :conn argument is present and not active.
|
|
106
|
+
def disconnect_error?(e, opts)
|
|
107
|
+
super || (opts[:conn] && !opts[:conn].active?)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Return a 2 element array with the literal value and type to use
|
|
111
|
+
# in the prepared statement call for the given value and connection.
|
|
112
|
+
def ps_arg_type(v)
|
|
113
|
+
case v
|
|
114
|
+
when Fixnum
|
|
115
|
+
[v, 'int']
|
|
116
|
+
when Bignum
|
|
117
|
+
[v, 'bigint']
|
|
118
|
+
when Float
|
|
119
|
+
[v, 'double precision']
|
|
120
|
+
when Numeric
|
|
121
|
+
[v, 'numeric']
|
|
122
|
+
when Time
|
|
123
|
+
if v.is_a?(SQLTime)
|
|
124
|
+
[literal(v), 'time']
|
|
125
|
+
else
|
|
126
|
+
[literal(v), 'datetime']
|
|
127
|
+
end
|
|
128
|
+
when DateTime
|
|
129
|
+
[literal(v), 'datetime']
|
|
130
|
+
when Date
|
|
131
|
+
[literal(v), 'date']
|
|
132
|
+
when nil
|
|
133
|
+
['NULL', 'nvarchar(max)']
|
|
134
|
+
when true
|
|
135
|
+
['1', 'int']
|
|
136
|
+
when false
|
|
137
|
+
['0', 'int']
|
|
138
|
+
when SQL::Blob
|
|
139
|
+
[literal(v), 'varbinary(max)']
|
|
140
|
+
else
|
|
141
|
+
[literal(v), 'nvarchar(max)']
|
|
142
|
+
end
|
|
143
|
+
end
|
|
81
144
|
end
|
|
82
145
|
|
|
83
146
|
class Dataset < Sequel::Dataset
|
|
84
147
|
include Sequel::MSSQL::DatasetMethods
|
|
148
|
+
|
|
149
|
+
Database::DatasetClass = self
|
|
150
|
+
|
|
151
|
+
# SQLite already supports named bind arguments, so use directly.
|
|
152
|
+
module ArgumentMapper
|
|
153
|
+
include Sequel::Dataset::ArgumentMapper
|
|
154
|
+
|
|
155
|
+
protected
|
|
156
|
+
|
|
157
|
+
# Return a hash with the same values as the given hash,
|
|
158
|
+
# but with the keys converted to strings.
|
|
159
|
+
def map_to_prepared_args(hash)
|
|
160
|
+
args = {}
|
|
161
|
+
hash.each{|k,v| args[k.to_s.gsub('.', '__')] = v}
|
|
162
|
+
args
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
private
|
|
166
|
+
|
|
167
|
+
# SQLite uses a : before the name of the argument for named
|
|
168
|
+
# arguments.
|
|
169
|
+
def prepared_arg(k)
|
|
170
|
+
LiteralString.new("@#{k.to_s.gsub('.', '__')}")
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
# Always assume a prepared argument.
|
|
174
|
+
def prepared_arg?(k)
|
|
175
|
+
true
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
# SQLite prepared statement uses a new prepared statement each time
|
|
180
|
+
# it is called, but it does use the bind arguments.
|
|
181
|
+
module PreparedStatementMethods
|
|
182
|
+
include ArgumentMapper
|
|
183
|
+
|
|
184
|
+
private
|
|
185
|
+
|
|
186
|
+
# Run execute_select on the database with the given SQL and the stored
|
|
187
|
+
# bind arguments.
|
|
188
|
+
def execute(sql, opts={}, &block)
|
|
189
|
+
super(prepared_sql, {:arguments=>bind_arguments}.merge(opts), &block)
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
# Same as execute, explicit due to intricacies of alias and super.
|
|
193
|
+
def execute_dui(sql, opts={}, &block)
|
|
194
|
+
super(prepared_sql, {:arguments=>bind_arguments}.merge(opts), &block)
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
# Same as execute, explicit due to intricacies of alias and super.
|
|
198
|
+
def execute_insert(sql, opts={}, &block)
|
|
199
|
+
super(prepared_sql, {:arguments=>bind_arguments}.merge(opts), &block)
|
|
200
|
+
end
|
|
201
|
+
end
|
|
85
202
|
|
|
86
203
|
# Yield hashes with symbol keys, attempting to optimize for
|
|
87
204
|
# various cases.
|
|
88
205
|
def fetch_rows(sql)
|
|
89
206
|
execute(sql) do |result|
|
|
90
207
|
each_opts = {:cache_rows=>false}
|
|
91
|
-
each_opts[:timezone] = :utc if
|
|
92
|
-
offset = @opts[:offset]
|
|
93
|
-
|
|
94
|
-
if
|
|
208
|
+
each_opts[:timezone] = :utc if db.timezone == :utc
|
|
209
|
+
rn = row_number_column if offset = @opts[:offset]
|
|
210
|
+
columns = cols = result.fields.map{|c| output_identifier(c)}
|
|
211
|
+
if offset
|
|
212
|
+
rn = row_number_column
|
|
213
|
+
columns = columns.dup
|
|
214
|
+
columns.delete(rn)
|
|
215
|
+
end
|
|
216
|
+
@columns = columns
|
|
217
|
+
#if identifier_output_method
|
|
95
218
|
each_opts[:as] = :array
|
|
96
219
|
result.each(each_opts) do |r|
|
|
97
220
|
h = {}
|
|
98
221
|
cols.zip(r).each{|k, v| h[k] = v}
|
|
99
|
-
h.delete(
|
|
222
|
+
h.delete(rn) if rn
|
|
100
223
|
yield h
|
|
101
224
|
end
|
|
225
|
+
=begin
|
|
226
|
+
# Temporarily disable this optimization, as tiny_tds uses string keys
|
|
227
|
+
# if result.fields is called before result.each(:symbolize_keys=>true).
|
|
228
|
+
# See https://github.com/rails-sqlserver/tiny_tds/issues/57
|
|
102
229
|
else
|
|
103
230
|
each_opts[:symbolize_keys] = true
|
|
104
231
|
if offset
|
|
105
232
|
result.each(each_opts) do |r|
|
|
106
|
-
r.delete(
|
|
233
|
+
r.delete(rn) if rn
|
|
107
234
|
yield r
|
|
108
235
|
end
|
|
109
236
|
else
|
|
110
|
-
result.each(each_opts, &
|
|
237
|
+
result.each(each_opts, &Proc.new)
|
|
111
238
|
end
|
|
112
239
|
end
|
|
240
|
+
=end
|
|
113
241
|
end
|
|
114
242
|
self
|
|
115
243
|
end
|
|
116
244
|
|
|
245
|
+
# Create a named prepared statement that is stored in the
|
|
246
|
+
# database (and connection) for reuse.
|
|
247
|
+
def prepare(type, name=nil, *values)
|
|
248
|
+
ps = to_prepared_statement(type, values)
|
|
249
|
+
ps.extend(PreparedStatementMethods)
|
|
250
|
+
if name
|
|
251
|
+
ps.prepared_statement_name = name
|
|
252
|
+
db.prepared_statements[name] = ps
|
|
253
|
+
end
|
|
254
|
+
ps
|
|
255
|
+
end
|
|
256
|
+
|
|
117
257
|
private
|
|
118
258
|
|
|
119
259
|
# Properly escape the given string +v+.
|
|
120
|
-
def
|
|
121
|
-
|
|
260
|
+
def literal_string_append(sql, v)
|
|
261
|
+
sql << 'N' if mssql_unicode_strings
|
|
262
|
+
sql << "'" << db.synchronize{|c| c.escape(v)} << "'"
|
|
122
263
|
end
|
|
123
264
|
end
|
|
124
265
|
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
module Sequel
|
|
2
|
+
module EmulateOffsetWithRowNumber
|
|
3
|
+
# When a subselect that uses :offset is used in IN or NOT IN,
|
|
4
|
+
# use a nested subselect that only includes the first column
|
|
5
|
+
# instead of the ROW_NUMBER column added by the emulated offset support.
|
|
6
|
+
def complex_expression_sql_append(sql, op, args)
|
|
7
|
+
case op
|
|
8
|
+
when :IN, :"NOT IN"
|
|
9
|
+
ds = args.at(1)
|
|
10
|
+
if ds.is_a?(Sequel::Dataset) && ds.opts[:offset]
|
|
11
|
+
c = ds.opts[:select].first
|
|
12
|
+
case c
|
|
13
|
+
when Symbol
|
|
14
|
+
t, cl, a = split_symbol(c)
|
|
15
|
+
if a
|
|
16
|
+
c = SQL::Identifier.new(a)
|
|
17
|
+
elsif t
|
|
18
|
+
c = SQL::Identifier.new(cl)
|
|
19
|
+
end
|
|
20
|
+
when SQL::AliasedExpression
|
|
21
|
+
c = SQL::Identifier.new(c.aliaz)
|
|
22
|
+
when SQL::QualifiedIdentifier
|
|
23
|
+
c = SQL::Identifier.new(c.column)
|
|
24
|
+
end
|
|
25
|
+
super(sql, op, [args.at(0), ds.from_self.select(c)])
|
|
26
|
+
else
|
|
27
|
+
super
|
|
28
|
+
end
|
|
29
|
+
else
|
|
30
|
+
super
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Emulate OFFSET support with the ROW_NUMBER window function
|
|
35
|
+
#
|
|
36
|
+
# The implementation is ugly, cloning the current dataset and modifying
|
|
37
|
+
# the clone to add a ROW_NUMBER window function (and some other things),
|
|
38
|
+
# then using the modified clone in a subselect which is selected from.
|
|
39
|
+
#
|
|
40
|
+
# If offset is used, an order must be provided, because the use of ROW_NUMBER
|
|
41
|
+
# requires an order.
|
|
42
|
+
def select_sql
|
|
43
|
+
return super unless o = @opts[:offset]
|
|
44
|
+
raise(Error, "#{db.database_type} requires an order be provided if using an offset") unless order = @opts[:order]
|
|
45
|
+
dsa1 = dataset_alias(1)
|
|
46
|
+
rn = row_number_column
|
|
47
|
+
sql = @opts[:append_sql] || ''
|
|
48
|
+
subselect_sql_append(sql, unlimited.
|
|
49
|
+
unordered.
|
|
50
|
+
select_append{ROW_NUMBER(:over, :order=>order){}.as(rn)}.
|
|
51
|
+
from_self(:alias=>dsa1).
|
|
52
|
+
limit(@opts[:limit]).
|
|
53
|
+
where(SQL::Identifier.new(rn) > o).
|
|
54
|
+
order(rn))
|
|
55
|
+
sql
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
private
|
|
59
|
+
|
|
60
|
+
# This emulation adds an extra row number column that should be
|
|
61
|
+
# eliminated.
|
|
62
|
+
def offset_returns_row_number_column?
|
|
63
|
+
true
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
module Sequel
|
|
2
2
|
class Dataset
|
|
3
3
|
module StoredProcedureMethods
|
|
4
|
-
SQL_QUERY_TYPE = Hash.new{|h,k| h[k] = k}
|
|
5
|
-
SQL_QUERY_TYPE[:first] = SQL_QUERY_TYPE[:all] = :select
|
|
6
|
-
|
|
7
4
|
# The name of the stored procedure to call
|
|
8
5
|
attr_accessor :sproc_name
|
|
9
6
|
|
|
@@ -44,14 +41,7 @@ module Sequel
|
|
|
44
41
|
# ignored anyway).
|
|
45
42
|
def sproc_type=(type)
|
|
46
43
|
@sproc_type = type
|
|
47
|
-
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
private
|
|
51
|
-
|
|
52
|
-
# The type of query (:select, :insert, :delete, :update).
|
|
53
|
-
def sql_query_type
|
|
54
|
-
SQL_QUERY_TYPE[@sproc_type]
|
|
44
|
+
@opts[:sql] = ''
|
|
55
45
|
end
|
|
56
46
|
end
|
|
57
47
|
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
module Sequel
|
|
2
|
+
# The +ASTTransformer+ class is designed to handle the abstract syntax trees
|
|
3
|
+
# that Sequel uses internally and produce modified copies of them. By itself
|
|
4
|
+
# it only produces a straight copy. It's designed to be subclassed and have
|
|
5
|
+
# subclasses returned modified copies of the specific nodes that need to
|
|
6
|
+
# be modified.
|
|
7
|
+
class ASTTransformer
|
|
8
|
+
# Return +obj+ or a potentially transformed version of it.
|
|
9
|
+
def transform(obj)
|
|
10
|
+
v(obj)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
private
|
|
14
|
+
|
|
15
|
+
# Recursive version that handles all of Sequel's internal object types
|
|
16
|
+
# and produces copies of them.
|
|
17
|
+
def v(o)
|
|
18
|
+
case o
|
|
19
|
+
when Symbol, Numeric, String, Class, TrueClass, FalseClass, NilClass
|
|
20
|
+
o
|
|
21
|
+
when Array
|
|
22
|
+
o.map{|x| v(x)}
|
|
23
|
+
when Hash
|
|
24
|
+
h = {}
|
|
25
|
+
o.each{|k, val| h[v(k)] = v(val)}
|
|
26
|
+
h
|
|
27
|
+
when SQL::ComplexExpression
|
|
28
|
+
SQL::ComplexExpression.new(o.op, *v(o.args))
|
|
29
|
+
when SQL::Identifier
|
|
30
|
+
SQL::Identifier.new(v(o.value))
|
|
31
|
+
when SQL::QualifiedIdentifier
|
|
32
|
+
SQL::QualifiedIdentifier.new(v(o.table), v(o.column))
|
|
33
|
+
when SQL::OrderedExpression
|
|
34
|
+
SQL::OrderedExpression.new(v(o.expression), o.descending, :nulls=>o.nulls)
|
|
35
|
+
when SQL::AliasedExpression
|
|
36
|
+
SQL::AliasedExpression.new(v(o.expression), o.aliaz)
|
|
37
|
+
when SQL::CaseExpression
|
|
38
|
+
args = [v(o.conditions), v(o.default)]
|
|
39
|
+
args << v(o.expression) if o.expression?
|
|
40
|
+
SQL::CaseExpression.new(*args)
|
|
41
|
+
when SQL::Cast
|
|
42
|
+
SQL::Cast.new(v(o.expr), o.type)
|
|
43
|
+
when SQL::Function
|
|
44
|
+
SQL::Function.new(o.f, *v(o.args))
|
|
45
|
+
when SQL::Subscript
|
|
46
|
+
SQL::Subscript.new(v(o.f), v(o.sub))
|
|
47
|
+
when SQL::WindowFunction
|
|
48
|
+
SQL::WindowFunction.new(v(o.function), v(o.window))
|
|
49
|
+
when SQL::Window
|
|
50
|
+
opts = o.opts.dup
|
|
51
|
+
opts[:partition] = v(opts[:partition]) if opts[:partition]
|
|
52
|
+
opts[:order] = v(opts[:order]) if opts[:order]
|
|
53
|
+
SQL::Window.new(opts)
|
|
54
|
+
when SQL::PlaceholderLiteralString
|
|
55
|
+
args = if o.args.is_a?(Hash)
|
|
56
|
+
h = {}
|
|
57
|
+
o.args.each{|k,val| h[k] = v(val)}
|
|
58
|
+
h
|
|
59
|
+
else
|
|
60
|
+
v(o.args)
|
|
61
|
+
end
|
|
62
|
+
SQL::PlaceholderLiteralString.new(o.str, args, o.parens)
|
|
63
|
+
when SQL::JoinOnClause
|
|
64
|
+
SQL::JoinOnClause.new(v(o.on), o.join_type, v(o.table), v(o.table_alias))
|
|
65
|
+
when SQL::JoinUsingClause
|
|
66
|
+
SQL::JoinUsingClause.new(v(o.using), o.join_type, v(o.table), v(o.table_alias))
|
|
67
|
+
when SQL::JoinClause
|
|
68
|
+
SQL::JoinClause.new(o.join_type, v(o.table), v(o.table_alias))
|
|
69
|
+
else
|
|
70
|
+
o
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Handles qualifying existing datasets, so that unqualified columns
|
|
76
|
+
# in the dataset are qualified with a given table name.
|
|
77
|
+
class Qualifier < ASTTransformer
|
|
78
|
+
# Store the dataset to use as the basis for qualification,
|
|
79
|
+
# and the table used to qualify unqualified columns.
|
|
80
|
+
def initialize(ds, table)
|
|
81
|
+
@ds = ds
|
|
82
|
+
@table = table
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
private
|
|
86
|
+
|
|
87
|
+
# Turn <tt>SQL::Identifier</tt>s and symbols that aren't implicitly
|
|
88
|
+
# qualified into <tt>SQL::QualifiedIdentifier</tt>s. For symbols that
|
|
89
|
+
# are not implicitly qualified by are implicitly aliased, return an
|
|
90
|
+
# <tt>SQL::AliasedExpression</tt>s with a qualified version of the symbol.
|
|
91
|
+
def v(o)
|
|
92
|
+
case o
|
|
93
|
+
when Symbol
|
|
94
|
+
t, column, aliaz = @ds.send(:split_symbol, o)
|
|
95
|
+
if t
|
|
96
|
+
o
|
|
97
|
+
elsif aliaz
|
|
98
|
+
SQL::AliasedExpression.new(SQL::QualifiedIdentifier.new(@table, SQL::Identifier.new(column)), aliaz)
|
|
99
|
+
else
|
|
100
|
+
SQL::QualifiedIdentifier.new(@table, o)
|
|
101
|
+
end
|
|
102
|
+
when SQL::Identifier
|
|
103
|
+
SQL::QualifiedIdentifier.new(@table, o)
|
|
104
|
+
when SQL::QualifiedIdentifier, SQL::JoinClause
|
|
105
|
+
# Return these directly, so we don't accidentally qualify symbols in them.
|
|
106
|
+
o
|
|
107
|
+
else
|
|
108
|
+
super
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# +Unbinder+ is used to take a dataset filter and return a modified version
|
|
114
|
+
# that unbinds already bound values and returns a dataset with bound value
|
|
115
|
+
# placeholders and a hash of bind values. You can then prepare the dataset
|
|
116
|
+
# and use the bound variables to execute it with the same values.
|
|
117
|
+
#
|
|
118
|
+
# This class only does a limited form of unbinding where the variable names
|
|
119
|
+
# and values can be associated unambiguously. The only cases it handles
|
|
120
|
+
# are <tt>SQL::ComplexExpression<tt> with an operator in +UNBIND_OPS+, a
|
|
121
|
+
# first argument that's an instance of a member of +UNBIND_KEY_CLASSES+, and
|
|
122
|
+
# a second argument that's an instance of a member of +UNBIND_VALUE_CLASSES+.
|
|
123
|
+
#
|
|
124
|
+
# So it can handle cases like:
|
|
125
|
+
#
|
|
126
|
+
# DB.filter(:a=>1).exclude(:b=>2).where{c > 3}
|
|
127
|
+
#
|
|
128
|
+
# But it cannot handle cases like:
|
|
129
|
+
#
|
|
130
|
+
# DB.filter(:a + 1 < 0)
|
|
131
|
+
class Unbinder < ASTTransformer
|
|
132
|
+
# The <tt>SQL::ComplexExpression<tt> operates that will be considered
|
|
133
|
+
# for transformation.
|
|
134
|
+
UNBIND_OPS = [:'=', :'!=', :<, :>, :<=, :>=]
|
|
135
|
+
|
|
136
|
+
# The key classes (first argument of the ComplexExpression) that will
|
|
137
|
+
# considered for transformation.
|
|
138
|
+
UNBIND_KEY_CLASSES = [Symbol, SQL::Identifier, SQL::QualifiedIdentifier]
|
|
139
|
+
|
|
140
|
+
# The value classes (second argument of the ComplexExpression) that
|
|
141
|
+
# will be considered for transformation.
|
|
142
|
+
UNBIND_VALUE_CLASSES = [Numeric, String, Date, Time]
|
|
143
|
+
|
|
144
|
+
# The hash of bind variables that were extracted from the dataset filter.
|
|
145
|
+
attr_reader :binds
|
|
146
|
+
|
|
147
|
+
# Intialize an empty +binds+ hash.
|
|
148
|
+
def initialize
|
|
149
|
+
@binds = {}
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
private
|
|
153
|
+
|
|
154
|
+
# Create a suitable bound variable key for the object, which should be
|
|
155
|
+
# an instance of one of the +UNBIND_KEY_CLASSES+.
|
|
156
|
+
def bind_key(obj)
|
|
157
|
+
case obj
|
|
158
|
+
when Symbol, String
|
|
159
|
+
obj
|
|
160
|
+
when SQL::Identifier
|
|
161
|
+
bind_key(obj.value)
|
|
162
|
+
when SQL::QualifiedIdentifier
|
|
163
|
+
:"#{bind_key(obj.table)}.#{bind_key(obj.column)}"
|
|
164
|
+
else
|
|
165
|
+
raise Error, "unhandled object in Sequel::Unbinder#bind_key: #{obj}"
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
# Handle <tt>SQL::ComplexExpression</tt> instances with suitable ops
|
|
170
|
+
# and arguments, substituting the value with a bound variable placeholder
|
|
171
|
+
# and assigning it an entry in the +binds+ hash with a matching key.
|
|
172
|
+
def v(o)
|
|
173
|
+
if o.is_a?(SQL::ComplexExpression) && UNBIND_OPS.include?(o.op)
|
|
174
|
+
l, r = o.args
|
|
175
|
+
if UNBIND_KEY_CLASSES.any?{|c| l.is_a?(c)} && UNBIND_VALUE_CLASSES.any?{|c| r.is_a?(c)} && !r.is_a?(LiteralString)
|
|
176
|
+
key = bind_key(l)
|
|
177
|
+
if (old = binds[key]) && old != r
|
|
178
|
+
raise UnbindDuplicate, "two different values for #{key.inspect}: #{[r, old].inspect}"
|
|
179
|
+
end
|
|
180
|
+
binds[key] = r
|
|
181
|
+
SQL::ComplexExpression.new(o.op, l, :"$#{key}")
|
|
182
|
+
else
|
|
183
|
+
super
|
|
184
|
+
end
|
|
185
|
+
else
|
|
186
|
+
super
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
end
|
|
@@ -83,9 +83,10 @@ class Sequel::ThreadedConnectionPool < Sequel::ConnectionPool
|
|
|
83
83
|
end
|
|
84
84
|
yield conn
|
|
85
85
|
rescue Sequel::DatabaseDisconnectError
|
|
86
|
-
|
|
87
|
-
@allocated.delete(t)
|
|
86
|
+
oconn = conn
|
|
88
87
|
conn = nil
|
|
88
|
+
@disconnection_proc.call(oconn) if @disconnection_proc && oconn
|
|
89
|
+
@allocated.delete(t)
|
|
89
90
|
raise
|
|
90
91
|
ensure
|
|
91
92
|
sync{release(t)} if conn
|
|
@@ -53,7 +53,7 @@ class Sequel::ConnectionPool
|
|
|
53
53
|
|
|
54
54
|
# Return a connection pool class based on the given options.
|
|
55
55
|
def connection_pool_class(opts)
|
|
56
|
-
opts[:pool_class] || CONNECTION_POOL_MAP[[!!opts[:single_threaded], !!opts[:servers]]]
|
|
56
|
+
CONNECTION_POOL_MAP[opts[:pool_class]] || opts[:pool_class] || CONNECTION_POOL_MAP[[!!opts[:single_threaded], !!opts[:servers]]]
|
|
57
57
|
end
|
|
58
58
|
end
|
|
59
59
|
extend ClassMethods
|
data/lib/sequel/core.rb
CHANGED
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
module Sequel
|
|
26
26
|
@convert_two_digit_years = true
|
|
27
27
|
@datetime_class = Time
|
|
28
|
+
@empty_array_handle_nulls = true
|
|
28
29
|
@virtual_row_instance_eval = true
|
|
29
30
|
@require_thread = nil
|
|
30
31
|
|
|
@@ -54,6 +55,27 @@ module Sequel
|
|
|
54
55
|
# days on +DateTime+).
|
|
55
56
|
attr_accessor :datetime_class
|
|
56
57
|
|
|
58
|
+
# Sets whether or not to attempt to handle NULL values correctly when given
|
|
59
|
+
# an empty array. By default:
|
|
60
|
+
#
|
|
61
|
+
# DB[:a].filter(:b=>[])
|
|
62
|
+
# # SELECT * FROM a WHERE (b != b)
|
|
63
|
+
# DB[:a].exclude(:b=>[])
|
|
64
|
+
# # SELECT * FROM a WHERE (b = b)
|
|
65
|
+
#
|
|
66
|
+
# However, some databases (e.g. MySQL) will perform very poorly
|
|
67
|
+
# with this type of query. You can set this to false to get the
|
|
68
|
+
# following behavior:
|
|
69
|
+
#
|
|
70
|
+
# DB[:a].filter(:b=>[])
|
|
71
|
+
# # SELECT * FROM a WHERE 1 = 0
|
|
72
|
+
# DB[:a].exclude(:b=>[])
|
|
73
|
+
# # SELECT * FROM a WHERE 1 = 1
|
|
74
|
+
#
|
|
75
|
+
# This may not handle NULLs correctly, but can be much faster on
|
|
76
|
+
# some databases.
|
|
77
|
+
attr_accessor :empty_array_handle_nulls
|
|
78
|
+
|
|
57
79
|
# For backwards compatibility, has no effect.
|
|
58
80
|
attr_accessor :virtual_row_instance_eval
|
|
59
81
|
|
|
@@ -188,7 +210,7 @@ module Sequel
|
|
|
188
210
|
# This is used to ensure that the files loaded are from the same version of
|
|
189
211
|
# Sequel as this file.
|
|
190
212
|
def self.require(files, subdir=nil)
|
|
191
|
-
Array(files).each{|f| super("#{File.dirname(__FILE__)}/#{"#{subdir}/" if subdir}#{f}")}
|
|
213
|
+
Array(files).each{|f| super("#{File.dirname(__FILE__).untaint}/#{"#{subdir}/" if subdir}#{f}")}
|
|
192
214
|
end
|
|
193
215
|
|
|
194
216
|
# Set whether to set the single threaded mode for all databases by default. By default,
|
|
@@ -228,17 +250,58 @@ module Sequel
|
|
|
228
250
|
end
|
|
229
251
|
end
|
|
230
252
|
|
|
231
|
-
# Converts the given +string+ into a
|
|
253
|
+
# Converts the given +string+ into a <tt>Sequel::SQLTime</tt> object.
|
|
232
254
|
#
|
|
233
|
-
# Sequel.
|
|
255
|
+
# v = Sequel.string_to_time('10:20:30') # Sequel::SQLTime.parse('10:20:30')
|
|
256
|
+
# DB.literal(v) # => '10:20:30'
|
|
234
257
|
def self.string_to_time(string)
|
|
235
258
|
begin
|
|
236
|
-
|
|
259
|
+
SQLTime.parse(string)
|
|
237
260
|
rescue => e
|
|
238
261
|
raise convert_exception_class(e, InvalidValue)
|
|
239
262
|
end
|
|
240
263
|
end
|
|
241
264
|
|
|
265
|
+
# Uses a transaction on all given databases with the given options. This:
|
|
266
|
+
#
|
|
267
|
+
# Sequel.transaction([DB1, DB2, DB3]){...}
|
|
268
|
+
#
|
|
269
|
+
# is equivalent to:
|
|
270
|
+
#
|
|
271
|
+
# DB1.transaction do
|
|
272
|
+
# DB2.transaction do
|
|
273
|
+
# DB3.transaction do
|
|
274
|
+
# ...
|
|
275
|
+
# end
|
|
276
|
+
# end
|
|
277
|
+
# end
|
|
278
|
+
#
|
|
279
|
+
# except that if Sequel::Rollback is raised by the block, the transaction is
|
|
280
|
+
# rolled back on all databases instead of just the last one.
|
|
281
|
+
#
|
|
282
|
+
# Note that this method cannot guarantee that all databases will commit or
|
|
283
|
+
# rollback. For example, if DB3 commits but attempting to commit on DB2
|
|
284
|
+
# fails (maybe because foreign key checks are deferred), there is no way
|
|
285
|
+
# to uncommit the changes on DB3. For that kind of support, you need to
|
|
286
|
+
# have two-phase commit/prepared transactions (which Sequel supports on
|
|
287
|
+
# some databases).
|
|
288
|
+
def self.transaction(dbs, opts={}, &block)
|
|
289
|
+
unless opts[:rollback]
|
|
290
|
+
rescue_rollback = true
|
|
291
|
+
opts = opts.merge(:rollback=>:reraise)
|
|
292
|
+
end
|
|
293
|
+
pr = dbs.reverse.inject(block){|bl, db| proc{db.transaction(opts, &bl)}}
|
|
294
|
+
if rescue_rollback
|
|
295
|
+
begin
|
|
296
|
+
pr.call
|
|
297
|
+
rescue Sequel::Rollback => e
|
|
298
|
+
nil
|
|
299
|
+
end
|
|
300
|
+
else
|
|
301
|
+
pr.call
|
|
302
|
+
end
|
|
303
|
+
end
|
|
304
|
+
|
|
242
305
|
# Same as Sequel.require, but wrapped in a mutex in order to be thread safe.
|
|
243
306
|
def self.ts_require(*args)
|
|
244
307
|
check_requiring_thread{require(*args)}
|
|
@@ -292,7 +355,7 @@ module Sequel
|
|
|
292
355
|
|
|
293
356
|
private_class_method :adapter_method, :def_adapter_method
|
|
294
357
|
|
|
295
|
-
require(%w"metaprogramming sql connection_pool exceptions dataset database timezones version")
|
|
358
|
+
require(%w"metaprogramming sql connection_pool exceptions dataset database timezones ast_transformer version")
|
|
296
359
|
require('core_sql') if !defined?(::SEQUEL_NO_CORE_EXTENSIONS) && !ENV.has_key?('SEQUEL_NO_CORE_EXTENSIONS')
|
|
297
360
|
|
|
298
361
|
# Add the database adapter class methods to Sequel via metaprogramming
|