sequel 3.5.0 → 3.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. data/CHANGELOG +108 -0
  2. data/README.rdoc +25 -14
  3. data/Rakefile +20 -1
  4. data/doc/advanced_associations.rdoc +61 -64
  5. data/doc/cheat_sheet.rdoc +16 -7
  6. data/doc/opening_databases.rdoc +3 -3
  7. data/doc/prepared_statements.rdoc +1 -1
  8. data/doc/reflection.rdoc +2 -1
  9. data/doc/release_notes/3.6.0.txt +366 -0
  10. data/doc/schema.rdoc +19 -14
  11. data/lib/sequel/adapters/amalgalite.rb +5 -27
  12. data/lib/sequel/adapters/jdbc.rb +13 -3
  13. data/lib/sequel/adapters/jdbc/h2.rb +17 -0
  14. data/lib/sequel/adapters/jdbc/mysql.rb +20 -7
  15. data/lib/sequel/adapters/mysql.rb +4 -3
  16. data/lib/sequel/adapters/oracle.rb +1 -1
  17. data/lib/sequel/adapters/postgres.rb +87 -28
  18. data/lib/sequel/adapters/shared/mssql.rb +47 -6
  19. data/lib/sequel/adapters/shared/mysql.rb +12 -31
  20. data/lib/sequel/adapters/shared/postgres.rb +15 -12
  21. data/lib/sequel/adapters/shared/sqlite.rb +18 -0
  22. data/lib/sequel/adapters/sqlite.rb +1 -16
  23. data/lib/sequel/connection_pool.rb +1 -1
  24. data/lib/sequel/core.rb +1 -1
  25. data/lib/sequel/database.rb +1 -1
  26. data/lib/sequel/database/schema_generator.rb +2 -0
  27. data/lib/sequel/database/schema_sql.rb +1 -1
  28. data/lib/sequel/dataset.rb +5 -179
  29. data/lib/sequel/dataset/actions.rb +123 -0
  30. data/lib/sequel/dataset/convenience.rb +18 -10
  31. data/lib/sequel/dataset/features.rb +65 -0
  32. data/lib/sequel/dataset/prepared_statements.rb +29 -23
  33. data/lib/sequel/dataset/query.rb +429 -0
  34. data/lib/sequel/dataset/sql.rb +67 -435
  35. data/lib/sequel/model/associations.rb +77 -13
  36. data/lib/sequel/model/base.rb +30 -8
  37. data/lib/sequel/model/errors.rb +4 -4
  38. data/lib/sequel/plugins/caching.rb +38 -15
  39. data/lib/sequel/plugins/force_encoding.rb +18 -7
  40. data/lib/sequel/plugins/hook_class_methods.rb +4 -0
  41. data/lib/sequel/plugins/many_through_many.rb +1 -1
  42. data/lib/sequel/plugins/nested_attributes.rb +40 -11
  43. data/lib/sequel/plugins/serialization.rb +17 -3
  44. data/lib/sequel/plugins/validation_helpers.rb +65 -18
  45. data/lib/sequel/sql.rb +23 -1
  46. data/lib/sequel/version.rb +1 -1
  47. data/spec/adapters/mssql_spec.rb +96 -10
  48. data/spec/adapters/mysql_spec.rb +19 -0
  49. data/spec/adapters/postgres_spec.rb +65 -2
  50. data/spec/adapters/sqlite_spec.rb +10 -0
  51. data/spec/core/core_sql_spec.rb +9 -0
  52. data/spec/core/database_spec.rb +8 -4
  53. data/spec/core/dataset_spec.rb +122 -29
  54. data/spec/core/expression_filters_spec.rb +17 -0
  55. data/spec/extensions/caching_spec.rb +43 -3
  56. data/spec/extensions/force_encoding_spec.rb +43 -1
  57. data/spec/extensions/nested_attributes_spec.rb +55 -2
  58. data/spec/extensions/validation_helpers_spec.rb +71 -0
  59. data/spec/integration/associations_test.rb +281 -0
  60. data/spec/integration/dataset_test.rb +383 -9
  61. data/spec/integration/eager_loader_test.rb +0 -65
  62. data/spec/integration/model_test.rb +110 -0
  63. data/spec/integration/plugin_test.rb +306 -0
  64. data/spec/integration/prepared_statement_test.rb +32 -0
  65. data/spec/integration/schema_test.rb +8 -3
  66. data/spec/integration/spec_helper.rb +1 -25
  67. data/spec/model/association_reflection_spec.rb +38 -0
  68. data/spec/model/associations_spec.rb +184 -8
  69. data/spec/model/eager_loading_spec.rb +23 -0
  70. data/spec/model/model_spec.rb +8 -0
  71. data/spec/model/record_spec.rb +84 -1
  72. metadata +9 -2
