sequel 5.45.0 → 5.77.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +434 -0
- data/MIT-LICENSE +1 -1
- data/README.rdoc +59 -27
- data/bin/sequel +11 -3
- data/doc/advanced_associations.rdoc +16 -14
- data/doc/association_basics.rdoc +119 -24
- data/doc/cheat_sheet.rdoc +11 -3
- data/doc/mass_assignment.rdoc +1 -1
- data/doc/migration.rdoc +27 -6
- data/doc/model_hooks.rdoc +1 -1
- data/doc/object_model.rdoc +8 -8
- data/doc/opening_databases.rdoc +28 -12
- data/doc/postgresql.rdoc +16 -8
- data/doc/querying.rdoc +5 -3
- data/doc/release_notes/5.46.0.txt +87 -0
- data/doc/release_notes/5.47.0.txt +59 -0
- data/doc/release_notes/5.48.0.txt +14 -0
- data/doc/release_notes/5.49.0.txt +59 -0
- data/doc/release_notes/5.50.0.txt +78 -0
- data/doc/release_notes/5.51.0.txt +47 -0
- data/doc/release_notes/5.52.0.txt +87 -0
- data/doc/release_notes/5.53.0.txt +23 -0
- data/doc/release_notes/5.54.0.txt +27 -0
- data/doc/release_notes/5.55.0.txt +21 -0
- data/doc/release_notes/5.56.0.txt +51 -0
- data/doc/release_notes/5.57.0.txt +23 -0
- data/doc/release_notes/5.58.0.txt +31 -0
- data/doc/release_notes/5.59.0.txt +73 -0
- data/doc/release_notes/5.60.0.txt +22 -0
- data/doc/release_notes/5.61.0.txt +43 -0
- data/doc/release_notes/5.62.0.txt +132 -0
- data/doc/release_notes/5.63.0.txt +33 -0
- data/doc/release_notes/5.64.0.txt +50 -0
- data/doc/release_notes/5.65.0.txt +21 -0
- data/doc/release_notes/5.66.0.txt +24 -0
- data/doc/release_notes/5.67.0.txt +32 -0
- data/doc/release_notes/5.68.0.txt +61 -0
- data/doc/release_notes/5.69.0.txt +26 -0
- data/doc/release_notes/5.70.0.txt +35 -0
- data/doc/release_notes/5.71.0.txt +21 -0
- data/doc/release_notes/5.72.0.txt +33 -0
- data/doc/release_notes/5.73.0.txt +66 -0
- data/doc/release_notes/5.74.0.txt +45 -0
- data/doc/release_notes/5.75.0.txt +35 -0
- data/doc/release_notes/5.76.0.txt +86 -0
- data/doc/release_notes/5.77.0.txt +63 -0
- data/doc/schema_modification.rdoc +1 -1
- data/doc/security.rdoc +9 -9
- data/doc/sharding.rdoc +3 -1
- data/doc/sql.rdoc +27 -15
- data/doc/testing.rdoc +23 -13
- data/doc/transactions.rdoc +6 -6
- data/doc/virtual_rows.rdoc +1 -1
- data/lib/sequel/adapters/ado/access.rb +1 -1
- data/lib/sequel/adapters/ado.rb +1 -1
- data/lib/sequel/adapters/amalgalite.rb +3 -5
- data/lib/sequel/adapters/ibmdb.rb +3 -3
- data/lib/sequel/adapters/jdbc/derby.rb +8 -0
- data/lib/sequel/adapters/jdbc/h2.rb +63 -10
- data/lib/sequel/adapters/jdbc/hsqldb.rb +8 -0
- data/lib/sequel/adapters/jdbc/postgresql.rb +7 -4
- data/lib/sequel/adapters/jdbc/sqlanywhere.rb +15 -0
- data/lib/sequel/adapters/jdbc/sqlserver.rb +4 -0
- data/lib/sequel/adapters/jdbc.rb +24 -22
- data/lib/sequel/adapters/mysql.rb +92 -67
- data/lib/sequel/adapters/mysql2.rb +56 -51
- data/lib/sequel/adapters/odbc/mssql.rb +1 -1
- data/lib/sequel/adapters/odbc.rb +1 -1
- data/lib/sequel/adapters/oracle.rb +4 -3
- data/lib/sequel/adapters/postgres.rb +89 -45
- data/lib/sequel/adapters/shared/access.rb +11 -1
- data/lib/sequel/adapters/shared/db2.rb +42 -0
- data/lib/sequel/adapters/shared/mssql.rb +91 -10
- data/lib/sequel/adapters/shared/mysql.rb +78 -3
- data/lib/sequel/adapters/shared/oracle.rb +86 -7
- data/lib/sequel/adapters/shared/postgres.rb +576 -171
- data/lib/sequel/adapters/shared/sqlanywhere.rb +21 -5
- data/lib/sequel/adapters/shared/sqlite.rb +92 -8
- data/lib/sequel/adapters/sqlanywhere.rb +1 -1
- data/lib/sequel/adapters/sqlite.rb +99 -18
- data/lib/sequel/adapters/tinytds.rb +1 -1
- data/lib/sequel/adapters/trilogy.rb +117 -0
- data/lib/sequel/adapters/utils/columns_limit_1.rb +22 -0
- data/lib/sequel/adapters/utils/mysql_mysql2.rb +1 -1
- data/lib/sequel/ast_transformer.rb +6 -0
- data/lib/sequel/connection_pool/sharded_single.rb +5 -7
- data/lib/sequel/connection_pool/sharded_threaded.rb +16 -11
- data/lib/sequel/connection_pool/sharded_timed_queue.rb +374 -0
- data/lib/sequel/connection_pool/single.rb +6 -8
- data/lib/sequel/connection_pool/threaded.rb +14 -8
- data/lib/sequel/connection_pool/timed_queue.rb +270 -0
- data/lib/sequel/connection_pool.rb +57 -31
- data/lib/sequel/core.rb +17 -18
- data/lib/sequel/database/connecting.rb +27 -3
- data/lib/sequel/database/dataset.rb +16 -6
- data/lib/sequel/database/misc.rb +70 -14
- data/lib/sequel/database/query.rb +73 -2
- data/lib/sequel/database/schema_generator.rb +11 -6
- data/lib/sequel/database/schema_methods.rb +23 -4
- data/lib/sequel/database/transactions.rb +6 -0
- data/lib/sequel/dataset/actions.rb +111 -15
- data/lib/sequel/dataset/deprecated_singleton_class_methods.rb +42 -0
- data/lib/sequel/dataset/features.rb +20 -1
- data/lib/sequel/dataset/misc.rb +12 -2
- data/lib/sequel/dataset/placeholder_literalizer.rb +20 -9
- data/lib/sequel/dataset/query.rb +170 -41
- data/lib/sequel/dataset/sql.rb +190 -71
- data/lib/sequel/dataset.rb +4 -0
- data/lib/sequel/extensions/_model_pg_row.rb +0 -12
- data/lib/sequel/extensions/_pretty_table.rb +1 -1
- data/lib/sequel/extensions/any_not_empty.rb +2 -2
- data/lib/sequel/extensions/async_thread_pool.rb +14 -13
- data/lib/sequel/extensions/auto_cast_date_and_time.rb +94 -0
- data/lib/sequel/extensions/auto_literal_strings.rb +1 -1
- data/lib/sequel/extensions/connection_expiration.rb +15 -9
- data/lib/sequel/extensions/connection_validator.rb +16 -11
- data/lib/sequel/extensions/constraint_validations.rb +1 -1
- data/lib/sequel/extensions/core_refinements.rb +36 -11
- data/lib/sequel/extensions/date_arithmetic.rb +36 -8
- data/lib/sequel/extensions/date_parse_input_handler.rb +67 -0
- data/lib/sequel/extensions/datetime_parse_to_time.rb +5 -1
- data/lib/sequel/extensions/duplicate_columns_handler.rb +11 -10
- data/lib/sequel/extensions/index_caching.rb +5 -1
- data/lib/sequel/extensions/inflector.rb +1 -1
- data/lib/sequel/extensions/is_distinct_from.rb +141 -0
- data/lib/sequel/extensions/looser_typecasting.rb +3 -0
- data/lib/sequel/extensions/migration.rb +57 -15
- data/lib/sequel/extensions/named_timezones.rb +22 -6
- data/lib/sequel/extensions/pagination.rb +1 -1
- data/lib/sequel/extensions/pg_array.rb +33 -4
- data/lib/sequel/extensions/pg_array_ops.rb +2 -2
- data/lib/sequel/extensions/pg_auto_parameterize.rb +509 -0
- data/lib/sequel/extensions/pg_auto_parameterize_in_array.rb +110 -0
- data/lib/sequel/extensions/pg_enum.rb +1 -2
- data/lib/sequel/extensions/pg_extended_date_support.rb +39 -28
- data/lib/sequel/extensions/pg_extended_integer_support.rb +116 -0
- data/lib/sequel/extensions/pg_hstore.rb +6 -1
- data/lib/sequel/extensions/pg_hstore_ops.rb +53 -3
- data/lib/sequel/extensions/pg_inet.rb +10 -11
- data/lib/sequel/extensions/pg_inet_ops.rb +1 -1
- data/lib/sequel/extensions/pg_interval.rb +11 -11
- data/lib/sequel/extensions/pg_json.rb +13 -15
- data/lib/sequel/extensions/pg_json_ops.rb +125 -2
- data/lib/sequel/extensions/pg_multirange.rb +367 -0
- data/lib/sequel/extensions/pg_range.rb +13 -26
- data/lib/sequel/extensions/pg_range_ops.rb +37 -9
- data/lib/sequel/extensions/pg_row.rb +20 -19
- data/lib/sequel/extensions/pg_row_ops.rb +1 -1
- data/lib/sequel/extensions/pg_timestamptz.rb +27 -3
- data/lib/sequel/extensions/round_timestamps.rb +1 -1
- data/lib/sequel/extensions/s.rb +2 -1
- data/lib/sequel/extensions/schema_caching.rb +1 -1
- data/lib/sequel/extensions/schema_dumper.rb +45 -11
- data/lib/sequel/extensions/server_block.rb +10 -13
- data/lib/sequel/extensions/set_literalizer.rb +58 -0
- data/lib/sequel/extensions/sql_comments.rb +110 -3
- data/lib/sequel/extensions/sql_log_normalizer.rb +108 -0
- data/lib/sequel/extensions/sqlite_json_ops.rb +255 -0
- data/lib/sequel/extensions/string_agg.rb +1 -1
- data/lib/sequel/extensions/string_date_time.rb +19 -23
- data/lib/sequel/extensions/symbol_aref.rb +2 -0
- data/lib/sequel/extensions/transaction_connection_validator.rb +78 -0
- data/lib/sequel/model/associations.rb +286 -92
- data/lib/sequel/model/base.rb +53 -33
- data/lib/sequel/model/dataset_module.rb +3 -0
- data/lib/sequel/model/errors.rb +10 -1
- data/lib/sequel/model/exceptions.rb +15 -3
- data/lib/sequel/model/inflections.rb +1 -1
- data/lib/sequel/plugins/auto_restrict_eager_graph.rb +62 -0
- data/lib/sequel/plugins/auto_validations.rb +74 -16
- data/lib/sequel/plugins/class_table_inheritance.rb +2 -2
- data/lib/sequel/plugins/column_encryption.rb +29 -8
- data/lib/sequel/plugins/composition.rb +3 -2
- data/lib/sequel/plugins/concurrent_eager_loading.rb +4 -4
- data/lib/sequel/plugins/constraint_validations.rb +8 -5
- data/lib/sequel/plugins/defaults_setter.rb +16 -0
- data/lib/sequel/plugins/dirty.rb +1 -1
- data/lib/sequel/plugins/enum.rb +124 -0
- data/lib/sequel/plugins/finder.rb +4 -2
- data/lib/sequel/plugins/insert_conflict.rb +4 -0
- data/lib/sequel/plugins/instance_specific_default.rb +1 -1
- data/lib/sequel/plugins/json_serializer.rb +2 -2
- data/lib/sequel/plugins/lazy_attributes.rb +3 -0
- data/lib/sequel/plugins/list.rb +8 -3
- data/lib/sequel/plugins/many_through_many.rb +109 -10
- data/lib/sequel/plugins/mssql_optimistic_locking.rb +8 -38
- data/lib/sequel/plugins/nested_attributes.rb +4 -4
- data/lib/sequel/plugins/optimistic_locking.rb +9 -42
- data/lib/sequel/plugins/optimistic_locking_base.rb +55 -0
- data/lib/sequel/plugins/paged_operations.rb +181 -0
- data/lib/sequel/plugins/pg_array_associations.rb +46 -34
- data/lib/sequel/plugins/pg_auto_constraint_validations.rb +9 -3
- data/lib/sequel/plugins/pg_xmin_optimistic_locking.rb +109 -0
- data/lib/sequel/plugins/prepared_statements.rb +12 -2
- data/lib/sequel/plugins/prepared_statements_safe.rb +2 -1
- data/lib/sequel/plugins/primary_key_lookup_check_values.rb +154 -0
- data/lib/sequel/plugins/rcte_tree.rb +7 -4
- data/lib/sequel/plugins/require_valid_schema.rb +67 -0
- data/lib/sequel/plugins/serialization.rb +1 -0
- data/lib/sequel/plugins/serialization_modification_detection.rb +1 -0
- data/lib/sequel/plugins/single_table_inheritance.rb +8 -0
- data/lib/sequel/plugins/sql_comments.rb +189 -0
- data/lib/sequel/plugins/static_cache.rb +39 -1
- data/lib/sequel/plugins/static_cache_cache.rb +5 -1
- data/lib/sequel/plugins/subclasses.rb +28 -11
- data/lib/sequel/plugins/tactical_eager_loading.rb +23 -10
- data/lib/sequel/plugins/timestamps.rb +1 -1
- data/lib/sequel/plugins/unused_associations.rb +521 -0
- data/lib/sequel/plugins/update_or_create.rb +1 -1
- data/lib/sequel/plugins/validate_associated.rb +22 -12
- data/lib/sequel/plugins/validation_helpers.rb +41 -11
- data/lib/sequel/plugins/validation_helpers_generic_type_messages.rb +73 -0
- data/lib/sequel/plugins/xml_serializer.rb +1 -1
- data/lib/sequel/sql.rb +1 -1
- data/lib/sequel/timezones.rb +12 -14
- data/lib/sequel/version.rb +1 -1
- metadata +109 -19
@@ -5,6 +5,7 @@ require_relative 'shared/postgres'
|
|
5
5
|
begin
|
6
6
|
require 'pg'
|
7
7
|
|
8
|
+
# :nocov:
|
8
9
|
Sequel::Postgres::PGError = PG::Error if defined?(PG::Error)
|
9
10
|
Sequel::Postgres::PGconn = PG::Connection if defined?(PG::Connection)
|
10
11
|
Sequel::Postgres::PGresult = PG::Result if defined?(PG::Result)
|
@@ -14,30 +15,40 @@ begin
|
|
14
15
|
raise LoadError unless defined?(PGconn::CONNECTION_OK)
|
15
16
|
end
|
16
17
|
|
17
|
-
Sequel::Postgres::USES_PG = true
|
18
18
|
if defined?(PG::TypeMapByClass)
|
19
|
+
# :nocov:
|
19
20
|
type_map = Sequel::Postgres::PG_QUERY_TYPE_MAP = PG::TypeMapByClass.new
|
20
21
|
type_map[Integer] = PG::TextEncoder::Integer.new
|
21
22
|
type_map[FalseClass] = type_map[TrueClass] = PG::TextEncoder::Boolean.new
|
22
23
|
type_map[Float] = PG::TextEncoder::Float.new
|
23
24
|
end
|
25
|
+
|
26
|
+
Sequel::Postgres::USES_PG = true
|
24
27
|
rescue LoadError => e
|
28
|
+
# :nocov:
|
25
29
|
begin
|
26
|
-
require 'postgres-pr
|
27
|
-
Sequel::Postgres::USES_PG = false
|
30
|
+
require 'sequel/postgres-pr'
|
28
31
|
rescue LoadError
|
29
|
-
|
32
|
+
begin
|
33
|
+
require 'postgres-pr/postgres-compat'
|
34
|
+
rescue LoadError
|
35
|
+
raise e
|
36
|
+
end
|
30
37
|
end
|
38
|
+
Sequel::Postgres::USES_PG = false
|
39
|
+
# :nocov:
|
31
40
|
end
|
32
41
|
|
33
42
|
module Sequel
|
34
43
|
module Postgres
|
35
|
-
|
44
|
+
# :nocov:
|
45
|
+
if USES_PG
|
36
46
|
# Whether the given sequel_pg version integer is supported.
|
37
47
|
def self.sequel_pg_version_supported?(version)
|
38
48
|
version >= 10617
|
39
49
|
end
|
40
50
|
end
|
51
|
+
# :nocov:
|
41
52
|
|
42
53
|
# PGconn subclass for connection specific methods used with the
|
43
54
|
# pg or postgres-pr driver.
|
@@ -45,7 +56,9 @@ module Sequel
|
|
45
56
|
# The underlying exception classes to reraise as disconnect errors
|
46
57
|
# instead of regular database errors.
|
47
58
|
DISCONNECT_ERROR_CLASSES = [IOError, Errno::EPIPE, Errno::ECONNRESET]
|
59
|
+
# :nocov:
|
48
60
|
if defined?(::PG::ConnectionBad)
|
61
|
+
# :nocov:
|
49
62
|
DISCONNECT_ERROR_CLASSES << ::PG::ConnectionBad
|
50
63
|
end
|
51
64
|
DISCONNECT_ERROR_CLASSES.freeze
|
@@ -71,11 +84,14 @@ module Sequel
|
|
71
84
|
# are SQL strings.
|
72
85
|
attr_reader :prepared_statements
|
73
86
|
|
87
|
+
# :nocov:
|
74
88
|
unless public_method_defined?(:async_exec_params)
|
75
89
|
alias async_exec_params async_exec
|
76
90
|
end
|
77
|
-
|
78
|
-
#
|
91
|
+
elsif !const_defined?(:CONNECTION_OK)
|
92
|
+
# Handle old postgres-pr
|
93
|
+
# sequel-postgres-pr already implements this API
|
94
|
+
|
79
95
|
CONNECTION_OK = -1
|
80
96
|
|
81
97
|
# Escape bytea values. Uses historical format instead of hex
|
@@ -111,30 +127,29 @@ module Sequel
|
|
111
127
|
alias cmd_tuples cmdtuples
|
112
128
|
end
|
113
129
|
end
|
130
|
+
# :nocov:
|
114
131
|
|
115
132
|
# Raise a Sequel::DatabaseDisconnectError if a one of the disconnect
|
116
133
|
# error classes is raised, or a PGError is raised and the connection
|
117
134
|
# status cannot be determined or it is not OK.
|
118
135
|
def check_disconnect_errors
|
136
|
+
yield
|
137
|
+
rescue *DISCONNECT_ERROR_CLASSES => e
|
138
|
+
disconnect = true
|
139
|
+
raise(Sequel.convert_exception_class(e, Sequel::DatabaseDisconnectError))
|
140
|
+
rescue PGError => e
|
141
|
+
disconnect = false
|
119
142
|
begin
|
120
|
-
|
121
|
-
rescue
|
143
|
+
s = status
|
144
|
+
rescue PGError
|
122
145
|
disconnect = true
|
123
|
-
raise(Sequel.convert_exception_class(e, Sequel::DatabaseDisconnectError))
|
124
|
-
rescue PGError => e
|
125
|
-
disconnect = false
|
126
|
-
begin
|
127
|
-
s = status
|
128
|
-
rescue PGError
|
129
|
-
disconnect = true
|
130
|
-
end
|
131
|
-
status_ok = (s == Adapter::CONNECTION_OK)
|
132
|
-
disconnect ||= !status_ok
|
133
|
-
disconnect ||= e.message =~ DISCONNECT_ERROR_RE
|
134
|
-
disconnect ? raise(Sequel.convert_exception_class(e, Sequel::DatabaseDisconnectError)) : raise
|
135
|
-
ensure
|
136
|
-
block if status_ok && !disconnect
|
137
146
|
end
|
147
|
+
status_ok = (s == Adapter::CONNECTION_OK)
|
148
|
+
disconnect ||= !status_ok
|
149
|
+
disconnect ||= e.message =~ DISCONNECT_ERROR_RE
|
150
|
+
disconnect ? raise(Sequel.convert_exception_class(e, Sequel::DatabaseDisconnectError)) : raise
|
151
|
+
ensure
|
152
|
+
block if status_ok && !disconnect
|
138
153
|
end
|
139
154
|
|
140
155
|
# Execute the given SQL with this connection. If a block is given,
|
@@ -143,7 +158,7 @@ module Sequel
|
|
143
158
|
args = args.map{|v| @db.bound_variable_arg(v, self)} if args
|
144
159
|
q = check_disconnect_errors{execute_query(sql, args)}
|
145
160
|
begin
|
146
|
-
|
161
|
+
defined?(yield) ? yield(q) : q.cmd_tuples
|
147
162
|
ensure
|
148
163
|
q.clear if q && q.respond_to?(:clear)
|
149
164
|
end
|
@@ -170,8 +185,12 @@ module Sequel
|
|
170
185
|
case arg
|
171
186
|
when Sequel::SQL::Blob
|
172
187
|
{:value=>arg, :type=>17, :format=>1}
|
173
|
-
|
174
|
-
|
188
|
+
# :nocov:
|
189
|
+
# Not covered by tests as tests use pg_extended_date_support
|
190
|
+
# extension, which has basically the same code.
|
191
|
+
when Time, DateTime
|
192
|
+
@default_dataset.literal_date_or_time(arg)
|
193
|
+
# :nocov:
|
175
194
|
else
|
176
195
|
arg
|
177
196
|
end
|
@@ -206,7 +225,9 @@ module Sequel
|
|
206
225
|
:sslmode => opts[:sslmode],
|
207
226
|
:sslrootcert => opts[:sslrootcert]
|
208
227
|
}.delete_if { |key, value| blank_object?(value) }
|
228
|
+
# :nocov:
|
209
229
|
connection_params.merge!(opts[:driver_options]) if opts[:driver_options]
|
230
|
+
# :nocov:
|
210
231
|
conn = Adapter.connect(opts[:conn_str] || connection_params)
|
211
232
|
|
212
233
|
conn.instance_variable_set(:@prepared_statements, {})
|
@@ -214,6 +235,13 @@ module Sequel
|
|
214
235
|
if receiver = opts[:notice_receiver]
|
215
236
|
conn.set_notice_receiver(&receiver)
|
216
237
|
end
|
238
|
+
|
239
|
+
# :nocov:
|
240
|
+
if conn.respond_to?(:type_map_for_queries=) && defined?(PG_QUERY_TYPE_MAP)
|
241
|
+
# :nocov:
|
242
|
+
conn.type_map_for_queries = PG_QUERY_TYPE_MAP
|
243
|
+
end
|
244
|
+
# :nocov:
|
217
245
|
else
|
218
246
|
unless typecast_value_boolean(@opts.fetch(:force_standard_strings, true))
|
219
247
|
raise Error, "Cannot create connection using postgres-pr unless force_standard_strings is set"
|
@@ -228,12 +256,11 @@ module Sequel
|
|
228
256
|
opts[:password]
|
229
257
|
)
|
230
258
|
end
|
259
|
+
# :nocov:
|
231
260
|
|
232
261
|
conn.instance_variable_set(:@db, self)
|
233
|
-
if USES_PG && conn.respond_to?(:type_map_for_queries=) && defined?(PG_QUERY_TYPE_MAP)
|
234
|
-
conn.type_map_for_queries = PG_QUERY_TYPE_MAP
|
235
|
-
end
|
236
262
|
|
263
|
+
# :nocov:
|
237
264
|
if encoding = opts[:encoding] || opts[:charset]
|
238
265
|
if conn.respond_to?(:set_client_encoding)
|
239
266
|
conn.set_client_encoding(encoding)
|
@@ -241,6 +268,7 @@ module Sequel
|
|
241
268
|
conn.async_exec("set client_encoding to '#{encoding}'")
|
242
269
|
end
|
243
270
|
end
|
271
|
+
# :nocov:
|
244
272
|
|
245
273
|
connection_configuration_sqls(opts).each{|sql| conn.execute(sql)}
|
246
274
|
conn
|
@@ -267,7 +295,9 @@ module Sequel
|
|
267
295
|
nil
|
268
296
|
end
|
269
297
|
|
298
|
+
# :nocov:
|
270
299
|
if USES_PG && Object.const_defined?(:PG) && ::PG.const_defined?(:Constants) && ::PG::Constants.const_defined?(:PG_DIAG_SCHEMA_NAME)
|
300
|
+
# :nocov:
|
271
301
|
# Return a hash of information about the related PGError (or Sequel::DatabaseError that
|
272
302
|
# wraps a PGError), with the following entries (any of which may be +nil+):
|
273
303
|
#
|
@@ -318,7 +348,9 @@ module Sequel
|
|
318
348
|
synchronize(opts[:server]){|conn| check_database_errors{_execute(conn, sql, opts, &block)}}
|
319
349
|
end
|
320
350
|
|
351
|
+
# :nocov:
|
321
352
|
if USES_PG
|
353
|
+
# :nocov:
|
322
354
|
# +copy_table+ uses PostgreSQL's +COPY TO STDOUT+ SQL statement to return formatted
|
323
355
|
# results directly to the caller. This method is only supported if pg is the
|
324
356
|
# underlying ruby driver. This method should only be called if you want
|
@@ -350,7 +382,7 @@ module Sequel
|
|
350
382
|
synchronize(opts[:server]) do |conn|
|
351
383
|
conn.execute(copy_table_sql(table, opts))
|
352
384
|
begin
|
353
|
-
if
|
385
|
+
if defined?(yield)
|
354
386
|
while buf = conn.get_copy_data
|
355
387
|
yield buf
|
356
388
|
end
|
@@ -400,16 +432,16 @@ module Sequel
|
|
400
432
|
data = opts[:data]
|
401
433
|
data = Array(data) if data.is_a?(String)
|
402
434
|
|
403
|
-
if
|
435
|
+
if defined?(yield) && data
|
404
436
|
raise Error, "Cannot provide both a :data option and a block to copy_into"
|
405
|
-
elsif !
|
437
|
+
elsif !defined?(yield) && !data
|
406
438
|
raise Error, "Must provide either a :data option or a block to copy_into"
|
407
439
|
end
|
408
440
|
|
409
441
|
synchronize(opts[:server]) do |conn|
|
410
442
|
conn.execute(copy_into_sql(table, opts))
|
411
443
|
begin
|
412
|
-
if
|
444
|
+
if defined?(yield)
|
413
445
|
while buf = yield
|
414
446
|
conn.put_copy_data(buf)
|
415
447
|
end
|
@@ -511,32 +543,35 @@ module Sequel
|
|
511
543
|
def adapter_initialize
|
512
544
|
@use_iso_date_format = typecast_value_boolean(@opts.fetch(:use_iso_date_format, true))
|
513
545
|
initialize_postgres_adapter
|
546
|
+
# :nocov:
|
514
547
|
add_conversion_proc(17, method(:unescape_bytea)) if USES_PG
|
515
548
|
add_conversion_proc(1082, TYPE_TRANSLATOR_DATE) if @use_iso_date_format
|
549
|
+
# :nocov:
|
516
550
|
self.convert_infinite_timestamps = @opts[:convert_infinite_timestamps]
|
517
551
|
end
|
518
552
|
|
519
553
|
# Convert exceptions raised from the block into DatabaseErrors.
|
520
554
|
def check_database_errors
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
raise_error(e, :classes=>database_error_classes)
|
525
|
-
end
|
555
|
+
yield
|
556
|
+
rescue => e
|
557
|
+
raise_error(e, :classes=>database_error_classes)
|
526
558
|
end
|
527
|
-
|
528
559
|
# Set the DateStyle to ISO if configured, for faster date parsing.
|
529
560
|
def connection_configuration_sqls(opts=@opts)
|
530
561
|
sqls = super
|
562
|
+
# :nocov:
|
531
563
|
sqls << "SET DateStyle = 'ISO'" if @use_iso_date_format
|
564
|
+
# :nocov:
|
532
565
|
sqls
|
533
566
|
end
|
534
567
|
|
568
|
+
# :nocov:
|
535
569
|
if USES_PG
|
536
570
|
def unescape_bytea(s)
|
537
571
|
::Sequel::SQL::Blob.new(Adapter.unescape_bytea(s))
|
538
572
|
end
|
539
573
|
end
|
574
|
+
# :nocov:
|
540
575
|
|
541
576
|
DATABASE_ERROR_CLASSES = [PGError].freeze
|
542
577
|
def database_error_classes
|
@@ -550,7 +585,9 @@ module Sequel
|
|
550
585
|
end
|
551
586
|
|
552
587
|
def database_exception_sqlstate(exception, opts)
|
588
|
+
# :nocov:
|
553
589
|
if exception.respond_to?(:result) && (result = exception.result)
|
590
|
+
# :nocov:
|
554
591
|
result.error_field(PGresult::PG_DIAG_SQLSTATE)
|
555
592
|
end
|
556
593
|
end
|
@@ -590,7 +627,7 @@ module Sequel
|
|
590
627
|
|
591
628
|
q = conn.check_disconnect_errors{log_connection_yield(log_sql, conn, args){_execute_prepared_statement(conn, ps_name, args, opts)}}
|
592
629
|
begin
|
593
|
-
|
630
|
+
defined?(yield) ? yield(q) : q.cmd_tuples
|
594
631
|
ensure
|
595
632
|
q.clear if q && q.respond_to?(:clear)
|
596
633
|
end
|
@@ -616,7 +653,7 @@ module Sequel
|
|
616
653
|
|
617
654
|
# Use a cursor for paging.
|
618
655
|
def paged_each(opts=OPTS, &block)
|
619
|
-
unless
|
656
|
+
unless defined?(yield)
|
620
657
|
return enum_for(:paged_each, opts)
|
621
658
|
end
|
622
659
|
use_cursor(opts).each(&block)
|
@@ -635,6 +672,7 @@ module Sequel
|
|
635
672
|
# cursor usage.
|
636
673
|
# :rows_per_fetch :: The number of rows per fetch (default 1000). Higher
|
637
674
|
# numbers result in fewer queries but greater memory use.
|
675
|
+
# :skip_transaction :: Same as :hold, but :hold takes priority.
|
638
676
|
#
|
639
677
|
# Usage:
|
640
678
|
#
|
@@ -660,7 +698,9 @@ module Sequel
|
|
660
698
|
clone(:where=>Sequel.lit(['CURRENT OF '], Sequel.identifier(cursor_name)))
|
661
699
|
end
|
662
700
|
|
701
|
+
# :nocov:
|
663
702
|
if USES_PG
|
703
|
+
# :nocov:
|
664
704
|
PREPARED_ARG_PLACEHOLDER = LiteralString.new('$').freeze
|
665
705
|
|
666
706
|
# PostgreSQL specific argument mapper used for mapping the named
|
@@ -717,19 +757,21 @@ module Sequel
|
|
717
757
|
sql = String.new
|
718
758
|
sql << "CALL "
|
719
759
|
identifier_append(sql, name)
|
720
|
-
|
760
|
+
sql << "("
|
761
|
+
expression_list_append(sql, args)
|
762
|
+
sql << ")"
|
721
763
|
with_sql_first(sql)
|
722
764
|
end
|
723
765
|
|
724
766
|
# Use a cursor to fetch groups of records at a time, yielding them to the block.
|
725
767
|
def cursor_fetch_rows(sql)
|
726
|
-
server_opts = {:server=>@opts[:server] || :read_only}
|
727
768
|
cursor = @opts[:cursor]
|
728
|
-
hold = cursor[:
|
769
|
+
hold = cursor.fetch(:hold){cursor[:skip_transaction]}
|
770
|
+
server_opts = {:server=>@opts[:server] || :read_only, :skip_transaction=>hold}
|
729
771
|
cursor_name = quote_identifier(cursor[:cursor_name] || 'sequel_cursor')
|
730
772
|
rows_per_fetch = cursor[:rows_per_fetch].to_i
|
731
773
|
|
732
|
-
db.
|
774
|
+
db.transaction(server_opts) do
|
733
775
|
begin
|
734
776
|
execute_ddl("DECLARE #{cursor_name} NO SCROLL CURSOR WITH#{'OUT' unless hold} HOLD FOR #{sql}", server_opts)
|
735
777
|
rows_per_fetch = 1000 if rows_per_fetch <= 0
|
@@ -805,6 +847,7 @@ module Sequel
|
|
805
847
|
end
|
806
848
|
end
|
807
849
|
|
850
|
+
# :nocov:
|
808
851
|
if Sequel::Postgres::USES_PG && !ENV['NO_SEQUEL_PG']
|
809
852
|
begin
|
810
853
|
require 'sequel_pg'
|
@@ -816,3 +859,4 @@ if Sequel::Postgres::USES_PG && !ENV['NO_SEQUEL_PG']
|
|
816
859
|
rescue LoadError
|
817
860
|
end
|
818
861
|
end
|
862
|
+
# :nocov:
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require_relative '../utils/emulate_offset_with_reverse_and_count'
|
4
4
|
require_relative '../utils/unmodified_identifiers'
|
5
|
+
require_relative '../utils/columns_limit_1'
|
5
6
|
|
6
7
|
module Sequel
|
7
8
|
module Access
|
@@ -16,7 +17,7 @@ module Sequel
|
|
16
17
|
|
17
18
|
# Doesn't work, due to security restrictions on MSysObjects
|
18
19
|
#def tables
|
19
|
-
# from(:MSysObjects).where(:
|
20
|
+
# from(:MSysObjects).where(Type: 1, Flags: 0).select_map(:Name).map(&:to_sym)
|
20
21
|
#end
|
21
22
|
|
22
23
|
# Access doesn't support renaming tables from an SQL query,
|
@@ -56,6 +57,14 @@ module Sequel
|
|
56
57
|
DATABASE_ERROR_REGEXPS
|
57
58
|
end
|
58
59
|
|
60
|
+
# Access's Byte type will accept much larger values,
|
61
|
+
# even though it only stores 0-255. Do not set min/max
|
62
|
+
# values for the Byte type.
|
63
|
+
def column_schema_integer_min_max_values(column)
|
64
|
+
return if /byte/i =~ column[:db_type]
|
65
|
+
super
|
66
|
+
end
|
67
|
+
|
59
68
|
def drop_index_sql(table, op)
|
60
69
|
"DROP INDEX #{quote_identifier(op[:name] || default_index_name(table, op[:columns]))} ON #{quote_schema_table(table)}"
|
61
70
|
end
|
@@ -83,6 +92,7 @@ module Sequel
|
|
83
92
|
end)
|
84
93
|
include EmulateOffsetWithReverseAndCount
|
85
94
|
include UnmodifiedIdentifiers::DatasetMethods
|
95
|
+
include ::Sequel::Dataset::ColumnsLimit1
|
86
96
|
|
87
97
|
EXTRACT_MAP = {:year=>"'yyyy'", :month=>"'m'", :day=>"'d'", :hour=>"'h'", :minute=>"'n'", :second=>"'s'"}.freeze
|
88
98
|
EXTRACT_MAP.each_value(&:freeze)
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen-string-literal: true
|
2
2
|
|
3
3
|
require_relative '../utils/emulate_offset_with_row_number'
|
4
|
+
require_relative '../utils/columns_limit_1'
|
4
5
|
|
5
6
|
module Sequel
|
6
7
|
module DB2
|
@@ -214,6 +215,18 @@ module Sequel
|
|
214
215
|
DATABASE_ERROR_REGEXPS
|
215
216
|
end
|
216
217
|
|
218
|
+
DISCONNECT_SQL_STATES = %w'40003 08001 08003'.freeze
|
219
|
+
def disconnect_error?(exception, opts)
|
220
|
+
sqlstate = database_exception_sqlstate(exception, opts)
|
221
|
+
|
222
|
+
case sqlstate
|
223
|
+
when *DISCONNECT_SQL_STATES
|
224
|
+
true
|
225
|
+
else
|
226
|
+
super
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
217
230
|
# DB2 has issues with quoted identifiers, so
|
218
231
|
# turn off database quoting by default.
|
219
232
|
def quote_identifiers_default
|
@@ -273,6 +286,7 @@ module Sequel
|
|
273
286
|
|
274
287
|
module DatasetMethods
|
275
288
|
include EmulateOffsetWithRowNumber
|
289
|
+
include ::Sequel::Dataset::ColumnsLimit1
|
276
290
|
|
277
291
|
BITWISE_METHOD_MAP = {:& =>:BITAND, :| => :BITOR, :^ => :BITXOR, :'B~'=>:BITNOT}.freeze
|
278
292
|
|
@@ -336,6 +350,11 @@ module Sequel
|
|
336
350
|
true
|
337
351
|
end
|
338
352
|
|
353
|
+
# DB2 supports MERGE
|
354
|
+
def supports_merge?
|
355
|
+
true
|
356
|
+
end
|
357
|
+
|
339
358
|
# DB2 does not support multiple columns in IN.
|
340
359
|
def supports_multiple_column_in?
|
341
360
|
false
|
@@ -358,6 +377,29 @@ module Sequel
|
|
358
377
|
|
359
378
|
private
|
360
379
|
|
380
|
+
# Normalize conditions for MERGE WHEN.
|
381
|
+
def _merge_when_conditions_sql(sql, data)
|
382
|
+
if data.has_key?(:conditions)
|
383
|
+
sql << " AND "
|
384
|
+
literal_append(sql, _normalize_merge_when_conditions(data[:conditions]))
|
385
|
+
end
|
386
|
+
end
|
387
|
+
|
388
|
+
# Handle nil, false, and true MERGE WHEN conditions to avoid non-boolean
|
389
|
+
# type error.
|
390
|
+
def _normalize_merge_when_conditions(conditions)
|
391
|
+
case conditions
|
392
|
+
when nil, false
|
393
|
+
{1=>0}
|
394
|
+
when true
|
395
|
+
{1=>1}
|
396
|
+
when Sequel::SQL::DelayedEvaluation
|
397
|
+
Sequel.delay{_normalize_merge_when_conditions(conditions.call(self))}
|
398
|
+
else
|
399
|
+
conditions
|
400
|
+
end
|
401
|
+
end
|
402
|
+
|
361
403
|
def empty_from_sql
|
362
404
|
' FROM "SYSIBM"."SYSDUMMY1"'
|
363
405
|
end
|
@@ -24,6 +24,10 @@ module Sequel
|
|
24
24
|
# Database object.
|
25
25
|
attr_accessor :mssql_unicode_strings
|
26
26
|
|
27
|
+
# Whether to use LIKE without COLLATE Latin1_General_CS_AS. Skipping the COLLATE
|
28
|
+
# can significantly increase performance in some cases.
|
29
|
+
attr_accessor :like_without_collate
|
30
|
+
|
27
31
|
# Execute the given stored procedure with the given name.
|
28
32
|
#
|
29
33
|
# Options:
|
@@ -321,6 +325,11 @@ module Sequel
|
|
321
325
|
false
|
322
326
|
end
|
323
327
|
|
328
|
+
# MSSQL tinyint types are unsigned.
|
329
|
+
def column_schema_tinyint_type_is_unsigned?
|
330
|
+
true
|
331
|
+
end
|
332
|
+
|
324
333
|
# Handle MSSQL specific default format.
|
325
334
|
def column_schema_normalize_default(default, type)
|
326
335
|
if m = /\A(?:\(N?('.*')\)|\(\((-?\d+(?:\.\d+)?)\)\))\z/.match(default)
|
@@ -395,10 +404,15 @@ module Sequel
|
|
395
404
|
# Backbone of the tables and views support.
|
396
405
|
def information_schema_tables(type, opts)
|
397
406
|
m = output_identifier_meth
|
398
|
-
|
407
|
+
schema = opts[:schema]||'dbo'
|
408
|
+
tables = metadata_dataset.from(Sequel[:information_schema][:tables].as(:t)).
|
399
409
|
select(:table_name).
|
400
|
-
where(:table_type=>type, :table_schema=>
|
410
|
+
where(:table_type=>type, :table_schema=>schema.to_s).
|
401
411
|
map{|x| m.call(x[:table_name])}
|
412
|
+
|
413
|
+
tables.map!{|t| Sequel.qualify(m.call(schema).to_s, m.call(t).to_s)} if opts[:qualify]
|
414
|
+
|
415
|
+
tables
|
402
416
|
end
|
403
417
|
|
404
418
|
# Always quote identifiers in the metadata_dataset, so schema parsing works.
|
@@ -548,9 +562,9 @@ module Sequel
|
|
548
562
|
when :'||'
|
549
563
|
super(sql, :+, args)
|
550
564
|
when :LIKE, :"NOT LIKE"
|
551
|
-
super(sql, op, args
|
565
|
+
super(sql, op, complex_expression_sql_like_args(args, " COLLATE Latin1_General_CS_AS)"))
|
552
566
|
when :ILIKE, :"NOT ILIKE"
|
553
|
-
super(sql, (op == :ILIKE ? :LIKE : :"NOT LIKE"), args
|
567
|
+
super(sql, (op == :ILIKE ? :LIKE : :"NOT LIKE"), complex_expression_sql_like_args(args, " COLLATE Latin1_General_CI_AS)"))
|
554
568
|
when :<<, :>>
|
555
569
|
complex_expression_emulate_append(sql, op, args)
|
556
570
|
when :extract
|
@@ -582,6 +596,18 @@ module Sequel
|
|
582
596
|
end
|
583
597
|
end
|
584
598
|
|
599
|
+
# For a dataset with custom SQL, since it may include ORDER BY, you
|
600
|
+
# cannot wrap it in a subquery. Load entire query in this case to get
|
601
|
+
# the number of rows. In general, you should avoid calling this method
|
602
|
+
# on datasets with custom SQL.
|
603
|
+
def count(*a, &block)
|
604
|
+
if (@opts[:sql] && a.empty? && !block)
|
605
|
+
naked.to_a.length
|
606
|
+
else
|
607
|
+
super
|
608
|
+
end
|
609
|
+
end
|
610
|
+
|
585
611
|
# Uses CROSS APPLY to join the given table into the current dataset.
|
586
612
|
def cross_apply(table)
|
587
613
|
join_table(:cross_apply, table)
|
@@ -592,6 +618,19 @@ module Sequel
|
|
592
618
|
clone(:disable_insert_output=>true)
|
593
619
|
end
|
594
620
|
|
621
|
+
# For a dataset with custom SQL, since it may include ORDER BY, you
|
622
|
+
# cannot wrap it in a subquery. Run query, and if it returns any
|
623
|
+
# records, return true. In general, you should avoid calling this method
|
624
|
+
# on datasets with custom SQL.
|
625
|
+
def empty?
|
626
|
+
if @opts[:sql]
|
627
|
+
naked.each{return false}
|
628
|
+
true
|
629
|
+
else
|
630
|
+
super
|
631
|
+
end
|
632
|
+
end
|
633
|
+
|
595
634
|
# MSSQL treats [] as a metacharacter in LIKE expresions.
|
596
635
|
def escape_like(string)
|
597
636
|
string.gsub(/[\\%_\[\]]/){|m| "\\#{m}"}
|
@@ -730,6 +769,11 @@ module Sequel
|
|
730
769
|
false
|
731
770
|
end
|
732
771
|
|
772
|
+
# MSSQL 2008+ supports MERGE
|
773
|
+
def supports_merge?
|
774
|
+
is_2008_or_later?
|
775
|
+
end
|
776
|
+
|
733
777
|
# MSSQL 2005+ supports modifying joined datasets
|
734
778
|
def supports_modifying_joins?
|
735
779
|
is_2005_or_later?
|
@@ -791,11 +835,10 @@ module Sequel
|
|
791
835
|
if opts[:return] == :primary_key && !@opts[:output]
|
792
836
|
output(nil, [SQL::QualifiedIdentifier.new(:inserted, first_primary_key)])._import(columns, values, opts)
|
793
837
|
elsif @opts[:output]
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
end.first.map{|v| v.length == 1 ? v.values.first : v}
|
838
|
+
# no transaction: our multi_insert_sql_strategy should guarantee
|
839
|
+
# that there's only ever a single statement.
|
840
|
+
sql = multi_insert_sql(columns, values)[0]
|
841
|
+
naked.with_sql(sql).map{|v| v.length == 1 ? v.values.first : v}
|
799
842
|
else
|
800
843
|
super
|
801
844
|
end
|
@@ -820,6 +863,35 @@ module Sequel
|
|
820
863
|
|
821
864
|
private
|
822
865
|
|
866
|
+
# Normalize conditions for MERGE WHEN.
|
867
|
+
def _merge_when_conditions_sql(sql, data)
|
868
|
+
if data.has_key?(:conditions)
|
869
|
+
sql << " AND "
|
870
|
+
literal_append(sql, _normalize_merge_when_conditions(data[:conditions]))
|
871
|
+
end
|
872
|
+
end
|
873
|
+
|
874
|
+
# Handle nil, false, and true MERGE WHEN conditions to avoid non-boolean
|
875
|
+
# type error.
|
876
|
+
def _normalize_merge_when_conditions(conditions)
|
877
|
+
case conditions
|
878
|
+
when nil, false
|
879
|
+
{1=>0}
|
880
|
+
when true
|
881
|
+
{1=>1}
|
882
|
+
when Sequel::SQL::DelayedEvaluation
|
883
|
+
Sequel.delay{_normalize_merge_when_conditions(conditions.call(self))}
|
884
|
+
else
|
885
|
+
conditions
|
886
|
+
end
|
887
|
+
end
|
888
|
+
|
889
|
+
# MSSQL requires a semicolon at the end of MERGE.
|
890
|
+
def _merge_when_sql(sql)
|
891
|
+
super
|
892
|
+
sql << ';'
|
893
|
+
end
|
894
|
+
|
823
895
|
# MSSQL does not allow ordering in sub-clauses unless TOP (limit) is specified
|
824
896
|
def aggregate_dataset
|
825
897
|
(options_overlap(Sequel::Dataset::COUNT_FROM_SELF_OPTS) && !options_overlap([:limit])) ? unordered.from_self : super
|
@@ -847,11 +919,20 @@ module Sequel
|
|
847
919
|
server_version >= 11000000
|
848
920
|
end
|
849
921
|
|
922
|
+
# Determine whether to add the COLLATE for LIKE arguments, based on the Database setting.
|
923
|
+
def complex_expression_sql_like_args(args, collation)
|
924
|
+
if db.like_without_collate
|
925
|
+
args
|
926
|
+
else
|
927
|
+
args.map{|a| Sequel.lit(["(", collation], a)}
|
928
|
+
end
|
929
|
+
end
|
930
|
+
|
850
931
|
# Use strict ISO-8601 format with T between date and time,
|
851
932
|
# since that is the format that is multilanguage and not
|
852
933
|
# DATEFORMAT dependent.
|
853
934
|
def default_timestamp_format
|
854
|
-
"'%Y-%m-%dT%H:%M:%S
|
935
|
+
"'%Y-%m-%dT%H:%M:%S.%3N'"
|
855
936
|
end
|
856
937
|
|
857
938
|
# Only include the primary table in the main delete clause
|