sequel 5.68.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 +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(', ')
|