sequel 4.48.0 → 4.49.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +56 -0
  3. data/doc/advanced_associations.rdoc +1 -1
  4. data/doc/opening_databases.rdoc +3 -2
  5. data/doc/release_notes/4.49.0.txt +222 -0
  6. data/lib/sequel/adapters/ibmdb.rb +6 -1
  7. data/lib/sequel/adapters/jdbc.rb +3 -1
  8. data/lib/sequel/adapters/jdbc/h2.rb +10 -1
  9. data/lib/sequel/adapters/jdbc/postgresql.rb +3 -2
  10. data/lib/sequel/adapters/jdbc/sqlserver.rb +9 -2
  11. data/lib/sequel/adapters/mock.rb +3 -0
  12. data/lib/sequel/adapters/mysql2.rb +1 -1
  13. data/lib/sequel/adapters/postgres.rb +2 -1
  14. data/lib/sequel/adapters/shared/mysql.rb +4 -1
  15. data/lib/sequel/adapters/shared/oracle.rb +26 -3
  16. data/lib/sequel/connection_pool.rb +9 -2
  17. data/lib/sequel/connection_pool/sharded_single.rb +1 -1
  18. data/lib/sequel/connection_pool/sharded_threaded.rb +1 -1
  19. data/lib/sequel/connection_pool/single.rb +2 -2
  20. data/lib/sequel/connection_pool/threaded.rb +2 -2
  21. data/lib/sequel/database/connecting.rb +3 -3
  22. data/lib/sequel/database/dataset_defaults.rb +14 -1
  23. data/lib/sequel/dataset.rb +1 -1
  24. data/lib/sequel/dataset/actions.rb +54 -0
  25. data/lib/sequel/dataset/dataset_module.rb +58 -0
  26. data/lib/sequel/dataset/query.rb +3 -3
  27. data/lib/sequel/exceptions.rb +8 -0
  28. data/lib/sequel/extensions/_model_pg_row.rb +5 -2
  29. data/lib/sequel/extensions/current_datetime_timestamp.rb +2 -1
  30. data/lib/sequel/extensions/date_arithmetic.rb +1 -0
  31. data/lib/sequel/extensions/duplicate_columns_handler.rb +2 -2
  32. data/lib/sequel/extensions/migration.rb +5 -2
  33. data/lib/sequel/extensions/null_dataset.rb +1 -0
  34. data/lib/sequel/model/associations.rb +3 -0
  35. data/lib/sequel/model/base.rb +10 -55
  36. data/lib/sequel/model/dataset_module.rb +5 -43
  37. data/lib/sequel/model/errors.rb +2 -1
  38. data/lib/sequel/model/inflections.rb +17 -5
  39. data/lib/sequel/plugins/active_model.rb +2 -2
  40. data/lib/sequel/plugins/class_table_inheritance.rb +1 -0
  41. data/lib/sequel/plugins/composition.rb +2 -2
  42. data/lib/sequel/plugins/dataset_associations.rb +25 -13
  43. data/lib/sequel/plugins/json_serializer.rb +2 -2
  44. data/lib/sequel/plugins/pg_row.rb +4 -2
  45. data/lib/sequel/plugins/serialization.rb +1 -0
  46. data/lib/sequel/plugins/single_table_inheritance.rb +6 -1
  47. data/lib/sequel/plugins/touch.rb +2 -1
  48. data/lib/sequel/plugins/validation_helpers.rb +10 -2
  49. data/lib/sequel/sql.rb +16 -7
  50. data/lib/sequel/version.rb +1 -1
  51. data/spec/adapters/mssql_spec.rb +4 -4
  52. data/spec/adapters/mysql_spec.rb +5 -1
  53. data/spec/adapters/oracle_spec.rb +4 -0
  54. data/spec/bin_spec.rb +7 -1
  55. data/spec/core/connection_pool_spec.rb +28 -14
  56. data/spec/core/database_spec.rb +149 -0
  57. data/spec/core/dataset_spec.rb +173 -0
  58. data/spec/extensions/class_table_inheritance_spec.rb +58 -17
  59. data/spec/extensions/composition_spec.rb +13 -0
  60. data/spec/extensions/dataset_associations_spec.rb +12 -0
  61. data/spec/extensions/many_through_many_spec.rb +4 -4
  62. data/spec/extensions/null_dataset_spec.rb +1 -1
  63. data/spec/extensions/serialization_spec.rb +1 -1
  64. data/spec/extensions/single_table_inheritance_spec.rb +16 -0
  65. data/spec/extensions/validation_helpers_spec.rb +1 -2
  66. data/spec/integration/associations_test.rb +8 -0
  67. data/spec/integration/plugin_test.rb +8 -3
  68. data/spec/model/association_reflection_spec.rb +1 -1
  69. data/spec/model/associations_spec.rb +29 -9
  70. data/spec/model/class_dataset_methods_spec.rb +6 -0
  71. data/spec/model/eager_loading_spec.rb +8 -8
  72. data/spec/model/plugins_spec.rb +34 -0
  73. data/spec/model/record_spec.rb +1 -1
  74. data/spec/spec_config.rb +2 -0
  75. metadata +5 -2
