sequel 3.21.0 → 3.36.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 +855 -3
- data/MIT-LICENSE +1 -1
- data/README.rdoc +23 -7
- data/Rakefile +42 -24
- data/bin/sequel +26 -8
- data/doc/active_record.rdoc +1 -0
- data/doc/advanced_associations.rdoc +171 -11
- data/doc/association_basics.rdoc +293 -43
- data/doc/dataset_basics.rdoc +5 -5
- data/doc/dataset_filtering.rdoc +8 -0
- data/doc/mass_assignment.rdoc +56 -0
- data/doc/migration.rdoc +85 -552
- data/doc/model_hooks.rdoc +78 -27
- data/doc/object_model.rdoc +541 -0
- data/doc/opening_databases.rdoc +97 -50
- data/doc/prepared_statements.rdoc +40 -14
- data/doc/querying.rdoc +28 -4
- data/doc/reflection.rdoc +30 -4
- 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/release_notes/3.33.0.txt +157 -0
- data/doc/release_notes/3.34.0.txt +671 -0
- data/doc/release_notes/3.35.0.txt +144 -0
- data/doc/release_notes/3.36.0.txt +245 -0
- data/doc/schema_modification.rdoc +572 -0
- data/doc/sharding.rdoc +95 -3
- data/doc/testing.rdoc +129 -0
- data/doc/thread_safety.rdoc +17 -0
- data/doc/transactions.rdoc +137 -0
- data/doc/virtual_rows.rdoc +51 -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 +17 -11
- data/lib/sequel/adapters/do/postgres.rb +1 -57
- data/lib/sequel/adapters/do/sqlite.rb +0 -10
- data/lib/sequel/adapters/do.rb +18 -36
- data/lib/sequel/adapters/firebird.rb +27 -208
- data/lib/sequel/adapters/ibmdb.rb +453 -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 +47 -0
- data/lib/sequel/adapters/jdbc/derby.rb +287 -0
- data/lib/sequel/adapters/jdbc/firebird.rb +24 -0
- data/lib/sequel/adapters/jdbc/h2.rb +73 -31
- data/lib/sequel/adapters/jdbc/hsqldb.rb +184 -0
- data/lib/sequel/adapters/jdbc/informix.rb +21 -0
- data/lib/sequel/adapters/jdbc/jtds.rb +29 -0
- data/lib/sequel/adapters/jdbc/mssql.rb +3 -33
- data/lib/sequel/adapters/jdbc/mysql.rb +7 -24
- data/lib/sequel/adapters/jdbc/oracle.rb +88 -25
- data/lib/sequel/adapters/jdbc/postgresql.rb +58 -48
- data/lib/sequel/adapters/jdbc/progress.rb +21 -0
- data/lib/sequel/adapters/jdbc/sqlite.rb +20 -10
- data/lib/sequel/adapters/jdbc/sqlserver.rb +66 -0
- data/lib/sequel/adapters/jdbc/transactions.rb +83 -0
- data/lib/sequel/adapters/jdbc.rb +265 -94
- data/lib/sequel/adapters/mock.rb +361 -0
- data/lib/sequel/adapters/mysql.rb +118 -222
- data/lib/sequel/adapters/mysql2.rb +58 -57
- data/lib/sequel/adapters/odbc/mssql.rb +15 -7
- data/lib/sequel/adapters/odbc.rb +28 -9
- data/lib/sequel/adapters/openbase.rb +3 -5
- data/lib/sequel/adapters/oracle.rb +349 -53
- data/lib/sequel/adapters/postgres.rb +356 -107
- data/lib/sequel/adapters/shared/access.rb +32 -9
- data/lib/sequel/adapters/shared/db2.rb +342 -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 +335 -118
- data/lib/sequel/adapters/shared/mysql.rb +340 -76
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +155 -0
- data/lib/sequel/adapters/shared/oracle.rb +243 -45
- data/lib/sequel/adapters/shared/postgres.rb +524 -279
- data/lib/sequel/adapters/shared/progress.rb +5 -8
- data/lib/sequel/adapters/shared/sqlite.rb +265 -89
- data/lib/sequel/adapters/sqlite.rb +101 -39
- data/lib/sequel/adapters/swift/mysql.rb +9 -12
- data/lib/sequel/adapters/swift/postgres.rb +9 -74
- data/lib/sequel/adapters/swift/sqlite.rb +8 -6
- data/lib/sequel/adapters/swift.rb +8 -7
- data/lib/sequel/adapters/tinytds.rb +161 -21
- 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 +194 -0
- data/lib/sequel/connection_pool/sharded_single.rb +11 -1
- data/lib/sequel/connection_pool/sharded_threaded.rb +28 -2
- data/lib/sequel/connection_pool/single.rb +5 -0
- data/lib/sequel/connection_pool/threaded.rb +38 -14
- data/lib/sequel/connection_pool.rb +10 -2
- data/lib/sequel/core.rb +118 -11
- data/lib/sequel/database/connecting.rb +38 -28
- data/lib/sequel/database/dataset.rb +4 -4
- data/lib/sequel/database/dataset_defaults.rb +63 -2
- data/lib/sequel/database/logging.rb +7 -2
- data/lib/sequel/database/misc.rb +150 -46
- data/lib/sequel/database/query.rb +215 -65
- data/lib/sequel/database/schema_generator.rb +64 -20
- data/lib/sequel/database/schema_methods.rb +212 -54
- data/lib/sequel/dataset/actions.rb +322 -85
- data/lib/sequel/dataset/features.rb +96 -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 +68 -30
- data/lib/sequel/dataset/query.rb +237 -44
- data/lib/sequel/dataset/sql.rb +698 -278
- data/lib/sequel/dataset.rb +8 -0
- data/lib/sequel/exceptions.rb +4 -0
- data/lib/sequel/extensions/_pretty_table.rb +79 -0
- data/lib/sequel/extensions/arbitrary_servers.rb +108 -0
- data/lib/sequel/extensions/columns_introspection.rb +61 -0
- data/lib/sequel/{core_sql.rb → extensions/core_extensions.rb} +16 -34
- data/lib/sequel/extensions/migration.rb +97 -11
- data/lib/sequel/extensions/named_timezones.rb +5 -0
- data/lib/sequel/extensions/null_dataset.rb +90 -0
- data/lib/sequel/extensions/pg_array.rb +460 -0
- data/lib/sequel/extensions/pg_array_ops.rb +220 -0
- data/lib/sequel/extensions/pg_auto_parameterize.rb +169 -0
- data/lib/sequel/extensions/pg_hstore.rb +296 -0
- data/lib/sequel/extensions/pg_hstore_ops.rb +259 -0
- data/lib/sequel/extensions/pg_inet.rb +89 -0
- data/lib/sequel/extensions/pg_json.rb +178 -0
- data/lib/sequel/extensions/pg_statement_cache.rb +316 -0
- data/lib/sequel/extensions/pretty_table.rb +5 -71
- data/lib/sequel/extensions/query.rb +1 -1
- data/lib/sequel/extensions/query_literals.rb +79 -0
- data/lib/sequel/extensions/schema_caching.rb +76 -0
- data/lib/sequel/extensions/schema_dumper.rb +251 -37
- data/lib/sequel/extensions/select_remove.rb +35 -0
- data/lib/sequel/extensions/server_block.rb +139 -0
- data/lib/sequel/extensions/sql_expr.rb +4 -110
- 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 +1187 -393
- data/lib/sequel/model/base.rb +578 -170
- data/lib/sequel/model/errors.rb +1 -1
- data/lib/sequel/model/exceptions.rb +5 -1
- data/lib/sequel/model/inflections.rb +1 -1
- data/lib/sequel/model.rb +30 -11
- data/lib/sequel/no_core_ext.rb +2 -0
- data/lib/sequel/plugins/active_model.rb +13 -1
- data/lib/sequel/plugins/association_pks.rb +22 -4
- data/lib/sequel/plugins/caching.rb +25 -18
- data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
- data/lib/sequel/plugins/composition.rb +44 -12
- data/lib/sequel/plugins/dataset_associations.rb +100 -0
- data/lib/sequel/plugins/defaults_setter.rb +58 -0
- data/lib/sequel/plugins/dirty.rb +214 -0
- data/lib/sequel/plugins/eager_each.rb +59 -0
- data/lib/sequel/plugins/force_encoding.rb +6 -6
- data/lib/sequel/plugins/hook_class_methods.rb +1 -1
- data/lib/sequel/plugins/identity_map.rb +123 -8
- data/lib/sequel/plugins/instance_filters.rb +10 -0
- data/lib/sequel/plugins/instance_hooks.rb +1 -1
- data/lib/sequel/plugins/json_serializer.rb +58 -6
- data/lib/sequel/plugins/list.rb +12 -2
- data/lib/sequel/plugins/many_through_many.rb +79 -28
- data/lib/sequel/plugins/many_to_one_pk_lookup.rb +71 -0
- data/lib/sequel/plugins/nested_attributes.rb +139 -63
- data/lib/sequel/plugins/optimistic_locking.rb +8 -0
- data/lib/sequel/plugins/prepared_statements.rb +167 -0
- data/lib/sequel/plugins/prepared_statements_associations.rb +87 -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/schema.rb +7 -2
- 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 +5 -3
- data/lib/sequel/plugins/static_cache.rb +99 -0
- data/lib/sequel/plugins/subclasses.rb +10 -2
- data/lib/sequel/plugins/tactical_eager_loading.rb +7 -7
- data/lib/sequel/plugins/timestamps.rb +1 -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/validation_class_methods.rb +1 -1
- data/lib/sequel/plugins/xml_serializer.rb +15 -4
- data/lib/sequel/sql.rb +526 -59
- 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/firebird_spec.rb +1 -1
- data/spec/adapters/mssql_spec.rb +142 -40
- data/spec/adapters/mysql_spec.rb +380 -234
- data/spec/adapters/oracle_spec.rb +67 -77
- data/spec/adapters/postgres_spec.rb +1050 -212
- data/spec/adapters/spec_helper.rb +8 -5
- data/spec/adapters/sqlite_spec.rb +139 -27
- data/spec/core/connection_pool_spec.rb +196 -93
- data/spec/core/database_spec.rb +879 -510
- data/spec/core/dataset_spec.rb +1415 -1086
- data/spec/core/expression_filters_spec.rb +554 -109
- data/spec/core/mock_adapter_spec.rb +449 -0
- data/spec/core/object_graph_spec.rb +86 -114
- data/spec/core/schema_generator_spec.rb +4 -4
- data/spec/core/schema_spec.rb +482 -38
- data/spec/core/spec_helper.rb +6 -48
- data/spec/extensions/active_model_spec.rb +13 -0
- data/spec/extensions/arbitrary_servers_spec.rb +110 -0
- data/spec/extensions/association_autoreloading_spec.rb +18 -10
- data/spec/extensions/association_dependencies_spec.rb +15 -25
- data/spec/extensions/association_pks_spec.rb +66 -32
- data/spec/extensions/association_proxies_spec.rb +4 -4
- data/spec/extensions/caching_spec.rb +47 -51
- 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/{core/core_sql_spec.rb → extensions/core_extensions_spec.rb} +119 -139
- data/spec/extensions/dataset_associations_spec.rb +199 -0
- data/spec/extensions/defaults_setter_spec.rb +64 -0
- data/spec/extensions/dirty_spec.rb +155 -0
- data/spec/extensions/eager_each_spec.rb +34 -0
- data/spec/extensions/force_encoding_spec.rb +4 -2
- data/spec/extensions/hook_class_methods_spec.rb +69 -92
- data/spec/extensions/identity_map_spec.rb +131 -22
- data/spec/extensions/inflector_spec.rb +0 -4
- data/spec/extensions/instance_filters_spec.rb +11 -21
- data/spec/extensions/instance_hooks_spec.rb +72 -0
- data/spec/extensions/json_serializer_spec.rb +49 -6
- data/spec/extensions/lazy_attributes_spec.rb +16 -20
- data/spec/extensions/list_spec.rb +48 -39
- data/spec/extensions/many_through_many_spec.rb +283 -250
- data/spec/extensions/many_to_one_pk_lookup_spec.rb +140 -0
- data/spec/extensions/migration_spec.rb +140 -35
- data/spec/extensions/named_timezones_spec.rb +29 -11
- data/spec/extensions/nested_attributes_spec.rb +251 -89
- data/spec/extensions/null_dataset_spec.rb +85 -0
- data/spec/extensions/optimistic_locking_spec.rb +24 -21
- data/spec/extensions/pg_array_ops_spec.rb +105 -0
- data/spec/extensions/pg_array_spec.rb +196 -0
- data/spec/extensions/pg_auto_parameterize_spec.rb +65 -0
- data/spec/extensions/pg_hstore_ops_spec.rb +136 -0
- data/spec/extensions/pg_hstore_spec.rb +195 -0
- data/spec/extensions/pg_inet_spec.rb +44 -0
- data/spec/extensions/pg_json_spec.rb +101 -0
- data/spec/extensions/pg_statement_cache_spec.rb +209 -0
- 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 +87 -0
- data/spec/extensions/prepared_statements_with_pk_spec.rb +31 -0
- data/spec/extensions/pretty_table_spec.rb +7 -6
- data/spec/extensions/query_literals_spec.rb +168 -0
- data/spec/extensions/query_spec.rb +6 -0
- data/spec/extensions/rcte_tree_spec.rb +50 -43
- data/spec/extensions/schema_caching_spec.rb +41 -0
- data/spec/extensions/schema_dumper_spec.rb +429 -22
- data/spec/extensions/schema_spec.rb +25 -21
- data/spec/extensions/select_remove_spec.rb +38 -0
- data/spec/extensions/serialization_modification_detection_spec.rb +72 -0
- data/spec/extensions/serialization_spec.rb +85 -43
- data/spec/extensions/server_block_spec.rb +90 -0
- data/spec/extensions/sharding_spec.rb +69 -143
- data/spec/extensions/single_table_inheritance_spec.rb +23 -29
- data/spec/extensions/skip_create_refresh_spec.rb +1 -1
- data/spec/extensions/spec_helper.rb +22 -61
- data/spec/extensions/sql_expr_spec.rb +29 -60
- data/spec/extensions/static_cache_spec.rb +145 -0
- data/spec/extensions/tactical_eager_loading_spec.rb +17 -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 +9 -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 +29 -4
- data/spec/files/transaction_specified_migrations/001_create_alt_basic.rb +4 -0
- data/spec/files/transaction_specified_migrations/002_create_basic.rb +4 -0
- data/spec/files/transaction_unspecified_migrations/001_create_alt_basic.rb +3 -0
- data/spec/files/transaction_unspecified_migrations/002_create_basic.rb +3 -0
- data/spec/integration/associations_test.rb +659 -21
- data/spec/integration/database_test.rb +9 -3
- data/spec/integration/dataset_test.rb +605 -91
- data/spec/integration/eager_loader_test.rb +19 -21
- data/spec/integration/migrator_test.rb +2 -3
- data/spec/integration/model_test.rb +81 -2
- data/spec/integration/plugin_test.rb +454 -143
- data/spec/integration/prepared_statement_test.rb +263 -128
- data/spec/integration/schema_test.rb +309 -43
- data/spec/integration/spec_helper.rb +40 -30
- data/spec/integration/timezone_test.rb +38 -12
- data/spec/integration/transaction_test.rb +183 -8
- data/spec/integration/type_test.rb +18 -4
- data/spec/model/association_reflection_spec.rb +201 -7
- data/spec/model/associations_spec.rb +1067 -661
- data/spec/model/base_spec.rb +329 -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 +240 -168
- data/spec/model/plugins_spec.rb +24 -13
- data/spec/model/record_spec.rb +490 -232
- data/spec/model/spec_helper.rb +14 -71
- data/spec/model/validations_spec.rb +11 -0
- data/spec/rcov.opts +2 -0
- metadata +178 -80
|
@@ -7,20 +7,14 @@ module Sequel
|
|
|
7
7
|
include Sequel::MSSQL::DatabaseMethods
|
|
8
8
|
set_adapter_scheme :tinytds
|
|
9
9
|
|
|
10
|
-
# Transfer the :
|
|
11
|
-
# :dataserver and :username options.
|
|
10
|
+
# Transfer the :user option to the :username option.
|
|
12
11
|
def connect(server)
|
|
13
12
|
opts = server_opts(server)
|
|
14
|
-
opts[:dataserver] = opts[:host]
|
|
15
13
|
opts[:username] = opts[:user]
|
|
14
|
+
set_mssql_unicode_strings
|
|
16
15
|
TinyTds::Client.new(opts)
|
|
17
16
|
end
|
|
18
17
|
|
|
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
18
|
# Execute the given +sql+ on the server. If the :return option
|
|
25
19
|
# is present, its value should be a method symbol that is called
|
|
26
20
|
# on the TinyTds::Result object returned from executing the
|
|
@@ -32,13 +26,36 @@ module Sequel
|
|
|
32
26
|
begin
|
|
33
27
|
m = opts[:return]
|
|
34
28
|
r = nil
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
29
|
+
if (args = opts[:arguments]) && !args.empty?
|
|
30
|
+
types = []
|
|
31
|
+
values = []
|
|
32
|
+
args.each_with_index do |(k, v), i|
|
|
33
|
+
v, type = ps_arg_type(v)
|
|
34
|
+
types << "@#{k} #{type}"
|
|
35
|
+
values << "@#{k} = #{v}"
|
|
36
|
+
end
|
|
37
|
+
case m
|
|
38
|
+
when :do
|
|
39
|
+
sql = "#{sql}; SELECT @@ROWCOUNT AS AffectedRows"
|
|
40
|
+
single_value = true
|
|
41
|
+
when :insert
|
|
42
|
+
sql = "#{sql}; SELECT CAST(SCOPE_IDENTITY() AS bigint) AS Ident"
|
|
43
|
+
single_value = true
|
|
44
|
+
end
|
|
45
|
+
sql = "EXEC sp_executesql N'#{c.escape(sql)}', N'#{c.escape(types.join(', '))}', #{values.join(', ')}"
|
|
46
|
+
log_yield(sql) do
|
|
47
|
+
r = c.execute(sql)
|
|
48
|
+
r.each{|row| return row.values.first} if single_value
|
|
49
|
+
end
|
|
50
|
+
else
|
|
51
|
+
log_yield(sql) do
|
|
52
|
+
r = c.execute(sql)
|
|
53
|
+
return r.send(m) if m
|
|
54
|
+
end
|
|
38
55
|
end
|
|
39
56
|
yield(r) if block_given?
|
|
40
57
|
rescue TinyTds::Error => e
|
|
41
|
-
raise_error(e)
|
|
58
|
+
raise_error(e, :disconnect=>!c.active?)
|
|
42
59
|
ensure
|
|
43
60
|
r.cancel if r && c.sqlsent?
|
|
44
61
|
end
|
|
@@ -74,51 +91,174 @@ module Sequel
|
|
|
74
91
|
super
|
|
75
92
|
end
|
|
76
93
|
|
|
94
|
+
# tiny_tds uses TinyTds::Error as the base error class.
|
|
95
|
+
def database_error_classes
|
|
96
|
+
[TinyTds::Error]
|
|
97
|
+
end
|
|
98
|
+
|
|
77
99
|
# Close the TinyTds::Client object.
|
|
78
100
|
def disconnect_connection(c)
|
|
79
101
|
c.close
|
|
80
102
|
end
|
|
103
|
+
|
|
104
|
+
# Return true if the :conn argument is present and not active.
|
|
105
|
+
def disconnect_error?(e, opts)
|
|
106
|
+
super || (opts[:conn] && !opts[:conn].active?)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Return a 2 element array with the literal value and type to use
|
|
110
|
+
# in the prepared statement call for the given value and connection.
|
|
111
|
+
def ps_arg_type(v)
|
|
112
|
+
case v
|
|
113
|
+
when Fixnum
|
|
114
|
+
[v, 'int']
|
|
115
|
+
when Bignum
|
|
116
|
+
[v, 'bigint']
|
|
117
|
+
when Float
|
|
118
|
+
[v, 'double precision']
|
|
119
|
+
when Numeric
|
|
120
|
+
[v, 'numeric']
|
|
121
|
+
when Time
|
|
122
|
+
if v.is_a?(SQLTime)
|
|
123
|
+
[literal(v), 'time']
|
|
124
|
+
else
|
|
125
|
+
[literal(v), 'datetime']
|
|
126
|
+
end
|
|
127
|
+
when DateTime
|
|
128
|
+
[literal(v), 'datetime']
|
|
129
|
+
when Date
|
|
130
|
+
[literal(v), 'date']
|
|
131
|
+
when nil
|
|
132
|
+
['NULL', 'nvarchar(max)']
|
|
133
|
+
when true
|
|
134
|
+
['1', 'int']
|
|
135
|
+
when false
|
|
136
|
+
['0', 'int']
|
|
137
|
+
when SQL::Blob
|
|
138
|
+
[literal(v), 'varbinary(max)']
|
|
139
|
+
else
|
|
140
|
+
[literal(v), 'nvarchar(max)']
|
|
141
|
+
end
|
|
142
|
+
end
|
|
81
143
|
end
|
|
82
144
|
|
|
83
145
|
class Dataset < Sequel::Dataset
|
|
84
146
|
include Sequel::MSSQL::DatasetMethods
|
|
147
|
+
|
|
148
|
+
Database::DatasetClass = self
|
|
149
|
+
|
|
150
|
+
# SQLite already supports named bind arguments, so use directly.
|
|
151
|
+
module ArgumentMapper
|
|
152
|
+
include Sequel::Dataset::ArgumentMapper
|
|
153
|
+
|
|
154
|
+
protected
|
|
155
|
+
|
|
156
|
+
# Return a hash with the same values as the given hash,
|
|
157
|
+
# but with the keys converted to strings.
|
|
158
|
+
def map_to_prepared_args(hash)
|
|
159
|
+
args = {}
|
|
160
|
+
hash.each{|k,v| args[k.to_s.gsub('.', '__')] = v}
|
|
161
|
+
args
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
private
|
|
165
|
+
|
|
166
|
+
# SQLite uses a : before the name of the argument for named
|
|
167
|
+
# arguments.
|
|
168
|
+
def prepared_arg(k)
|
|
169
|
+
LiteralString.new("@#{k.to_s.gsub('.', '__')}")
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
# Always assume a prepared argument.
|
|
173
|
+
def prepared_arg?(k)
|
|
174
|
+
true
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# SQLite prepared statement uses a new prepared statement each time
|
|
179
|
+
# it is called, but it does use the bind arguments.
|
|
180
|
+
module PreparedStatementMethods
|
|
181
|
+
include ArgumentMapper
|
|
182
|
+
|
|
183
|
+
private
|
|
184
|
+
|
|
185
|
+
# Run execute_select on the database with the given SQL and the stored
|
|
186
|
+
# bind arguments.
|
|
187
|
+
def execute(sql, opts={}, &block)
|
|
188
|
+
super(prepared_sql, {:arguments=>bind_arguments}.merge(opts), &block)
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
# Same as execute, explicit due to intricacies of alias and super.
|
|
192
|
+
def execute_dui(sql, opts={}, &block)
|
|
193
|
+
super(prepared_sql, {:arguments=>bind_arguments}.merge(opts), &block)
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
# Same as execute, explicit due to intricacies of alias and super.
|
|
197
|
+
def execute_insert(sql, opts={}, &block)
|
|
198
|
+
super(prepared_sql, {:arguments=>bind_arguments}.merge(opts), &block)
|
|
199
|
+
end
|
|
200
|
+
end
|
|
85
201
|
|
|
86
202
|
# Yield hashes with symbol keys, attempting to optimize for
|
|
87
203
|
# various cases.
|
|
88
204
|
def fetch_rows(sql)
|
|
89
205
|
execute(sql) do |result|
|
|
90
206
|
each_opts = {:cache_rows=>false}
|
|
91
|
-
each_opts[:timezone] = :utc if
|
|
92
|
-
offset = @opts[:offset]
|
|
93
|
-
|
|
94
|
-
if
|
|
207
|
+
each_opts[:timezone] = :utc if db.timezone == :utc
|
|
208
|
+
rn = row_number_column if offset = @opts[:offset]
|
|
209
|
+
columns = cols = result.fields.map{|c| output_identifier(c)}
|
|
210
|
+
if offset
|
|
211
|
+
rn = row_number_column
|
|
212
|
+
columns = columns.dup
|
|
213
|
+
columns.delete(rn)
|
|
214
|
+
end
|
|
215
|
+
@columns = columns
|
|
216
|
+
#if identifier_output_method
|
|
95
217
|
each_opts[:as] = :array
|
|
96
218
|
result.each(each_opts) do |r|
|
|
97
219
|
h = {}
|
|
98
220
|
cols.zip(r).each{|k, v| h[k] = v}
|
|
99
|
-
h.delete(
|
|
221
|
+
h.delete(rn) if rn
|
|
100
222
|
yield h
|
|
101
223
|
end
|
|
224
|
+
=begin
|
|
225
|
+
# Temporarily disable this optimization, as tiny_tds uses string keys
|
|
226
|
+
# if result.fields is called before result.each(:symbolize_keys=>true).
|
|
227
|
+
# See https://github.com/rails-sqlserver/tiny_tds/issues/57
|
|
102
228
|
else
|
|
103
229
|
each_opts[:symbolize_keys] = true
|
|
104
230
|
if offset
|
|
105
231
|
result.each(each_opts) do |r|
|
|
106
|
-
r.delete(
|
|
232
|
+
r.delete(rn) if rn
|
|
107
233
|
yield r
|
|
108
234
|
end
|
|
109
235
|
else
|
|
110
|
-
result.each(each_opts, &
|
|
236
|
+
result.each(each_opts, &Proc.new)
|
|
111
237
|
end
|
|
112
238
|
end
|
|
239
|
+
=end
|
|
113
240
|
end
|
|
114
241
|
self
|
|
115
242
|
end
|
|
116
243
|
|
|
244
|
+
# Create a named prepared statement that is stored in the
|
|
245
|
+
# database (and connection) for reuse.
|
|
246
|
+
def prepare(type, name=nil, *values)
|
|
247
|
+
ps = to_prepared_statement(type, values)
|
|
248
|
+
ps.extend(PreparedStatementMethods)
|
|
249
|
+
if name
|
|
250
|
+
ps.prepared_statement_name = name
|
|
251
|
+
db.set_prepared_statement(name, ps)
|
|
252
|
+
end
|
|
253
|
+
ps
|
|
254
|
+
end
|
|
255
|
+
|
|
117
256
|
private
|
|
118
257
|
|
|
119
258
|
# Properly escape the given string +v+.
|
|
120
|
-
def
|
|
121
|
-
|
|
259
|
+
def literal_string_append(sql, v)
|
|
260
|
+
sql << (mssql_unicode_strings ? UNICODE_STRING_START : APOS)
|
|
261
|
+
sql << db.synchronize{|c| c.escape(v)}.gsub(BACKSLASH_CRLF_RE, BACKSLASH_CRLF_REPLACE) << APOS
|
|
122
262
|
end
|
|
123
263
|
end
|
|
124
264
|
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,194 @@
|
|
|
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
|
+
when SQL::Wrapper
|
|
70
|
+
SQL::Wrapper.new(v(o.value))
|
|
71
|
+
else
|
|
72
|
+
o
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Handles qualifying existing datasets, so that unqualified columns
|
|
78
|
+
# in the dataset are qualified with a given table name.
|
|
79
|
+
class Qualifier < ASTTransformer
|
|
80
|
+
# Store the dataset to use as the basis for qualification,
|
|
81
|
+
# and the table used to qualify unqualified columns.
|
|
82
|
+
def initialize(ds, table)
|
|
83
|
+
@ds = ds
|
|
84
|
+
@table = table
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
private
|
|
88
|
+
|
|
89
|
+
# Turn <tt>SQL::Identifier</tt>s and symbols that aren't implicitly
|
|
90
|
+
# qualified into <tt>SQL::QualifiedIdentifier</tt>s. For symbols that
|
|
91
|
+
# are not implicitly qualified by are implicitly aliased, return an
|
|
92
|
+
# <tt>SQL::AliasedExpression</tt>s with a qualified version of the symbol.
|
|
93
|
+
def v(o)
|
|
94
|
+
case o
|
|
95
|
+
when Symbol
|
|
96
|
+
t, column, aliaz = @ds.send(:split_symbol, o)
|
|
97
|
+
if t
|
|
98
|
+
o
|
|
99
|
+
elsif aliaz
|
|
100
|
+
SQL::AliasedExpression.new(SQL::QualifiedIdentifier.new(@table, SQL::Identifier.new(column)), aliaz)
|
|
101
|
+
else
|
|
102
|
+
SQL::QualifiedIdentifier.new(@table, o)
|
|
103
|
+
end
|
|
104
|
+
when SQL::Identifier
|
|
105
|
+
SQL::QualifiedIdentifier.new(@table, o)
|
|
106
|
+
when SQL::QualifiedIdentifier, SQL::JoinClause
|
|
107
|
+
# Return these directly, so we don't accidentally qualify symbols in them.
|
|
108
|
+
o
|
|
109
|
+
else
|
|
110
|
+
super
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# +Unbinder+ is used to take a dataset filter and return a modified version
|
|
116
|
+
# that unbinds already bound values and returns a dataset with bound value
|
|
117
|
+
# placeholders and a hash of bind values. You can then prepare the dataset
|
|
118
|
+
# and use the bound variables to execute it with the same values.
|
|
119
|
+
#
|
|
120
|
+
# This class only does a limited form of unbinding where the variable names
|
|
121
|
+
# and values can be associated unambiguously. The only cases it handles
|
|
122
|
+
# are <tt>SQL::ComplexExpression<tt> with an operator in +UNBIND_OPS+, a
|
|
123
|
+
# first argument that's an instance of a member of +UNBIND_KEY_CLASSES+, and
|
|
124
|
+
# a second argument that's an instance of a member of +UNBIND_VALUE_CLASSES+.
|
|
125
|
+
#
|
|
126
|
+
# So it can handle cases like:
|
|
127
|
+
#
|
|
128
|
+
# DB.filter(:a=>1).exclude(:b=>2).where{c > 3}
|
|
129
|
+
#
|
|
130
|
+
# But it cannot handle cases like:
|
|
131
|
+
#
|
|
132
|
+
# DB.filter(:a + 1 < 0)
|
|
133
|
+
class Unbinder < ASTTransformer
|
|
134
|
+
# The <tt>SQL::ComplexExpression<tt> operates that will be considered
|
|
135
|
+
# for transformation.
|
|
136
|
+
UNBIND_OPS = [:'=', :'!=', :<, :>, :<=, :>=]
|
|
137
|
+
|
|
138
|
+
# The key classes (first argument of the ComplexExpression) that will
|
|
139
|
+
# considered for transformation.
|
|
140
|
+
UNBIND_KEY_CLASSES = [Symbol, SQL::Identifier, SQL::QualifiedIdentifier]
|
|
141
|
+
|
|
142
|
+
# The value classes (second argument of the ComplexExpression) that
|
|
143
|
+
# will be considered for transformation.
|
|
144
|
+
UNBIND_VALUE_CLASSES = [Numeric, String, Date, Time]
|
|
145
|
+
|
|
146
|
+
# The hash of bind variables that were extracted from the dataset filter.
|
|
147
|
+
attr_reader :binds
|
|
148
|
+
|
|
149
|
+
# Intialize an empty +binds+ hash.
|
|
150
|
+
def initialize
|
|
151
|
+
@binds = {}
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
private
|
|
155
|
+
|
|
156
|
+
# Create a suitable bound variable key for the object, which should be
|
|
157
|
+
# an instance of one of the +UNBIND_KEY_CLASSES+.
|
|
158
|
+
def bind_key(obj)
|
|
159
|
+
case obj
|
|
160
|
+
when Symbol, String
|
|
161
|
+
obj
|
|
162
|
+
when SQL::Identifier
|
|
163
|
+
bind_key(obj.value)
|
|
164
|
+
when SQL::QualifiedIdentifier
|
|
165
|
+
:"#{bind_key(obj.table)}.#{bind_key(obj.column)}"
|
|
166
|
+
else
|
|
167
|
+
raise Error, "unhandled object in Sequel::Unbinder#bind_key: #{obj}"
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# Handle <tt>SQL::ComplexExpression</tt> instances with suitable ops
|
|
172
|
+
# and arguments, substituting the value with a bound variable placeholder
|
|
173
|
+
# and assigning it an entry in the +binds+ hash with a matching key.
|
|
174
|
+
def v(o)
|
|
175
|
+
if o.is_a?(SQL::ComplexExpression) && UNBIND_OPS.include?(o.op)
|
|
176
|
+
l, r = o.args
|
|
177
|
+
l = l.value if l.is_a?(Sequel::SQL::Wrapper)
|
|
178
|
+
r = r.value if r.is_a?(Sequel::SQL::Wrapper)
|
|
179
|
+
if UNBIND_KEY_CLASSES.any?{|c| l.is_a?(c)} && UNBIND_VALUE_CLASSES.any?{|c| r.is_a?(c)} && !r.is_a?(LiteralString)
|
|
180
|
+
key = bind_key(l)
|
|
181
|
+
if (old = binds[key]) && old != r
|
|
182
|
+
raise UnbindDuplicate, "two different values for #{key.inspect}: #{[r, old].inspect}"
|
|
183
|
+
end
|
|
184
|
+
binds[key] = r
|
|
185
|
+
SQL::ComplexExpression.new(o.op, l, :"$#{key}")
|
|
186
|
+
else
|
|
187
|
+
super
|
|
188
|
+
end
|
|
189
|
+
else
|
|
190
|
+
super
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
end
|
|
@@ -26,6 +26,11 @@ class Sequel::ShardedSingleConnectionPool < Sequel::ConnectionPool
|
|
|
26
26
|
def add_servers(servers)
|
|
27
27
|
servers.each{|s| @servers[s] = s}
|
|
28
28
|
end
|
|
29
|
+
|
|
30
|
+
# Yield all of the currently established connections
|
|
31
|
+
def all_connections
|
|
32
|
+
@conns.values.each{|c| yield c}
|
|
33
|
+
end
|
|
29
34
|
|
|
30
35
|
# The connection for the given server.
|
|
31
36
|
def conn(server=:default)
|
|
@@ -45,7 +50,7 @@ class Sequel::ShardedSingleConnectionPool < Sequel::ConnectionPool
|
|
|
45
50
|
# This method simulates the ConnectionPool#hold API.
|
|
46
51
|
def hold(server=:default)
|
|
47
52
|
begin
|
|
48
|
-
server =
|
|
53
|
+
server = pick_server(server)
|
|
49
54
|
yield(@conns[server] ||= make_new(server))
|
|
50
55
|
rescue Sequel::DatabaseDisconnectError
|
|
51
56
|
disconnect_server(server, &@disconnection_proc)
|
|
@@ -83,6 +88,11 @@ class Sequel::ShardedSingleConnectionPool < Sequel::ConnectionPool
|
|
|
83
88
|
block.call(conn) if block
|
|
84
89
|
end
|
|
85
90
|
end
|
|
91
|
+
|
|
92
|
+
# If the server given is in the hash, return it, otherwise, return the default server.
|
|
93
|
+
def pick_server(server)
|
|
94
|
+
@servers[server]
|
|
95
|
+
end
|
|
86
96
|
|
|
87
97
|
CONNECTION_POOL_MAP[[true, true]] = self
|
|
88
98
|
end
|
|
@@ -45,6 +45,23 @@ class Sequel::ShardedThreadedConnectionPool < Sequel::ThreadedConnectionPool
|
|
|
45
45
|
@allocated[server]
|
|
46
46
|
end
|
|
47
47
|
|
|
48
|
+
# Yield all of the available connections, and the ones currently allocated to
|
|
49
|
+
# this thread. This will not yield connections currently allocated to other
|
|
50
|
+
# threads, as it is not safe to operate on them. This holds the mutex while
|
|
51
|
+
# it is yielding all of the connections, which means that until
|
|
52
|
+
# the method's block returns, the pool is locked.
|
|
53
|
+
def all_connections
|
|
54
|
+
t = Thread.current
|
|
55
|
+
sync do
|
|
56
|
+
@allocated.values.each do |threads|
|
|
57
|
+
threads.each do |thread, conn|
|
|
58
|
+
yield conn if t == thread
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
@available_connections.values.each{|v| v.each{|c| yield c}}
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
48
65
|
# An array of connections opened but not currently used, for the given
|
|
49
66
|
# server. Nonexistent servers will return nil. Treat this as read only, do
|
|
50
67
|
# not modify the resulting object.
|
|
@@ -94,7 +111,7 @@ class Sequel::ShardedThreadedConnectionPool < Sequel::ThreadedConnectionPool
|
|
|
94
111
|
# connection can be acquired, a Sequel::PoolTimeout is
|
|
95
112
|
# raised.
|
|
96
113
|
def hold(server=:default)
|
|
97
|
-
|
|
114
|
+
server = pick_server(server)
|
|
98
115
|
t = Thread.current
|
|
99
116
|
if conn = owned_connection(t, server)
|
|
100
117
|
return yield(conn)
|
|
@@ -190,6 +207,11 @@ class Sequel::ShardedThreadedConnectionPool < Sequel::ThreadedConnectionPool
|
|
|
190
207
|
def owned_connection(thread, server)
|
|
191
208
|
sync{@allocated[server][thread]}
|
|
192
209
|
end
|
|
210
|
+
|
|
211
|
+
# If the server given is in the hash, return it, otherwise, return the default server.
|
|
212
|
+
def pick_server(server)
|
|
213
|
+
sync{@servers[server]}
|
|
214
|
+
end
|
|
193
215
|
|
|
194
216
|
# Releases the connection assigned to the supplied thread and server. If the
|
|
195
217
|
# server or connection given is scheduled for disconnection, remove the
|
|
@@ -199,7 +221,11 @@ class Sequel::ShardedThreadedConnectionPool < Sequel::ThreadedConnectionPool
|
|
|
199
221
|
if @connections_to_remove.include?(conn)
|
|
200
222
|
remove(thread, conn, server)
|
|
201
223
|
else
|
|
202
|
-
|
|
224
|
+
if @queue
|
|
225
|
+
available_connections(server).unshift(allocated(server).delete(thread))
|
|
226
|
+
else
|
|
227
|
+
available_connections(server) << allocated(server).delete(thread)
|
|
228
|
+
end
|
|
203
229
|
end
|
|
204
230
|
end
|
|
205
231
|
|
|
@@ -8,6 +8,11 @@ class Sequel::SingleConnectionPool < Sequel::ConnectionPool
|
|
|
8
8
|
@conn ? 1 : 0
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
+
# Yield the connection if one has been made.
|
|
12
|
+
def all_connections
|
|
13
|
+
yield @conn if @conn
|
|
14
|
+
end
|
|
15
|
+
|
|
11
16
|
# Disconnect the connection from the database.
|
|
12
17
|
def disconnect(opts=nil, &block)
|
|
13
18
|
return unless @conn
|