sequel 5.8.0 → 5.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +30 -0
  3. data/doc/release_notes/5.9.0.txt +99 -0
  4. data/doc/testing.rdoc +10 -10
  5. data/lib/sequel/adapters/ado.rb +1 -1
  6. data/lib/sequel/adapters/amalgalite.rb +1 -1
  7. data/lib/sequel/adapters/jdbc.rb +19 -7
  8. data/lib/sequel/adapters/jdbc/oracle.rb +1 -1
  9. data/lib/sequel/adapters/jdbc/postgresql.rb +0 -5
  10. data/lib/sequel/adapters/postgres.rb +3 -3
  11. data/lib/sequel/adapters/shared/access.rb +5 -6
  12. data/lib/sequel/adapters/shared/mysql.rb +28 -2
  13. data/lib/sequel/adapters/shared/postgres.rb +16 -6
  14. data/lib/sequel/adapters/shared/sqlite.rb +1 -1
  15. data/lib/sequel/adapters/sqlanywhere.rb +1 -1
  16. data/lib/sequel/adapters/sqlite.rb +2 -2
  17. data/lib/sequel/connection_pool.rb +2 -1
  18. data/lib/sequel/connection_pool/sharded_threaded.rb +12 -4
  19. data/lib/sequel/connection_pool/threaded.rb +19 -7
  20. data/lib/sequel/core.rb +1 -1
  21. data/lib/sequel/database/connecting.rb +6 -6
  22. data/lib/sequel/database/misc.rb +3 -3
  23. data/lib/sequel/database/query.rb +2 -2
  24. data/lib/sequel/database/schema_generator.rb +9 -3
  25. data/lib/sequel/database/schema_methods.rb +12 -5
  26. data/lib/sequel/dataset/features.rb +5 -0
  27. data/lib/sequel/dataset/misc.rb +1 -1
  28. data/lib/sequel/dataset/prepared_statements.rb +4 -4
  29. data/lib/sequel/dataset/query.rb +5 -0
  30. data/lib/sequel/dataset/sql.rb +8 -6
  31. data/lib/sequel/extensions/escaped_like.rb +100 -0
  32. data/lib/sequel/extensions/eval_inspect.rb +3 -1
  33. data/lib/sequel/extensions/looser_typecasting.rb +3 -3
  34. data/lib/sequel/extensions/pg_extended_date_support.rb +23 -10
  35. data/lib/sequel/model/associations.rb +18 -4
  36. data/lib/sequel/model/base.rb +9 -2
  37. data/lib/sequel/plugins/defaults_setter.rb +1 -1
  38. data/lib/sequel/plugins/many_through_many.rb +1 -1
  39. data/lib/sequel/plugins/nested_attributes.rb +2 -2
  40. data/lib/sequel/plugins/pg_auto_constraint_validations.rb +2 -2
  41. data/lib/sequel/plugins/rcte_tree.rb +5 -7
  42. data/lib/sequel/plugins/sharding.rb +2 -2
  43. data/lib/sequel/plugins/tactical_eager_loading.rb +1 -1
  44. data/lib/sequel/plugins/tree.rb +2 -2
  45. data/lib/sequel/plugins/validation_class_methods.rb +1 -1
  46. data/lib/sequel/sql.rb +2 -2
  47. data/lib/sequel/version.rb +4 -1
  48. data/spec/adapters/mysql_spec.rb +24 -0
  49. data/spec/adapters/postgres_spec.rb +9 -9
  50. data/spec/adapters/sqlite_spec.rb +10 -10
  51. data/spec/core/connection_pool_spec.rb +22 -0
  52. data/spec/core/database_spec.rb +6 -6
  53. data/spec/core/dataset_spec.rb +16 -5
  54. data/spec/core/expression_filters_spec.rb +1 -1
  55. data/spec/core/schema_spec.rb +1 -1
  56. data/spec/core/version_spec.rb +7 -0
  57. data/spec/extensions/connection_expiration_spec.rb +20 -2
  58. data/spec/extensions/connection_validator_spec.rb +20 -3
  59. data/spec/extensions/escaped_like_spec.rb +40 -0
  60. data/spec/extensions/eval_inspect_spec.rb +1 -1
  61. data/spec/extensions/nested_attributes_spec.rb +6 -0
  62. data/spec/extensions/pg_array_spec.rb +13 -13
  63. data/spec/extensions/pg_auto_constraint_validations_spec.rb +0 -1
  64. data/spec/extensions/pg_range_spec.rb +1 -1
  65. data/spec/extensions/schema_dumper_spec.rb +2 -2
  66. data/spec/extensions/sql_expr_spec.rb +1 -1
  67. data/spec/extensions/string_agg_spec.rb +1 -1
  68. data/spec/extensions/timestamps_spec.rb +2 -2
  69. data/spec/extensions/validation_helpers_spec.rb +1 -1
  70. data/spec/integration/associations_test.rb +12 -0
  71. data/spec/integration/dataset_test.rb +21 -0
  72. data/spec/integration/type_test.rb +4 -4
  73. data/spec/model/base_spec.rb +9 -0
  74. data/spec/model/eager_loading_spec.rb +25 -0
  75. data/spec/model/record_spec.rb +1 -1
  76. metadata +6 -2