@@ -1,4 +1,7 @@
1
1
  module Sequel
2
+ Dataset::NON_SQL_OPTIONS << :insert_ignore
3
+ Dataset::NON_SQL_OPTIONS << :on_duplicate_key_update
4
+
2
5
  module MySQL
3
6
  class << self
4
7
  # Set the default options used for CREATE TABLE
@@ -311,37 +314,7 @@ module Sequel
311
314
  # MySQL specific syntax for REPLACE (aka UPSERT, or update if exists,
312
315
  # insert if it doesn't).
313
316
  def replace_sql(*values)
314
- from = source_list(@opts[:from])
315
- if values.empty?
316
- "REPLACE INTO #{from} DEFAULT VALUES"
317
- else
318
- values = values[0] if values.size == 1
319
-
320
- case values
321
- when Array
322
- if values.empty?
323
- "REPLACE INTO #{from} DEFAULT VALUES"
324
- else
325
- "REPLACE INTO #{from} VALUES #{literal(values)}"
326
- end
327
- when Hash
328
- if values.empty?
329
- "REPLACE INTO #{from} DEFAULT VALUES"
330
- else
331
- fl, vl = [], []
332
- values.each {|k, v| fl << literal(k.is_a?(String) ? k.to_sym : k); vl << literal(v)}
333
- "REPLACE INTO #{from} (#{fl.join(COMMA_SEPARATOR)}) VALUES (#{vl.join(COMMA_SEPARATOR)})"
334
- end
335
- when Dataset
336
- "REPLACE INTO #{from} #{literal(values)}"
337
- else
338
- if values.respond_to?(:values)
339
- replace_sql(values.values)
340
- else
341
- "REPLACE INTO #{from} VALUES (#{literal(values)})"
342
- end
343
- end
344
- end
317
+ clone(:replace=>true).insert_sql(*values)
345
318
  end
346
319
 
347
320
  # does not support DISTINCT ON
@@ -360,6 +333,13 @@ module Sequel
360
333
  def supports_timestamp_usecs?
361
334
  false
362
335
  end
336
+
337
+ protected
338
+
339
+ # If this is an replace instead of an insert, use replace instead
340
+ def _insert_sql
341
+ @opts[:replace] ? clause_sql(:replace) : super
342
+ end
363
343
 
364
344
  private
365
345
 
@@ -372,6 +352,7 @@ module Sequel
372
352
  def insert_clause_methods
373
353
  INSERT_CLAUSE_METHODS
374
354
  end
355
+ alias replace_clause_methods insert_clause_methods
375
356
 
376
357
  # MySQL doesn't use the SQL standard DEFAULT VALUES.
377
358
  def insert_columns_sql(sql)
@@ -1,4 +1,6 @@
1
1
  module Sequel
2
+ Dataset::NON_SQL_OPTIONS << :disable_insert_returning
3
+
2
4
  # Top level module for holding all PostgreSQL-related modules and classes
3
5
  # for Sequel. There are a few module level accessors that are added via
4
6
  # metaprogramming. These are:
@@ -601,7 +603,7 @@ module Sequel
601
603
  return @prepared_sql if @prepared_sql
602
604
  super
603
605
  if @prepared_type == :insert and !@opts[:disable_insert_returning] and server_version >= 80200
604
- @prepared_sql = insert_returning_pk_sql(@prepared_modify_values)
606
+ @prepared_sql = insert_returning_pk_sql(*@prepared_modify_values)
605
607
  meta_def(:insert_returning_pk_sql){|*args| prepared_sql}
606
608
  end
607
609
  @prepared_sql
@@ -672,17 +674,18 @@ module Sequel
672
674
  naked.clone(default_server_opts(:sql=>insert_returning_sql(nil, *values))).single_record
673
675
  end
674
676
 