@@ -260,7 +260,7 @@ module Sequel
260
260
 
261
261
  # Use streaming to implement paging if Mysql2 supports it.
262
262
  def paged_each(opts=OPTS, &block)
263
- if STREAMING_SUPPORTED
263
+ if STREAMING_SUPPORTED && opts[:stream] != false
264
264
  stream.each(&block)
265
265
  else
266
266
  super
@@ -218,7 +218,8 @@ module Sequel
218
218
  :user => opts[:user],
219
219
  :password => opts[:password],
220
220
  :connect_timeout => opts[:connect_timeout] || 20,
221
- :sslmode => opts[:sslmode]
221
+ :sslmode => opts[:sslmode],
222
+ :sslrootcert => opts[:sslrootcert]
222
223
  }.delete_if { |key, value| blank_object?(value) }
223
224
  connection_params.merge!(opts[:driver_options]) if opts[:driver_options]
224
225
  conn = Adapter.connect(connection_params)
@@ -841,7 +841,10 @@ module Sequel
841
841
  # Transforms an CROSS JOIN to an INNER JOIN if the expr is not nil.
842
842
  # Raises an error on use of :full_outer type, since MySQL doesn't support it.
843
843
  def join_table(type, table, expr=nil, opts=OPTS, &block)
844
- type = :inner if (type == :cross) && !expr.nil?
844
+ if (type == :cross) && !expr.nil?
845
+ Sequel::Deprecation.deprecate(":cross join type with conditions being converted to INNER JOIN on MySQL", "Use :inner join type instead")
846
+ type = :inner
847
+ end
845
848
  raise(Sequel::Error, "MySQL doesn't support FULL OUTER JOIN or NATURAL FULL JOIN") if type == :full_outer || type == :natural_full
846
849
  super(type, table, expr, opts, &block)
847
850
  end
@@ -348,7 +348,7 @@ module Sequel
348
348
  Sequel::Deprecation.deprecate_constant(self, :SKIP_LOCKED)
349
349
 
350
350
  include(Module.new do
351
- Dataset.def_sql_method(self, :select, %w'with select distinct columns from join where group having compounds order lock')
351
+ Dataset.def_sql_method(self, :select, %w'with select distinct columns from join where group having compounds order limit lock')
352
352
  end)
353
353
 
354
354
  def complex_expression_sql_append(sql, op, args)
@@ -421,7 +421,10 @@ module Sequel
421
421
  # Handle LIMIT by using a unlimited subselect filtered with ROWNUM.
422
422
  def select_sql
423
423
  return super if @opts[:sql]
