sequel 5.58.0 → 5.78.0
Sign up to get free protection for your applications and to get access to all the features.
- 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)
|