@@ -60,7 +60,7 @@ module Sequel
60
60
  [17] => tt.method(:bytea),
61
61
  [20, 21, 23, 26] => tt.method(:integer),
62
62
  [700, 701] => tt.method(:float),
63
- [1700] => ::BigDecimal.method(:new),
63
+ [1700] => ::Kernel.method(:BigDecimal),
64
64
  [1083, 1266] => ::Sequel.method(:string_to_time),
65
65
  [1082] => ::Sequel.method(:string_to_date),
66
66
  [1184, 1114] => ::Sequel.method(:database_to_application_timestamp),
@@ -261,7 +261,7 @@ module Sequel
261
261
  raise Error, "convert_serial_to_identity is only supported on PostgreSQL 10.2+" unless server_version >= 100002
262
262
 
263
263
  server = opts[:server]
264
- server_hash = server ? {:server=>server} : {}
264
+ server_hash = server ? {:server=>server} : OPTS
265
265
  ds = dataset
266
266
  ds = ds.server(server) if server
267
267
 
@@ -269,7 +269,7 @@ module Sequel
269
269
 
270
270
  table_oid = regclass_oid(table)
271
271
  im = input_identifier_meth
272
- unless column = im.call(opts[:column] || ((sch = schema(table).find{|col, sch| sch[:primary_key] && sch[:auto_increment]}) && sch[0]))
272
+ unless column = im.call(opts[:column] || ((sch = schema(table).find{|_, sc| sc[:primary_key] && sc[:auto_increment]}) && sch[0]))
273
273
  raise Error, "could not determine column to convert from serial to identity automatically"
274
274
  end
275
275
 
@@ -482,6 +482,10 @@ module Sequel
482
482
  nsp[:nspname].as(:schema)
483
483
  ]}
484
484
 
485
+ if reverse
486
+ ds = ds.order_append(Sequel[:nsp][:nspname], Sequel[:cl2][:relname])
487
+ end
488
+
485
489
  h = {}
486
490
  fklod_map = FOREIGN_KEY_LIST_ON_DELETE_MAP
487
491
 
@@ -1689,8 +1693,8 @@ module Sequel
1689
1693
  end
1690
1694
 
1691
1695
  # Return a clone of the dataset with an addition named window that can be
1692
- # referenced in window functions. See {SQL::Window} for a list of options
1693
- # that can be passed in.
1696
+ # referenced in window functions. See Sequel::SQL::Window for a list of
1697
+ # options that can be passed in.
1694
1698
  def window(name, opts)
1695
1699
  clone(:window=>(@opts[:window]||[]) + [[name, SQL::Window.new(opts)]])
1696
1700
  end