424
- if o = @opts[:offset]
424
+ return super if supports_fetch_next_rows?
425
+
426
+ o = @opts[:offset]
427
+ if o && o != 0
425
428
  columns = clone(:append_sql=>String.new, :placeholder_literal_null=>true).columns
426
429
  dsa1 = dataset_alias(1)
427
430
  rn = row_number_column
@@ -437,7 +440,7 @@ module Sequel
437
440
  subselect_sql_append(sql, ds)
438
441
  sql
439
442
  elsif limit = @opts[:limit]
440
- ds = clone(:limit=>nil)
443
+ ds = unlimited
441
444
  # Lock doesn't work in subselects, so don't use a subselect when locking.
442
445
  # Don't use a subselect if custom SQL is used, as it breaks somethings.
443
446
  ds = ds.from_self unless @opts[:lock]
@@ -449,6 +452,21 @@ module Sequel
449
452
  end
450
453
  end
451
454
 
455
+ def select_limit_sql(sql)
456
+ return unless supports_fetch_next_rows?
457
+
458
+ if offset = @opts[:offset]
459
+ sql << " OFFSET "
460
+ literal_append(sql, offset)
461
+ sql << " ROWS"
462
+ end
463
+
464
+ if limit = @opts[:limit]
465
+ sql << " FETCH NEXT "
466
+ literal_append(sql, limit)
467
+ sql << " ROWS ONLY"
468
+ end
469
+ end
452
470
  # Oracle requires recursive CTEs to have column aliases.
453
471
  def recursive_cte_requires_column_aliases?
454
472
  true
@@ -463,6 +481,11 @@ module Sequel
463
481
  false
464
482
  end
465
483
 
484
+ # Oracle supports FETCH NEXT ROWS since 12c
485
+ def supports_fetch_next_rows?
486
+ server_version >= 12000000 && !(@opts[:lock] || @opts[:skip_locked])
487
+ end
488
+
466
489
  # Oracle supports GROUP BY CUBE
467
490
  def supports_group_cube?
468
491
  true
@@ -29,12 +29,15 @@ class Sequel::ConnectionPool
29
29
 
30
30
  # The default server to use
31
31
  DEFAULT_SERVER = :default
32
+ Sequel::Deprecation.deprecate_constant(self, :DEFAULT_SERVER)
32
33
 
33
34
  # A map of [single threaded, sharded] values to symbols or ConnectionPool subclasses.
34
35
  CONNECTION_POOL_MAP = {[true, false] => :single,
35
36
  [true, true] => :sharded_single,
36
37
  [false, false] => :threaded,
37
38
  [false, true] => :sharded_threaded}
39
+ CONNECTION_POOL__MAP = CONNECTION_POOL_MAP
40
+ Sequel::Deprecation.deprecate_constant(self, :CONNECTION_POOL_MAP)
38
41
 
39
42
  # Class methods used to return an appropriate pool subclass, separated
40
43
  # into a module for easier overridding by extensions.
@@ -57,7 +60,10 @@ class Sequel::ConnectionPool
57
60
 
58
61
  # Return a connection pool class based on the given options.
59
62
  def connection_pool_class(opts)
60
- CONNECTION_POOL_MAP[opts[:pool_class]] || opts[:pool_class] || CONNECTION_POOL_MAP[[!!opts[:single_threaded], !!opts[:servers]]]
63
+ if opts[:pool_class] && !opts[:pool_class].is_a?(Class) && ![:threaded, :single, :sharded_threaded, :sharded_single].include?(opts[:pool_class])
64
+ Sequel::Deprecation.deprecate("Using an unrecognized :pool_class option", "Use a class for the :pool_class option to select a custom pool class, or one of the following symbols for one of the default pool classes: :threaded, :single, :sharded_threaded, :sharded_single")
65
+ end
66
+ CONNECTION_POOL__MAP[opts[:pool_class]] || opts[:pool_class] || CONNECTION_POOL__MAP[[!!opts[:single_threaded], !!opts[:servers]]]
61
67
  end
