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
|
@@ -5,97 +5,66 @@ rescue LoadError
|
|
|
5
5
|
end
|
|
6
6
|
raise(LoadError, "require 'mysql' did not define Mysql::CLIENT_MULTI_RESULTS!\n You are probably using the pure ruby mysql.rb driver,\n which Sequel does not support. You need to install\n the C based adapter, and make sure that the mysql.so\n file is loaded instead of the mysql.rb file.\n") unless defined?(Mysql::CLIENT_MULTI_RESULTS)
|
|
7
7
|
|
|
8
|
-
Sequel.require %w'shared/
|
|
8
|
+
Sequel.require %w'shared/mysql_prepared_statements', 'adapters'
|
|
9
9
|
|
|
10
10
|
module Sequel
|
|
11
11
|
# Module for holding all MySQL-related classes and modules for Sequel.
|
|
12
12
|
module MySQL
|
|
13
13
|
TYPE_TRANSLATOR = tt = Class.new do
|
|
14
14
|
def boolean(s) s.to_i != 0 end
|
|
15
|
-
def blob(s) ::Sequel::SQL::Blob.new(s) end
|
|
16
15
|
def integer(s) s.to_i end
|
|
17
16
|
def float(s) s.to_f end
|
|
18
|
-
def decimal(s) ::BigDecimal.new(s) end
|
|
19
|
-
def date(s) ::Sequel.string_to_date(s) end
|
|
20
|
-
def time(s) ::Sequel.string_to_time(s) end
|
|
21
|
-
def timestamp(s) ::Sequel.database_to_application_timestamp(s) end
|
|
22
|
-
def date_conv(s) ::Sequel::MySQL.convert_date_time(:string_to_date, s) end
|
|
23
|
-
def time_conv(s) ::Sequel::MySQL.convert_date_time(:string_to_time, s) end
|
|
24
|
-
def timestamp_conv(s) ::Sequel::MySQL.convert_date_time(:database_to_application_timestamp, s) end
|
|
25
17
|
end.new
|
|
26
18
|
|
|
27
19
|
# Hash with integer keys and callable values for converting MySQL types.
|
|
28
20
|
MYSQL_TYPES = {}
|
|
29
21
|
{
|
|
30
|
-
[0, 246]
|
|
31
|
-
[2, 3, 8, 9, 13, 247, 248]
|
|
32
|
-
[4, 5]
|
|
33
|
-
[249, 250, 251, 252]
|
|
22
|
+
[0, 246] => ::BigDecimal.method(:new),
|
|
23
|
+
[2, 3, 8, 9, 13, 247, 248] => tt.method(:integer),
|
|
24
|
+
[4, 5] => tt.method(:float),
|
|
25
|
+
[249, 250, 251, 252] => ::Sequel::SQL::Blob.method(:new)
|
|
34
26
|
}.each do |k,v|
|
|
35
27
|
k.each{|n| MYSQL_TYPES[n] = v}
|
|
36
28
|
end
|
|
37
29
|
|
|
38
|
-
# Modify the type translator used for the tinyint type based
|
|
39
|
-
# on the value given.
|
|
40
|
-
def self.convert_tinyint_to_bool=(v)
|
|
41
|
-
MYSQL_TYPES[1] = TYPE_TRANSLATOR.method(v ? :boolean : :integer)
|
|
42
|
-
@convert_tinyint_to_bool = v
|
|
43
|
-
end
|
|
44
|
-
self.convert_tinyint_to_bool = convert_tinyint_to_bool
|
|
45
|
-
|
|
46
30
|
class << self
|
|
47
|
-
#
|
|
48
|
-
#
|
|
49
|
-
#
|
|
50
|
-
#
|
|
51
|
-
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
# Modify the type translators for the date, time, and timestamp types
|
|
55
|
-
# depending on the value given.
|
|
56
|
-
def self.convert_invalid_date_time=(v)
|
|
57
|
-
MYSQL_TYPES[11] = TYPE_TRANSLATOR.method(v == false ? :time : :time_conv)
|
|
58
|
-
m = TYPE_TRANSLATOR.method(v == false ? :date : :date_conv)
|
|
59
|
-
[10, 14].each{|i| MYSQL_TYPES[i] = m}
|
|
60
|
-
m = TYPE_TRANSLATOR.method(v == false ? :timestamp : :timestamp_conv)
|
|
61
|
-
[7, 12].each{|i| MYSQL_TYPES[i] = m}
|
|
62
|
-
@convert_invalid_date_time = v
|
|
31
|
+
# Whether to convert invalid date time values by default.
|
|
32
|
+
#
|
|
33
|
+
# Only applies to Sequel::Database instances created after this
|
|
34
|
+
# has been set.
|
|
35
|
+
attr_accessor :convert_invalid_date_time
|
|
63
36
|
end
|
|
64
37
|
self.convert_invalid_date_time = false
|
|
65
38
|
|
|
66
|
-
# If convert_invalid_date_time is nil, :nil, or :string and
|
|
67
|
-
# the conversion raises an InvalidValue exception, return v
|
|
68
|
-
# if :string and nil otherwise.
|
|
69
|
-
def self.convert_date_time(meth, v)
|
|
70
|
-
begin
|
|
71
|
-
Sequel.send(meth, v)
|
|
72
|
-
rescue InvalidValue
|
|
73
|
-
case @convert_invalid_date_time
|
|
74
|
-
when nil, :nil
|
|
75
|
-
nil
|
|
76
|
-
when :string
|
|
77
|
-
v
|
|
78
|
-
else
|
|
79
|
-
raise
|
|
80
|
-
end
|
|
81
|
-
end
|
|
82
|
-
end
|
|
83
|
-
|
|
84
39
|
# Database class for MySQL databases used with Sequel.
|
|
85
40
|
class Database < Sequel::Database
|
|
86
41
|
include Sequel::MySQL::DatabaseMethods
|
|
42
|
+
include Sequel::MySQL::PreparedStatements::DatabaseMethods
|
|
87
43
|
|
|
88
44
|
# Mysql::Error messages that indicate the current connection should be disconnected
|
|
89
45
|
MYSQL_DATABASE_DISCONNECT_ERRORS = /\A(Commands out of sync; you can't run this command now|Can't connect to local MySQL server through socket|MySQL server has gone away|Lost connection to MySQL server during query)/
|
|
90
46
|
|
|
91
47
|
set_adapter_scheme :mysql
|
|
48
|
+
|
|
49
|
+
# Hash of conversion procs for the current database
|
|
50
|
+
attr_reader :conversion_procs
|
|
51
|
+
#
|
|
52
|
+
# Whether to convert tinyint columns to bool for the current database
|
|
53
|
+
attr_reader :convert_tinyint_to_bool
|
|
54
|
+
|
|
55
|
+
# By default, Sequel raises an exception if in invalid date or time is used.
|
|
56
|
+
# However, if this is set to nil or :nil, the adapter treats dates
|
|
57
|
+
# like 0000-00-00 and times like 838:00:00 as nil values. If set to :string,
|
|
58
|
+
# it returns the strings as is.
|
|
59
|
+
attr_reader :convert_invalid_date_time
|
|
92
60
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
61
|
+
def initialize(opts={})
|
|
62
|
+
super
|
|
63
|
+
@conversion_procs = MYSQL_TYPES.dup
|
|
64
|
+
self.convert_tinyint_to_bool = Sequel::MySQL.convert_tinyint_to_bool
|
|
65
|
+
self.convert_invalid_date_time = Sequel::MySQL.convert_invalid_date_time
|
|
97
66
|
end
|
|
98
|
-
|
|
67
|
+
|
|
99
68
|
# Connect to the database. In addition to the usual database options,
|
|
100
69
|
# the following options have effect:
|
|
101
70
|
#
|
|
@@ -139,7 +108,7 @@ module Sequel
|
|
|
139
108
|
opts[:user],
|
|
140
109
|
opts[:password],
|
|
141
110
|
opts[:database],
|
|
142
|
-
opts[:port],
|
|
111
|
+
(opts[:port].to_i if opts[:port]),
|
|
143
112
|
opts[:socket],
|
|
144
113
|
Mysql::CLIENT_MULTI_RESULTS +
|
|
145
114
|
Mysql::CLIENT_MULTI_STATEMENTS +
|
|
@@ -161,30 +130,31 @@ module Sequel
|
|
|
161
130
|
|
|
162
131
|
sqls.each{|sql| log_yield(sql){conn.query(sql)}}
|
|
163
132
|
|
|
164
|
-
|
|
165
|
-
attr_accessor :prepared_statements
|
|
166
|
-
end
|
|
167
|
-
conn.prepared_statements = {}
|
|
133
|
+
add_prepared_statements_cache(conn)
|
|
168
134
|
conn
|
|
169
135
|
end
|
|
170
136
|
|
|
171
|
-
#
|
|
172
|
-
|
|
173
|
-
|
|
137
|
+
# Modify the type translators for the date, time, and timestamp types
|
|
138
|
+
# depending on the value given.
|
|
139
|
+
def convert_invalid_date_time=(v)
|
|
140
|
+
m0 = ::Sequel.method(:string_to_time)
|
|
141
|
+
@conversion_procs[11] = (v != false) ? lambda{|v| convert_date_time(v, &m0)} : m0
|
|
142
|
+
m1 = ::Sequel.method(:string_to_date)
|
|
143
|
+
m = (v != false) ? lambda{|v| convert_date_time(v, &m1)} : m1
|
|
144
|
+
[10, 14].each{|i| @conversion_procs[i] = m}
|
|
145
|
+
m2 = method(:to_application_timestamp)
|
|
146
|
+
m = (v != false) ? lambda{|v| convert_date_time(v, &m2)} : m2
|
|
147
|
+
[7, 12].each{|i| @conversion_procs[i] = m}
|
|
148
|
+
@convert_invalid_date_time = v
|
|
174
149
|
end
|
|
175
|
-
|
|
176
|
-
#
|
|
177
|
-
#
|
|
178
|
-
def
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
elsif sql.is_a?(Symbol)
|
|
182
|
-
execute_prepared_statement(sql, opts, &block)
|
|
183
|
-
else
|
|
184
|
-
synchronize(opts[:server]){|conn| _execute(conn, sql, opts, &block)}
|
|
185
|
-
end
|
|
150
|
+
|
|
151
|
+
# Modify the type translator used for the tinyint type based
|
|
152
|
+
# on the value given.
|
|
153
|
+
def convert_tinyint_to_bool=(v)
|
|
154
|
+
@conversion_procs[1] = TYPE_TRANSLATOR.method(v ? :boolean : :integer)
|
|
155
|
+
@convert_tinyint_to_bool = v
|
|
186
156
|
end
|
|
187
|
-
|
|
157
|
+
|
|
188
158
|
# Return the version of the MySQL server two which we are connecting.
|
|
189
159
|
def server_version(server=nil)
|
|
190
160
|
@server_version ||= (synchronize(server){|conn| conn.server_version if conn.respond_to?(:server_version)} || super)
|
|
@@ -220,7 +190,7 @@ module Sequel
|
|
|
220
190
|
end
|
|
221
191
|
end
|
|
222
192
|
rescue Mysql::Error => e
|
|
223
|
-
raise_error(e
|
|
193
|
+
raise_error(e)
|
|
224
194
|
ensure
|
|
225
195
|
r.free if r
|
|
226
196
|
# Use up all results to avoid a commands out of sync message.
|
|
@@ -244,10 +214,34 @@ module Sequel
|
|
|
244
214
|
:query
|
|
245
215
|
end
|
|
246
216
|
|
|
217
|
+
# If convert_invalid_date_time is nil, :nil, or :string and
|
|
218
|
+
# the conversion raises an InvalidValue exception, return v
|
|
219
|
+
# if :string and nil otherwise.
|
|
220
|
+
def convert_date_time(v)
|
|
221
|
+
begin
|
|
222
|
+
yield v
|
|
223
|
+
rescue InvalidValue
|
|
224
|
+
case @convert_invalid_date_time
|
|
225
|
+
when nil, :nil
|
|
226
|
+
nil
|
|
227
|
+
when :string
|
|
228
|
+
v
|
|
229
|
+
else
|
|
230
|
+
raise
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
|
|
247
235
|
# The MySQL adapter main error class is Mysql::Error
|
|
248
236
|
def database_error_classes
|
|
249
237
|
[Mysql::Error]
|
|
250
238
|
end
|
|
239
|
+
|
|
240
|
+
# Raise a disconnect error if the exception message matches the list
|
|
241
|
+
# of recognized exceptions.
|
|
242
|
+
def disconnect_error?(e, opts)
|
|
243
|
+
super || (e.is_a?(::Mysql::Error) && MYSQL_DATABASE_DISCONNECT_ERRORS.match(e.message))
|
|
244
|
+
end
|
|
251
245
|
|
|
252
246
|
# The database name when using the native adapter is always stored in
|
|
253
247
|
# the :database option.
|
|
@@ -262,97 +256,18 @@ module Sequel
|
|
|
262
256
|
nil
|
|
263
257
|
end
|
|
264
258
|
|
|
265
|
-
# Executes a prepared statement on an available connection. If the
|
|
266
|
-
# prepared statement already exists for the connection and has the same
|
|
267
|
-
# SQL, reuse it, otherwise, prepare the new statement. Because of the
|
|
268
|
-
# usual MySQL stupidity, we are forced to name arguments via separate
|
|
269
|
-
# SET queries. Use @sequel_arg_N (for N starting at 1) for these
|
|
270
|
-
# arguments.
|
|
271
|
-
def execute_prepared_statement(ps_name, opts, &block)
|
|
272
|
-
args = opts[:arguments]
|
|
273
|
-
ps = prepared_statements[ps_name]
|
|
274
|
-
sql = ps.prepared_sql
|
|
275
|
-
synchronize(opts[:server]) do |conn|
|
|
276
|
-
unless conn.prepared_statements[ps_name] == sql
|
|
277
|
-
conn.prepared_statements[ps_name] = sql
|
|
278
|
-
_execute(conn, "PREPARE #{ps_name} FROM '#{::Mysql.quote(sql)}'", opts)
|
|
279
|
-
end
|
|
280
|
-
i = 0
|
|
281
|
-
_execute(conn, "SET " + args.map {|arg| "@sequel_arg_#{i+=1} = #{literal(arg)}"}.join(", "), opts) unless args.empty?
|
|
282
|
-
_execute(conn, "EXECUTE #{ps_name}#{" USING #{(1..i).map{|j| "@sequel_arg_#{j}"}.join(', ')}" unless i == 0}", opts, &block)
|
|
283
|
-
end
|
|
284
|
-
end
|
|
285
|
-
|
|
286
259
|
# Convert tinyint(1) type to boolean if convert_tinyint_to_bool is true
|
|
287
260
|
def schema_column_type(db_type)
|
|
288
|
-
|
|
261
|
+
convert_tinyint_to_bool && db_type == 'tinyint(1)' ? :boolean : super
|
|
289
262
|
end
|
|
290
263
|
end
|
|
291
264
|
|
|
292
265
|
# Dataset class for MySQL datasets accessed via the native driver.
|
|
293
266
|
class Dataset < Sequel::Dataset
|
|
294
267
|
include Sequel::MySQL::DatasetMethods
|
|
295
|
-
include
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
# real database prepared statement and bound variables.
|
|
299
|
-
module CallableStatementMethods
|
|
300
|
-
# Extend given dataset with this module so subselects inside subselects in
|
|
301
|
-
# prepared statements work.
|
|
302
|
-
def subselect_sql(ds)
|
|
303
|
-
ps = ds.to_prepared_statement(:select)
|
|
304
|
-
ps.extend(CallableStatementMethods)
|
|
305
|
-
ps = ps.bind(@opts[:bind_vars]) if @opts[:bind_vars]
|
|
306
|
-
ps.prepared_args = prepared_args
|
|
307
|
-
ps.prepared_sql
|
|
308
|
-
end
|
|
309
|
-
end
|
|
310
|
-
|
|
311
|
-
# Methods for MySQL prepared statements using the native driver.
|
|
312
|
-
module PreparedStatementMethods
|
|
313
|
-
include Sequel::Dataset::UnnumberedArgumentMapper
|
|
314
|
-
|
|
315
|
-
private
|
|
316
|
-
|
|
317
|
-
# Execute the prepared statement with the bind arguments instead of
|
|
318
|
-
# the given SQL.
|
|
319
|
-
def execute(sql, opts={}, &block)
|
|
320
|
-
super(prepared_statement_name, {:arguments=>bind_arguments}.merge(opts), &block)
|
|
321
|
-
end
|
|
322
|
-
|
|
323
|
-
# Same as execute, explicit due to intricacies of alias and super.
|
|
324
|
-
def execute_dui(sql, opts={}, &block)
|
|
325
|
-
super(prepared_statement_name, {:arguments=>bind_arguments}.merge(opts), &block)
|
|
326
|
-
end
|
|
327
|
-
end
|
|
328
|
-
|
|
329
|
-
# Methods for MySQL stored procedures using the native driver.
|
|
330
|
-
module StoredProcedureMethods
|
|
331
|
-
include Sequel::Dataset::StoredProcedureMethods
|
|
332
|
-
|
|
333
|
-
private
|
|
334
|
-
|
|
335
|
-
# Execute the database stored procedure with the stored arguments.
|
|
336
|
-
def execute(sql, opts={}, &block)
|
|
337
|
-
super(@sproc_name, {:args=>@sproc_args, :sproc=>true}.merge(opts), &block)
|
|
338
|
-
end
|
|
339
|
-
|
|
340
|
-
# Same as execute, explicit due to intricacies of alias and super.
|
|
341
|
-
def execute_dui(sql, opts={}, &block)
|
|
342
|
-
super(@sproc_name, {:args=>@sproc_args, :sproc=>true}.merge(opts), &block)
|
|
343
|
-
end
|
|
344
|
-
end
|
|
345
|
-
|
|
346
|
-
# MySQL is different in that it supports prepared statements but not bound
|
|
347
|
-
# variables outside of prepared statements. The default implementation
|
|
348
|
-
# breaks the use of subselects in prepared statements, so extend the
|
|
349
|
-
# temporary prepared statement that this creates with a module that
|
|
350
|
-
# fixes it.
|
|
351
|
-
def call(type, bind_arguments={}, *values, &block)
|
|
352
|
-
ps = to_prepared_statement(type, values)
|
|
353
|
-
ps.extend(CallableStatementMethods)
|
|
354
|
-
ps.call(bind_arguments, &block)
|
|
355
|
-
end
|
|
268
|
+
include Sequel::MySQL::PreparedStatements::DatasetMethods
|
|
269
|
+
|
|
270
|
+
Database::DatasetClass = self
|
|
356
271
|
|
|
357
272
|
# Delete rows matching this dataset
|
|
358
273
|
def delete
|
|
@@ -365,11 +280,12 @@ module Sequel
|
|
|
365
280
|
def fetch_rows(sql, &block)
|
|
366
281
|
execute(sql) do |r|
|
|
367
282
|
i = -1
|
|
283
|
+
cps = db.conversion_procs
|
|
368
284
|
cols = r.fetch_fields.map do |f|
|
|
369
285
|
# Pretend tinyint is another integer type if its length is not 1, to
|
|
370
286
|
# avoid casting to boolean if Sequel::MySQL.convert_tinyint_to_bool
|
|
371
287
|
# is set.
|
|
372
|
-
type_proc = f.type == 1 && f.length != 1 ?
|
|
288
|
+
type_proc = f.type == 1 && f.length != 1 ? cps[2] : cps[f.type]
|
|
373
289
|
[output_identifier(f.name), type_proc, i+=1]
|
|
374
290
|
end
|
|
375
291
|
@columns = cols.map{|c| c.first}
|
|
@@ -395,18 +311,6 @@ module Sequel
|
|
|
395
311
|
execute_dui(insert_sql(*values)){|c| return c.insert_id}
|
|
396
312
|
end
|
|
397
313
|
|
|
398
|
-
# Store the given type of prepared statement in the associated database
|
|
399
|
-
# with the given name.
|
|
400
|
-
def prepare(type, name=nil, *values)
|
|
401
|
-
ps = to_prepared_statement(type, values)
|
|
402
|
-
ps.extend(PreparedStatementMethods)
|
|
403
|
-
if name
|
|
404
|
-
ps.prepared_statement_name = name
|
|
405
|
-
db.prepared_statements[name] = ps
|
|
406
|
-
end
|
|
407
|
-
ps
|
|
408
|
-
end
|
|
409
|
-
|
|
410
314
|
# Replace (update or insert) the matching row.
|
|
411
315
|
def replace(*args)
|
|
412
316
|
execute_dui(replace_sql(*args)){|c| return c.insert_id}
|
|
@@ -446,13 +350,10 @@ module Sequel
|
|
|
446
350
|
end
|
|
447
351
|
|
|
448
352
|
# Handle correct quoting of strings using ::MySQL.quote.
|
|
449
|
-
def
|
|
450
|
-
"'
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
# Extend the dataset with the MySQL stored procedure methods.
|
|
454
|
-
def prepare_extend_sproc(ds)
|
|
455
|
-
ds.extend(StoredProcedureMethods)
|
|
353
|
+
def literal_string_append(sql, v)
|
|
354
|
+
sql << "'"
|
|
355
|
+
sql << ::Mysql.quote(v)
|
|
356
|
+
sql << "'"
|
|
456
357
|
end
|
|
457
358
|
|
|
458
359
|
# Yield each row of the given result set r with columns cols
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
require 'mysql2' unless defined? Mysql2
|
|
2
|
-
|
|
3
|
-
Sequel.require %w'shared/mysql', 'adapters'
|
|
2
|
+
Sequel.require %w'shared/mysql_prepared_statements', 'adapters'
|
|
4
3
|
|
|
5
4
|
module Sequel
|
|
6
5
|
# Module for holding all Mysql2-related classes and modules for Sequel.
|
|
@@ -8,11 +7,21 @@ module Sequel
|
|
|
8
7
|
# Database class for MySQL databases used with Sequel.
|
|
9
8
|
class Database < Sequel::Database
|
|
10
9
|
include Sequel::MySQL::DatabaseMethods
|
|
10
|
+
include Sequel::MySQL::PreparedStatements::DatabaseMethods
|
|
11
11
|
|
|
12
12
|
# Mysql::Error messages that indicate the current connection should be disconnected
|
|
13
|
-
MYSQL_DATABASE_DISCONNECT_ERRORS = /\A(Commands out of sync; you can't run this command now|Can't connect to local MySQL server through socket|MySQL server has gone away)/
|
|
13
|
+
MYSQL_DATABASE_DISCONNECT_ERRORS = /\A(Commands out of sync; you can't run this command now|Can't connect to local MySQL server through socket|MySQL server has gone away|This connection is still waiting for a result, try again once you have the result)/
|
|
14
14
|
|
|
15
15
|
set_adapter_scheme :mysql2
|
|
16
|
+
|
|
17
|
+
# Whether to convert tinyint columns to bool for this database
|
|
18
|
+
attr_accessor :convert_tinyint_to_bool
|
|
19
|
+
|
|
20
|
+
# Set the convert_tinyint_to_bool setting based on the default value.
|
|
21
|
+
def initialize(opts={})
|
|
22
|
+
super
|
|
23
|
+
self.convert_tinyint_to_bool = Sequel::MySQL.convert_tinyint_to_bool
|
|
24
|
+
end
|
|
16
25
|
|
|
17
26
|
# Connect to the database. In addition to the usual database options,
|
|
18
27
|
# the following options have effect:
|
|
@@ -21,7 +30,6 @@ module Sequel
|
|
|
21
30
|
# a filter for an autoincrement column equals NULL to return the last
|
|
22
31
|
# inserted row.
|
|
23
32
|
# * :charset - Same as :encoding (:encoding takes precendence)
|
|
24
|
-
# * :compress - Set to false to not compress results from the server
|
|
25
33
|
# * :config_default_group - The default group to read from the in
|
|
26
34
|
# the MySQL config file.
|
|
27
35
|
# * :config_local_infile - If provided, sets the Mysql::OPT_LOCAL_INFILE
|
|
@@ -57,24 +65,10 @@ module Sequel
|
|
|
57
65
|
|
|
58
66
|
sqls.each{|sql| log_yield(sql){conn.query(sql)}}
|
|
59
67
|
|
|
68
|
+
add_prepared_statements_cache(conn)
|
|
60
69
|
conn
|
|
61
70
|
end
|
|
62
71
|
|
|
63
|
-
# Returns instance of Sequel::MySQL::Dataset with the given options.
|
|
64
|
-
def dataset(opts = nil)
|
|
65
|
-
Mysql2::Dataset.new(self, opts)
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
# Executes the given SQL using an available connection, yielding the
|
|
69
|
-
# connection if the block is given.
|
|
70
|
-
def execute(sql, opts={}, &block)
|
|
71
|
-
if opts[:sproc]
|
|
72
|
-
call_sproc(sql, opts, &block)
|
|
73
|
-
else
|
|
74
|
-
synchronize(opts[:server]){|conn| _execute(conn, sql, opts, &block)}
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
|
|
78
72
|
# Return the version of the MySQL server two which we are connecting.
|
|
79
73
|
def server_version(server=nil)
|
|
80
74
|
@server_version ||= (synchronize(server){|conn| conn.server_info[:id]} || super)
|
|
@@ -87,14 +81,14 @@ module Sequel
|
|
|
87
81
|
# yield the connection if a block is given.
|
|
88
82
|
def _execute(conn, sql, opts)
|
|
89
83
|
begin
|
|
90
|
-
r = log_yield(sql){conn.query(sql, :symbolize_keys => true, :database_timezone =>
|
|
84
|
+
r = log_yield(sql){conn.query(sql, :symbolize_keys => true, :database_timezone => timezone, :application_timezone => Sequel.application_timezone)}
|
|
91
85
|
if opts[:type] == :select
|
|
92
86
|
yield r if r
|
|
93
87
|
elsif block_given?
|
|
94
88
|
yield conn
|
|
95
89
|
end
|
|
96
90
|
rescue ::Mysql2::Error => e
|
|
97
|
-
raise_error(e
|
|
91
|
+
raise_error(e)
|
|
98
92
|
end
|
|
99
93
|
end
|
|
100
94
|
|
|
@@ -108,6 +102,10 @@ module Sequel
|
|
|
108
102
|
[::Mysql2::Error]
|
|
109
103
|
end
|
|
110
104
|
|
|
105
|
+
def disconnect_error?(e, opts)
|
|
106
|
+
super || (e.is_a?(::Mysql2::Error) && MYSQL_DATABASE_DISCONNECT_ERRORS.match(e.message))
|
|
107
|
+
end
|
|
108
|
+
|
|
111
109
|
# The database name when using the native adapter is always stored in
|
|
112
110
|
# the :database option.
|
|
113
111
|
def database_name
|
|
@@ -121,13 +119,16 @@ module Sequel
|
|
|
121
119
|
|
|
122
120
|
# Convert tinyint(1) type to boolean if convert_tinyint_to_bool is true
|
|
123
121
|
def schema_column_type(db_type)
|
|
124
|
-
|
|
122
|
+
convert_tinyint_to_bool && db_type == 'tinyint(1)' ? :boolean : super
|
|
125
123
|
end
|
|
126
124
|
end
|
|
127
125
|
|
|
128
126
|
# Dataset class for MySQL datasets accessed via the native driver.
|
|
129
127
|
class Dataset < Sequel::Dataset
|
|
130
128
|
include Sequel::MySQL::DatasetMethods
|
|
129
|
+
include Sequel::MySQL::PreparedStatements::DatasetMethods
|
|
130
|
+
|
|
131
|
+
Database::DatasetClass = self
|
|
131
132
|
|
|
132
133
|
# Delete rows matching this dataset
|
|
133
134
|
def delete
|
|
@@ -138,7 +139,7 @@ module Sequel
|
|
|
138
139
|
def fetch_rows(sql, &block)
|
|
139
140
|
execute(sql) do |r|
|
|
140
141
|
@columns = r.fields
|
|
141
|
-
r.each(:cast_booleans =>
|
|
142
|
+
r.each(:cast_booleans => db.convert_tinyint_to_bool, &block)
|
|
142
143
|
end
|
|
143
144
|
self
|
|
144
145
|
end
|
|
@@ -171,8 +172,8 @@ module Sequel
|
|
|
171
172
|
end
|
|
172
173
|
|
|
173
174
|
# Handle correct quoting of strings using ::Mysql2::Client#escape.
|
|
174
|
-
def
|
|
175
|
-
db.synchronize{|c|
|
|
175
|
+
def literal_string_append(sql, v)
|
|
176
|
+
sql << "'" << db.synchronize{|c| c.escape(v)} << "'"
|
|
176
177
|
end
|
|
177
178
|
end
|
|
178
179
|
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
Sequel.require 'adapters/shared/db2'
|
|
2
|
+
|
|
3
|
+
module Sequel
|
|
4
|
+
module ODBC
|
|
5
|
+
# Database and Dataset instance methods for DB2 specific
|
|
6
|
+
# support via ODBC.
|
|
7
|
+
module DB2
|
|
8
|
+
module DatabaseMethods
|
|
9
|
+
include ::Sequel::DB2::DatabaseMethods
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
class Dataset < ODBC::Dataset
|
|
13
|
+
include ::Sequel::DB2::DatasetMethods
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -7,12 +7,7 @@ module Sequel
|
|
|
7
7
|
module MSSQL
|
|
8
8
|
module DatabaseMethods
|
|
9
9
|
include Sequel::MSSQL::DatabaseMethods
|
|
10
|
-
LAST_INSERT_ID_SQL='SELECT SCOPE_IDENTITY()'
|
|
11
|
-
|
|
12
|
-
# Return an instance of Sequel::ODBC::MSSQL::Dataset with the given opts.
|
|
13
|
-
def dataset(opts=nil)
|
|
14
|
-
Sequel::ODBC::MSSQL::Dataset.new(self, opts)
|
|
15
|
-
end
|
|
10
|
+
LAST_INSERT_ID_SQL='SELECT SCOPE_IDENTITY()'.freeze
|
|
16
11
|
|
|
17
12
|
# Return the last inserted identity value.
|
|
18
13
|
def execute_insert(sql, opts={})
|
data/lib/sequel/adapters/odbc.rb
CHANGED
|
@@ -15,9 +15,16 @@ module Sequel
|
|
|
15
15
|
when 'mssql'
|
|
16
16
|
Sequel.ts_require 'adapters/odbc/mssql'
|
|
17
17
|
extend Sequel::ODBC::MSSQL::DatabaseMethods
|
|
18
|
+
@dataset_class = Sequel::ODBC::MSSQL::Dataset
|
|
19
|
+
set_mssql_unicode_strings
|
|
18
20
|
when 'progress'
|
|
19
21
|
Sequel.ts_require 'adapters/shared/progress'
|
|
20
22
|
extend Sequel::Progress::DatabaseMethods
|
|
23
|
+
extend_datasets(Sequel::Progress::DatasetMethods)
|
|
24
|
+
when 'db2'
|
|
25
|
+
Sequel.ts_require 'adapters/odbc/db2'
|
|
26
|
+
extend Sequel::ODBC::DB2::DatabaseMethods
|
|
27
|
+
@dataset_class = Sequel::ODBC::DB2::Dataset
|
|
21
28
|
end
|
|
22
29
|
end
|
|
23
30
|
|
|
@@ -41,17 +48,13 @@ module Sequel
|
|
|
41
48
|
conn
|
|
42
49
|
end
|
|
43
50
|
|
|
44
|
-
def dataset(opts = nil)
|
|
45
|
-
ODBC::Dataset.new(self, opts)
|
|
46
|
-
end
|
|
47
|
-
|
|
48
51
|
def execute(sql, opts={})
|
|
49
52
|
synchronize(opts[:server]) do |conn|
|
|
50
53
|
begin
|
|
51
54
|
r = log_yield(sql){conn.run(sql)}
|
|
52
55
|
yield(r) if block_given?
|
|
53
56
|
rescue ::ODBC::Error, ArgumentError => e
|
|
54
|
-
raise_error(e
|
|
57
|
+
raise_error(e)
|
|
55
58
|
ensure
|
|
56
59
|
r.drop if r
|
|
57
60
|
end
|
|
@@ -64,7 +67,7 @@ module Sequel
|
|
|
64
67
|
begin
|
|
65
68
|
log_yield(sql){conn.do(sql)}
|
|
66
69
|
rescue ::ODBC::Error, ArgumentError => e
|
|
67
|
-
raise_error(e
|
|
70
|
+
raise_error(e)
|
|
68
71
|
end
|
|
69
72
|
end
|
|
70
73
|
end
|
|
@@ -76,9 +79,17 @@ module Sequel
|
|
|
76
79
|
:do
|
|
77
80
|
end
|
|
78
81
|
|
|
82
|
+
def database_error_classes
|
|
83
|
+
[::ODBC::Error]
|
|
84
|
+
end
|
|
85
|
+
|
|
79
86
|
def disconnect_connection(c)
|
|
80
87
|
c.disconnect
|
|
81
88
|
end
|
|
89
|
+
|
|
90
|
+
def disconnect_error?(e, opts)
|
|
91
|
+
super || (e.is_a?(::ODBC::Error) && DISCONNECT_ERRORS.match(e.message))
|
|
92
|
+
end
|
|
82
93
|
end
|
|
83
94
|
|
|
84
95
|
class Dataset < Sequel::Dataset
|
|
@@ -87,15 +98,23 @@ module Sequel
|
|
|
87
98
|
ODBC_DATE_FORMAT = "{d '%Y-%m-%d'}".freeze
|
|
88
99
|
TIMESTAMP_FORMAT="{ts '%Y-%m-%d %H:%M:%S'}".freeze
|
|
89
100
|
|
|
101
|
+
Database::DatasetClass = self
|
|
102
|
+
|
|
90
103
|
def fetch_rows(sql)
|
|
91
104
|
execute(sql) do |s|
|
|
92
105
|
i = -1
|
|
93
106
|
cols = s.columns(true).map{|c| [output_identifier(c.name), i+=1]}
|
|
94
|
-
|
|
107
|
+
columns = cols.map{|c| c.at(0)}
|
|
108
|
+
if opts[:offset] && offset_returns_row_number_column?
|
|
109
|
+
rn = row_number_column
|
|
110
|
+
columns.delete(rn)
|
|
111
|
+
end
|
|
112
|
+
@columns = columns
|
|
95
113
|
if rows = s.fetch_all
|
|
96
114
|
rows.each do |row|
|
|
97
115
|
hash = {}
|
|
98
116
|
cols.each{|n,i| hash[n] = convert_odbc_value(row[i])}
|
|
117
|
+
hash.delete(rn) if rn
|
|
99
118
|
yield hash
|
|
100
119
|
end
|
|
101
120
|
end
|
|
@@ -114,9 +133,9 @@ module Sequel
|
|
|
114
133
|
# ODBCColumn#mapSqlTypeToGenericType and Column#klass.
|
|
115
134
|
case v
|
|
116
135
|
when ::ODBC::TimeStamp
|
|
117
|
-
|
|
136
|
+
db.to_application_timestamp([v.year, v.month, v.day, v.hour, v.minute, v.second])
|
|
118
137
|
when ::ODBC::Time
|
|
119
|
-
Sequel.
|
|
138
|
+
Sequel::SQLTime.create(v.hour, v.minute, v.second)
|
|
120
139
|
when ::ODBC::Date
|
|
121
140
|
Date.new(v.year, v.month, v.day)
|
|
122
141
|
else
|
|
@@ -15,10 +15,6 @@ module Sequel
|
|
|
15
15
|
)
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
-
def dataset(opts = nil)
|
|
19
|
-
OpenBase::Dataset.new(self, opts)
|
|
20
|
-
end
|
|
21
|
-
|
|
22
18
|
def execute(sql, opts={})
|
|
23
19
|
synchronize(opts[:server]) do |conn|
|
|
24
20
|
r = log_yield(sql){conn.execute(sql)}
|
|
@@ -36,7 +32,9 @@ module Sequel
|
|
|
36
32
|
end
|
|
37
33
|
|
|
38
34
|
class Dataset < Sequel::Dataset
|
|
39
|
-
SELECT_CLAUSE_METHODS = clause_methods(:select, %w'distinct columns from join where group having compounds order limit')
|
|
35
|
+
SELECT_CLAUSE_METHODS = clause_methods(:select, %w'select distinct columns from join where group having compounds order limit')
|
|
36
|
+
|
|
37
|
+
Database::DatasetClass = self
|
|
40
38
|
|
|
41
39
|
def fetch_rows(sql)
|
|
42
40
|
execute(sql) do |result|
|