@@ -1718,7 +1722,7 @@ module Sequel
1718
1722
 
1719
1723
  # Format TRUNCATE statement with PostgreSQL specific options.
1720
1724
  def _truncate_sql(table)
1721
- to = @opts[:truncate_opts] || {}
1725
+ to = @opts[:truncate_opts] || OPTS
1722
1726
  "TRUNCATE TABLE#{' ONLY' if to[:only]} #{table}#{' RESTART IDENTITY' if to[:restart]}#{' CASCADE' if to[:cascade]}"
1723
1727
  end
1724
1728
 
@@ -1855,6 +1859,12 @@ module Sequel
1855
1859
  sql << ')'
1856
1860
  end
1857
1861
 
1862
+ # Backslash is supported by default as the escape character on PostgreSQL,
1863
+ # and using ESCAPE can break LIKE ANY() usage.
1864
+ def requires_like_escape?
1865
+ false
1866
+ end
1867
+
1858
1868
  # Support FOR SHARE locking when using the :share lock style.
1859
1869
  # Use SKIP LOCKED if skipping locked rows.
1860
1870
  def select_lock_sql(sql)
@@ -328,7 +328,7 @@ module Sequel
328
328
 
329
329
  # The array of column schema hashes for the current columns in the table
330
330
  def defined_columns_for(table)
331
- cols = parse_pragma(table, {})
331
+ cols = parse_pragma(table, OPTS)
332
332
  cols.each do |c|
333
333
  c[:default] = LiteralString.new(c[:default]) if c[:default]
334
334
  c[:type] = c[:db_type]
@@ -21,7 +21,7 @@ module Sequel
21
21
  def blob(s) ::Sequel::SQL::Blob.new(s) end
22
22
  def boolean(s) s.to_i != 0 end
23
23
  def date(s) ::Date.strptime(s) end
24
- def decimal(s) ::BigDecimal.new(s) end
24
+ def decimal(s) BigDecimal(s) end
25
25
  def time(s) ::Sequel.string_to_time(s) end
26
26
  end.new
27
27
 
@@ -40,7 +40,7 @@ module Sequel
40
40
 
41
41
  def numeric(s)
42
42
  s = s.to_s unless s.is_a?(String)
43
- ::BigDecimal.new(s) rescue s
43
+ BigDecimal(s) rescue s
44
44
  end
45
45
 
46
46
  def time(s)
@@ -181,7 +181,7 @@ module Sequel
181
181
  return execute_prepared_statement(conn, type, sql, opts, &block) if sql.is_a?(Symbol)
182
182
  log_args = opts[:arguments]
183
183
  args = {}
184
- opts.fetch(:arguments, {}).each{|k, v| args[k] = prepared_statement_argument(v)}
184
+ opts.fetch(:arguments, OPTS).each{|k, v| args[k] = prepared_statement_argument(v)}
185
185
  case type
186
186
  when :select
187
187
  log_connection_yield(sql, conn, log_args){conn.query(sql, args, &block)}
@@ -109,7 +109,8 @@ class Sequel::ConnectionPool
109
109
 
110
110
  private
111
111
 
112
- # Remove the connection from the pool.
112
+ # Remove the connection from the pool. For threaded connections, this should be
113
+ # called without the mutex, because the disconnection may block.
113
114
  def disconnect_connection(conn)
114
115
  db.disconnect_connection(conn)
115
116
  end
@@ -19,6 +19,7 @@ class Sequel::ShardedThreadedConnectionPool < Sequel::ThreadedConnectionPool
19
19
  super
20
20
  @available_connections = {}
21
21
  @connections_to_remove = []
22
+ @connections_to_disconnect = []
22
23
  @servers = opts.fetch(:servers_hash, Hash.new(:default))
23
24
  remove_instance_variable(:@waiter)
24
25
  @waiters = {}
@@ -130,6 +131,9 @@ class Sequel::ShardedThreadedConnectionPool < Sequel::ThreadedConnectionPool
130
131
  raise