62
68
  end
63
69
  extend ClassMethods
@@ -89,12 +95,13 @@ class Sequel::ConnectionPool
89
95
 
90
96
  # Alias for +size+, not aliased directly for ease of subclass implementation
91
97
  def created_count(*args)
98
+ Sequel::Deprecation.deprecate("Sequel::ConnectionPool#created_count", "Use #size instead")
92
99
  size(*args)
93
100
  end
94
101
 
95
102
  # An array of symbols for all shards/servers, which is a single <tt>:default</tt> by default.
96
103
  def servers
97
- [DEFAULT_SERVER]
104
+ [:default]
98
105
  end
99
106
 
100
107
  private
@@ -111,5 +111,5 @@ class Sequel::ShardedSingleConnectionPool < Sequel::ConnectionPool
111
111
  servers.each{|s| hold(s){}}
112
112
  end
113
113
 
114
- CONNECTION_POOL_MAP[[true, true]] = self
114
+ CONNECTION_POOL__MAP[[true, true]] = self
115
115
  end
@@ -353,5 +353,5 @@ class Sequel::ShardedThreadedConnectionPool < Sequel::ThreadedConnectionPool
353
353
  disconnect_connection(conn)
354
354
  end
355
355
 
356
- CONNECTION_POOL_MAP[[false, true]] = self
356
+ CONNECTION_POOL__MAP[[false, true]] = self
357
357
  end
@@ -26,7 +26,7 @@ class Sequel::SingleConnectionPool < Sequel::ConnectionPool
26
26
  def hold(server=nil)
27
27
  begin
28
28
  unless c = @conn.first
29
- @conn.replace([c = make_new(DEFAULT_SERVER)])
29
+ @conn.replace([c = make_new(:default)])
30
30
  end
31
31
  yield c
32
32
  rescue Sequel::DatabaseDisconnectError, *@error_classes => e
@@ -57,5 +57,5 @@ class Sequel::SingleConnectionPool < Sequel::ConnectionPool
57
57
  hold{}
58
58
  end
59
59
 
60
- CONNECTION_POOL_MAP[[true, false]] = self
60
+ CONNECTION_POOL__MAP[[true, false]] = self
61
61
  end
@@ -198,7 +198,7 @@ class Sequel::ThreadedConnectionPool < Sequel::ConnectionPool
198
198
  # available, tries to create a new connection. The calling code should already
199
199
  # have the mutex before calling this.
200
200
  def available
201
- next_available || make_new(DEFAULT_SERVER)
201
+ next_available || make_new(:default)
202
202
  end
203
203
 
204
204
  # Return a connection to the pool of available connections, returns the connection.
@@ -282,5 +282,5 @@ class Sequel::ThreadedConnectionPool < Sequel::ConnectionPool
282
282
  @mutex.synchronize{yield}
283
283
  end
284
284
 
285
- CONNECTION_POOL_MAP[[false, false]] = self
285
+ CONNECTION_POOL__MAP[[false, false]] = self
286
286
  end
@@ -220,14 +220,14 @@ module Sequel
220
220
 
221
221
  # Disconnects all available connections from the connection pool. Any
222
222
  # connections currently in use will not be disconnected. Options:
223
- # :servers :: Should be a symbol specifing the server to disconnect from,
223
+ # :server :: Should be a symbol specifing the server to disconnect from,
224
224
  # or an array of symbols to specify multiple servers.
225
225
  #
226
226
  # Example:
227
227
  #
228
228
  # DB.disconnect # All servers
229
- # DB.disconnect(:servers=>:server1) # Single server
230
- # DB.disconnect(:servers=>[:server1, :server2]) # Multiple servers
229
+ # DB.disconnect(:server=>:server1) # Single server
230
+ # DB.disconnect(:server=>[:server1, :server2]) # Multiple servers
231
231
  def disconnect(opts = OPTS)