675
- # Locks the table with the specified mode.
676
- def lock(mode, server=nil)
677
- sql = LOCK % [source_list(@opts[:from]), mode]
678
- @db.synchronize(server) do
679
- if block_given? # perform locking inside a transaction and yield to block
680
- @db.transaction(server){@db.execute(sql, :server=>server); yield}
681
- else
682
- @db.execute(sql, :server=>server) # lock without a transaction
683
- self
684
- end
677
+ # Locks all tables in the dataset's FROM clause (but not in JOINs) with
678
+ # the specified mode (e.g. 'EXCLUSIVE'). If a block is given, starts
679
+ # a new transaction, locks the table, and yields. If a block is not given
680
+ # just locks the tables. Note that PostgreSQL will probably raise an error
681
+ # if you lock the table outside of an existing transaction. Returns nil.
682
+ def lock(mode, opts={})
683
+ if block_given? # perform locking inside a transaction and yield to block
684
+ @db.transaction(opts){lock(mode, opts); yield}
685
+ else
686
+ @db.execute(LOCK % [source_list(@opts[:from]), mode], opts) # lock without a transaction
685
687
  end
688
+ nil
686
689
  end
687
690
 
688
691
  # For PostgreSQL version > 8.2, allow inserting multiple rows at once.
@@ -705,7 +708,7 @@ module Sequel
705
708
 
706
709
  # Return a clone of the dataset with an addition named window that can be referenced in window functions.
707
710
  def window(name, opts)
708
- clone(:window=>(@opts[:windows]||[]) + [[name, SQL::Window.new(opts)]])
711
+ clone(:window=>(@opts[:window]||[]) + [[name, SQL::Window.new(opts)]])
709
712
  end
710
713
 
711
714
  private
@@ -265,6 +265,19 @@ module Sequel
265
265
  @opts[:where] ? super : filter(1=>1).delete
266
266
  end
267
267
 