131
132
  ensure
132
133
  sync{release(t, conn, server)} if conn
134
+ while dconn = sync{@connections_to_disconnect.shift}
135
+ disconnect_connection(dconn)
136
+ end
133
137
  end
134
138
  end
135
139
 
@@ -201,7 +205,7 @@ class Sequel::ShardedThreadedConnectionPool < Sequel::ThreadedConnectionPool
201
205
 
202
206
  # :nocov:
203
207
  # It's difficult to get to this point, it can only happen if there is a race condition
204
- # where a connection cannot be acquired even after the thread is signalled by the condition
208
+ # where a connection cannot be acquired even after the thread is signalled by the condition variable
205
209
  sync do
206
210
  @waiters[server].wait(@mutex, timeout - elapsed)
207
211
  if conn = next_available(server)
@@ -227,7 +231,11 @@ class Sequel::ShardedThreadedConnectionPool < Sequel::ThreadedConnectionPool
227
231
  end
228
232
 
229
233
  if (n = _size(server)) >= (max = @max_size)
230
- alloc.to_a.each{|t,c| release(t, c, server) unless t.alive?}
234
+ alloc.to_a.each do |t,c|
235
+ unless t.alive?
236
+ remove(t, c, server)
237
+ end
238
+ end
231
239
  n = nil
232
240
  end
233
241
 
@@ -339,7 +347,7 @@ class Sequel::ShardedThreadedConnectionPool < Sequel::ThreadedConnectionPool
339
347
  conn = allocated(server).delete(thread)
340
348
 
341
349
  if @connection_handling == :disconnect
342
- disconnect_connection(conn)
350
+ @connections_to_disconnect << conn
343
351
  else
344
352
  checkin_connection(server, conn)
345
353
  end
@@ -355,6 +363,6 @@ class Sequel::ShardedThreadedConnectionPool < Sequel::ThreadedConnectionPool
355
363
  def remove(thread, conn, server)
356
364
  @connections_to_remove.delete(conn)
357
365
  allocated(server).delete(thread) if @servers.include?(server)
358
- disconnect_connection(conn)
366
+ @connections_to_disconnect << conn
359
367
  end
360
368
  end
@@ -101,7 +101,12 @@ class Sequel::ThreadedConnectionPool < Sequel::ConnectionPool
101
101
  end
102
102
  raise
103
103
  ensure
104
- sync{release(t)} if conn
104
+ if conn
105
+ sync{release(t)}
106
+ if @connection_handling == :disconnect
107
+ disconnect_connection(conn)
108
+ end
109
+ end
105
110
  end
106
111
  end
107
112
 
@@ -150,7 +155,7 @@ class Sequel::ThreadedConnectionPool < Sequel::ConnectionPool
150
155
 
151
156
  # :nocov:
152
157
  # It's difficult to get to this point, it can only happen if there is a race condition
153
- # where a connection cannot be acquired even after the thread is signalled by the condition
158
+ # where a connection cannot be acquired even after the thread is signalled by the condition variable
154
159
  sync do
155
160
  @waiter.wait(@mutex, timeout - elapsed)
156
161
  if conn = next_available
@@ -167,15 +172,20 @@ class Sequel::ThreadedConnectionPool < Sequel::ConnectionPool
167
172
  # The caller should NOT have the mutex before calling this.
168
173
  def assign_connection(thread)
169
174
  allocated = @allocated
170
-
171
175
  do_make_new = false
176
+ to_disconnect = nil
177
+
172
178
  sync do
173
179
  if conn = next_available
174
180
  return(allocated[thread] = conn)
175
181
  end
176
182
 
177
183
  if (n = _size) >= (max = @max_size)
178
- allocated.keys.each{|t| release(t) unless t.alive?}
184
+ allocated.keys.each do |t|
185
+ unless t.alive?
186
+ (to_disconnect ||= []) << @allocated.delete(t)
187
+ end
188
+ end
179
189
  n = nil