232
232
  pool.disconnect(opts)
233
233
  end
@@ -69,6 +69,9 @@ module Sequel
69
69
  # This allows you to override any of the dataset methods even if they are
70
70
  # defined directly on the dataset class that this Database object uses.
71
71
  #
72
+ # If a block is given, a Dataset::DatasetModule instance is created, allowing
73
+ # for the easy creation of named dataset methods that will do caching.
74
+ #
72
75
  # Examples:
73
76
  #
74
77
  # # Introspec columns for all of DB's datasets
@@ -82,9 +85,19 @@ module Sequel
82
85
  # super
83
86
  # end
84
87
  # end
88
+ #
89
+ # # Add some named dataset methods
90
+ # DB.extend_datasets do
91
+ # order :by_id, :id
92
+ # select :with_id_and_name, :id, :name
93
+ # where :active, :active
94
+ # end
95
+ #
96
+ # DB[:table].active.with_id_and_name.by_id
97
+ # # SELECT id, name FROM table WHERE active ORDER BY id
85
98
  def extend_datasets(mod=nil, &block)
86
99
  raise(Error, "must provide either mod or block, not both") if mod && block
87
- mod = Module.new(&block) if block
100
+ mod = Dataset::DatasetModule.new(&block) if block
88
101
  if @dataset_modules.empty?
89
102
  @dataset_modules = [mod]
90
103
  @dataset_class = Class.new(@dataset_class)
@@ -42,5 +42,5 @@ module Sequel
42
42
  include SQL::StringMethods
43
43
  end
44
44
 
45
- require(%w"query actions features graph prepared_statements misc mutation sql placeholder_literalizer", 'dataset')
45
+ require(%w"query actions features graph prepared_statements misc mutation sql placeholder_literalizer dataset_module", 'dataset')
46
46
  end
@@ -15,6 +15,7 @@ module Sequel
15
15
  empty? fetch_rows first first! get import insert interval last
16
16
  map max min multi_insert paged_each range select_hash select_hash_groups select_map select_order_map
17
17
  single_record single_record! single_value single_value! sum to_hash to_hash_groups truncate update
18
+ where_all where_each where_single_value
18
19
  METHS
19
20
  # SEQUEL5: Remove interval, range
20
21
 
@@ -917,6 +918,52 @@ module Sequel
917
918
  end
918
919
  end
919
920
 
921
+ # Return an array of all rows matching the given filter condition, also
922
+ # yielding each row to the given block. Basically the same as where(cond).all(&block),
923
+ # except it can be optimized to not create an intermediate dataset.
924
+ #
925
+ # DB[:table].where_all(:id=>[1,2,3])
926
+ # # SELECT * FROM table WHERE (id IN (1, 2, 3))
927
+ def where_all(cond, &block)
928
+ if loader = _where_loader
929
+ loader.all(filter_expr(cond), &block)
930
+ else
931
+ where(cond).all(&block)
932
+ end
933
+ end
934
+
935
+ # Iterate over all rows matching the given filter condition,
936
+ # yielding each row to the given block. Basically the same as where(cond).each(&block),
937
+ # except it can be optimized to not create an intermediate dataset.
938
+ #
939
+ # DB[:table].where_each(:id=>[1,2,3]){|row| p row}
940
+ # # SELECT * FROM table WHERE (id IN (1, 2, 3))
941
+ def where_each(cond, &block)
942
+ if loader = _where_loader
943
+ loader.each(filter_expr(cond), &block)
944
+ else
945
+ where(cond).each(&block)
946
+ end
947
+ end
948
+
949
+ # Filter the datasets using the given filter condition, then return a single value.
950
+ # This assumes that the dataset has already been setup to limit the selection to
951
+ # a single column. Basically the same as where(cond).single_value,
952
+ # except it can be optimized to not create an intermediate dataset.
953
+ #
954
+ # DB[:table].select(:name).where_single_value(:id=>1)
955
+ # # SELECT name FROM table WHERE (id = 1) LIMIT 1
956
+ def where_single_value(cond)
957
+ if loader = cached_placeholder_literalizer(:_where_single_value_loader) do |pl|
958
+ single_value_ds.where(pl.arg)
959
+ end
960
+
961
+ loader.get(filter_expr(cond))
962
+ else
963
+ where(cond).single_value
964
+ end
965
+ end
966
+
920
967
  # Run the given SQL and return an array of all rows. If a block is given,
