sequel 5.58.0 → 5.78.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 +288 -0
- data/MIT-LICENSE +1 -1
- data/README.rdoc +24 -23
- data/bin/sequel +11 -3
- data/doc/advanced_associations.rdoc +16 -14
- data/doc/association_basics.rdoc +53 -17
- data/doc/cheat_sheet.rdoc +3 -3
- data/doc/mass_assignment.rdoc +1 -1
- data/doc/migration.rdoc +15 -0
- data/doc/model_hooks.rdoc +1 -1
- data/doc/object_model.rdoc +8 -8
- data/doc/opening_databases.rdoc +20 -12
- data/doc/postgresql.rdoc +8 -8
- data/doc/querying.rdoc +1 -1
- 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/release_notes/5.78.0.txt +67 -0
- data/doc/schema_modification.rdoc +3 -3
- data/doc/security.rdoc +9 -9
- data/doc/sharding.rdoc +3 -1
- data/doc/sql.rdoc +14 -14
- data/doc/testing.rdoc +16 -12
- data/doc/transactions.rdoc +6 -6
- data/doc/virtual_rows.rdoc +1 -1
- 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/oracle.rb +1 -0
- data/lib/sequel/adapters/postgres.rb +62 -16
- data/lib/sequel/adapters/shared/access.rb +9 -1
- data/lib/sequel/adapters/shared/db2.rb +12 -0
- data/lib/sequel/adapters/shared/mssql.rb +71 -9
- data/lib/sequel/adapters/shared/mysql.rb +80 -1
- data/lib/sequel/adapters/shared/oracle.rb +17 -7
- data/lib/sequel/adapters/shared/postgres.rb +494 -164
- data/lib/sequel/adapters/shared/sqlanywhere.rb +18 -5
- data/lib/sequel/adapters/shared/sqlite.rb +40 -4
- data/lib/sequel/adapters/sqlite.rb +42 -3
- data/lib/sequel/adapters/trilogy.rb +117 -0
- 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/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/database/connecting.rb +25 -1
- data/lib/sequel/database/dataset.rb +16 -6
- data/lib/sequel/database/misc.rb +65 -14
- data/lib/sequel/database/query.rb +72 -1
- data/lib/sequel/database/schema_generator.rb +2 -1
- data/lib/sequel/database/schema_methods.rb +13 -3
- data/lib/sequel/database/transactions.rb +6 -0
- data/lib/sequel/dataset/actions.rb +60 -13
- data/lib/sequel/dataset/deprecated_singleton_class_methods.rb +42 -0
- data/lib/sequel/dataset/features.rb +15 -1
- data/lib/sequel/dataset/misc.rb +12 -2
- data/lib/sequel/dataset/placeholder_literalizer.rb +20 -9
- data/lib/sequel/dataset/query.rb +62 -37
- data/lib/sequel/dataset/sql.rb +58 -36
- data/lib/sequel/dataset.rb +4 -0
- data/lib/sequel/exceptions.rb +5 -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 +21 -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/date_arithmetic.rb +36 -8
- data/lib/sequel/extensions/duplicate_columns_handler.rb +10 -9
- data/lib/sequel/extensions/index_caching.rb +5 -1
- data/lib/sequel/extensions/is_distinct_from.rb +3 -1
- data/lib/sequel/extensions/looser_typecasting.rb +3 -0
- data/lib/sequel/extensions/migration.rb +65 -15
- data/lib/sequel/extensions/named_timezones.rb +22 -6
- data/lib/sequel/extensions/pg_array.rb +33 -4
- 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 +38 -27
- data/lib/sequel/extensions/pg_extended_integer_support.rb +116 -0
- data/lib/sequel/extensions/pg_hstore.rb +5 -0
- data/lib/sequel/extensions/pg_inet.rb +10 -11
- data/lib/sequel/extensions/pg_interval.rb +10 -11
- data/lib/sequel/extensions/pg_json.rb +10 -10
- data/lib/sequel/extensions/pg_json_ops.rb +52 -0
- data/lib/sequel/extensions/pg_multirange.rb +6 -11
- data/lib/sequel/extensions/pg_range.rb +9 -14
- data/lib/sequel/extensions/pg_row.rb +20 -19
- 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/schema_dumper.rb +32 -9
- data/lib/sequel/extensions/server_block.rb +2 -1
- data/lib/sequel/extensions/set_literalizer.rb +58 -0
- data/lib/sequel/extensions/sqlite_json_ops.rb +76 -18
- 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 +50 -11
- data/lib/sequel/model/base.rb +45 -21
- data/lib/sequel/model/dataset_module.rb +3 -0
- data/lib/sequel/model/exceptions.rb +15 -3
- data/lib/sequel/plugins/auto_validations.rb +53 -15
- data/lib/sequel/plugins/class_table_inheritance.rb +2 -2
- data/lib/sequel/plugins/column_encryption.rb +27 -6
- data/lib/sequel/plugins/composition.rb +2 -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/finder.rb +4 -2
- data/lib/sequel/plugins/list.rb +8 -3
- data/lib/sequel/plugins/many_through_many.rb +1 -1
- 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_auto_constraint_validations.rb +9 -3
- data/lib/sequel/plugins/pg_xmin_optimistic_locking.rb +109 -0
- data/lib/sequel/plugins/prepared_statements.rb +2 -1
- 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/single_table_inheritance.rb +8 -0
- data/lib/sequel/plugins/sql_comments.rb +5 -5
- data/lib/sequel/plugins/static_cache.rb +38 -0
- data/lib/sequel/plugins/static_cache_cache.rb +5 -1
- data/lib/sequel/plugins/tactical_eager_loading.rb +21 -14
- data/lib/sequel/plugins/validate_associated.rb +22 -12
- data/lib/sequel/plugins/validation_helpers.rb +29 -2
- data/lib/sequel/plugins/validation_helpers_generic_type_messages.rb +73 -0
- data/lib/sequel/version.rb +1 -1
- metadata +76 -6
@@ -30,8 +30,12 @@ class Sequel::ConnectionPool
|
|
30
30
|
:threaded => :ThreadedConnectionPool,
|
31
31
|
:single => :SingleConnectionPool,
|
32
32
|
:sharded_threaded => :ShardedThreadedConnectionPool,
|
33
|
-
:sharded_single => :ShardedSingleConnectionPool
|
34
|
-
|
33
|
+
:sharded_single => :ShardedSingleConnectionPool,
|
34
|
+
:timed_queue => :TimedQueueConnectionPool,
|
35
|
+
:sharded_timed_queue => :ShardedTimedQueueConnectionPool,
|
36
|
+
}
|
37
|
+
POOL_CLASS_MAP.to_a.each{|k, v| POOL_CLASS_MAP[k.to_s] = v}
|
38
|
+
POOL_CLASS_MAP.freeze
|
35
39
|
|
36
40
|
# Class methods used to return an appropriate pool subclass, separated
|
37
41
|
# into a module for easier overridding by extensions.
|
@@ -39,7 +43,8 @@ class Sequel::ConnectionPool
|
|
39
43
|
# Return a pool subclass instance based on the given options. If a <tt>:pool_class</tt>
|
40
44
|
# option is provided is provided, use that pool class, otherwise
|
41
45
|
# use a new instance of an appropriate pool subclass based on the
|
42
|
-
#
|
46
|
+
# +SEQUEL_DEFAULT_CONNECTION_POOL+ environment variable if set, or
|
47
|
+
# the <tt>:single_threaded</tt> and <tt>:servers</tt> options, otherwise.
|
43
48
|
def get_pool(db, opts = OPTS)
|
44
49
|
connection_pool_class(opts).new(db, opts)
|
45
50
|
end
|
@@ -59,9 +64,16 @@ class Sequel::ConnectionPool
|
|
59
64
|
end
|
60
65
|
|
61
66
|
pc
|
67
|
+
elsif pc = ENV['SEQUEL_DEFAULT_CONNECTION_POOL']
|
68
|
+
pc = "sharded_#{pc}" if opts[:servers] && !pc.start_with?('sharded_')
|
69
|
+
connection_pool_class(:pool_class=>pc)
|
62
70
|
else
|
63
71
|
pc = if opts[:single_threaded]
|
64
72
|
opts[:servers] ? :sharded_single : :single
|
73
|
+
# :nocov:
|
74
|
+
elsif RUBY_VERSION >= '3.4' # SEQUEL6 or maybe earlier switch to 3.2
|
75
|
+
opts[:servers] ? :sharded_timed_queue : :timed_queue
|
76
|
+
# :nocov:
|
65
77
|
else
|
66
78
|
opts[:servers] ? :sharded_threaded : :threaded
|
67
79
|
end
|
@@ -74,26 +86,35 @@ class Sequel::ConnectionPool
|
|
74
86
|
|
75
87
|
# The after_connect proc used for this pool. This is called with each new
|
76
88
|
# connection made, and is usually used to set custom per-connection settings.
|
77
|
-
|
89
|
+
# Deprecated.
|
90
|
+
attr_reader :after_connect # SEQUEL6: Remove
|
91
|
+
|
92
|
+
# Override the after_connect proc for the connection pool. Deprecated.
|
93
|
+
# Disables support for shard-specific :after_connect and :connect_sqls if used.
|
94
|
+
def after_connect=(v) # SEQUEL6: Remove
|
95
|
+
@use_old_connect_api = true
|
96
|
+
@after_connect = v
|
97
|
+
end
|
78
98
|
|
79
|
-
# An array of sql strings to execute on each new connection.
|
80
|
-
|
99
|
+
# An array of sql strings to execute on each new connection. Deprecated.
|
100
|
+
attr_reader :connect_sqls # SEQUEL6: Remove
|
101
|
+
|
102
|
+
# Override the connect_sqls for the connection pool. Deprecated.
|
103
|
+
# Disables support for shard-specific :after_connect and :connect_sqls if used.
|
104
|
+
def connect_sqls=(v) # SEQUEL6: Remove
|
105
|
+
@use_old_connect_api = true
|
106
|
+
@connect_sqls = v
|
107
|
+
end
|
81
108
|
|
82
109
|
# The Sequel::Database object tied to this connection pool.
|
83
110
|
attr_accessor :db
|
84
111
|
|
85
|
-
# Instantiates a connection pool with the given options.
|
86
|
-
|
87
|
-
# connection is needed. The following options are respected for all connection
|
88
|
-
# pools:
|
89
|
-
# :after_connect :: A callable object called after each new connection is made, with the
|
90
|
-
# connection object (and server argument if the callable accepts 2 arguments),
|
91
|
-
# useful for customizations that you want to apply to all connections.
|
92
|
-
# :connect_sqls :: An array of sql strings to execute on each new connection, after :after_connect runs.
|
93
|
-
def initialize(db, opts=OPTS)
|
112
|
+
# Instantiates a connection pool with the given Database and options.
|
113
|
+
def initialize(db, opts=OPTS) # SEQUEL6: Remove second argument, always use db.opts
|
94
114
|
@db = db
|
95
|
-
@
|
96
|
-
@
|
115
|
+
@use_old_connect_api = false # SEQUEL6: Remove
|
116
|
+
@after_connect = opts[:after_connect] # SEQUEL6: Remove
|
117
|
+
@connect_sqls = opts[:connect_sqls] # SEQUEL6: Remove
|
97
118
|
@error_classes = db.send(:database_error_classes).dup.freeze
|
98
119
|
end
|
99
120
|
|
@@ -119,25 +140,30 @@ class Sequel::ConnectionPool
|
|
119
140
|
# and checking for connection errors.
|
120
141
|
def make_new(server)
|
121
142
|
begin
|
122
|
-
|
143
|
+
if @use_old_connect_api
|
144
|
+
# SEQUEL6: Remove block
|
145
|
+
conn = @db.connect(server)
|
123
146
|
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
147
|
+
if ac = @after_connect
|
148
|
+
if ac.arity == 2
|
149
|
+
ac.call(conn, server)
|
150
|
+
else
|
151
|
+
ac.call(conn)
|
152
|
+
end
|
129
153
|
end
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
154
|
+
|
155
|
+
if cs = @connect_sqls
|
156
|
+
cs.each do |sql|
|
157
|
+
db.send(:log_connection_execute, conn, sql)
|
158
|
+
end
|
135
159
|
end
|
160
|
+
|
161
|
+
conn
|
162
|
+
else
|
163
|
+
@db.new_connection(server)
|
136
164
|
end
|
137
165
|
rescue Exception=>exception
|
138
166
|
raise Sequel.convert_exception_class(exception, Sequel::DatabaseConnectionError)
|
139
|
-
end
|
140
|
-
raise(Sequel::DatabaseConnectionError, "Connection parameters not valid") unless conn
|
141
|
-
conn
|
167
|
+
end || raise(Sequel::DatabaseConnectionError, "Connection parameters not valid")
|
142
168
|
end
|
143
169
|
end
|
@@ -8,7 +8,7 @@ module Sequel
|
|
8
8
|
# ---------------------
|
9
9
|
|
10
10
|
# Array of supported database adapters
|
11
|
-
ADAPTERS = %w'ado amalgalite ibmdb jdbc mock mysql mysql2 odbc oracle postgres sqlanywhere sqlite tinytds'.map(&:to_sym)
|
11
|
+
ADAPTERS = %w'ado amalgalite ibmdb jdbc mock mysql mysql2 odbc oracle postgres sqlanywhere sqlite tinytds trilogy'.map(&:to_sym)
|
12
12
|
|
13
13
|
# The Database subclass for the given adapter scheme.
|
14
14
|
# Raises Sequel::AdapterNotFound if the adapter
|
@@ -241,6 +241,30 @@ module Sequel
|
|
241
241
|
pool.servers
|
242
242
|
end
|
243
243
|
|
244
|
+
# Connect to the given server/shard. Handles database-generic post-connection
|
245
|
+
# setup not handled by #connect, using the :after_connect and :connect_sqls
|
246
|
+
# options.
|
247
|
+
def new_connection(server)
|
248
|
+
conn = connect(server)
|
249
|
+
opts = server_opts(server)
|
250
|
+
|
251
|
+
if ac = opts[:after_connect]
|
252
|
+
if ac.arity == 2
|
253
|
+
ac.call(conn, server)
|
254
|
+
else
|
255
|
+
ac.call(conn)
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
if cs = opts[:connect_sqls]
|
260
|
+
cs.each do |sql|
|
261
|
+
log_connection_execute(conn, sql)
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
conn
|
266
|
+
end
|
267
|
+
|
244
268
|
# Returns true if the database is using a single-threaded connection pool.
|
245
269
|
def single_threaded?
|
246
270
|
@single_threaded
|
@@ -30,19 +30,29 @@ module Sequel
|
|
30
30
|
@dataset_class.new(self)
|
31
31
|
end
|
32
32
|
|
33
|
-
#
|
34
|
-
# it is used to iterate over the records:
|
33
|
+
# Returns a dataset instance for the given SQL string:
|
35
34
|
#
|
36
|
-
# DB.fetch('SELECT * FROM items')
|
35
|
+
# ds = DB.fetch('SELECT * FROM items')
|
36
|
+
#
|
37
|
+
# You can then call methods on the dataset to retrieve results:
|
37
38
|
#
|
38
|
-
#
|
39
|
+
# ds.all
|
40
|
+
# # SELECT * FROM items
|
41
|
+
# # => [{:column=>value, ...}, ...]
|
39
42
|
#
|
40
|
-
#
|
43
|
+
# If a block is given, it is passed to #each on the resulting dataset to
|
44
|
+
# iterate over the records returned by the query:
|
45
|
+
#
|
46
|
+
# DB.fetch('SELECT * FROM items'){|r| p r}
|
47
|
+
# # {:column=>value, ...}
|
48
|
+
# # ...
|
41
49
|
#
|
42
50
|
# +fetch+ can also perform parameterized queries for protection against SQL
|
43
51
|
# injection:
|
44
52
|
#
|
45
|
-
# DB.fetch('SELECT * FROM items WHERE name = ?',
|
53
|
+
# ds = DB.fetch('SELECT * FROM items WHERE name = ?', "my name")
|
54
|
+
# ds.all
|
55
|
+
# # SELECT * FROM items WHERE name = 'my name'
|
46
56
|
#
|
47
57
|
# See caveats listed in Dataset#with_sql regarding datasets using custom
|
48
58
|
# SQL and the methods that can be called on them.
|
data/lib/sequel/database/misc.rb
CHANGED
@@ -91,13 +91,23 @@ module Sequel
|
|
91
91
|
# The specific default size of string columns for this Sequel::Database, usually 255 by default.
|
92
92
|
attr_accessor :default_string_column_size
|
93
93
|
|
94
|
+
# Whether to check the bytesize of strings before typecasting (to avoid typecasting strings that
|
95
|
+
# would be too long for the given type), true by default. Strings that are too long will raise
|
96
|
+
# a typecasting error.
|
97
|
+
attr_accessor :check_string_typecast_bytesize
|
98
|
+
|
94
99
|
# Constructs a new instance of a database connection with the specified
|
95
100
|
# options hash.
|
96
101
|
#
|
97
102
|
# Accepts the following options:
|
103
|
+
# :after_connect :: A callable object called after each new connection is made, with the
|
104
|
+
# connection object (and server argument if the callable accepts 2 arguments),
|
105
|
+
# useful for customizations that you want to apply to all connections.
|
98
106
|
# :before_preconnect :: Callable that runs after extensions from :preconnect_extensions are loaded,
|
99
107
|
# but before any connections are created.
|
100
108
|
# :cache_schema :: Whether schema should be cached for this Database instance
|
109
|
+
# :check_string_typecast_bytesize :: Whether to check the bytesize of strings before typecasting.
|
110
|
+
# :connect_sqls :: An array of sql strings to execute on each new connection, after :after_connect runs.
|
101
111
|
# :default_string_column_size :: The default size of string columns, 255 by default.
|
102
112
|
# :extensions :: Extensions to load into this Database instance. Can be a symbol, array of symbols,
|
103
113
|
# or string with extensions separated by columns. These extensions are loaded after
|
@@ -107,7 +117,7 @@ module Sequel
|
|
107
117
|
# :loggers :: An array of loggers to use.
|
108
118
|
# :log_connection_info :: Whether connection information should be logged when logging queries.
|
109
119
|
# :log_warn_duration :: The number of elapsed seconds after which queries should be logged at warn level.
|
110
|
-
# :name :: A name to use for the Database object, displayed in PoolTimeout
|
120
|
+
# :name :: A name to use for the Database object, displayed in PoolTimeout.
|
111
121
|
# :preconnect :: Automatically create the maximum number of connections, so that they don't
|
112
122
|
# need to be created as needed. This is useful when connecting takes a long time
|
113
123
|
# and you want to avoid possible latency during runtime.
|
@@ -116,13 +126,15 @@ module Sequel
|
|
116
126
|
# :preconnect_extensions :: Similar to the :extensions option, but loads the extensions before the
|
117
127
|
# connections are made by the :preconnect option.
|
118
128
|
# :quote_identifiers :: Whether to quote identifiers.
|
119
|
-
# :servers :: A hash specifying a server/shard specific options, keyed by shard symbol
|
129
|
+
# :servers :: A hash specifying a server/shard specific options, keyed by shard symbol.
|
120
130
|
# :single_threaded :: Whether to use a single-threaded connection pool.
|
121
131
|
# :sql_log_level :: Method to use to log SQL to a logger, :info by default.
|
122
132
|
#
|
133
|
+
# For sharded connection pools, :after_connect and :connect_sqls can be specified per-shard.
|
134
|
+
#
|
123
135
|
# All options given are also passed to the connection pool. Additional options respected by
|
124
|
-
# the connection pool are :
|
125
|
-
#
|
136
|
+
# the connection pool are :max_connections, :pool_timeout, :servers, and :servers_hash. See the
|
137
|
+
# connection pool documentation for details.
|
126
138
|
def initialize(opts = OPTS)
|
127
139
|
@opts ||= opts
|
128
140
|
@opts = connection_pool_default_options.merge(@opts)
|
@@ -132,10 +144,12 @@ module Sequel
|
|
132
144
|
@opts[:adapter_class] = self.class
|
133
145
|
@opts[:single_threaded] = @single_threaded = typecast_value_boolean(@opts.fetch(:single_threaded, Sequel.single_threaded))
|
134
146
|
@default_string_column_size = @opts[:default_string_column_size] || DEFAULT_STRING_COLUMN_SIZE
|
147
|
+
@check_string_typecast_bytesize = typecast_value_boolean(@opts.fetch(:check_string_typecast_bytesize, true))
|
135
148
|
|
136
149
|
@schemas = {}
|
137
150
|
@prepared_statements = {}
|
138
151
|
@transactions = {}
|
152
|
+
@transactions.compare_by_identity
|
139
153
|
@symbol_literal_cache = {}
|
140
154
|
|
141
155
|
@timezone = nil
|
@@ -250,8 +264,8 @@ module Sequel
|
|
250
264
|
# Proxy the literal call to the dataset.
|
251
265
|
#
|
252
266
|
# DB.literal(1) # 1
|
253
|
-
# DB.literal(:a) # a
|
254
|
-
# DB.literal(
|
267
|
+
# DB.literal(:a) # "a" # or `a`, [a], or a, depending on identifier quoting
|
268
|
+
# DB.literal("a") # 'a'
|
255
269
|
def literal(v)
|
256
270
|
schema_utility_dataset.literal(v)
|
257
271
|
end
|
@@ -465,6 +479,21 @@ module Sequel
|
|
465
479
|
# Don't rescue other exceptions, they will be raised normally.
|
466
480
|
end
|
467
481
|
|
482
|
+
# Check the bytesize of a string before conversion. There is no point
|
483
|
+
# trying to typecast strings that would be way too long.
|
484
|
+
def typecast_check_string_length(string, max_size)
|
485
|
+
if @check_string_typecast_bytesize && string.bytesize > max_size
|
486
|
+
raise InvalidValue, "string too long to typecast (bytesize: #{string.bytesize}, max: #{max_size})"
|
487
|
+
end
|
488
|
+
string
|
489
|
+
end
|
490
|
+
|
491
|
+
# Check the bytesize of the string value, if value is a string.
|
492
|
+
def typecast_check_length(value, max_size)
|
493
|
+
typecast_check_string_length(value, max_size) if String === value
|
494
|
+
value
|
495
|
+
end
|
496
|
+
|
468
497
|
# Typecast the value to an SQL::Blob
|
469
498
|
def typecast_value_blob(value)
|
470
499
|
value.is_a?(Sequel::SQL::Blob) ? value : Sequel::SQL::Blob.new(value)
|
@@ -488,9 +517,9 @@ module Sequel
|
|
488
517
|
when Date
|
489
518
|
value
|
490
519
|
when String
|
491
|
-
Sequel.string_to_date(value)
|
520
|
+
Sequel.string_to_date(typecast_check_string_length(value, 100))
|
492
521
|
when Hash
|
493
|
-
Date.new(*[:year, :month, :day].map{|x| (value[x] || value[x.to_s]).to_i})
|
522
|
+
Date.new(*[:year, :month, :day].map{|x| typecast_check_length(value[x] || value[x.to_s], 100).to_i})
|
494
523
|
else
|
495
524
|
raise InvalidValue, "invalid value for Date: #{value.inspect}"
|
496
525
|
end
|
@@ -498,7 +527,17 @@ module Sequel
|
|
498
527
|
|
499
528
|
# Typecast the value to a DateTime or Time depending on Sequel.datetime_class
|
500
529
|
def typecast_value_datetime(value)
|
501
|
-
|
530
|
+
case value
|
531
|
+
when String
|
532
|
+
Sequel.typecast_to_application_timestamp(typecast_check_string_length(value, 100))
|
533
|
+
when Hash
|
534
|
+
[:year, :month, :day, :hour, :minute, :second, :nanos, :offset].each do |x|
|
535
|
+
typecast_check_length(value[x] || value[x.to_s], 100)
|
536
|
+
end
|
537
|
+
Sequel.typecast_to_application_timestamp(value)
|
538
|
+
else
|
539
|
+
Sequel.typecast_to_application_timestamp(value)
|
540
|
+
end
|
502
541
|
end
|
503
542
|
|
504
543
|
if RUBY_VERSION >= '2.4'
|
@@ -531,18 +570,30 @@ module Sequel
|
|
531
570
|
when Numeric
|
532
571
|
BigDecimal(value.to_s)
|
533
572
|
when String
|
534
|
-
_typecast_value_string_to_decimal(value)
|
573
|
+
_typecast_value_string_to_decimal(typecast_check_string_length(value, 1000))
|
535
574
|
else
|
536
575
|
raise InvalidValue, "invalid value for BigDecimal: #{value.inspect}"
|
537
576
|
end
|
538
577
|
end
|
539
578
|
|
540
579
|
# Typecast the value to a Float
|
541
|
-
|
580
|
+
def typecast_value_float(value)
|
581
|
+
Float(typecast_check_length(value, 1000))
|
582
|
+
end
|
542
583
|
|
543
584
|
# Typecast the value to an Integer
|
544
585
|
def typecast_value_integer(value)
|
545
|
-
|
586
|
+
case value
|
587
|
+
when String
|
588
|
+
typecast_check_string_length(value, 100)
|
589
|
+
if value =~ /\A-?0+(\d)/
|
590
|
+
Integer(value, 10)
|
591
|
+
else
|
592
|
+
Integer(value)
|
593
|
+
end
|
594
|
+
else
|
595
|
+
Integer(value)
|
596
|
+
end
|
546
597
|
end
|
547
598
|
|
548
599
|
# Typecast the value to a String
|
@@ -565,9 +616,9 @@ module Sequel
|
|
565
616
|
SQLTime.create(value.hour, value.min, value.sec, value.nsec/1000.0)
|
566
617
|
end
|
567
618
|
when String
|
568
|
-
Sequel.string_to_time(value)
|
619
|
+
Sequel.string_to_time(typecast_check_string_length(value, 100))
|
569
620
|
when Hash
|
570
|
-
SQLTime.create(*[:hour, :minute, :second].map{|x| (value[x] || value[x.to_s]).to_i})
|
621
|
+
SQLTime.create(*[:hour, :minute, :second].map{|x| typecast_check_length(value[x] || value[x.to_s], 100).to_i})
|
571
622
|
else
|
572
623
|
raise Sequel::InvalidValue, "invalid value for Time: #{value.inspect}"
|
573
624
|
end
|
@@ -175,6 +175,15 @@ module Sequel
|
|
175
175
|
if !c[:max_length] && c[:type] == :string && (max_length = column_schema_max_length(c[:db_type]))
|
176
176
|
c[:max_length] = max_length
|
177
177
|
end
|
178
|
+
if !c[:max_value] && !c[:min_value]
|
179
|
+
min_max = case c[:type]
|
180
|
+
when :integer
|
181
|
+
column_schema_integer_min_max_values(c)
|
182
|
+
when :decimal
|
183
|
+
column_schema_decimal_min_max_values(c)
|
184
|
+
end
|
185
|
+
c[:min_value], c[:max_value] = min_max if min_max
|
186
|
+
end
|
178
187
|
end
|
179
188
|
schema_post_process(cols)
|
180
189
|
|
@@ -272,6 +281,68 @@ module Sequel
|
|
272
281
|
column_schema_default_to_ruby_value(default, type) rescue nil
|
273
282
|
end
|
274
283
|
|
284
|
+
INTEGER1_MIN_MAX = [-128, 127].freeze
|
285
|
+
INTEGER2_MIN_MAX = [-32768, 32767].freeze
|
286
|
+
INTEGER3_MIN_MAX = [-8388608, 8388607].freeze
|
287
|
+
INTEGER4_MIN_MAX = [-2147483648, 2147483647].freeze
|
288
|
+
INTEGER8_MIN_MAX = [-9223372036854775808, 9223372036854775807].freeze
|
289
|
+
UNSIGNED_INTEGER1_MIN_MAX = [0, 255].freeze
|
290
|
+
UNSIGNED_INTEGER2_MIN_MAX = [0, 65535].freeze
|
291
|
+
UNSIGNED_INTEGER3_MIN_MAX = [0, 16777215].freeze
|
292
|
+
UNSIGNED_INTEGER4_MIN_MAX = [0, 4294967295].freeze
|
293
|
+
UNSIGNED_INTEGER8_MIN_MAX = [0, 18446744073709551615].freeze
|
294
|
+
|
295
|
+
# Look at the db_type and guess the minimum and maximum integer values for
|
296
|
+
# the column.
|
297
|
+
def column_schema_integer_min_max_values(column)
|
298
|
+
db_type = column[:db_type]
|
299
|
+
if /decimal|numeric|number/i =~ db_type
|
300
|
+
if min_max = column_schema_decimal_min_max_values(column)
|
301
|
+
min_max.map!(&:to_i)
|
302
|
+
end
|
303
|
+
return min_max
|
304
|
+
end
|
305
|
+
|
306
|
+
unsigned = /unsigned/i =~ db_type
|
307
|
+
case db_type
|
308
|
+
when /big|int8/i
|
309
|
+
unsigned ? UNSIGNED_INTEGER8_MIN_MAX : INTEGER8_MIN_MAX
|
310
|
+
when /medium/i
|
311
|
+
unsigned ? UNSIGNED_INTEGER3_MIN_MAX : INTEGER3_MIN_MAX
|
312
|
+
when /small|int2/i
|
313
|
+
unsigned ? UNSIGNED_INTEGER2_MIN_MAX : INTEGER2_MIN_MAX
|
314
|
+
when /tiny/i
|
315
|
+
(unsigned || column_schema_tinyint_type_is_unsigned?) ? UNSIGNED_INTEGER1_MIN_MAX : INTEGER1_MIN_MAX
|
316
|
+
else
|
317
|
+
unsigned ? UNSIGNED_INTEGER4_MIN_MAX : INTEGER4_MIN_MAX
|
318
|
+
end
|
319
|
+
end
|
320
|
+
|
321
|
+
# Look at the db_type and guess the minimum and maximum decimal values for
|
322
|
+
# the column.
|
323
|
+
def column_schema_decimal_min_max_values(column)
|
324
|
+
if column[:column_size] && column[:scale]
|
325
|
+
precision = column[:column_size]
|
326
|
+
scale = column[:scale]
|
327
|
+
elsif /\((\d+)(?:,\s*(-?\d+))?\)/ =~ column[:db_type]
|
328
|
+
precision = $1.to_i
|
329
|
+
scale = $2.to_i if $2
|
330
|
+
end
|
331
|
+
|
332
|
+
if precision
|
333
|
+
limit = BigDecimal("9" * precision)
|
334
|
+
if scale
|
335
|
+
limit /= 10**(scale)
|
336
|
+
end
|
337
|
+
[-limit, limit]
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
# Whether the tinyint type (if supported by the database) is unsigned by default.
|
342
|
+
def column_schema_tinyint_type_is_unsigned?
|
343
|
+
false
|
344
|
+
end
|
345
|
+
|
275
346
|
# Look at the db_type and guess the maximum length of the column.
|
276
347
|
# This assumes types such as varchar(255).
|
277
348
|
def column_schema_max_length(db_type)
|
@@ -333,7 +404,7 @@ module Sequel
|
|
333
404
|
:boolean
|
334
405
|
when /\A(real|float( unsigned)?|double( precision)?|double\(\d+,\d+\)( unsigned)?)\z/io
|
335
406
|
:float
|
336
|
-
when /\A(?:(?:(?:num(?:ber|eric)?|decimal)(?:\(\d+,\s*(
|
407
|
+
when /\A(?:(?:(?:num(?:ber|eric)?|decimal)(?:\(\d+,\s*(-?\d+|false|true)\))?))\z/io
|
337
408
|
$1 && ['0', 'false'].include?($1) ? :integer : :decimal
|
338
409
|
when /bytea|blob|image|(var)?binary/io
|
339
410
|
:blob
|
@@ -262,6 +262,7 @@ module Sequel
|
|
262
262
|
# operations on the table while the index is being
|
263
263
|
# built.
|
264
264
|
# :if_not_exists :: Only create the index if an index of the same name doesn't already exist.
|
265
|
+
# :nulls_distinct :: Set whether separate NULLs should be considered distinct values in unique indexes.
|
265
266
|
# :opclass :: Set an opclass to use for all columns (per-column opclasses require
|
266
267
|
# custom SQL).
|
267
268
|
# :tablespace :: Specify tablespace for index.
|
@@ -306,7 +307,7 @@ module Sequel
|
|
306
307
|
# Examples:
|
307
308
|
# primary_key(:id)
|
308
309
|
# primary_key(:id, type: :Bignum, keep_order: true)
|
309
|
-
# primary_key([:street_number, :house_number], name: :
|
310
|
+
# primary_key([:street_number, :house_number], name: :some_constraint_name)
|
310
311
|
def primary_key(name, *args)
|
311
312
|
return composite_primary_key(name, *args) if name.is_a?(Array)
|
312
313
|
column = @db.serial_primary_key_options.merge({:name => name})
|
@@ -191,6 +191,12 @@ module Sequel
|
|
191
191
|
# The +any+ type is treated like a SQLite column in a non-strict table,
|
192
192
|
# allowing any type of data to be stored. This option is supported on
|
193
193
|
# SQLite 3.37.0+.
|
194
|
+
# :without_rowid :: Create a WITHOUT ROWID table. Every row in SQLite has a special
|
195
|
+
# 'rowid' column, that uniquely identifies that row within the table.
|
196
|
+
# If this option is used, the 'rowid' column is omitted, which can
|
197
|
+
# sometimes provide some space and speed advantages. Note that you
|
198
|
+
# must then provide an explicit primary key when you create the table.
|
199
|
+
# This option is supported on SQLite 3.8.2+.
|
194
200
|
#
|
195
201
|
# See <tt>Schema::CreateTableGenerator</tt> and the {"Schema Modification" guide}[rdoc-ref:doc/schema_modification.rdoc].
|
196
202
|
def create_table(name, options=OPTS, &block)
|
@@ -295,6 +301,9 @@ module Sequel
|
|
295
301
|
# in a subquery, if you are providing a Dataset as the source
|
296
302
|
# argument, if should probably call the union method with the
|
297
303
|
# all: true and from_self: false options.
|
304
|
+
# :security_invoker :: Set the security_invoker property on the view, making
|
305
|
+
# the access to the view use the current user's permissions,
|
306
|
+
# instead of the view owner's permissions.
|
298
307
|
# :tablespace :: The tablespace to use for materialized views.
|
299
308
|
def create_view(name, source, options = OPTS)
|
300
309
|
execute_ddl(create_view_sql(name, source, options))
|
@@ -709,8 +718,9 @@ module Sequel
|
|
709
718
|
e = options[:ignore_index_errors] || options[:if_not_exists]
|
710
719
|
generator.indexes.each do |index|
|
711
720
|
begin
|
712
|
-
|
713
|
-
|
721
|
+
transaction(:savepoint=>:only, :skip_transaction=>supports_transactional_ddl? == false) do
|
722
|
+
index_sql_list(name, [index]).each{|sql| execute_ddl(sql)}
|
723
|
+
end
|
714
724
|
rescue Error
|
715
725
|
raise unless e
|
716
726
|
end
|
@@ -897,7 +907,7 @@ module Sequel
|
|
897
907
|
#
|
898
908
|
# Any other object given is just converted to a string, with "_" converted to " " and upcased.
|
899
909
|
def on_delete_clause(action)
|
900
|
-
action.to_s.
|
910
|
+
action.to_s.tr("_", " ").upcase
|
901
911
|
end
|
902
912
|
|
903
913
|
# Alias of #on_delete_clause, since the two usually behave the same.
|
@@ -166,6 +166,8 @@ module Sequel
|
|
166
166
|
# uses :auto_savepoint, you can set this to false to not use a savepoint.
|
167
167
|
# If the value given for this option is :only, it will only create a
|
168
168
|
# savepoint if it is inside a transaction.
|
169
|
+
# :skip_transaction :: If set, do not actually open a transaction or savepoint,
|
170
|
+
# just checkout a connection and yield it.
|
169
171
|
#
|
170
172
|
# PostgreSQL specific options:
|
171
173
|
#
|
@@ -193,6 +195,10 @@ module Sequel
|
|
193
195
|
end
|
194
196
|
else
|
195
197
|
synchronize(opts[:server]) do |conn|
|
198
|
+
if opts[:skip_transaction]
|
199
|
+
return yield(conn)
|
200
|
+
end
|
201
|
+
|
196
202
|
if opts[:savepoint] == :only
|
197
203
|
if supports_savepoints?
|
198
204
|
if _trans(conn)
|