180
190
  end
181
191
 
@@ -184,6 +194,10 @@ class Sequel::ThreadedConnectionPool < Sequel::ConnectionPool
184
194
  end
185
195
  end
186
196
 
197
+ if to_disconnect
198
+ to_disconnect.each{|dconn| disconnect_connection(dconn)}
199
+ end
200
+
187
201
  # Connect to the database outside of the connection pool mutex,
188
202
  # as that can take a long time and the connection pool mutex
189
203
  # shouldn't be locked while the connection takes place.
@@ -252,9 +266,7 @@ class Sequel::ThreadedConnectionPool < Sequel::ConnectionPool
252
266
  def release(thread)
253
267
  conn = @allocated.delete(thread)
254
268
 
255
- if @connection_handling == :disconnect
256
- disconnect_connection(conn)
257
- else
269
+ unless @connection_handling == :disconnect
258
270
  checkin_connection(conn)
259
271
  end
260
272
 
@@ -384,7 +384,7 @@ module Sequel
384
384
  # Helper method that the database adapter class methods that are added to Sequel via
385
385
  # metaprogramming use to parse arguments.
386
386
  def self.adapter_method(adapter, *args, &block)
387
- options = args.last.is_a?(Hash) ? args.pop : {}
387
+ options = args.last.is_a?(Hash) ? args.pop : OPTS
388
388
  opts = {:adapter => adapter.to_sym}
389
389
  opts[:database] = args.shift if args.first.is_a?(String)
390
390
  if args.any?
@@ -248,6 +248,12 @@ module Sequel
248
248
  end
249
249
 
250
250
  if RUBY_ENGINE == 'ruby' && RUBY_VERSION < '2.5'
251
+ # :nocov:
252
+ def synchronize(server=nil)
253
+ @pool.hold(server || :default){|conn| yield conn}
254
+ end
255
+ # :nocov:
256
+ else
251
257
  # Acquires a database connection, yielding it to the passed block. This is
252
258
  # useful if you want to make sure the same connection is used for all
253
259
  # database queries in the block. It is also useful if you want to gain
@@ -260,15 +266,9 @@ module Sequel
260
266
  # DB.synchronize do |conn|
261
267
  # # ...
262
268
  # end
263
- def synchronize(server=nil)
264
- @pool.hold(server || :default){|conn| yield conn}
265
- end
266
- else
267
- # :nocov:
268
269
  def synchronize(server=nil, &block)
269
270
  @pool.hold(server || :default, &block)
270
271
  end
271
- # :nocov:
272
272
  end
273
273
 
274
274
  # Attempts to acquire a database connection. Returns true if successful.
@@ -461,12 +461,12 @@ module Sequel
461
461
  if RUBY_VERSION >= '2.4'
462
462
  # Typecast a string to a BigDecimal
463
463
  def _typecast_value_string_to_decimal(value)
464
- BigDecimal.new(value)
464
+ BigDecimal(value)
465
465
  end
466
466
  else
467
467
  # :nocov:
468
468
  def _typecast_value_string_to_decimal(value)
469
- d = BigDecimal.new(value)
469
+ d = BigDecimal(value)
470
470
  if d.zero?
471
471
  # BigDecimal parsing is loose by default, returning a 0 value for
472
472
  # invalid input. If a zero value is received, use Float to check
@@ -488,7 +488,7 @@ module Sequel
488
488
  when BigDecimal
489
489
  value
490
490
  when Numeric
491
- BigDecimal.new(value.to_s)
491
+ BigDecimal(value.to_s)
492
492
  when String
493
493
  _typecast_value_string_to_decimal(value)
494
494
  else
@@ -32,7 +32,7 @@ module Sequel
32
32
  #
33
33
  # DB[:items].where(id: 1).prepare(:first, :sa)
34
34
  # DB.call(:sa) # SELECT * FROM items WHERE id = 1