921
968
  # each row is yielded to the block after all rows are loaded. See with_sql_each.
922
969
  def with_sql_all(sql, &block)
@@ -1044,6 +1091,13 @@ module Sequel
1044
1091
  cached_dataset(:_single_record_ds){clone(:limit=>1)}
1045
1092
  end
1046
1093
 
1094
+ # Loader used for where_all and where_each.
1095
+ def _where_loader
1096
+ cached_placeholder_literalizer(:_where_loader) do |pl|
1097
+ where(pl.arg)
1098
+ end
1099
+ end
1100
+
1047
1101
  # Automatically alias the given expression if it does not have an identifiable alias.
1048
1102
  def auto_alias_expression(v)
1049
1103
  case v
@@ -0,0 +1,58 @@
1
+ # frozen-string-literal: true
2
+
3
+ module Sequel
4
+ class Dataset
5
+ # This Module subclass is used by Database#extend_datasets
6
+ # and Dataset#with_extend to add dataset methods to classes.
7
+ # It adds some helper methods inside the module that can define
8
+ # named methods on the dataset instances which do specific actions.
9
+ # For example:
10
+ #
11
+ # DB.extend_datasets do
12
+ # order :by_id, :id
13
+ # select :with_id_and_name, :id, :name
14
+ # where :active, :active
15
+ # end
16
+ #
17
+ # DB[:table].active.with_id_and_name.by_id
18
+ # # SELECT id, name FROM table WHERE active ORDER BY id
19
+ class DatasetModule < ::Module
20
+ %w'where exclude exclude_having having'.map(&:to_sym).each do |meth|
21
+ define_method(meth) do |name, *args, &block|
22
+ if block || args.flatten.any?{|arg| arg.is_a?(Proc)}
23
+ define_method(name){send(meth, *args, &block)}
24
+ else
25
+ key = :"_#{meth}_#{name}_ds"
26
+ define_method(name) do
27
+ cached_dataset(key){send(meth, *args)}
28
+ end
29
+ end
30
+ end
31
+ end
32
+
33
+ meths = (<<-METHS).split.map(&:to_sym)
34
+ distinct grep group group_and_count group_append
35
+ limit offset order order_append order_prepend
36
+ select select_all select_append select_group server
37
+ METHS
38
+
39
+ # Define a method in the module
40
+ def self.def_dataset_caching_method(mod, meth)
41
+ mod.send(:define_method, meth) do |name, *args, &block|
42
+ if block
43
+ define_method(name){send(meth, *args, &block)}
44
+ else
45
+ key = :"_#{meth}_#{name}_ds"
46
+ define_method(name) do
47
+ cached_dataset(key){send(meth, *args)}
48
+ end
49
+ end
50
+ end
51
+ end
52
+
53
+ meths.each do |meth|
54
+ def_dataset_caching_method(self, meth)
55
+ end
56
+ end
57
+ end
58
+ end
@@ -1087,12 +1087,12 @@ module Sequel
1087
1087
  # Return a clone of the dataset extended with the given modules.
1088
1088
  # Note that like Object#extend, when multiple modules are provided
1089
1089
  # as arguments the cloned dataset is extended with the modules in reverse
1090
- # order. If a block is provided, a module is created using the block and
1090
+ # order. If a block is provided, a DatasetModule is created using the block and
1091
1091
  # the clone is extended with that module after any modules given as arguments.
1092
1092
  def with_extend(*mods, &block)
