sequel 5.45.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 +434 -0
- data/MIT-LICENSE +1 -1
- data/README.rdoc +59 -27
- data/bin/sequel +11 -3
- data/doc/advanced_associations.rdoc +16 -14
- data/doc/association_basics.rdoc +119 -24
- data/doc/cheat_sheet.rdoc +11 -3
- data/doc/mass_assignment.rdoc +1 -1
- data/doc/migration.rdoc +27 -6
- data/doc/model_hooks.rdoc +1 -1
- data/doc/object_model.rdoc +8 -8
- data/doc/opening_databases.rdoc +28 -12
- data/doc/postgresql.rdoc +16 -8
- data/doc/querying.rdoc +5 -3
- data/doc/release_notes/5.46.0.txt +87 -0
- data/doc/release_notes/5.47.0.txt +59 -0
- data/doc/release_notes/5.48.0.txt +14 -0
- data/doc/release_notes/5.49.0.txt +59 -0
- data/doc/release_notes/5.50.0.txt +78 -0
- data/doc/release_notes/5.51.0.txt +47 -0
- data/doc/release_notes/5.52.0.txt +87 -0
- data/doc/release_notes/5.53.0.txt +23 -0
- data/doc/release_notes/5.54.0.txt +27 -0
- data/doc/release_notes/5.55.0.txt +21 -0
- data/doc/release_notes/5.56.0.txt +51 -0
- data/doc/release_notes/5.57.0.txt +23 -0
- data/doc/release_notes/5.58.0.txt +31 -0
- data/doc/release_notes/5.59.0.txt +73 -0
- data/doc/release_notes/5.60.0.txt +22 -0
- data/doc/release_notes/5.61.0.txt +43 -0
- data/doc/release_notes/5.62.0.txt +132 -0
- data/doc/release_notes/5.63.0.txt +33 -0
- data/doc/release_notes/5.64.0.txt +50 -0
- data/doc/release_notes/5.65.0.txt +21 -0
- data/doc/release_notes/5.66.0.txt +24 -0
- data/doc/release_notes/5.67.0.txt +32 -0
- data/doc/release_notes/5.68.0.txt +61 -0
- data/doc/release_notes/5.69.0.txt +26 -0
- data/doc/release_notes/5.70.0.txt +35 -0
- data/doc/release_notes/5.71.0.txt +21 -0
- data/doc/release_notes/5.72.0.txt +33 -0
- data/doc/release_notes/5.73.0.txt +66 -0
- data/doc/release_notes/5.74.0.txt +45 -0
- data/doc/release_notes/5.75.0.txt +35 -0
- data/doc/release_notes/5.76.0.txt +86 -0
- data/doc/release_notes/5.77.0.txt +63 -0
- data/doc/schema_modification.rdoc +1 -1
- data/doc/security.rdoc +9 -9
- data/doc/sharding.rdoc +3 -1
- data/doc/sql.rdoc +27 -15
- data/doc/testing.rdoc +23 -13
- data/doc/transactions.rdoc +6 -6
- data/doc/virtual_rows.rdoc +1 -1
- data/lib/sequel/adapters/ado/access.rb +1 -1
- data/lib/sequel/adapters/ado.rb +1 -1
- data/lib/sequel/adapters/amalgalite.rb +3 -5
- data/lib/sequel/adapters/ibmdb.rb +3 -3
- data/lib/sequel/adapters/jdbc/derby.rb +8 -0
- data/lib/sequel/adapters/jdbc/h2.rb +63 -10
- data/lib/sequel/adapters/jdbc/hsqldb.rb +8 -0
- data/lib/sequel/adapters/jdbc/postgresql.rb +7 -4
- data/lib/sequel/adapters/jdbc/sqlanywhere.rb +15 -0
- data/lib/sequel/adapters/jdbc/sqlserver.rb +4 -0
- data/lib/sequel/adapters/jdbc.rb +24 -22
- data/lib/sequel/adapters/mysql.rb +92 -67
- data/lib/sequel/adapters/mysql2.rb +56 -51
- data/lib/sequel/adapters/odbc/mssql.rb +1 -1
- data/lib/sequel/adapters/odbc.rb +1 -1
- data/lib/sequel/adapters/oracle.rb +4 -3
- data/lib/sequel/adapters/postgres.rb +89 -45
- data/lib/sequel/adapters/shared/access.rb +11 -1
- data/lib/sequel/adapters/shared/db2.rb +42 -0
- data/lib/sequel/adapters/shared/mssql.rb +91 -10
- data/lib/sequel/adapters/shared/mysql.rb +78 -3
- data/lib/sequel/adapters/shared/oracle.rb +86 -7
- data/lib/sequel/adapters/shared/postgres.rb +576 -171
- data/lib/sequel/adapters/shared/sqlanywhere.rb +21 -5
- data/lib/sequel/adapters/shared/sqlite.rb +92 -8
- data/lib/sequel/adapters/sqlanywhere.rb +1 -1
- data/lib/sequel/adapters/sqlite.rb +99 -18
- data/lib/sequel/adapters/tinytds.rb +1 -1
- data/lib/sequel/adapters/trilogy.rb +117 -0
- data/lib/sequel/adapters/utils/columns_limit_1.rb +22 -0
- data/lib/sequel/adapters/utils/mysql_mysql2.rb +1 -1
- data/lib/sequel/ast_transformer.rb +6 -0
- data/lib/sequel/connection_pool/sharded_single.rb +5 -7
- data/lib/sequel/connection_pool/sharded_threaded.rb +16 -11
- data/lib/sequel/connection_pool/sharded_timed_queue.rb +374 -0
- data/lib/sequel/connection_pool/single.rb +6 -8
- data/lib/sequel/connection_pool/threaded.rb +14 -8
- data/lib/sequel/connection_pool/timed_queue.rb +270 -0
- data/lib/sequel/connection_pool.rb +57 -31
- data/lib/sequel/core.rb +17 -18
- data/lib/sequel/database/connecting.rb +27 -3
- data/lib/sequel/database/dataset.rb +16 -6
- data/lib/sequel/database/misc.rb +70 -14
- data/lib/sequel/database/query.rb +73 -2
- data/lib/sequel/database/schema_generator.rb +11 -6
- data/lib/sequel/database/schema_methods.rb +23 -4
- data/lib/sequel/database/transactions.rb +6 -0
- data/lib/sequel/dataset/actions.rb +111 -15
- data/lib/sequel/dataset/deprecated_singleton_class_methods.rb +42 -0
- data/lib/sequel/dataset/features.rb +20 -1
- data/lib/sequel/dataset/misc.rb +12 -2
- data/lib/sequel/dataset/placeholder_literalizer.rb +20 -9
- data/lib/sequel/dataset/query.rb +170 -41
- data/lib/sequel/dataset/sql.rb +190 -71
- data/lib/sequel/dataset.rb +4 -0
- data/lib/sequel/extensions/_model_pg_row.rb +0 -12
- data/lib/sequel/extensions/_pretty_table.rb +1 -1
- data/lib/sequel/extensions/any_not_empty.rb +2 -2
- data/lib/sequel/extensions/async_thread_pool.rb +14 -13
- data/lib/sequel/extensions/auto_cast_date_and_time.rb +94 -0
- data/lib/sequel/extensions/auto_literal_strings.rb +1 -1
- data/lib/sequel/extensions/connection_expiration.rb +15 -9
- data/lib/sequel/extensions/connection_validator.rb +16 -11
- data/lib/sequel/extensions/constraint_validations.rb +1 -1
- data/lib/sequel/extensions/core_refinements.rb +36 -11
- data/lib/sequel/extensions/date_arithmetic.rb +36 -8
- data/lib/sequel/extensions/date_parse_input_handler.rb +67 -0
- data/lib/sequel/extensions/datetime_parse_to_time.rb +5 -1
- data/lib/sequel/extensions/duplicate_columns_handler.rb +11 -10
- data/lib/sequel/extensions/index_caching.rb +5 -1
- data/lib/sequel/extensions/inflector.rb +1 -1
- data/lib/sequel/extensions/is_distinct_from.rb +141 -0
- data/lib/sequel/extensions/looser_typecasting.rb +3 -0
- data/lib/sequel/extensions/migration.rb +57 -15
- data/lib/sequel/extensions/named_timezones.rb +22 -6
- data/lib/sequel/extensions/pagination.rb +1 -1
- data/lib/sequel/extensions/pg_array.rb +33 -4
- data/lib/sequel/extensions/pg_array_ops.rb +2 -2
- data/lib/sequel/extensions/pg_auto_parameterize.rb +509 -0
- data/lib/sequel/extensions/pg_auto_parameterize_in_array.rb +110 -0
- data/lib/sequel/extensions/pg_enum.rb +1 -2
- data/lib/sequel/extensions/pg_extended_date_support.rb +39 -28
- data/lib/sequel/extensions/pg_extended_integer_support.rb +116 -0
- data/lib/sequel/extensions/pg_hstore.rb +6 -1
- data/lib/sequel/extensions/pg_hstore_ops.rb +53 -3
- data/lib/sequel/extensions/pg_inet.rb +10 -11
- data/lib/sequel/extensions/pg_inet_ops.rb +1 -1
- data/lib/sequel/extensions/pg_interval.rb +11 -11
- data/lib/sequel/extensions/pg_json.rb +13 -15
- data/lib/sequel/extensions/pg_json_ops.rb +125 -2
- data/lib/sequel/extensions/pg_multirange.rb +367 -0
- data/lib/sequel/extensions/pg_range.rb +13 -26
- data/lib/sequel/extensions/pg_range_ops.rb +37 -9
- data/lib/sequel/extensions/pg_row.rb +20 -19
- data/lib/sequel/extensions/pg_row_ops.rb +1 -1
- data/lib/sequel/extensions/pg_timestamptz.rb +27 -3
- data/lib/sequel/extensions/round_timestamps.rb +1 -1
- data/lib/sequel/extensions/s.rb +2 -1
- data/lib/sequel/extensions/schema_caching.rb +1 -1
- data/lib/sequel/extensions/schema_dumper.rb +45 -11
- data/lib/sequel/extensions/server_block.rb +10 -13
- data/lib/sequel/extensions/set_literalizer.rb +58 -0
- data/lib/sequel/extensions/sql_comments.rb +110 -3
- data/lib/sequel/extensions/sql_log_normalizer.rb +108 -0
- data/lib/sequel/extensions/sqlite_json_ops.rb +255 -0
- data/lib/sequel/extensions/string_agg.rb +1 -1
- data/lib/sequel/extensions/string_date_time.rb +19 -23
- data/lib/sequel/extensions/symbol_aref.rb +2 -0
- data/lib/sequel/extensions/transaction_connection_validator.rb +78 -0
- data/lib/sequel/model/associations.rb +286 -92
- data/lib/sequel/model/base.rb +53 -33
- data/lib/sequel/model/dataset_module.rb +3 -0
- data/lib/sequel/model/errors.rb +10 -1
- data/lib/sequel/model/exceptions.rb +15 -3
- data/lib/sequel/model/inflections.rb +1 -1
- data/lib/sequel/plugins/auto_restrict_eager_graph.rb +62 -0
- data/lib/sequel/plugins/auto_validations.rb +74 -16
- data/lib/sequel/plugins/class_table_inheritance.rb +2 -2
- data/lib/sequel/plugins/column_encryption.rb +29 -8
- data/lib/sequel/plugins/composition.rb +3 -2
- data/lib/sequel/plugins/concurrent_eager_loading.rb +4 -4
- data/lib/sequel/plugins/constraint_validations.rb +8 -5
- data/lib/sequel/plugins/defaults_setter.rb +16 -0
- data/lib/sequel/plugins/dirty.rb +1 -1
- data/lib/sequel/plugins/enum.rb +124 -0
- data/lib/sequel/plugins/finder.rb +4 -2
- data/lib/sequel/plugins/insert_conflict.rb +4 -0
- data/lib/sequel/plugins/instance_specific_default.rb +1 -1
- data/lib/sequel/plugins/json_serializer.rb +2 -2
- data/lib/sequel/plugins/lazy_attributes.rb +3 -0
- data/lib/sequel/plugins/list.rb +8 -3
- data/lib/sequel/plugins/many_through_many.rb +109 -10
- data/lib/sequel/plugins/mssql_optimistic_locking.rb +8 -38
- data/lib/sequel/plugins/nested_attributes.rb +4 -4
- data/lib/sequel/plugins/optimistic_locking.rb +9 -42
- data/lib/sequel/plugins/optimistic_locking_base.rb +55 -0
- data/lib/sequel/plugins/paged_operations.rb +181 -0
- data/lib/sequel/plugins/pg_array_associations.rb +46 -34
- data/lib/sequel/plugins/pg_auto_constraint_validations.rb +9 -3
- data/lib/sequel/plugins/pg_xmin_optimistic_locking.rb +109 -0
- data/lib/sequel/plugins/prepared_statements.rb +12 -2
- data/lib/sequel/plugins/prepared_statements_safe.rb +2 -1
- data/lib/sequel/plugins/primary_key_lookup_check_values.rb +154 -0
- data/lib/sequel/plugins/rcte_tree.rb +7 -4
- data/lib/sequel/plugins/require_valid_schema.rb +67 -0
- data/lib/sequel/plugins/serialization.rb +1 -0
- data/lib/sequel/plugins/serialization_modification_detection.rb +1 -0
- data/lib/sequel/plugins/single_table_inheritance.rb +8 -0
- data/lib/sequel/plugins/sql_comments.rb +189 -0
- data/lib/sequel/plugins/static_cache.rb +39 -1
- data/lib/sequel/plugins/static_cache_cache.rb +5 -1
- data/lib/sequel/plugins/subclasses.rb +28 -11
- data/lib/sequel/plugins/tactical_eager_loading.rb +23 -10
- data/lib/sequel/plugins/timestamps.rb +1 -1
- data/lib/sequel/plugins/unused_associations.rb +521 -0
- data/lib/sequel/plugins/update_or_create.rb +1 -1
- data/lib/sequel/plugins/validate_associated.rb +22 -12
- data/lib/sequel/plugins/validation_helpers.rb +41 -11
- data/lib/sequel/plugins/validation_helpers_generic_type_messages.rb +73 -0
- data/lib/sequel/plugins/xml_serializer.rb +1 -1
- data/lib/sequel/sql.rb +1 -1
- data/lib/sequel/timezones.rb +12 -14
- data/lib/sequel/version.rb +1 -1
- metadata +109 -19
data/lib/sequel/database/misc.rb
CHANGED
@@ -91,11 +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.
|
106
|
+
# :before_preconnect :: Callable that runs after extensions from :preconnect_extensions are loaded,
|
107
|
+
# but before any connections are created.
|
98
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.
|
99
111
|
# :default_string_column_size :: The default size of string columns, 255 by default.
|
100
112
|
# :extensions :: Extensions to load into this Database instance. Can be a symbol, array of symbols,
|
101
113
|
# or string with extensions separated by columns. These extensions are loaded after
|
@@ -105,7 +117,7 @@ module Sequel
|
|
105
117
|
# :loggers :: An array of loggers to use.
|
106
118
|
# :log_connection_info :: Whether connection information should be logged when logging queries.
|
107
119
|
# :log_warn_duration :: The number of elapsed seconds after which queries should be logged at warn level.
|
108
|
-
# :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.
|
109
121
|
# :preconnect :: Automatically create the maximum number of connections, so that they don't
|
110
122
|
# need to be created as needed. This is useful when connecting takes a long time
|
111
123
|
# and you want to avoid possible latency during runtime.
|
@@ -114,13 +126,15 @@ module Sequel
|
|
114
126
|
# :preconnect_extensions :: Similar to the :extensions option, but loads the extensions before the
|
115
127
|
# connections are made by the :preconnect option.
|
116
128
|
# :quote_identifiers :: Whether to quote identifiers.
|
117
|
-
# :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.
|
118
130
|
# :single_threaded :: Whether to use a single-threaded connection pool.
|
119
131
|
# :sql_log_level :: Method to use to log SQL to a logger, :info by default.
|
120
132
|
#
|
133
|
+
# For sharded connection pools, :after_connect and :connect_sqls can be specified per-shard.
|
134
|
+
#
|
121
135
|
# All options given are also passed to the connection pool. Additional options respected by
|
122
|
-
# the connection pool are :
|
123
|
-
#
|
136
|
+
# the connection pool are :max_connections, :pool_timeout, :servers, and :servers_hash. See the
|
137
|
+
# connection pool documentation for details.
|
124
138
|
def initialize(opts = OPTS)
|
125
139
|
@opts ||= opts
|
126
140
|
@opts = connection_pool_default_options.merge(@opts)
|
@@ -130,6 +144,7 @@ module Sequel
|
|
130
144
|
@opts[:adapter_class] = self.class
|
131
145
|
@opts[:single_threaded] = @single_threaded = typecast_value_boolean(@opts.fetch(:single_threaded, Sequel.single_threaded))
|
132
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))
|
133
148
|
|
134
149
|
@schemas = {}
|
135
150
|
@prepared_statements = {}
|
@@ -160,6 +175,10 @@ module Sequel
|
|
160
175
|
|
161
176
|
initialize_load_extensions(:preconnect_extensions)
|
162
177
|
|
178
|
+
if before_preconnect = @opts[:before_preconnect]
|
179
|
+
before_preconnect.call(self)
|
180
|
+
end
|
181
|
+
|
163
182
|
if typecast_value_boolean(@opts[:preconnect]) && @pool.respond_to?(:preconnect, true)
|
164
183
|
concurrent = typecast_value_string(@opts[:preconnect]) == "concurrently"
|
165
184
|
@pool.send(:preconnect, concurrent)
|
@@ -244,8 +263,8 @@ module Sequel
|
|
244
263
|
# Proxy the literal call to the dataset.
|
245
264
|
#
|
246
265
|
# DB.literal(1) # 1
|
247
|
-
# DB.literal(:a) # a
|
248
|
-
# DB.literal(
|
266
|
+
# DB.literal(:a) # "a" # or `a`, [a], or a, depending on identifier quoting
|
267
|
+
# DB.literal("a") # 'a'
|
249
268
|
def literal(v)
|
250
269
|
schema_utility_dataset.literal(v)
|
251
270
|
end
|
@@ -459,6 +478,21 @@ module Sequel
|
|
459
478
|
# Don't rescue other exceptions, they will be raised normally.
|
460
479
|
end
|
461
480
|
|
481
|
+
# Check the bytesize of a string before conversion. There is no point
|
482
|
+
# trying to typecast strings that would be way too long.
|
483
|
+
def typecast_check_string_length(string, max_size)
|
484
|
+
if @check_string_typecast_bytesize && string.bytesize > max_size
|
485
|
+
raise InvalidValue, "string too long to typecast (bytesize: #{string.bytesize}, max: #{max_size})"
|
486
|
+
end
|
487
|
+
string
|
488
|
+
end
|
489
|
+
|
490
|
+
# Check the bytesize of the string value, if value is a string.
|
491
|
+
def typecast_check_length(value, max_size)
|
492
|
+
typecast_check_string_length(value, max_size) if String === value
|
493
|
+
value
|
494
|
+
end
|
495
|
+
|
462
496
|
# Typecast the value to an SQL::Blob
|
463
497
|
def typecast_value_blob(value)
|
464
498
|
value.is_a?(Sequel::SQL::Blob) ? value : Sequel::SQL::Blob.new(value)
|
@@ -482,9 +516,9 @@ module Sequel
|
|
482
516
|
when Date
|
483
517
|
value
|
484
518
|
when String
|
485
|
-
Sequel.string_to_date(value)
|
519
|
+
Sequel.string_to_date(typecast_check_string_length(value, 100))
|
486
520
|
when Hash
|
487
|
-
Date.new(*[:year, :month, :day].map{|x| (value[x] || value[x.to_s]).to_i})
|
521
|
+
Date.new(*[:year, :month, :day].map{|x| typecast_check_length(value[x] || value[x.to_s], 100).to_i})
|
488
522
|
else
|
489
523
|
raise InvalidValue, "invalid value for Date: #{value.inspect}"
|
490
524
|
end
|
@@ -492,7 +526,17 @@ module Sequel
|
|
492
526
|
|
493
527
|
# Typecast the value to a DateTime or Time depending on Sequel.datetime_class
|
494
528
|
def typecast_value_datetime(value)
|
495
|
-
|
529
|
+
case value
|
530
|
+
when String
|
531
|
+
Sequel.typecast_to_application_timestamp(typecast_check_string_length(value, 100))
|
532
|
+
when Hash
|
533
|
+
[:year, :month, :day, :hour, :minute, :second, :nanos, :offset].each do |x|
|
534
|
+
typecast_check_length(value[x] || value[x.to_s], 100)
|
535
|
+
end
|
536
|
+
Sequel.typecast_to_application_timestamp(value)
|
537
|
+
else
|
538
|
+
Sequel.typecast_to_application_timestamp(value)
|
539
|
+
end
|
496
540
|
end
|
497
541
|
|
498
542
|
if RUBY_VERSION >= '2.4'
|
@@ -525,18 +569,30 @@ module Sequel
|
|
525
569
|
when Numeric
|
526
570
|
BigDecimal(value.to_s)
|
527
571
|
when String
|
528
|
-
_typecast_value_string_to_decimal(value)
|
572
|
+
_typecast_value_string_to_decimal(typecast_check_string_length(value, 1000))
|
529
573
|
else
|
530
574
|
raise InvalidValue, "invalid value for BigDecimal: #{value.inspect}"
|
531
575
|
end
|
532
576
|
end
|
533
577
|
|
534
578
|
# Typecast the value to a Float
|
535
|
-
|
579
|
+
def typecast_value_float(value)
|
580
|
+
Float(typecast_check_length(value, 1000))
|
581
|
+
end
|
536
582
|
|
537
583
|
# Typecast the value to an Integer
|
538
584
|
def typecast_value_integer(value)
|
539
|
-
|
585
|
+
case value
|
586
|
+
when String
|
587
|
+
typecast_check_string_length(value, 100)
|
588
|
+
if value =~ /\A-?0+(\d)/
|
589
|
+
Integer(value, 10)
|
590
|
+
else
|
591
|
+
Integer(value)
|
592
|
+
end
|
593
|
+
else
|
594
|
+
Integer(value)
|
595
|
+
end
|
540
596
|
end
|
541
597
|
|
542
598
|
# Typecast the value to a String
|
@@ -559,9 +615,9 @@ module Sequel
|
|
559
615
|
SQLTime.create(value.hour, value.min, value.sec, value.nsec/1000.0)
|
560
616
|
end
|
561
617
|
when String
|
562
|
-
Sequel.string_to_time(value)
|
618
|
+
Sequel.string_to_time(typecast_check_string_length(value, 100))
|
563
619
|
when Hash
|
564
|
-
SQLTime.create(*[:hour, :minute, :second].map{|x| (value[x] || value[x.to_s]).to_i})
|
620
|
+
SQLTime.create(*[:hour, :minute, :second].map{|x| typecast_check_length(value[x] || value[x.to_s], 100).to_i})
|
565
621
|
else
|
566
622
|
raise Sequel::InvalidValue, "invalid value for Time: #{value.inspect}"
|
567
623
|
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
|
|
@@ -236,7 +245,7 @@ module Sequel
|
|
236
245
|
when :date
|
237
246
|
Sequel.string_to_date(default)
|
238
247
|
when :datetime
|
239
|
-
|
248
|
+
Sequel.string_to_datetime(default)
|
240
249
|
when :time
|
241
250
|
Sequel.string_to_time(default)
|
242
251
|
when :decimal
|
@@ -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
|
@@ -146,6 +146,9 @@ module Sequel
|
|
146
146
|
#
|
147
147
|
# :generated_type :: Set the type of column when using :generated_always_as,
|
148
148
|
# should be :virtual or :stored to force a type.
|
149
|
+
# :on_update_current_timestamp :: Use ON UPDATE CURRENT TIMESTAMP when defining the column,
|
150
|
+
# which will update the column value to CURRENT_TIMESTAMP
|
151
|
+
# on every UPDATE.
|
149
152
|
#
|
150
153
|
# Microsoft SQL Server specific options:
|
151
154
|
#
|
@@ -259,6 +262,7 @@ module Sequel
|
|
259
262
|
# operations on the table while the index is being
|
260
263
|
# built.
|
261
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.
|
262
266
|
# :opclass :: Set an opclass to use for all columns (per-column opclasses require
|
263
267
|
# custom SQL).
|
264
268
|
# :tablespace :: Specify tablespace for index.
|
@@ -303,7 +307,7 @@ module Sequel
|
|
303
307
|
# Examples:
|
304
308
|
# primary_key(:id)
|
305
309
|
# primary_key(:id, type: :Bignum, keep_order: true)
|
306
|
-
# primary_key([:street_number, :house_number], name: :
|
310
|
+
# primary_key([:street_number, :house_number], name: :some_constraint_name)
|
307
311
|
def primary_key(name, *args)
|
308
312
|
return composite_primary_key(name, *args) if name.is_a?(Array)
|
309
313
|
column = @db.serial_primary_key_options.merge({:name => name})
|
@@ -387,8 +391,7 @@ module Sequel
|
|
387
391
|
end
|
388
392
|
|
389
393
|
# Add a column with the given name, type, and opts.
|
390
|
-
# See CreateTableGenerator#column for the available options
|
391
|
-
# separate +add_index+ call to add an index for the column).
|
394
|
+
# See CreateTableGenerator#column for the available options.
|
392
395
|
#
|
393
396
|
# add_column(:name, String) # ADD COLUMN name varchar(255)
|
394
397
|
#
|
@@ -401,7 +404,10 @@ module Sequel
|
|
401
404
|
# :after :: The name of an existing column that the new column should be positioned after
|
402
405
|
# :first :: Create this new column before all other existing columns
|
403
406
|
def add_column(name, type, opts = OPTS)
|
404
|
-
|
407
|
+
op = {:op => :add_column, :name => name, :type => type}.merge!(opts)
|
408
|
+
index_opts = op.delete(:index)
|
409
|
+
@operations << op
|
410
|
+
add_index(name, index_opts.is_a?(Hash) ? index_opts : OPTS) if index_opts
|
405
411
|
nil
|
406
412
|
end
|
407
413
|
|
@@ -430,8 +436,7 @@ module Sequel
|
|
430
436
|
end
|
431
437
|
|
432
438
|
# Add a foreign key with the given name and referencing the given table.
|
433
|
-
# See CreateTableGenerator#column for the available options
|
434
|
-
# separate +add_index+ call to add an index for the column).
|
439
|
+
# See CreateTableGenerator#column for the available options.
|
435
440
|
#
|
436
441
|
# You can also pass an array of column names for creating composite foreign
|
437
442
|
# keys. In this case, it will assume the columns exist and will only add
|
@@ -63,7 +63,7 @@ module Sequel
|
|
63
63
|
# definitions using <tt>create_table</tt>, and +add_index+ accepts all the options
|
64
64
|
# available for index definition.
|
65
65
|
#
|
66
|
-
# See <tt>Schema::AlterTableGenerator</tt> and the {
|
66
|
+
# See <tt>Schema::AlterTableGenerator</tt> and the {Migrations guide}[rdoc-ref:doc/migration.rdoc].
|
67
67
|
def alter_table(name, &block)
|
68
68
|
generator = alter_table_generator(&block)
|
69
69
|
remove_cached_schema(name)
|
@@ -183,6 +183,21 @@ module Sequel
|
|
183
183
|
# keys.
|
184
184
|
# :tablespace :: The tablespace to use for the table.
|
185
185
|
#
|
186
|
+
# SQLite specific options:
|
187
|
+
# :strict :: Create a STRICT table, which checks that the values for the columns
|
188
|
+
# are the correct type (similar to all other SQL databases). Note that
|
189
|
+
# when using this option, all column types used should be one of the
|
190
|
+
# following: +int+, +integer+, +real+, +text+, +blob+, and +any+.
|
191
|
+
# The +any+ type is treated like a SQLite column in a non-strict table,
|
192
|
+
# allowing any type of data to be stored. This option is supported on
|
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+.
|
200
|
+
#
|
186
201
|
# See <tt>Schema::CreateTableGenerator</tt> and the {"Schema Modification" guide}[rdoc-ref:doc/schema_modification.rdoc].
|
187
202
|
def create_table(name, options=OPTS, &block)
|
188
203
|
remove_cached_schema(name)
|
@@ -286,6 +301,9 @@ module Sequel
|
|
286
301
|
# in a subquery, if you are providing a Dataset as the source
|
287
302
|
# argument, if should probably call the union method with the
|
288
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.
|
289
307
|
# :tablespace :: The tablespace to use for materialized views.
|
290
308
|
def create_view(name, source, options = OPTS)
|
291
309
|
execute_ddl(create_view_sql(name, source, options))
|
@@ -700,8 +718,9 @@ module Sequel
|
|
700
718
|
e = options[:ignore_index_errors] || options[:if_not_exists]
|
701
719
|
generator.indexes.each do |index|
|
702
720
|
begin
|
703
|
-
|
704
|
-
|
721
|
+
transaction(:savepoint=>:only, :skip_transaction=>supports_transactional_ddl? == false) do
|
722
|
+
index_sql_list(name, [index]).each{|sql| execute_ddl(sql)}
|
723
|
+
end
|
705
724
|
rescue Error
|
706
725
|
raise unless e
|
707
726
|
end
|
@@ -888,7 +907,7 @@ module Sequel
|
|
888
907
|
#
|
889
908
|
# Any other object given is just converted to a string, with "_" converted to " " and upcased.
|
890
909
|
def on_delete_clause(action)
|
891
|
-
action.to_s.
|
910
|
+
action.to_s.tr("_", " ").upcase
|
892
911
|
end
|
893
912
|
|
894
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)
|
@@ -19,7 +19,7 @@ module Sequel
|
|
19
19
|
METHS
|
20
20
|
|
21
21
|
# The clone options to use when retrieving columns for a dataset.
|
22
|
-
COLUMNS_CLONE_OPTIONS = {:distinct => nil, :limit =>
|
22
|
+
COLUMNS_CLONE_OPTIONS = {:distinct => nil, :limit => 0, :offset=>nil, :where=>nil, :having=>nil, :order=>nil, :row_proc=>nil, :graph=>nil, :eager_graph=>nil}.freeze
|
23
23
|
|
24
24
|
# Inserts the given argument into the database. Returns self so it
|
25
25
|
# can be used safely when chaining:
|
@@ -127,6 +127,18 @@ module Sequel
|
|
127
127
|
#
|
128
128
|
# DB[:table].delete # DELETE * FROM table
|
129
129
|
# # => 3
|
130
|
+
#
|
131
|
+
# Some databases support using multiple tables in a DELETE query. This requires
|
132
|
+
# multiple FROM tables (JOINs can also be used). As multiple FROM tables use
|
133
|
+
# an implicit CROSS JOIN, you should make sure your WHERE condition uses the
|
134
|
+
# appropriate filters for the FROM tables:
|
135
|
+
#
|
136
|
+
# DB.from(:a, :b).join(:c, :d=>Sequel[:b][:e]).where{{a[:f]=>b[:g], a[:id]=>c[:h]}}.
|
137
|
+
# delete
|
138
|
+
# # DELETE FROM a
|
139
|
+
# # USING b
|
140
|
+
# # INNER JOIN c ON (c.d = b.e)
|
141
|
+
# # WHERE ((a.f = b.g) AND (a.id = c.h))
|
130
142
|
def delete(&block)
|
131
143
|
sql = delete_sql
|
132
144
|
if uses_returning?(:delete)
|
@@ -162,7 +174,7 @@ module Sequel
|
|
162
174
|
# # => false
|
163
175
|
def empty?
|
164
176
|
cached_dataset(:_empty_ds) do
|
165
|
-
single_value_ds.unordered.select(EMPTY_SELECT)
|
177
|
+
(@opts[:sql] ? from_self : self).single_value_ds.unordered.select(EMPTY_SELECT)
|
166
178
|
end.single_value!.nil?
|
167
179
|
end
|
168
180
|
|
@@ -313,14 +325,18 @@ module Sequel
|
|
313
325
|
|
314
326
|
# Inserts multiple records into the associated table. This method can be
|
315
327
|
# used to efficiently insert a large number of records into a table in a
|
316
|
-
# single query if the database supports it. Inserts
|
317
|
-
#
|
328
|
+
# single query if the database supports it. Inserts are automatically
|
329
|
+
# wrapped in a transaction if necessary.
|
318
330
|
#
|
319
331
|
# This method is called with a columns array and an array of value arrays:
|
320
332
|
#
|
321
333
|
# DB[:table].import([:x, :y], [[1, 2], [3, 4]])
|
322
334
|
# # INSERT INTO table (x, y) VALUES (1, 2)
|
323
|
-
# # INSERT INTO table (x, y) VALUES (3, 4)
|
335
|
+
# # INSERT INTO table (x, y) VALUES (3, 4)
|
336
|
+
#
|
337
|
+
# or, if the database supports it:
|
338
|
+
#
|
339
|
+
# # INSERT INTO table (x, y) VALUES (1, 2), (3, 4)
|
324
340
|
#
|
325
341
|
# This method also accepts a dataset instead of an array of value arrays:
|
326
342
|
#
|
@@ -328,17 +344,23 @@ module Sequel
|
|
328
344
|
# # INSERT INTO table (x, y) SELECT a, b FROM table2
|
329
345
|
#
|
330
346
|
# Options:
|
331
|
-
# :commit_every :: Open a new transaction for every given number of
|
332
|
-
# For example, if you provide a value of 50,
|
333
|
-
# after every 50 records.
|
347
|
+
# :commit_every :: Open a new transaction for every given number of
|
348
|
+
# records. For example, if you provide a value of 50,
|
349
|
+
# will commit after every 50 records. When a
|
350
|
+
# transaction is not required, this option controls
|
351
|
+
# the maximum number of values to insert with a single
|
352
|
+
# statement; it does not force the use of a
|
353
|
+
# transaction.
|
334
354
|
# :return :: When this is set to :primary_key, returns an array of
|
335
355
|
# autoincremented primary key values for the rows inserted.
|
336
356
|
# This does not have an effect if +values+ is a Dataset.
|
337
357
|
# :server :: Set the server/shard to use for the transaction and insert
|
338
358
|
# queries.
|
359
|
+
# :skip_transaction :: Do not use a transaction even when using multiple
|
360
|
+
# INSERT queries.
|
339
361
|
# :slice :: Same as :commit_every, :commit_every takes precedence.
|
340
362
|
def import(columns, values, opts=OPTS)
|
341
|
-
return
|
363
|
+
return insert(columns, values) if values.is_a?(Dataset)
|
342
364
|
|
343
365
|
return if values.empty?
|
344
366
|
raise(Error, 'Using Sequel::Dataset#import with an empty column array is not allowed') if columns.empty?
|
@@ -457,6 +479,55 @@ module Sequel
|
|
457
479
|
_aggregate(:max, arg)
|
458
480
|
end
|
459
481
|
|
482
|
+
# Execute a MERGE statement, which allows for INSERT, UPDATE, and DELETE
|
483
|
+
# behavior in a single query, based on whether rows from a source table
|
484
|
+
# match rows in the current table, based on the join conditions.
|
485
|
+
#
|
486
|
+
# Unless the dataset uses static SQL, to use #merge, you must first have
|
487
|
+
# called #merge_using to specify the merge source and join conditions.
|
488
|
+
# You will then likely to call one or more of the following methods
|
489
|
+
# to specify MERGE behavior by adding WHEN [NOT] MATCHED clauses:
|
490
|
+
#
|
491
|
+
# * #merge_insert
|
492
|
+
# * #merge_update
|
493
|
+
# * #merge_delete
|
494
|
+
#
|
495
|
+
# The WHEN [NOT] MATCHED clauses are added to the SQL in the order these
|
496
|
+
# methods were called on the dataset. If none of these methods are
|
497
|
+
# called, an error is raised.
|
498
|
+
#
|
499
|
+
# Example:
|
500
|
+
#
|
501
|
+
# DB[:m1]
|
502
|
+
# merge_using(:m2, i1: :i2).
|
503
|
+
# merge_insert(i1: :i2, a: Sequel[:b]+11).
|
504
|
+
# merge_delete{a > 30}.
|
505
|
+
# merge_update(i1: Sequel[:i1]+:i2+10, a: Sequel[:a]+:b+20).
|
506
|
+
# merge
|
507
|
+
#
|
508
|
+
# SQL:
|
509
|
+
#
|
510
|
+
# MERGE INTO m1 USING m2 ON (i1 = i2)
|
511
|
+
# WHEN NOT MATCHED THEN INSERT (i1, a) VALUES (i2, (b + 11))
|
512
|
+
# WHEN MATCHED AND (a > 30) THEN DELETE
|
513
|
+
# WHEN MATCHED THEN UPDATE SET i1 = (i1 + i2 + 10), a = (a + b + 20)
|
514
|
+
#
|
515
|
+
# On PostgreSQL, two additional merge methods are supported, for the
|
516
|
+
# PostgreSQL-specific DO NOTHING syntax.
|
517
|
+
#
|
518
|
+
# * #merge_do_nothing_when_matched
|
519
|
+
# * #merge_do_nothing_when_not_matched
|
520
|
+
#
|
521
|
+
# This method is supported on Oracle, but Oracle's MERGE support is
|
522
|
+
# non-standard, and has the following issues:
|
523
|
+
#
|
524
|
+
# * DELETE clause requires UPDATE clause
|
525
|
+
# * DELETE clause requires a condition
|
526
|
+
# * DELETE clause only affects rows updated by UPDATE clause
|
527
|
+
def merge
|
528
|
+
execute_ddl(merge_sql)
|
529
|
+
end
|
530
|
+
|
460
531
|
# Returns the minimum value for the given column/expression.
|
461
532
|
# Uses a virtual row block if no argument is given.
|
462
533
|
#
|
@@ -519,6 +590,8 @@ module Sequel
|
|
519
590
|
# if your ORDER BY expressions are not simple columns, if they contain
|
520
591
|
# qualified identifiers that would be ambiguous unqualified, if they contain
|
521
592
|
# any identifiers that are aliased in SELECT, and potentially other cases.
|
593
|
+
# :skip_transaction :: Do not use a transaction. This can be useful if you want to prevent
|
594
|
+
# a lock on the database table, at the expense of consistency.
|
522
595
|
#
|
523
596
|
# Examples:
|
524
597
|
#
|
@@ -527,7 +600,7 @@ module Sequel
|
|
527
600
|
# # SELECT * FROM table ORDER BY id LIMIT 1000 OFFSET 1000
|
528
601
|
# # ...
|
529
602
|
#
|
530
|
-
# DB[:table].order(:id).paged_each(:
|
603
|
+
# DB[:table].order(:id).paged_each(rows_per_fetch: 100){|row| }
|
531
604
|
# # SELECT * FROM table ORDER BY id LIMIT 100
|
532
605
|
# # SELECT * FROM table ORDER BY id LIMIT 100 OFFSET 100
|
533
606
|
# # ...
|
@@ -546,7 +619,7 @@ module Sequel
|
|
546
619
|
unless @opts[:order]
|
547
620
|
raise Sequel::Error, "Dataset#paged_each requires the dataset be ordered"
|
548
621
|
end
|
549
|
-
unless
|
622
|
+
unless defined?(yield)
|
550
623
|
return enum_for(:paged_each, opts)
|
551
624
|
end
|
552
625
|
|
@@ -869,6 +942,19 @@ module Sequel
|
|
869
942
|
#
|
870
943
|
# DB[:table].update(x: Sequel[:x]+1, y: 0) # UPDATE table SET x = (x + 1), y = 0
|
871
944
|
# # => 10
|
945
|
+
#
|
946
|
+
# Some databases support using multiple tables in an UPDATE query. This requires
|
947
|
+
# multiple FROM tables (JOINs can also be used). As multiple FROM tables use
|
948
|
+
# an implicit CROSS JOIN, you should make sure your WHERE condition uses the
|
949
|
+
# appropriate filters for the FROM tables:
|
950
|
+
#
|
951
|
+
# DB.from(:a, :b).join(:c, :d=>Sequel[:b][:e]).where{{a[:f]=>b[:g], a[:id]=>10}}.
|
952
|
+
# update(:f=>Sequel[:c][:h])
|
953
|
+
# # UPDATE a
|
954
|
+
# # SET f = c.h
|
955
|
+
# # FROM b
|
956
|
+
# # INNER JOIN c ON (c.d = b.e)
|
957
|
+
# # WHERE ((a.f = b.g) AND (a.id = 10))
|
872
958
|
def update(values=OPTS, &block)
|
873
959
|
sql = update_sql(values)
|
874
960
|
if uses_returning?(:update)
|
@@ -974,18 +1060,19 @@ module Sequel
|
|
974
1060
|
|
975
1061
|
# Internals of #import. If primary key values are requested, use
|
976
1062
|
# separate insert commands for each row. Otherwise, call #multi_insert_sql
|
977
|
-
# and execute each statement it gives separately.
|
1063
|
+
# and execute each statement it gives separately. A transaction is only used
|
1064
|
+
# if there are multiple statements to execute.
|
978
1065
|
def _import(columns, values, opts)
|
979
1066
|
trans_opts = Hash[opts]
|
980
1067
|
trans_opts[:server] = @opts[:server]
|
981
1068
|
if opts[:return] == :primary_key
|
982
|
-
|
1069
|
+
_import_transaction(values, trans_opts){values.map{|v| insert(columns, v)}}
|
983
1070
|
else
|
984
1071
|
stmts = multi_insert_sql(columns, values)
|
985
|
-
|
1072
|
+
_import_transaction(stmts, trans_opts){stmts.each{|st| execute_dui(st)}}
|
986
1073
|
end
|
987
1074
|
end
|
988
|
-
|
1075
|
+
|
989
1076
|
# Return an array of arrays of values given by the symbols in ret_cols.
|
990
1077
|
def _select_map_multiple(ret_cols)
|
991
1078
|
map{|r| r.values_at(*ret_cols)}
|
@@ -1024,6 +1111,15 @@ module Sequel
|
|
1024
1111
|
end
|
1025
1112
|
end
|
1026
1113
|
|
1114
|
+
# Use a transaction when yielding to the block if multiple values/statements
|
1115
|
+
# are provided. When only a single value or statement is provided, then yield
|
1116
|
+
# without using a transaction.
|
1117
|
+
def _import_transaction(values, trans_opts, &block)
|
1118
|
+
# OK to mutate trans_opts as it is generated by _import
|
1119
|
+
trans_opts[:skip_transaction] = true if values.length <= 1
|
1120
|
+
@db.transaction(trans_opts, &block)
|
1121
|
+
end
|
1122
|
+
|
1027
1123
|
# Internals of +select_hash+ and +select_hash_groups+
|
1028
1124
|
def _select_hash(meth, key_column, value_column, opts=OPTS)
|
1029
1125
|
select(*(key_column.is_a?(Array) ? key_column : [key_column]) + (value_column.is_a?(Array) ? value_column : [value_column])).
|