35
- def call(ps_name, hash={}, &block)
35
+ def call(ps_name, hash=OPTS, &block)
36
36
  prepared_statement(ps_name).call(hash, &block)
37
37
  end
38
38
 
@@ -240,7 +240,7 @@ module Sequel
240
240
  when :time
241
241
  Sequel.string_to_time(default)
242
242
  when :decimal
243
- BigDecimal.new(default)
243
+ BigDecimal(default)
244
244
  end
245
245
  end
246
246
 
@@ -67,7 +67,7 @@ module Sequel
67
67
  method = type.to_s
68
68
  end
69
69
 
70
- define_method(method){|name, opts={}| column(name, type, opts)}
70
+ define_method(method){|name, opts=OPTS| column(name, type, opts)}
71
71
  end
72
72
  nil
73
73
  end
@@ -130,10 +130,16 @@ module Sequel
130
130
  # :unique :: Mark the column as unique, generally has the same effect as
131
131
  # creating a unique index on the column.
132
132
  # :unique_constraint_name :: The name to give the unique key constraint
133
+ #
134
+ # MySQL specific options:
135
+ # :generated_always_as :: Specify a GENERATED ALWAYS AS column expression,
136
+ # if generated columns are supported.
137
+ # :generated_type :: Set the type of column when using :generated_always_as,
138
+ # should be :virtual or :stored to force a type.
133
139
  def column(name, type, opts = OPTS)
134
140
  columns << {:name => name, :type => type}.merge!(opts)
135
141
  if index_opts = opts[:index]
136
- index(name, index_opts.is_a?(Hash) ? index_opts : {})
142
+ index(name, index_opts.is_a?(Hash) ? index_opts : OPTS)
137
143
  end
138
144
  nil
139
145
  end
@@ -311,7 +317,7 @@ module Sequel
311
317
 
312
318
  # Add a composite primary key constraint
313
319
  def composite_primary_key(columns, *args)
314
- opts = args.pop || {}
320
+ opts = args.pop || OPTS
315
321
  constraints << {:type => :primary_key, :columns => columns}.merge!(opts)
316
322
  nil
317
323
  end
@@ -80,7 +80,7 @@ module Sequel
80
80
  # Create a join table using a hash of foreign keys to referenced
81
81
  # table names. Example:
82
82
  #
83
- # create_join_table:cat_id: :cats, dog_id: :dogs)
83
+ # create_join_table(cat_id: :cats, dog_id: :dogs)
84
84
  # # CREATE TABLE cats_dogs (
85
85
  # # cat_id integer NOT NULL REFERENCES cats,
86
86
  # # dog_id integer NOT NULL REFERENCES dogs,
@@ -93,6 +93,13 @@ module Sequel
93
93
  # key ensures that entries in the table are unique, which is the typical
94
94
  # desire for a join table.
95
95
  #
96
+ # The default table name this will create is the sorted version of the two
97
+ # hash values, joined by an underscore. So the following two method calls
98
+ # create the same table:
99
+ #
100
+ # create_join_table(cat_id: :cats, dog_id: :dogs) # cats_dogs
101
+ # create_join_table(dog_id: :dogs, cat_id: :cats) # cats_dogs
102
+ #
96
103
  # You can provide column options by making the values in the hash
97
104
  # be option hashes, so long as the option hashes have a :table
98
105
  # entry giving the table referenced:
@@ -121,7 +128,7 @@ module Sequel
121
128
  foreign_key(key, v)
122
129
  end
123
130
  primary_key(keys) unless options[:no_primary_key]
124
- index(keys.reverse, options[:index_options] || {}) unless options[:no_index]
131
+ index(keys.reverse, options[:index_options] || OPTS) unless options[:no_index]
125
132
  end
126
133
  nil
127
134
  end
@@ -314,7 +321,7 @@ module Sequel
314
321
  # DB.drop_table(:posts, :comments)
315
322
  # DB.drop_table(:posts, :comments, cascade: true)
316
323
  def drop_table(*names)
