sequel 5.68.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 +134 -0
- data/README.rdoc +3 -3
- data/doc/mass_assignment.rdoc +1 -1
- data/doc/migration.rdoc +15 -0
- data/doc/opening_databases.rdoc +12 -3
- 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/sharding.rdoc +3 -1
- data/doc/testing.rdoc +4 -2
- data/lib/sequel/adapters/ibmdb.rb +1 -1
- data/lib/sequel/adapters/jdbc/h2.rb +3 -0
- data/lib/sequel/adapters/jdbc/hsqldb.rb +2 -0
- data/lib/sequel/adapters/jdbc/postgresql.rb +3 -0
- data/lib/sequel/adapters/jdbc/sqlanywhere.rb +15 -0
- data/lib/sequel/adapters/jdbc/sqlserver.rb +4 -0
- data/lib/sequel/adapters/jdbc.rb +10 -6
- data/lib/sequel/adapters/mysql.rb +19 -7
- data/lib/sequel/adapters/mysql2.rb +2 -2
- data/lib/sequel/adapters/odbc/mssql.rb +1 -1
- data/lib/sequel/adapters/postgres.rb +6 -5
- data/lib/sequel/adapters/shared/db2.rb +12 -0
- data/lib/sequel/adapters/shared/mssql.rb +1 -1
- data/lib/sequel/adapters/shared/mysql.rb +31 -1
- data/lib/sequel/adapters/shared/oracle.rb +4 -6
- data/lib/sequel/adapters/shared/postgres.rb +79 -4
- data/lib/sequel/adapters/shared/sqlanywhere.rb +10 -4
- data/lib/sequel/adapters/shared/sqlite.rb +20 -3
- data/lib/sequel/adapters/sqlite.rb +42 -3
- data/lib/sequel/adapters/trilogy.rb +117 -0
- data/lib/sequel/connection_pool/sharded_threaded.rb +11 -10
- data/lib/sequel/connection_pool/sharded_timed_queue.rb +374 -0
- data/lib/sequel/connection_pool/threaded.rb +6 -0
- data/lib/sequel/connection_pool/timed_queue.rb +16 -3
- data/lib/sequel/connection_pool.rb +10 -1
- data/lib/sequel/database/connecting.rb +1 -1
- data/lib/sequel/database/misc.rb +2 -2
- data/lib/sequel/database/schema_methods.rb +9 -2
- data/lib/sequel/database/transactions.rb +6 -0
- data/lib/sequel/dataset/actions.rb +8 -6
- data/lib/sequel/dataset/features.rb +10 -1
- data/lib/sequel/dataset/sql.rb +47 -34
- data/lib/sequel/extensions/any_not_empty.rb +2 -2
- data/lib/sequel/extensions/async_thread_pool.rb +3 -2
- data/lib/sequel/extensions/auto_cast_date_and_time.rb +94 -0
- data/lib/sequel/extensions/connection_expiration.rb +15 -9
- data/lib/sequel/extensions/connection_validator.rb +15 -10
- data/lib/sequel/extensions/duplicate_columns_handler.rb +10 -9
- data/lib/sequel/extensions/index_caching.rb +5 -1
- data/lib/sequel/extensions/migration.rb +52 -13
- data/lib/sequel/extensions/named_timezones.rb +1 -1
- data/lib/sequel/extensions/pg_array.rb +10 -0
- data/lib/sequel/extensions/pg_auto_parameterize_in_array.rb +110 -0
- data/lib/sequel/extensions/pg_extended_date_support.rb +4 -4
- data/lib/sequel/extensions/pg_json_ops.rb +52 -0
- data/lib/sequel/extensions/pg_range.rb +2 -2
- data/lib/sequel/extensions/pg_timestamptz.rb +27 -3
- data/lib/sequel/extensions/round_timestamps.rb +1 -1
- data/lib/sequel/extensions/schema_caching.rb +1 -1
- data/lib/sequel/extensions/server_block.rb +2 -1
- data/lib/sequel/extensions/transaction_connection_validator.rb +78 -0
- data/lib/sequel/model/associations.rb +9 -2
- data/lib/sequel/model/base.rb +25 -12
- data/lib/sequel/model/dataset_module.rb +3 -0
- data/lib/sequel/model/exceptions.rb +15 -3
- data/lib/sequel/plugins/column_encryption.rb +27 -6
- data/lib/sequel/plugins/defaults_setter.rb +16 -0
- data/lib/sequel/plugins/list.rb +5 -2
- data/lib/sequel/plugins/mssql_optimistic_locking.rb +8 -38
- 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_auto_constraint_validations.rb +5 -1
- data/lib/sequel/plugins/pg_xmin_optimistic_locking.rb +109 -0
- data/lib/sequel/plugins/rcte_tree.rb +7 -4
- data/lib/sequel/plugins/static_cache.rb +38 -0
- data/lib/sequel/plugins/static_cache_cache.rb +5 -1
- data/lib/sequel/plugins/validation_helpers.rb +1 -1
- data/lib/sequel/version.rb +1 -1
- metadata +43 -3
data/doc/sharding.rdoc
CHANGED
@@ -39,7 +39,9 @@ is the simplest configuration:
|
|
39
39
|
servers: {read_only: {host: 'replica_server'}})
|
40
40
|
|
41
41
|
This will use the replica_server for SELECT queries and primary_server for
|
42
|
-
other queries.
|
42
|
+
other queries. The :read_only key in the :servers hash is special in that
|
43
|
+
it sets the default database for Dataset methods that use SELECT queries
|
44
|
+
(which are generally read queries that do not modify the database).
|
43
45
|
|
44
46
|
If you want to ensure your queries are going to a specific database, you
|
45
47
|
can force this for a given query by using the .server method and passing
|
data/doc/testing.rdoc
CHANGED
@@ -159,12 +159,13 @@ The SEQUEL_INTEGRATION_URL environment variable specifies the Database connectio
|
|
159
159
|
|
160
160
|
=== Other
|
161
161
|
|
162
|
+
SEQUEL_AUTO_CAST_DATE_TIME :: Use the auto_cast_date_and_time extension when running the specs
|
162
163
|
SEQUEL_ASYNC_THREAD_POOL :: Use the async_thread_pool extension when running the specs
|
163
164
|
SEQUEL_ASYNC_THREAD_POOL_PREEMPT :: Use the async_thread_pool extension when running the specs, with the :preempt_async_thread option
|
164
165
|
SEQUEL_CHECK_PENDING :: Try running all specs (note, can cause lockups for some adapters), and raise errors for skipped specs that don't fail
|
165
166
|
SEQUEL_COLUMNS_INTROSPECTION :: Use the columns_introspection extension when running the specs
|
166
167
|
SEQUEL_CONCURRENT_EAGER_LOADING :: Use the async_thread_pool extension and concurrent_eager_loading plugin when running the specs
|
167
|
-
SEQUEL_CONNECTION_VALIDATOR :: Use the
|
168
|
+
SEQUEL_CONNECTION_VALIDATOR :: Use the connection_validator extension when running the adapter/integration specs
|
168
169
|
SEQUEL_DUPLICATE_COLUMNS_HANDLER :: Use the duplicate columns handler extension with value given when running the specs
|
169
170
|
SEQUEL_ERROR_SQL :: Use the error_sql extension when running the specs
|
170
171
|
SEQUEL_FIBER_CONCURRENCY :: Use the fiber_concurrency extension when running the adapter and integration specs
|
@@ -176,7 +177,7 @@ SEQUEL_MODEL_PREPARED_STATEMENTS :: Use the prepared_statements plugin when runn
|
|
176
177
|
SEQUEL_MODEL_THROW_FAILURES :: Use the throw_failures plugin when running the specs
|
177
178
|
SEQUEL_NO_CACHE_ASSOCIATIONS :: Don't cache association metadata when running the specs
|
178
179
|
SEQUEL_NO_PENDING :: Don't skip any specs, try running all specs (note, can cause lockups for some adapters)
|
179
|
-
SEQUEL_PG_AUTO_PARAMETERIZE :: Use the pg_auto_parameterize extension when running the postgres specs
|
180
|
+
SEQUEL_PG_AUTO_PARAMETERIZE :: Use the pg_auto_parameterize extension when running the postgres specs. Value can be +in_array+ to test the pg_auto_parameterize_in_array extension, and +in_array_string+ to test the pg_auto_parameterize_in_array extension with the +:treat_in_string_list_as_text_array+ Database option set.
|
180
181
|
SEQUEL_PG_TIMESTAMPTZ :: Use the pg_timestamptz extension when running the postgres specs
|
181
182
|
SEQUEL_PRIMARY_KEY_LOOKUP_CHECK_VALUES :: Use the primary_key_lookup_check_values extension when running the adapter or integration specs
|
182
183
|
SEQUEL_QUERY_PER_ASSOCIATION_DB_0_URL :: Run query-per-association integration tests with multiple databases (all 4 must be set to run)
|
@@ -185,4 +186,5 @@ SEQUEL_QUERY_PER_ASSOCIATION_DB_2_URL :: Run query-per-association integration t
|
|
185
186
|
SEQUEL_QUERY_PER_ASSOCIATION_DB_3_URL :: Run query-per-association integration tests with multiple databases (all 4 must be set to run)
|
186
187
|
SEQUEL_SPLIT_SYMBOLS :: Turn on symbol splitting when running the adapter and integration specs
|
187
188
|
SEQUEL_SYNCHRONIZE_SQL :: Use the synchronize_sql extension when running the specs
|
189
|
+
SEQUEL_TRANSACTION_CONNECTION_VALIDATOR :: Use the transaction_connection_validator extension when running the adapter/integration specs
|
188
190
|
SEQUEL_TZINFO_VERSION :: Force the given tzinfo version when running the specs (e.g. '>=2')
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen-string-literal: true
|
2
2
|
|
3
3
|
Sequel::JDBC.load_driver('org.h2.Driver', :H2)
|
4
|
+
require_relative '../../extensions/auto_cast_date_and_time'
|
4
5
|
|
5
6
|
module Sequel
|
6
7
|
module JDBC
|
@@ -14,6 +15,8 @@ module Sequel
|
|
14
15
|
|
15
16
|
module H2
|
16
17
|
module DatabaseMethods
|
18
|
+
include AutoCastDateAndTime
|
19
|
+
|
17
20
|
def commit_prepared_transaction(transaction_id, opts=OPTS)
|
18
21
|
run("COMMIT TRANSACTION #{transaction_id}", opts)
|
19
22
|
end
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
Sequel::JDBC.load_driver('org.hsqldb.jdbcDriver', :HSQLDB)
|
4
4
|
require_relative 'transactions'
|
5
|
+
require_relative '../../extensions/auto_cast_date_and_time'
|
5
6
|
|
6
7
|
module Sequel
|
7
8
|
module JDBC
|
@@ -15,6 +16,7 @@ module Sequel
|
|
15
16
|
|
16
17
|
module HSQLDB
|
17
18
|
module DatabaseMethods
|
19
|
+
include AutoCastDateAndTime
|
18
20
|
include ::Sequel::JDBC::Transactions
|
19
21
|
|
20
22
|
def database_type
|
@@ -199,6 +199,7 @@ module Sequel
|
|
199
199
|
v.strftime("'%H:%M:%S#{sprintf(".%03d", (v.usec/1000.0).round)}'")
|
200
200
|
end
|
201
201
|
|
202
|
+
INTEGER_TYPE = Java::JavaSQL::Types::INTEGER
|
202
203
|
STRING_TYPE = Java::JavaSQL::Types::VARCHAR
|
203
204
|
ARRAY_TYPE = Java::JavaSQL::Types::ARRAY
|
204
205
|
PG_SPECIFIC_TYPES = [Java::JavaSQL::Types::ARRAY, Java::JavaSQL::Types::OTHER, Java::JavaSQL::Types::STRUCT, Java::JavaSQL::Types::TIME_WITH_TIMEZONE, Java::JavaSQL::Types::TIME].freeze
|
@@ -219,6 +220,8 @@ module Sequel
|
|
219
220
|
oid = meta.getField(i).getOID
|
220
221
|
if pr = db.oid_convertor_proc(oid)
|
221
222
|
pr
|
223
|
+
elsif oid == 28 # XID (Transaction ID)
|
224
|
+
map[INTEGER_TYPE]
|
222
225
|
elsif oid == 2950 # UUID
|
223
226
|
map[STRING_TYPE]
|
224
227
|
elsif meta.getPGType(i) == 'hstore'
|
@@ -36,6 +36,10 @@ module Sequel
|
|
36
36
|
|
37
37
|
private
|
38
38
|
|
39
|
+
def database_exception_use_sqlstates?
|
40
|
+
false
|
41
|
+
end
|
42
|
+
|
39
43
|
# Use @@IDENTITY to get the last inserted id
|
40
44
|
def last_insert_id(conn, opts=OPTS)
|
41
45
|
statement(conn) do |stmt|
|
@@ -52,6 +56,17 @@ module Sequel
|
|
52
56
|
|
53
57
|
private
|
54
58
|
|
59
|
+
# JDBC SQLAnywhere driver does not appear to handle fractional
|
60
|
+
# times correctly.
|
61
|
+
def default_time_format
|
62
|
+
"'%H:%M:%S'"
|
63
|
+
end
|
64
|
+
|
65
|
+
# Set to zero to work around JDBC SQLAnywhere driver bug.
|
66
|
+
def sqltime_precision
|
67
|
+
0
|
68
|
+
end
|
69
|
+
|
55
70
|
SMALLINT_TYPE = Java::JavaSQL::Types::SMALLINT
|
56
71
|
BOOLEAN_METHOD = Object.new
|
57
72
|
def BOOLEAN_METHOD.call(r, i)
|
data/lib/sequel/adapters/jdbc.rb
CHANGED
@@ -396,11 +396,16 @@ module Sequel
|
|
396
396
|
|
397
397
|
def database_exception_sqlstate(exception, opts)
|
398
398
|
if database_exception_use_sqlstates?
|
399
|
-
|
400
|
-
exception = exception.cause
|
401
|
-
return exception.getSQLState if exception.respond_to?(:getSQLState)
|
402
|
-
end
|
399
|
+
_database_exception_sqlstate(exception, opts)
|
403
400
|
end
|
401
|
+
end
|
402
|
+
|
403
|
+
def _database_exception_sqlstate(exception, opts)
|
404
|
+
16.times do
|
405
|
+
return exception.getSQLState if exception.respond_to?(:getSQLState)
|
406
|
+
break unless exception.respond_to?(:cause) && (exception = exception.cause)
|
407
|
+
end
|
408
|
+
|
404
409
|
nil
|
405
410
|
end
|
406
411
|
|
@@ -415,8 +420,7 @@ module Sequel
|
|
415
420
|
|
416
421
|
# Raise a disconnect error if the SQL state of the cause of the exception indicates so.
|
417
422
|
def disconnect_error?(exception, opts)
|
418
|
-
|
419
|
-
super || (cause.respond_to?(:getSQLState) && cause.getSQLState =~ /^08/)
|
423
|
+
super || (_database_exception_sqlstate(exception, opts) =~ /^08/)
|
420
424
|
end
|
421
425
|
|
422
426
|
# Execute the prepared statement. If the provided name is a
|
@@ -29,6 +29,21 @@ module Sequel
|
|
29
29
|
end
|
30
30
|
MYSQL_TYPES.freeze
|
31
31
|
|
32
|
+
RUBY_MYSQL_3 = !Mysql.respond_to?(:init)
|
33
|
+
RUBY_MYSQL_4 = RUBY_MYSQL_3 && ::Mysql::VERSION.to_i >= 4
|
34
|
+
|
35
|
+
if RUBY_MYSQL_3
|
36
|
+
class Adapter < ::Mysql
|
37
|
+
alias real_connect connect
|
38
|
+
alias use_result store_result
|
39
|
+
if RUBY_MYSQL_4
|
40
|
+
def initialize(**opts)
|
41
|
+
super(**opts.merge(:cast=>false))
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
32
47
|
class Database < Sequel::Database
|
33
48
|
include Sequel::MySQL::DatabaseMethods
|
34
49
|
include Sequel::MySQL::MysqlMysql2::DatabaseMethods
|
@@ -72,7 +87,7 @@ module Sequel
|
|
72
87
|
def connect(server)
|
73
88
|
opts = server_opts(server)
|
74
89
|
|
75
|
-
if
|
90
|
+
if !RUBY_MYSQL_3
|
76
91
|
conn = Mysql.init
|
77
92
|
conn.options(Mysql::READ_DEFAULT_GROUP, opts[:config_default_group] || "client")
|
78
93
|
conn.options(Mysql::OPT_LOCAL_INFILE, opts[:config_local_infile]) if opts.has_key?(:config_local_infile)
|
@@ -88,8 +103,8 @@ module Sequel
|
|
88
103
|
conn.options(Mysql::OPT_CONNECT_TIMEOUT, connect_timeout)
|
89
104
|
end
|
90
105
|
else
|
91
|
-
# ruby-mysql 3 API
|
92
|
-
conn =
|
106
|
+
# ruby-mysql 3+ API
|
107
|
+
conn = Adapter.new
|
93
108
|
# no support for default group
|
94
109
|
conn.local_infile = opts[:config_local_infile] if opts.has_key?(:config_local_infile)
|
95
110
|
if encoding = opts[:encoding] || opts[:charset]
|
@@ -101,10 +116,7 @@ module Sequel
|
|
101
116
|
if connect_timeout = opts[:connect_timeout]
|
102
117
|
conn.connect_timeout = connect_timeout
|
103
118
|
end
|
104
|
-
|
105
|
-
alias real_connect connect
|
106
|
-
alias use_result store_result
|
107
|
-
end
|
119
|
+
opts[:compress] = false
|
108
120
|
end
|
109
121
|
|
110
122
|
conn.ssl_set(opts[:sslkey], opts[:sslcert], opts[:sslca], opts[:sslcapath], opts[:sslcipher]) if opts[:sslca] || opts[:sslkey]
|
@@ -43,7 +43,7 @@ module Sequel
|
|
43
43
|
# Use ODBC format, not Microsoft format, as the ODBC layer does
|
44
44
|
# some translation, but allow for millisecond precision.
|
45
45
|
def default_timestamp_format
|
46
|
-
"{ts '%Y-%m-%d %H:%M:%S
|
46
|
+
"{ts '%Y-%m-%d %H:%M:%S.%3N'}"
|
47
47
|
end
|
48
48
|
|
49
49
|
# Use ODBC format, not Microsoft format, as the ODBC layer does
|
@@ -188,8 +188,8 @@ module Sequel
|
|
188
188
|
# :nocov:
|
189
189
|
# Not covered by tests as tests use pg_extended_date_support
|
190
190
|
# extension, which has basically the same code.
|
191
|
-
when
|
192
|
-
|
191
|
+
when Time, DateTime
|
192
|
+
@default_dataset.literal_date_or_time(arg)
|
193
193
|
# :nocov:
|
194
194
|
else
|
195
195
|
arg
|
@@ -672,6 +672,7 @@ module Sequel
|
|
672
672
|
# cursor usage.
|
673
673
|
# :rows_per_fetch :: The number of rows per fetch (default 1000). Higher
|
674
674
|
# numbers result in fewer queries but greater memory use.
|
675
|
+
# :skip_transaction :: Same as :hold, but :hold takes priority.
|
675
676
|
#
|
676
677
|
# Usage:
|
677
678
|
#
|
@@ -764,13 +765,13 @@ module Sequel
|
|
764
765
|
|
765
766
|
# Use a cursor to fetch groups of records at a time, yielding them to the block.
|
766
767
|
def cursor_fetch_rows(sql)
|
767
|
-
server_opts = {:server=>@opts[:server] || :read_only}
|
768
768
|
cursor = @opts[:cursor]
|
769
|
-
hold = cursor[:
|
769
|
+
hold = cursor.fetch(:hold){cursor[:skip_transaction]}
|
770
|
+
server_opts = {:server=>@opts[:server] || :read_only, :skip_transaction=>hold}
|
770
771
|
cursor_name = quote_identifier(cursor[:cursor_name] || 'sequel_cursor')
|
771
772
|
rows_per_fetch = cursor[:rows_per_fetch].to_i
|
772
773
|
|
773
|
-
db.
|
774
|
+
db.transaction(server_opts) do
|
774
775
|
begin
|
775
776
|
execute_ddl("DECLARE #{cursor_name} NO SCROLL CURSOR WITH#{'OUT' unless hold} HOLD FOR #{sql}", server_opts)
|
776
777
|
rows_per_fetch = 1000 if rows_per_fetch <= 0
|
@@ -215,6 +215,18 @@ module Sequel
|
|
215
215
|
DATABASE_ERROR_REGEXPS
|
216
216
|
end
|
217
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
|
+
|
218
230
|
# DB2 has issues with quoted identifiers, so
|
219
231
|
# turn off database quoting by default.
|
220
232
|
def quote_identifiers_default
|
@@ -932,7 +932,7 @@ module Sequel
|
|
932
932
|
# since that is the format that is multilanguage and not
|
933
933
|
# DATEFORMAT dependent.
|
934
934
|
def default_timestamp_format
|
935
|
-
"'%Y-%m-%dT%H:%M:%S
|
935
|
+
"'%Y-%m-%dT%H:%M:%S.%3N'"
|
936
936
|
end
|
937
937
|
|
938
938
|
# Only include the primary table in the main delete clause
|
@@ -646,7 +646,7 @@ module Sequel
|
|
646
646
|
MATCH_AGAINST_BOOLEAN = ["MATCH ".freeze, " AGAINST (".freeze, " IN BOOLEAN MODE)".freeze].freeze
|
647
647
|
|
648
648
|
Dataset.def_sql_method(self, :delete, %w'with delete from where order limit')
|
649
|
-
Dataset.def_sql_method(self, :insert, %w'insert ignore into columns values on_duplicate_key_update')
|
649
|
+
Dataset.def_sql_method(self, :insert, %w'insert ignore into columns values on_duplicate_key_update returning')
|
650
650
|
Dataset.def_sql_method(self, :select, %w'with select distinct calc_found_rows columns from join where group having window compounds order limit lock')
|
651
651
|
Dataset.def_sql_method(self, :update, %w'with update ignore table set where order limit')
|
652
652
|
|
@@ -774,6 +774,21 @@ module Sequel
|
|
774
774
|
clone(:insert_ignore=>true)
|
775
775
|
end
|
776
776
|
|
777
|
+
# Support insert select for associations, so that the model code can use
|
778
|
+
# returning instead of a separate query.
|
779
|
+
def insert_select(*values)
|
780
|
+
return unless supports_insert_select?
|
781
|
+
# Handle case where query does not return a row
|
782
|
+
server?(:default).with_sql_first(insert_select_sql(*values)) || false
|
783
|
+
end
|
784
|
+
|
785
|
+
# The SQL to use for an insert_select, adds a RETURNING clause to the insert
|
786
|
+
# unless the RETURNING clause is already present.
|
787
|
+
def insert_select_sql(*values)
|
788
|
+
ds = opts[:returning] ? self : returning
|
789
|
+
ds.insert_sql(*values)
|
790
|
+
end
|
791
|
+
|
777
792
|
# Sets up the insert methods to use ON DUPLICATE KEY UPDATE
|
778
793
|
# If you pass no arguments, ALL fields will be
|
779
794
|
# updated with the new values. If you pass the fields you
|
@@ -871,6 +886,11 @@ module Sequel
|
|
871
886
|
true
|
872
887
|
end
|
873
888
|
|
889
|
+
# MariaDB 10.5.0 supports INSERT RETURNING.
|
890
|
+
def supports_returning?(type)
|
891
|
+
(type == :insert && db.mariadb? && db.adapter_scheme != :jdbc) ? (db.server_version >= 100500) : false
|
892
|
+
end
|
893
|
+
|
874
894
|
# MySQL 8+ supports SKIP LOCKED.
|
875
895
|
def supports_skip_locked?
|
876
896
|
!db.mariadb? && db.server_version >= 80000
|
@@ -909,6 +929,16 @@ module Sequel
|
|
909
929
|
super if type == :truncate || @opts[:offset]
|
910
930
|
end
|
911
931
|
|
932
|
+
# The strftime format to use when literalizing time (Sequel::SQLTime) values.
|
933
|
+
def default_time_format
|
934
|
+
db.supports_timestamp_usecs? ? super : "'%H:%M:%S'"
|
935
|
+
end
|
936
|
+
|
937
|
+
# The strftime format to use when literalizing timestamp (Time/DateTime) values.
|
938
|
+
def default_timestamp_format
|
939
|
+
db.supports_timestamp_usecs? ? super : "'%Y-%m-%d %H:%M:%S'"
|
940
|
+
end
|
941
|
+
|
912
942
|
# Consider the first table in the joined dataset is the table to delete
|
913
943
|
# from, but include the others for the purposes of selecting rows.
|
914
944
|
def delete_from_sql(sql)
|
@@ -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 '../../extensions/auto_cast_date_and_time'
|
4
5
|
|
5
6
|
module Sequel
|
6
7
|
module Oracle
|
@@ -326,6 +327,8 @@ module Sequel
|
|
326
327
|
end
|
327
328
|
|
328
329
|
module DatasetMethods
|
330
|
+
include AutoCastDateAndTime
|
331
|
+
|
329
332
|
ROW_NUMBER_EXPRESSION = LiteralString.new('ROWNUM').freeze
|
330
333
|
BITAND_PROC = lambda{|a, b| Sequel.lit(["CAST(BITAND(", ", ", ") AS INTEGER)"], a, b)}
|
331
334
|
|
@@ -623,7 +626,7 @@ module Sequel
|
|
623
626
|
|
624
627
|
# The strftime format to use when literalizing the time.
|
625
628
|
def default_timestamp_format
|
626
|
-
"
|
629
|
+
"'%Y-%m-%d %H:%M:%S.%6N %:z'"
|
627
630
|
end
|
628
631
|
|
629
632
|
def empty_from_sql
|
@@ -660,11 +663,6 @@ module Sequel
|
|
660
663
|
super
|
661
664
|
end
|
662
665
|
|
663
|
-
# Use a colon for the timestamp offset, since Oracle appears to require it.
|
664
|
-
def format_timestamp_offset(hour, minute)
|
665
|
-
sprintf("%+03i:%02i", hour, minute)
|
666
|
-
end
|
667
|
-
|
668
666
|
# Oracle doesn't support empty values when inserting.
|
669
667
|
def insert_supports_empty_values?
|
670
668
|
false
|
@@ -498,6 +498,25 @@ module Sequel
|
|
498
498
|
:postgres
|
499
499
|
end
|
500
500
|
|
501
|
+
# For constraints that are deferrable, defer constraints until
|
502
|
+
# transaction commit. Options:
|
503
|
+
#
|
504
|
+
# :constraints :: An identifier of the constraint, or an array of
|
505
|
+
# identifiers for constraints, to apply this
|
506
|
+
# change to specific constraints.
|
507
|
+
# :server :: The server/shard on which to run the query.
|
508
|
+
#
|
509
|
+
# Examples:
|
510
|
+
#
|
511
|
+
# DB.defer_constraints
|
512
|
+
# # SET CONSTRAINTS ALL DEFERRED
|
513
|
+
#
|
514
|
+
# DB.defer_constraints(constraints: [:c1, Sequel[:sc][:c2]])
|
515
|
+
# # SET CONSTRAINTS "c1", "sc"."s2" DEFERRED
|
516
|
+
def defer_constraints(opts=OPTS)
|
517
|
+
_set_constraints(' DEFERRED', opts)
|
518
|
+
end
|
519
|
+
|
501
520
|
# Use PostgreSQL's DO syntax to execute an anonymous code block. The code should
|
502
521
|
# be the literal code string to use in the underlying procedural language. Options:
|
503
522
|
#
|
@@ -611,6 +630,24 @@ module Sequel
|
|
611
630
|
super
|
612
631
|
end
|
613
632
|
|
633
|
+
# Immediately apply deferrable constraints.
|
634
|
+
#
|
635
|
+
# :constraints :: An identifier of the constraint, or an array of
|
636
|
+
# identifiers for constraints, to apply this
|
637
|
+
# change to specific constraints.
|
638
|
+
# :server :: The server/shard on which to run the query.
|
639
|
+
#
|
640
|
+
# Examples:
|
641
|
+
#
|
642
|
+
# DB.immediate_constraints
|
643
|
+
# # SET CONSTRAINTS ALL IMMEDIATE
|
644
|
+
#
|
645
|
+
# DB.immediate_constraints(constraints: [:c1, Sequel[:sc][:c2]])
|
646
|
+
# # SET CONSTRAINTS "c1", "sc"."s2" IMMEDIATE
|
647
|
+
def immediate_constraints(opts=OPTS)
|
648
|
+
_set_constraints(' IMMEDIATE', opts)
|
649
|
+
end
|
650
|
+
|
614
651
|
# Use the pg_* system tables to determine indexes on a table
|
615
652
|
def indexes(table, opts=OPTS)
|
616
653
|
m = output_identifier_meth
|
@@ -1038,6 +1075,31 @@ module Sequel
|
|
1038
1075
|
end
|
1039
1076
|
end
|
1040
1077
|
|
1078
|
+
# Internals of defer_constraints/immediate_constraints
|
1079
|
+
def _set_constraints(type, opts)
|
1080
|
+
execute_ddl(_set_constraints_sql(type, opts), opts)
|
1081
|
+
end
|
1082
|
+
|
1083
|
+
# SQL to use for SET CONSTRAINTS
|
1084
|
+
def _set_constraints_sql(type, opts)
|
1085
|
+
sql = String.new
|
1086
|
+
sql << "SET CONSTRAINTS "
|
1087
|
+
if constraints = opts[:constraints]
|
1088
|
+
dataset.send(:source_list_append, sql, Array(constraints))
|
1089
|
+
else
|
1090
|
+
sql << "ALL"
|
1091
|
+
end
|
1092
|
+
sql << type
|
1093
|
+
end
|
1094
|
+
|
1095
|
+
# Consider lock or statement timeout errors as evidence that the table exists
|
1096
|
+
# but is locked.
|
1097
|
+
def _table_exists?(ds)
|
1098
|
+
super
|
1099
|
+
rescue DatabaseError => e
|
1100
|
+
raise e unless /canceling statement due to (?:statement|lock) timeout/ =~ e.message
|
1101
|
+
end
|
1102
|
+
|
1041
1103
|
def alter_table_add_column_sql(table, op)
|
1042
1104
|
"ADD COLUMN#{' IF NOT EXISTS' if op[:if_not_exists]} #{column_definition_sql(op)}"
|
1043
1105
|
end
|
@@ -1451,7 +1513,11 @@ module Sequel
|
|
1451
1513
|
# currently visible schemas.
|
1452
1514
|
def filter_schema(ds, opts)
|
1453
1515
|
expr = if schema = opts[:schema]
|
1454
|
-
schema.
|
1516
|
+
if schema.is_a?(SQL::Identifier)
|
1517
|
+
schema.value.to_s
|
1518
|
+
else
|
1519
|
+
schema.to_s
|
1520
|
+
end
|
1455
1521
|
else
|
1456
1522
|
Sequel.function(:any, Sequel.function(:current_schemas, false))
|
1457
1523
|
end
|
@@ -1745,8 +1811,6 @@ module Sequel
|
|
1745
1811
|
literal_append(sql, args[0])
|
1746
1812
|
sql << ' ' << op.to_s << ' '
|
1747
1813
|
literal_append(sql, args[1])
|
1748
|
-
sql << " ESCAPE "
|
1749
|
-
literal_append(sql, "\\")
|
1750
1814
|
sql << ')'
|
1751
1815
|
else
|
1752
1816
|
super
|
@@ -1800,7 +1864,7 @@ module Sequel
|
|
1800
1864
|
# :phrase :: Similar to :plain, but also adding an ILIKE filter to ensure that
|
1801
1865
|
# returned rows also include the exact phrase used.
|
1802
1866
|
# :rank :: Set to true to order by the rank, so that closer matches are returned first.
|
1803
|
-
# :to_tsquery :: Can be set to :plain or :
|
1867
|
+
# :to_tsquery :: Can be set to :plain, :phrase, or :websearch to specify the function to use to
|
1804
1868
|
# convert the terms to a ts_query.
|
1805
1869
|
# :tsquery :: Specifies the terms argument is already a valid SQL expression returning a
|
1806
1870
|
# tsquery, and can be used directly in the query.
|
@@ -1820,6 +1884,8 @@ module Sequel
|
|
1820
1884
|
query_func = case to_tsquery = opts[:to_tsquery]
|
1821
1885
|
when :phrase, :plain
|
1822
1886
|
:"#{to_tsquery}to_tsquery"
|
1887
|
+
when :websearch
|
1888
|
+
:"websearch_to_tsquery"
|
1823
1889
|
else
|
1824
1890
|
(opts[:phrase] || opts[:plain]) ? :plainto_tsquery : :to_tsquery
|
1825
1891
|
end
|
@@ -2084,10 +2150,14 @@ module Sequel
|
|
2084
2150
|
server_version >= 90500
|
2085
2151
|
end
|
2086
2152
|
|
2153
|
+
# :nocov:
|
2154
|
+
|
2087
2155
|
# PostgreSQL supports timezones in literal timestamps
|
2088
2156
|
def supports_timestamp_timezones?
|
2157
|
+
# SEQUEL6: Remove
|
2089
2158
|
true
|
2090
2159
|
end
|
2160
|
+
# :nocov:
|
2091
2161
|
|
2092
2162
|
# PostgreSQL 8.4+ supports WINDOW clause.
|
2093
2163
|
def supports_window_clause?
|
@@ -2207,6 +2277,11 @@ module Sequel
|
|
2207
2277
|
raise(InvalidOperation, "Joined datasets cannot be truncated") if opts[:join]
|
2208
2278
|
end
|
2209
2279
|
|
2280
|
+
# The strftime format to use when literalizing the time.
|
2281
|
+
def default_timestamp_format
|
2282
|
+
"'%Y-%m-%d %H:%M:%S.%6N%z'"
|
2283
|
+
end
|
2284
|
+
|
2210
2285
|
# Only include the primary table in the main delete clause
|
2211
2286
|
def delete_from_sql(sql)
|
2212
2287
|
sql << ' FROM '
|
@@ -281,10 +281,6 @@ module Sequel
|
|
281
281
|
false
|
282
282
|
end
|
283
283
|
|
284
|
-
def supports_timestamp_usecs?
|
285
|
-
false
|
286
|
-
end
|
287
|
-
|
288
284
|
def supports_window_clause?
|
289
285
|
true
|
290
286
|
end
|
@@ -378,6 +374,16 @@ module Sequel
|
|
378
374
|
|
379
375
|
private
|
380
376
|
|
377
|
+
# SQLAnywhere only supports 3 digits after the decimal point for times.
|
378
|
+
def default_time_format
|
379
|
+
"'%H:%M:%S.%3N'"
|
380
|
+
end
|
381
|
+
|
382
|
+
# SQLAnywhere only supports 3 digits after the decimal point for timestamps.
|
383
|
+
def default_timestamp_format
|
384
|
+
"'%Y-%m-%d %H:%M:%S.%3N'"
|
385
|
+
end
|
386
|
+
|
381
387
|
# Use 1 for true on Sybase
|
382
388
|
def literal_true
|
383
389
|
'1'
|
@@ -145,6 +145,11 @@ module Sequel
|
|
145
145
|
sqlite_version >= 30608
|
146
146
|
end
|
147
147
|
|
148
|
+
# SQLite 3.8.2+ supports the without rowid table constraint
|
149
|
+
def support_without_rowid?
|
150
|
+
sqlite_version >= 30802
|
151
|
+
end
|
152
|
+
|
148
153
|
# Override the default setting for whether to use timezones in timestamps.
|
149
154
|
# It is set to +false+ by default, as SQLite's date/time methods do not
|
150
155
|
# support timezones in timestamps.
|
@@ -344,9 +349,17 @@ module Sequel
|
|
344
349
|
ps
|
345
350
|
end
|
346
351
|
|
347
|
-
# Support creating STRICT tables via :strict
|
352
|
+
# Support creating STRICT AND/OR WITHOUT ROWID tables via :strict and :without_rowid options
|
348
353
|
def create_table_sql(name, generator, options)
|
349
|
-
|
354
|
+
if options[:strict] && options[:without_rowid]
|
355
|
+
"#{super} STRICT, WITHOUT ROWID"
|
356
|
+
elsif options[:strict]
|
357
|
+
"#{super} STRICT"
|
358
|
+
elsif options[:without_rowid]
|
359
|
+
"#{super} WITHOUT ROWID"
|
360
|
+
else
|
361
|
+
super
|
362
|
+
end
|
350
363
|
end
|
351
364
|
|
352
365
|
# SQLite support creating temporary views.
|
@@ -504,7 +517,6 @@ module Sequel
|
|
504
517
|
# table_xinfo PRAGMA used, remove hidden columns
|
505
518
|
# that are not generated columns
|
506
519
|
if row[:generated] = (row.delete(:hidden) != 0)
|
507
|
-
next unless row[:type].end_with?(' GENERATED ALWAYS')
|
508
520
|
row[:type] = row[:type].sub(' GENERATED ALWAYS', '')
|
509
521
|
end
|
510
522
|
end
|
@@ -918,6 +930,11 @@ module Sequel
|
|
918
930
|
500
|
919
931
|
end
|
920
932
|
|
933
|
+
# The strftime format to use when literalizing the time.
|
934
|
+
def default_timestamp_format
|
935
|
+
db.use_timestamp_timezones? ? "'%Y-%m-%d %H:%M:%S.%6N%z'" : super
|
936
|
+
end
|
937
|
+
|
921
938
|
# SQL fragment specifying a list of identifiers
|
922
939
|
def identifier_list(columns)
|
923
940
|
columns.map{|i| quote_identifier(i)}.join(', ')
|