1093
1093
  c = _clone(:freeze=>false)
1094
1094
  c.extend(*mods) unless mods.empty?
1095
- c.extend(Module.new(&block)) if block
1095
+ c.extend(DatasetModule.new(&block)) if block
1096
1096
  c.freeze if frozen? # SEQUEL5: Remove if frozen?
1097
1097
  c
1098
1098
  end
@@ -1101,7 +1101,7 @@ module Sequel
1101
1101
  def with_extend(*mods, &block) # :nodoc:
1102
1102
  c = clone
1103
1103
  c.extend(*mods) unless mods.empty?
1104
- c.extend(Module.new(&block)) if block
1104
+ c.extend(DatasetModule.new(&block)) if block
1105
1105
  c
1106
1106
  end
1107
1107
  # :nocov:
@@ -7,6 +7,14 @@ module Sequel
7
7
  # If this exception wraps an underlying exception, the underlying
8
8
  # exception is held here.
9
9
  attr_accessor :wrapped_exception
10
+
11
+ if RUBY_VERSION >= '2.1'
12
+ # Returned the wrapped exception if one exists, otherwise use
13
+ # ruby's default behavior.
14
+ def cause
15
+ wrapped_exception || super
16
+ end
17
+ end
10
18
  end
11
19
 
12
20
  (
@@ -5,14 +5,17 @@ module Sequel
5
5
  module PgRow
6
6
  module DatabaseMethods
7
7
  ESCAPE_RE = /("|\\)/.freeze
8
+ Sequel::Deprecation.deprecate_constant(self, :ESCAPE_RE)
8
9
  ESCAPE_REPLACEMENT = '\\\\\1'.freeze
10
+ Sequel::Deprecation.deprecate_constant(self, :ESCAPE_REPLACEMENT)
9
11
  COMMA = ','
12
+ Sequel::Deprecation.deprecate_constant(self, :COMMA)
10
13
 
11
14
  # Handle Sequel::Model instances in bound variables.
12
15
  def bound_variable_arg(arg, conn)
13
16
  case arg
14
17
  when Sequel::Model
15
- "(#{arg.values.values_at(*arg.columns).map{|v| bound_variable_array(v)}.join(COMMA)})"
18
+ "(#{arg.values.values_at(*arg.columns).map{|v| bound_variable_array(v)}.join(',')})"
16
19
  else
17
20
  super
18
21
  end
@@ -34,7 +37,7 @@ module Sequel
34
37
  def bound_variable_array(arg)
35
38
  case arg
36
39
  when Sequel::Model
37
- "\"(#{arg.values.values_at(*arg.columns).map{|v| bound_variable_array(v)}.join(COMMA).gsub(ESCAPE_RE, ESCAPE_REPLACEMENT)})\""
40
+ "\"(#{arg.values.values_at(*arg.columns).map{|v| bound_variable_array(v)}.join(',').gsub(/("|\\)/, '\\\\\1')})\""
38
41
  else
39
42
  super
40
43
  end
@@ -32,7 +32,7 @@ module Sequel
32
32
  # Return an instance of Sequel.datetime_class that will be literalized
33
33
  # as CURRENT_TIMESTAMP.
34
34
  def current_datetime
35
- MAP.fetch(Sequel.datetime_class).now
35
+ (Sequel.datetime_class == ::Time ? Time : DateTime).now
36
36
  end
37
37
 
38
38
  private
@@ -56,6 +56,7 @@ module Sequel
56
56
 
57
57
  # Mapping of Time/DateTime classes to subclasses literalized as CURRENT_TIMESTAMP
58
58
  MAP = {::Time=>Time, ::DateTime=>DateTime}
59
+ Sequel::Deprecation.deprecate_constant(self, :MAP)
59
60
  end
60
61
 
61
62
  Dataset.register_extension(:current_datetime_timestamp, CurrentDateTimeTimestamp::DatasetMethods)