317
- options = names.last.is_a?(Hash) ? names.pop : {}
324
+ options = names.last.is_a?(Hash) ? names.pop : OPTS
318
325
  names.each do |n|
319
326
  execute_ddl(drop_table_sql(n, options))
320
327
  remove_cached_schema(n)
@@ -329,7 +336,7 @@ module Sequel
329
336
  # # SELECT NULL FROM a LIMIT 1 -- check existence
330
337
  # # DROP TABLE a -- if it already exists
331
338
  def drop_table?(*names)
332
- options = names.last.is_a?(Hash) ? names.pop : {}
339
+ options = names.last.is_a?(Hash) ? names.pop : OPTS
333
340
  if supports_drop_table_if_exists?
334
341
  options = options.merge(:if_exists=>true)
335
342
  names.each do |name|
@@ -357,7 +364,7 @@ module Sequel
357
364
  # PostgreSQL specific options:
358
365
  # :materialized :: Drop a materialized view.
359
366
  def drop_view(*names)
360
- options = names.last.is_a?(Hash) ? names.pop : {}
367
+ options = names.last.is_a?(Hash) ? names.pop : OPTS
361
368
  names.each do |n|
362
369
  execute_ddl(drop_view_sql(n, options))
363
370
  remove_cached_schema(n)
@@ -197,6 +197,11 @@ module Sequel
197
197
  true
198
198
  end
199
199
 
200
+ # Whether the dataset needs ESCAPE for LIKE for correct behavior.
201
+ def requires_like_escape?
202
+ true
203
+ end
204
+
200
205
  # Whether common table expressions are supported in UNION/INTERSECT/EXCEPT clauses.
201
206
  def supports_cte_in_compounds?
202
207
  supports_cte_in_subqueries?
@@ -226,7 +226,7 @@ module Sequel
226
226
  used_aliases += opts[:join].map{|j| j.table_alias ? alias_alias_symbol(j.table_alias) : alias_symbol(j.table)} if opts[:join]
227
227
  if used_aliases.include?(table_alias)
228
228
  i = 0
229
- loop do
229
+ while true
230
230
  ta = :"#{table_alias}_#{i}"
231
231
  return ta unless used_aliases.include?(ta)
232
232
  i += 1
@@ -52,7 +52,7 @@ module Sequel
52
52
  end
53
53
 
54
54
  # Set the bind arguments based on the hash and call super.
55
- def call(bind_vars={}, &block)
55
+ def call(bind_vars=OPTS, &block)
56
56
  sql = prepared_sql
57
57
  prepared_args.freeze
58
58
  ps = bind(bind_vars)
@@ -106,7 +106,7 @@ module Sequel
106
106
 
107
107
  # Sets the prepared_args to the given hash and runs the
108
108
  # prepared statement.
109
- def call(bind_vars={}, &block)
109
+ def call(bind_vars=OPTS, &block)
110
110
  bind(bind_vars).run(&block)
111
111
  end
112
112
 
@@ -272,7 +272,7 @@ module Sequel
272
272
  # DB[:table].where(id: :$id).bind(id: 1).call(:first)
273
273
  # # SELECT * FROM table WHERE id = ? LIMIT 1 -- (1)
274
274
  # # => {:id=>1}
275
- def bind(bind_vars={})
275
+ def bind(bind_vars=OPTS)
276
276
  bind_vars = if bv = @opts[:bind_vars]
277
277
  Hash[bv].merge!(bind_vars).freeze
278
278
  else
@@ -293,7 +293,7 @@ module Sequel
293
293
  # DB[:table].where(id: :$id).call(:first, id: 1)
294
294
  # # SELECT * FROM table WHERE id = ? LIMIT 1 -- (1)
295
295
  # # => {:id=>1}
296
- def call(type, bind_variables={}, *values, &block)
296
+ def call(type, bind_variables=OPTS, *values, &block)
297
297
  to_prepared_statement(type, values, :extend=>bound_variable_modules).call(bind_variables, &block)
298
298
  end
299
299