sequel 5.45.0 → 5.77.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.
- 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
|