268
+ # Return an array of strings specifying a query explanation for a SELECT of the
269
+ # current dataset.
270
+ def explain
271
+ db.send(:metadata_dataset).clone(:sql=>"EXPLAIN #{select_sql}").
272
+ map{|x| "#{x[:addr]}|#{x[:opcode]}|#{(1..5).map{|i| x[:"p#{i}"]}.join('|')}|#{x[:comment]}"}
273
+ end
274
+
275
+ # HAVING requires GROUP BY on SQLite
276
+ def having(*cond, &block)
277
+ raise(InvalidOperation, "Can only specify a HAVING clause on a grouped dataset") unless @opts[:group]
278
+ super
279
+ end
280
+
268
281
  # SQLite uses the nonstandard ` (backtick) for quoting identifiers.
269
282
  def quoted_identifier(c)
270
283
  "`#{c}`"
@@ -280,6 +293,11 @@ module Sequel
280
293
  false
281
294
  end
282
295
 
296
+ # SQLite does not support multiple columns for the IN/NOT IN operators
297
+ def supports_multiple_column_in?
298
+ false
299
+ end
300
+
283
301
  # SQLite supports timezones in literal timestamps, since it stores them
284
302
  # as text.
285
303
  def supports_timestamp_timezones?
@@ -122,7 +122,6 @@ module Sequel
122
122
  class Dataset < Sequel::Dataset
123
123
  include ::Sequel::SQLite::DatasetMethods
124
124
 
125
- EXPLAIN = 'EXPLAIN %s'.freeze
126
125
  PREPARED_ARG_PLACEHOLDER = ':'.freeze
127
126
 
128
127
  # SQLite already supports named bind arguments, so use directly.
@@ -172,20 +171,6 @@ module Sequel
172
171
  end
173
172
  end
174
173
 
175
- # Prepare an unnamed statement of the given type and call it with the
176
- # given values.
177
- def call(type, hash, values=nil, &block)
178
- prepare(type, nil, values).call(hash, &block)
179
- end
180
-
181
- # Return an array of strings specifying a query explanation for the
182
- # current dataset.
183
- def explain
184
- res = []
185
- @db.result_set(EXPLAIN % select_sql(opts), nil) {|r| res << r}
186
- res
187
- end
188
-
189
174
  # Yield a hash for each row in the dataset.
190
175
  def fetch_rows(sql)
191
176
  execute(sql) do |result|
@@ -203,7 +188,7 @@ module Sequel
203
188
  # Prepare the given type of query with the given name and store
204
189
  # it in the database. Note that a new native prepared statement is
205
190
  # created on each call to this prepared statement.
206
- def prepare(type, name=nil, values=nil)
191
+ def prepare(type, name=nil, *values)
207
192
  ps = to_prepared_statement(type, values)
208
193
  ps.extend(PreparedStatementMethods)
209
194
  db.prepared_statements[name] = ps if name
@@ -11,7 +11,7 @@ class Sequel::ConnectionPool
11
11
  # The maximum number of connections.
12
12
  attr_reader :max_size
13
13
 
14
- # The mutex that protects access to the other internal vairables. You must use
14
+ # The mutex that protects access to the other internal variables. You must use
15
15
  # this if you want to manipulate the variables safely.
16
16
  attr_reader :mutex
17
17
 
@@ -249,7 +249,7 @@ module Sequel
249
249
 
250
250
  require(%w"metaprogramming sql connection_pool exceptions dataset database timezones version")
251
251
  require(%w"schema_generator schema_methods schema_sql", 'database')
252
- require(%w"convenience graph prepared_statements sql", 'dataset')
252
+ require(%w"actions convenience features graph prepared_statements query sql", 'dataset')
253
253
  require('core_sql') if !defined?(::SEQUEL_NO_CORE_EXTENSIONS) && !ENV.has_key?('SEQUEL_NO_CORE_EXTENSIONS')
254
254
 
255
255
  # Add the database adapter class methods to Sequel via metaprogramming
@@ -576,7 +576,7 @@ module Sequel
576
576
  t = begin_transaction(conn)
577
577
  yield(conn)
578
578
  rescue Exception => e
579
- rollback_transaction(t)
579
+ rollback_transaction(t) if t
580
580
  transaction_error(e)
581
581
  ensure
582
582
  begin
@@ -78,6 +78,8 @@ module Sequel
78
78
  # See Schema::SQL#on_delete_clause for options.
79
79
  # * :size - The size of the column, generally used with string
80
80
  # columns to specify the maximum number of characters the column will hold.
81
+ # An array of two integers can be provided to set the size and the
82
+ # precision, respectively, of decimal columns.
81
83
  # * :unique - Mark the column as unique, generally has the same effect as
82
84
  # creating a unique index on the column.
83
85
  # * :unsigned - Make the column type unsigned, only useful for integer
@@ -159,7 +159,7 @@ module Sequel
159
159
  elsif index[:where]
160
160
  raise Error, "Partial indexes are not supported for this database"
161
161
  else
162
- "CREATE #{'UNIQUE ' if index[:unique]}INDEX #{quote_identifier(index_name)} ON #{quote_identifier(table_name)} #{literal(index[:columns])}"
162
+ "CREATE #{'UNIQUE ' if index[:unique]}INDEX #{quote_identifier(index_name)} ON #{quote_schema_table(table_name)} #{literal(index[:columns])}"
163
163
  end
164
164
  end
165
165
 
@@ -20,17 +20,6 @@ module Sequel
20
20
  #
21
21
  # Datasets are Enumerable objects, so they can be manipulated using any
22
22
  # of the Enumerable methods, such as map, inject, etc.
23
- #
24
- # === Methods added via metaprogramming
25
- #
26
- # Some methods are added via metaprogramming:
27
- #
28
- # * ! methods - These methods are the same as their non-! counterparts,
29
- # but they modify the receiver instead of returning a modified copy
30
- # of the dataset.
31
- # * inner_join, full_outer_join, right_outer_join, left_outer_join -
32
- # This methods are shortcuts to join_table with the join type
33
- # already specified.
34
23
  class Dataset
35
24
  extend Metaprogramming
36
25
  include Metaprogramming
@@ -50,6 +39,10 @@ module Sequel
50
39
  set_defaults set_graph_aliases set_overrides unfiltered ungraphed ungrouped union
51
40
  unlimited unordered where with with_recursive with_sql'.collect{|x| x.to_sym}
52
41
 
42
+ # Which options don't affect the SQL generation. Used by simple_select_all?
43
+ # to determine if this is a simple SELECT * FROM table.
44
+ NON_SQL_OPTIONS = [:server, :defaults, :overrides]
45
+
53
46
  NOTIMPL_MSG = "This method must be overridden in Sequel adapters".freeze
54
47
  WITH_SUPPORTED=:select_with_sql
55
48
 
@@ -103,12 +96,6 @@ module Sequel
103
96
 
104
97
  ### Instance Methods ###
105
98
 
106
- # Alias for insert, but not aliased directly so subclasses
107
- # don't have to override both methods.
108
- def <<(*args)
109
- insert(*args)
110
- end
111
-
112
99
  # Return the dataset as an aliased expression with the given alias. You can
113
100
  # use this as a FROM or JOIN dataset, or as a column if this dataset
114
101
  # returns a single row and column.
@@ -116,16 +103,6 @@ module Sequel
116
103
  ::Sequel::SQL::AliasedExpression.new(self, aliaz)
117
104
  end
118
105
 
119
- # Returns an array with all records in the dataset. If a block is given,
120
- # the array is iterated over after all items have been loaded.
121
- def all(&block)
122
- a = []
123
- each{|r| a << r}
124
- post_load(a)
125
- a.each(&block) if block
126
- a
127
- end
128
-
129
106
  # Returns a new clone of the dataset with with the given options merged.
130
107
  # If the options changed include options in COLUMN_CHANGE_OPTS, the cached
131
108
  # columns are deleted.
@@ -136,30 +113,6 @@ module Sequel
136
113
  c
137
114
  end
138
115
 
139
- # Returns the columns in the result set in order.
140
- # If the columns are currently cached, returns the cached value. Otherwise,
141
- # a SELECT query is performed to get a single row. Adapters are expected
142
- # to fill the columns cache with the column information when a query is performed.
143
- # If the dataset does not have any rows, this may be an empty array depending on how
144
- # the adapter is programmed.
145
- #
146
- # If you are looking for all columns for a single table and maybe some information about
147
- # each column (e.g. type), see Database#schema.
148
- def columns
149
- return @columns if @columns
150
- ds = unfiltered.unordered.clone(:distinct => nil, :limit => 1)
151
- ds.each{break}
152
- @columns = ds.instance_variable_get(:@columns)
153
- @columns || []
154
- end
155
-
156
- # Remove the cached list of columns and do a SELECT query to find
157
- # the columns.
158
- def columns!
159
- @columns = nil
160
- columns
161
- end
162
-
163
116
  # Add a mutation method to this dataset instance.
164
117
  def def_mutation_method(*meths)
165
118
  meths.each do |meth|
@@ -167,44 +120,6 @@ module Sequel
167
120
  end
168
121
  end
169
122
 
170
- # Deletes the records in the dataset. The returned value is generally the
171
- # number of records deleted, but that is adapter dependent. See delete_sql.
172
- def delete
173
- execute_dui(delete_sql)
174
- end
175
-
176
- # Iterates over the records in the dataset as they are yielded from the
177
- # database adapter, and returns self.
178
- #
179
- # Note that this method is not safe to use on many adapters if you are
180
- # running additional queries inside the provided block. If you are
181
- # running queries inside the block, you use should all instead of each.
182
- def each(&block)
183
- if @opts[:graph]
184
- graph_each(&block)
185
- else
186
- if row_proc = @row_proc
187
- fetch_rows(select_sql){|r| yield row_proc.call(r)}
188
- else
189
- fetch_rows(select_sql, &block)
190
- end
191
- end
192
- self
193
- end
194
-
195
- # Executes a select query and fetches records, passing each record to the
196
- # supplied block. The yielded records should be hashes with symbol keys.
197
- def fetch_rows(sql, &block)
198
- raise NotImplementedError, NOTIMPL_MSG
199
- end
200
-
201
- # Inserts values into the associated table. The returned value is generally
202
- # the value of the primary key for the inserted row, but that is adapter dependent.
203
- # See insert_sql.
204
- def insert(*values)
205
- execute_insert(insert_sql(*values))
206
- end
207
-
208
123
  # Returns a string representation of the dataset including the class name
209
124
  # and the corresponding SQL select statement.
210
125
  def inspect
@@ -219,17 +134,6 @@ module Sequel
219
134
  ds
220
135
  end
221
136
 
222
- # Whether this dataset quotes identifiers.
223
- def quote_identifiers?
224
- @quote_identifiers
225
- end
226
-
227
- # Whether the dataset requires SQL standard datetimes (false by default,
228
- # as most allow strings with ISO 8601 format.
229
- def requires_sql_standard_datetimes?
230
- false
231
- end
232
-
233
137
  # Set the server for this dataset to use. Used to pick a specific database
234
138
  # shard to run a query against, or to override the default (which is SELECT uses
235
139
  # :read_only database and all other queries use the :default database).
@@ -237,12 +141,6 @@ module Sequel
237
141
  clone(:server=>servr)
238
142
  end
239
143
 
240
- # Alias for set, but not aliased directly so subclasses
241
- # don't have to override both methods.
242
- def set(*args)
243
- update(*args)
244
- end
245
-
246
144
  # Set the default values for insert and update statements. The values hash passed
247
145
  # to insert or update are merged into this hash.
248
146
  def set_defaults(hash)
@@ -255,57 +153,6 @@ module Sequel
255
153
  clone(:overrides=>hash.merge(@opts[:overrides]||{}))
256
154
  end
257
155
 
258
- # Whether the dataset supports common table expressions (the WITH clause).
259
- def supports_cte?
260
- select_clause_methods.include?(WITH_SUPPORTED)
261
- end
262
-
263
- # Whether the dataset supports the DISTINCT ON clause, true by default.
264
- def supports_distinct_on?
265
- true
266
- end
267
-
268
- # Whether the dataset supports the INTERSECT and EXCEPT compound operations, true by default.
269
- def supports_intersect_except?
270
- true
271
- end
272
-
273
- # Whether the dataset supports the INTERSECT ALL and EXCEPT ALL compound operations, true by default.
274
- def supports_intersect_except_all?
275
- true
276
- end
277
-
278
- # Whether the dataset supports the IS TRUE syntax.
279
- def supports_is_true?
280
- true
281
- end
282
-
283
- # Whether the dataset supports timezones in literal timestamps
284
- def supports_timestamp_timezones?
285
- false
286
- end
287
-
288
- # Whether the dataset supports fractional seconds in literal timestamps
289
- def supports_timestamp_usecs?
290
- true
291
- end
292
-
293
- # Whether the dataset supports window functions.
294
- def supports_window_functions?
295
- false
296
- end
297
-
298
- # Truncates the dataset. Returns nil.
299
- def truncate
300
- execute_ddl(truncate_sql)
301
- end
302
-
303
- # Updates values for the dataset. The returned value is generally the
304
- # number of rows updated, but that is adapter dependent. See update_sql.
305
- def update(values={})
306
- execute_dui(update_sql(values))
307
- end
308
-
309
156
  # Add the mutation methods via metaprogramming
310
157
  def_mutation_method(*MUTATION_METHODS)
311
158
 
@@ -318,7 +165,7 @@ module Sequel
318
165
 
319
166
  # Whether this dataset is a simple SELECT * FROM table.
320
167
  def simple_select_all?
321
- o = @opts.reject{|k,v| v.nil?}
168
+ o = @opts.reject{|k,v| v.nil? || NON_SQL_OPTIONS.include?(k)}
322
169
  o.length == 1 && (f = o[:from]) && f.length == 1 && f.first.is_a?(Symbol)
323
170
  end
324
171
 
@@ -329,27 +176,6 @@ module Sequel
329
176
  {:server=>@opts[:server] || :default}.merge(opts)
330
177
  end
331
178
 
332
- # Execute the given SQL on the database using execute.
333
- def execute(sql, opts={}, &block)
334
- @db.execute(sql, {:server=>@opts[:server] || :read_only}.merge(opts), &block)
335
- end
336
-
337
- # Execute the given SQL on the database using execute_ddl.
338
- def execute_ddl(sql, opts={}, &block)
339
- @db.execute_ddl(sql, default_server_opts(opts), &block)
340
- nil
341
- end
342
-
343
- # Execute the given SQL on the database using execute_dui.
344
- def execute_dui(sql, opts={}, &block)
345
- @db.execute_dui(sql, default_server_opts(opts), &block)
346
- end
347
-
348
- # Execute the given SQL on the database using execute_insert.
349
- def execute_insert(sql, opts={}, &block)
350
- @db.execute_insert(sql, default_server_opts(opts), &block)
351
- end
352
-
353
179
  # Modify the identifier returned from the database based on the
354
180
  # identifier_output_method.
355
181
  def input_identifier(v)