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
@@ -56,7 +56,11 @@ module Sequel
|
|
56
56
|
|
57
57
|
# Dump the index cache to the filename given in Marshal format.
|
58
58
|
def dump_index_cache(file)
|
59
|
-
|
59
|
+
indexes = {}
|
60
|
+
@indexes.sort.each do |k, v|
|
61
|
+
indexes[k] = v
|
62
|
+
end
|
63
|
+
File.open(file, 'wb'){|f| f.write(Marshal.dump(indexes))}
|
60
64
|
nil
|
61
65
|
end
|
62
66
|
|
@@ -3,7 +3,7 @@
|
|
3
3
|
# The is_distinct_from extension adds the ability to use the
|
4
4
|
# SQL standard IS DISTINCT FROM operator, which is similar to the
|
5
5
|
# not equals operator, except that NULL values are considered
|
6
|
-
# equal.
|
6
|
+
# equal. PostgreSQL, SQLite 3.39+, and H2 currently support this operator. On
|
7
7
|
# other databases, support is emulated.
|
8
8
|
#
|
9
9
|
# First, you need to load the extension into the database:
|
@@ -90,6 +90,8 @@ module Sequel
|
|
90
90
|
case db.database_type
|
91
91
|
when :postgres, :h2
|
92
92
|
true
|
93
|
+
when :sqlite
|
94
|
+
db.sqlite_version >= 33900
|
93
95
|
else
|
94
96
|
false
|
95
97
|
end
|
@@ -8,6 +8,9 @@
|
|
8
8
|
# :decimal :: use 0.0 for unsupported strings
|
9
9
|
# :string :: silently allow hash and array conversion to string
|
10
10
|
#
|
11
|
+
# This also removes bytesize checks for string inputs for float, integer
|
12
|
+
# and decimal conversions.
|
13
|
+
#
|
11
14
|
# To load the extension into the database:
|
12
15
|
#
|
13
16
|
# DB.extension :looser_typecasting
|
@@ -159,6 +159,19 @@ module Sequel
|
|
159
159
|
migration.up = block
|
160
160
|
migration.down = MigrationReverser.new.reverse(&block)
|
161
161
|
end
|
162
|
+
|
163
|
+
# Creates a revert migration. This is the same as creating
|
164
|
+
# the same block with +down+, but it also calls the block and attempts
|
165
|
+
# to create a +up+ block that will reverse the changes made by
|
166
|
+
# the block. This is designed to revert the changes in the
|
167
|
+
# provided block.
|
168
|
+
#
|
169
|
+
# There are no guarantees that this will work perfectly
|
170
|
+
# in all cases, but it works for some simple cases.
|
171
|
+
def revert(&block)
|
172
|
+
migration.down = block
|
173
|
+
migration.up = MigrationReverser.new.reverse(&block)
|
174
|
+
end
|
162
175
|
end
|
163
176
|
|
164
177
|
# Handles the reversing of reversible migrations. Basically records
|
@@ -270,6 +283,10 @@ module Sequel
|
|
270
283
|
def rename_column(name, new_name)
|
271
284
|
@actions << [:rename_column, new_name, name]
|
272
285
|
end
|
286
|
+
|
287
|
+
def set_column_allow_null(name, allow_null=true)
|
288
|
+
@actions << [:set_column_allow_null, name, !allow_null]
|
289
|
+
end
|
273
290
|
end
|
274
291
|
|
275
292
|
# The preferred method for writing Sequel migrations, using a DSL:
|
@@ -377,7 +394,7 @@ module Sequel
|
|
377
394
|
# Raise a NotCurrentError unless the migrator is current, takes the same
|
378
395
|
# arguments as #run.
|
379
396
|
def self.check_current(*args)
|
380
|
-
raise(NotCurrentError, '
|
397
|
+
raise(NotCurrentError, 'current migration version does not match latest available version') unless is_current?(*args)
|
381
398
|
end
|
382
399
|
|
383
400
|
# Return whether the migrator is current (i.e. it does not need to make
|
@@ -386,6 +403,11 @@ module Sequel
|
|
386
403
|
migrator_class(directory).new(db, directory, opts).is_current?
|
387
404
|
end
|
388
405
|
|
406
|
+
# Lock ID to use for advisory locks when running migrations
|
407
|
+
# "sequel-migration".codepoints.reduce(:*) % (2**63)
|
408
|
+
MIGRATION_ADVISORY_LOCK_ID = 4966325471869609408
|
409
|
+
private_constant :MIGRATION_ADVISORY_LOCK_ID
|
410
|
+
|
389
411
|
# Migrates the supplied database using the migration files in the specified directory. Options:
|
390
412
|
# :allow_missing_migration_files :: Don't raise an error if there are missing migration files.
|
391
413
|
# It is very risky to use this option, since it can result in
|
@@ -399,6 +421,8 @@ module Sequel
|
|
399
421
|
# :table :: The table containing the schema version (default: :schema_info for integer migrations and
|
400
422
|
# :schema_migrations for timestamped migrations).
|
401
423
|
# :target :: The target version to which to migrate. If not given, migrates to the maximum version.
|
424
|
+
# :use_advisory_lock :: Use advisory locks in migrations (only use this if Sequel supports advisory
|
425
|
+
# locks for the database).
|
402
426
|
#
|
403
427
|
# Examples:
|
404
428
|
# Sequel::Migrator.run(DB, "migrations")
|
@@ -406,7 +430,11 @@ module Sequel
|
|
406
430
|
# Sequel::Migrator.run(DB, "app1/migrations", column: :app2_version)
|
407
431
|
# Sequel::Migrator.run(DB, "app2/migrations", column: :app2_version, table: :schema_info2)
|
408
432
|
def self.run(db, directory, opts=OPTS)
|
409
|
-
|
433
|
+
if opts[:use_advisory_lock]
|
434
|
+
db.with_advisory_lock(MIGRATION_ADVISORY_LOCK_ID){run(db, directory, opts.merge(:use_advisory_lock=>false))}
|
435
|
+
else
|
436
|
+
migrator_class(directory).new(db, directory, opts).run
|
437
|
+
end
|
410
438
|
end
|
411
439
|
|
412
440
|
# Choose the Migrator subclass to use. Uses the TimestampMigrator
|
@@ -478,11 +506,7 @@ module Sequel
|
|
478
506
|
@use_transactions
|
479
507
|
end
|
480
508
|
|
481
|
-
|
482
|
-
db.transaction(&block)
|
483
|
-
else
|
484
|
-
yield
|
485
|
-
end
|
509
|
+
db.transaction(:skip_transaction=>use_trans == false, &block)
|
486
510
|
end
|
487
511
|
|
488
512
|
# Load the migration file, raising an exception if the file does not define
|
@@ -680,6 +704,13 @@ module Sequel
|
|
680
704
|
@migration_tuples = get_migration_tuples
|
681
705
|
end
|
682
706
|
|
707
|
+
# Apply the migration in the given file path. See Migrator.run for the
|
708
|
+
# available options. Additionally, this method supports the :direction
|
709
|
+
# option for whether to run the migration up (default) or down.
|
710
|
+
def self.run_single(db, path, opts=OPTS)
|
711
|
+
new(db, File.dirname(path), opts).run_single(path, opts[:direction] || :up)
|
712
|
+
end
|
713
|
+
|
683
714
|
# The timestamp migrator is current if there are no migrations to apply
|
684
715
|
# in either direction.
|
685
716
|
def is_current?
|
@@ -689,20 +720,39 @@ module Sequel
|
|
689
720
|
# Apply all migration tuples on the database
|
690
721
|
def run
|
691
722
|
migration_tuples.each do |m, f, direction|
|
692
|
-
|
693
|
-
db.log_info("Begin applying migration #{f}, direction: #{direction}")
|
694
|
-
checked_transaction(m) do
|
695
|
-
m.apply(db, direction)
|
696
|
-
fi = f.downcase
|
697
|
-
direction == :up ? ds.insert(column=>fi) : ds.where(column=>fi).delete
|
698
|
-
end
|
699
|
-
db.log_info("Finished applying migration #{f}, direction: #{direction}, took #{sprintf('%0.6f', Time.now - t)} seconds")
|
723
|
+
apply_migration(m, f, direction)
|
700
724
|
end
|
701
725
|
nil
|
702
726
|
end
|
703
727
|
|
728
|
+
# Apply single migration tuple at the given path with the given direction
|
729
|
+
# on the database.
|
730
|
+
def run_single(path, direction)
|
731
|
+
migration = load_migration_file(path)
|
732
|
+
file_name = File.basename(path)
|
733
|
+
already_applied = applied_migrations.include?(file_name.downcase)
|
734
|
+
|
735
|
+
return if direction == :up ? already_applied : !already_applied
|
736
|
+
|
737
|
+
apply_migration(migration, file_name, direction)
|
738
|
+
nil
|
739
|
+
end
|
740
|
+
|
704
741
|
private
|
705
742
|
|
743
|
+
# Apply a single migration with the given filename in the given direction.
|
744
|
+
def apply_migration(migration, file_name, direction)
|
745
|
+
fi = file_name.downcase
|
746
|
+
t = Time.now
|
747
|
+
|
748
|
+
db.log_info("Begin applying migration #{file_name}, direction: #{direction}")
|
749
|
+
checked_transaction(migration) do
|
750
|
+
migration.apply(db, direction)
|
751
|
+
direction == :up ? ds.insert(column=>fi) : ds.where(column=>fi).delete
|
752
|
+
end
|
753
|
+
db.log_info("Finished applying migration #{file_name}, direction: #{direction}, took #{sprintf('%0.6f', Time.now - t)} seconds")
|
754
|
+
end
|
755
|
+
|
706
756
|
# Convert the schema_info table to the new schema_migrations table format,
|
707
757
|
# using the version of the schema_info table and the current migration files.
|
708
758
|
def convert_from_schema_info
|
@@ -68,6 +68,10 @@ module Sequel
|
|
68
68
|
private
|
69
69
|
|
70
70
|
if RUBY_VERSION >= '2.6'
|
71
|
+
# Whether Time.at with :nsec and :in is broken. True on JRuby < 9.3.9.0.
|
72
|
+
BROKEN_TIME_AT_WITH_NSEC = defined?(JRUBY_VERSION) && (JRUBY_VERSION < '9.3' || (JRUBY_VERSION < '9.4' && JRUBY_VERSION.split('.')[2].to_i < 9))
|
73
|
+
private_constant :BROKEN_TIME_AT_WITH_NSEC
|
74
|
+
|
71
75
|
# Convert the given input Time (which must be in UTC) to the given input timezone,
|
72
76
|
# which should be a TZInfo::Timezone instance.
|
73
77
|
def convert_input_time_other(v, input_timezone)
|
@@ -76,33 +80,45 @@ module Sequel
|
|
76
80
|
raise unless disamb = tzinfo_disambiguator_for(v)
|
77
81
|
period = input_timezone.period_for_local(v, &disamb)
|
78
82
|
offset = period.utc_total_offset
|
79
|
-
|
83
|
+
# :nocov:
|
84
|
+
if BROKEN_TIME_AT_WITH_NSEC
|
85
|
+
Time.at(v.to_i - offset, :in => input_timezone) + v.nsec/1000000000.0
|
86
|
+
# :nocov:
|
87
|
+
else
|
88
|
+
Time.at(v.to_i - offset, v.nsec, :nsec, :in => input_timezone)
|
89
|
+
end
|
80
90
|
end
|
81
91
|
|
82
92
|
# Convert the given input Time to the given output timezone,
|
83
93
|
# which should be a TZInfo::Timezone instance.
|
84
94
|
def convert_output_time_other(v, output_timezone)
|
85
|
-
|
95
|
+
# :nocov:
|
96
|
+
if BROKEN_TIME_AT_WITH_NSEC
|
97
|
+
Time.at(v.to_i, :in => output_timezone) + v.nsec/1000000000.0
|
98
|
+
# :nocov:
|
99
|
+
else
|
100
|
+
Time.at(v.to_i, v.nsec, :nsec, :in => output_timezone)
|
101
|
+
end
|
86
102
|
end
|
87
103
|
# :nodoc:
|
88
104
|
# :nocov:
|
89
105
|
else
|
90
106
|
def convert_input_time_other(v, input_timezone)
|
91
107
|
local_offset = input_timezone.period_for_local(v, &tzinfo_disambiguator_for(v)).utc_total_offset
|
92
|
-
Time.new(1970, 1, 1, 0, 0, 0, local_offset) + v.to_i
|
108
|
+
Time.new(1970, 1, 1, 0, 0, 0, local_offset) + v.to_i + v.nsec/1000000000.0
|
93
109
|
end
|
94
110
|
|
95
111
|
if defined?(TZInfo::VERSION) && TZInfo::VERSION > '2'
|
96
112
|
def convert_output_time_other(v, output_timezone)
|
97
113
|
v = output_timezone.utc_to_local(v.getutc)
|
98
114
|
local_offset = output_timezone.period_for_local(v, &tzinfo_disambiguator_for(v)).utc_total_offset
|
99
|
-
Time.new(1970, 1, 1, 0, 0, 0, local_offset) + v.to_i + local_offset
|
115
|
+
Time.new(1970, 1, 1, 0, 0, 0, local_offset) + v.to_i + v.nsec/1000000000.0 + local_offset
|
100
116
|
end
|
101
117
|
else
|
102
118
|
def convert_output_time_other(v, output_timezone)
|
103
119
|
v = output_timezone.utc_to_local(v.getutc)
|
104
120
|
local_offset = output_timezone.period_for_local(v, &tzinfo_disambiguator_for(v)).utc_total_offset
|
105
|
-
Time.new(1970, 1, 1, 0, 0, 0, local_offset) + v.to_i
|
121
|
+
Time.new(1970, 1, 1, 0, 0, 0, local_offset) + v.to_i + v.nsec/1000000000.0
|
106
122
|
end
|
107
123
|
end
|
108
124
|
# :nodoc:
|
@@ -120,7 +136,7 @@ module Sequel
|
|
120
136
|
v = output_timezone.utc_to_local(v.new_offset(0))
|
121
137
|
|
122
138
|
# Force DateTime output instead of TZInfo::DateTimeWithOffset
|
123
|
-
DateTime.
|
139
|
+
DateTime.civil(v.year, v.month, v.day, v.hour, v.minute, v.second + v.sec_fraction, v.offset, v.start)
|
124
140
|
end
|
125
141
|
# :nodoc:
|
126
142
|
# :nocov:
|
@@ -228,16 +228,37 @@ module Sequel
|
|
228
228
|
when Array
|
229
229
|
"{#{a.map{|i| bound_variable_array(i)}.join(',')}}"
|
230
230
|
when Sequel::SQL::Blob
|
231
|
-
|
231
|
+
bound_variable_array_string(literal(a)[BLOB_RANGE].gsub("''", "'"))
|
232
232
|
when Sequel::LiteralString
|
233
233
|
a
|
234
234
|
when String
|
235
|
-
|
235
|
+
bound_variable_array_string(a)
|
236
|
+
when Float
|
237
|
+
if a.infinite?
|
238
|
+
a > 0 ? '"Infinity"' : '"-Infinity"'
|
239
|
+
elsif a.nan?
|
240
|
+
'"NaN"'
|
241
|
+
else
|
242
|
+
literal(a)
|
243
|
+
end
|
244
|
+
when Time, Date
|
245
|
+
@default_dataset.literal_date_or_time(a)
|
236
246
|
else
|
237
|
-
|
247
|
+
if (s = bound_variable_arg(a, nil)).is_a?(String)
|
248
|
+
bound_variable_array_string(s)
|
249
|
+
else
|
250
|
+
literal(a)
|
251
|
+
end
|
238
252
|
end
|
239
253
|
end
|
240
254
|
|
255
|
+
# Escape strings used as array members in bound variables. Most complex
|
256
|
+
# will create a regular string with bound_variable_arg, and then use this
|
257
|
+
# escaping to format it as an array member.
|
258
|
+
def bound_variable_array_string(s)
|
259
|
+
"\"#{s.gsub(/("|\\)/, '\\\\\1')}\""
|
260
|
+
end
|
261
|
+
|
241
262
|
# Look into both the current database's array schema types and the global
|
242
263
|
# array schema types to get the type symbol for the given database type
|
243
264
|
# string.
|
@@ -246,7 +267,7 @@ module Sequel
|
|
246
267
|
end
|
247
268
|
|
248
269
|
# Make the column type detection handle registered array types.
|
249
|
-
def
|
270
|
+
def schema_array_type(db_type)
|
250
271
|
if (db_type =~ /\A([^(]+)(?:\([^(]+\))?\[\]\z/io) && (type = pg_array_schema_type($1))
|
251
272
|
type
|
252
273
|
else
|
@@ -457,6 +478,14 @@ module Sequel
|
|
457
478
|
end
|
458
479
|
end
|
459
480
|
|
481
|
+
# Allow automatic parameterization of the receiver if all elements can be
|
482
|
+
# can be automatically parameterized.
|
483
|
+
def sequel_auto_param_type(ds)
|
484
|
+
if array_type && all?{|x| nil == x || ds.send(:auto_param_type, x)}
|
485
|
+
"::#{array_type}[]"
|
486
|
+
end
|
487
|
+
end
|
488
|
+
|
460
489
|
private
|
461
490
|
|
462
491
|
# Recursive method that handles multi-dimensional
|