sequel 2.7.1 → 2.8.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 (50) hide show
  1. data/CHANGELOG +56 -0
  2. data/README +1 -0
  3. data/Rakefile +1 -1
  4. data/lib/sequel_core.rb +9 -16
  5. data/lib/sequel_core/adapters/ado.rb +6 -15
  6. data/lib/sequel_core/adapters/db2.rb +8 -10
  7. data/lib/sequel_core/adapters/dbi.rb +6 -4
  8. data/lib/sequel_core/adapters/informix.rb +21 -22
  9. data/lib/sequel_core/adapters/jdbc.rb +69 -10
  10. data/lib/sequel_core/adapters/jdbc/postgresql.rb +1 -0
  11. data/lib/sequel_core/adapters/mysql.rb +81 -13
  12. data/lib/sequel_core/adapters/odbc.rb +32 -4
  13. data/lib/sequel_core/adapters/openbase.rb +6 -5
  14. data/lib/sequel_core/adapters/oracle.rb +23 -7
  15. data/lib/sequel_core/adapters/postgres.rb +42 -32
  16. data/lib/sequel_core/adapters/shared/mssql.rb +37 -62
  17. data/lib/sequel_core/adapters/shared/mysql.rb +22 -7
  18. data/lib/sequel_core/adapters/shared/oracle.rb +27 -48
  19. data/lib/sequel_core/adapters/shared/postgres.rb +64 -43
  20. data/lib/sequel_core/adapters/shared/progress.rb +31 -0
  21. data/lib/sequel_core/adapters/shared/sqlite.rb +15 -4
  22. data/lib/sequel_core/adapters/sqlite.rb +6 -14
  23. data/lib/sequel_core/connection_pool.rb +47 -13
  24. data/lib/sequel_core/database.rb +60 -35
  25. data/lib/sequel_core/database/schema.rb +4 -4
  26. data/lib/sequel_core/dataset.rb +12 -3
  27. data/lib/sequel_core/dataset/convenience.rb +4 -13
  28. data/lib/sequel_core/dataset/prepared_statements.rb +30 -28
  29. data/lib/sequel_core/dataset/sql.rb +144 -85
  30. data/lib/sequel_core/dataset/stored_procedures.rb +75 -0
  31. data/lib/sequel_core/dataset/unsupported.rb +31 -0
  32. data/lib/sequel_core/exceptions.rb +6 -0
  33. data/lib/sequel_core/schema/generator.rb +4 -3
  34. data/lib/sequel_core/schema/sql.rb +41 -23
  35. data/lib/sequel_core/sql.rb +29 -1
  36. data/lib/sequel_model/associations.rb +1 -1
  37. data/lib/sequel_model/record.rb +31 -28
  38. data/spec/adapters/mysql_spec.rb +37 -4
  39. data/spec/adapters/oracle_spec.rb +26 -4
  40. data/spec/adapters/sqlite_spec.rb +7 -0
  41. data/spec/integration/prepared_statement_test.rb +24 -0
  42. data/spec/integration/schema_test.rb +1 -1
  43. data/spec/sequel_core/connection_pool_spec.rb +49 -2
  44. data/spec/sequel_core/core_sql_spec.rb +9 -2
  45. data/spec/sequel_core/database_spec.rb +64 -14
  46. data/spec/sequel_core/dataset_spec.rb +105 -7
  47. data/spec/sequel_core/schema_spec.rb +40 -12
  48. data/spec/sequel_core/spec_helper.rb +1 -0
  49. data/spec/sequel_model/spec_helper.rb +1 -0
  50. metadata +6 -3
data/CHANGELOG CHANGED
@@ -1,3 +1,59 @@
1
+ === 2.8.0 (2008-12-05)
2
+
3
+ * Support drop column operations inside a transaction on sqlite (jeremyevans)
4
+
5
+ * Support literal strings with placeholders and subselects in prepared statements (jeremyevans)
6
+
7
+ * Have the connection pool remove disconnected connections when the adapter supports it (jeremyevans)
8
+
9
+ * Make Dataset#exists return a LiteralString (jeremyevans)
10
+
11
+ * Support multiple SQL statements in one query in the MySQL adapter (jeremyevans)
12
+
13
+ * Add stored procedure support for the MySQL and JDBC adapters (jeremyevans, krsgoss) (#252)
14
+
15
+ * Support options when altering a column's type (for changing enums, varchar size, etc.) (jeremyevans)
16
+
17
+ * Support AliasedExpressions in tables when using implicitly qualified arguments in joins (jeremyevans)
18
+
19
+ * Support Dataset#except on Oracle (jeremyevans)
20
+
21
+ * Raise errors when EXCEPT/INTERSECT is used when not supported (jeremyevans)
22
+
23
+ * Fix ordering of UNION, INTERSECT, and EXCEPT statements (jeremyevans) (#253)
24
+
25
+ * Support aliasing subselects in the Oracle adapter (jeremyevans)
26
+
27
+ * Add a subadapter for the Progress RDBMS to the ODBC adapter (:db_type=>'progress') (groveriffic) (#251)
28
+
29
+ * Make MySQL and Oracle adapters raise an Error if asked to do a SELECT DISTINCT ON (jeremyevans)
30
+
31
+ * Set standard_conforming_strings = ON by default when using PostgreSQL, turn off with Sequel::Postgres.force_standard_strings = false (jeremyevans) (#247)
32
+
33
+ * Fix Database#rename_table when using PostgreSQL (jeremyevans) (#248)
34
+
35
+ * Whether to upcase or quote identifiers can now be set separately, via Sequel.upcase_identifiers= or the :upcase_identifiers database option (jeremyevans)
36
+
37
+ * Support transactions in the ODBC adapter (dlee)
38
+
39
+ * Support multi_insert_sql and unicode string literals in MSSQL shared adapter (dlee)
40
+
41
+ * Make PostgreSQL use the default schema if parsing the schema for all tables at once, even if :schema=>nil option is used (jeremyevans)
42
+
43
+ * Make MySQL adapter not raise an error when giving an SQL::Identifier object to the schema modification methods such as create_table (jeremyevans)
44
+
45
+ * The keys of the hash returned by Database#schema without a table name are now quoted strings instead of symbols (jeremyevans)
46
+
47
+ * Make Database#schema to handle implicit schemas on all databases and multiple identifier object types (jeremyevans)
48
+
49
+ * Remove Sequel.odbc_mssql method (jeremyevans) (#249)
50
+
51
+ * More optimization of Model#initialize (jeremyevans)
52
+
53
+ * Treat interval as it's own type, not an integer type (jeremyevans)
54
+
55
+ * Allow use of implicitly qualified symbol as argument to Symbol#qualify (:a.qualify(:b__c)=>b.c.a), fixes model associations in different schemas (jeremyevans) (#246)
56
+
1
57
  === 2.7.1 (2008-11-04)
2
58
 
3
59
  * Fix PostgreSQL Date optimization so that it doesn't reject dates like 11/03/2008 (jeremyevans)
data/README CHANGED
@@ -41,6 +41,7 @@ If you have any comments or suggestions please post to the Google group.
41
41
  DB = Sequel.sqlite # memory database
42
42
 
43
43
  DB.create_table :items do # Create a new table
44
+ primary_key :id
44
45
  column :name, :text
45
46
  column :price, :float
46
47
  end
data/Rakefile CHANGED
@@ -12,7 +12,7 @@ require "fileutils"
12
12
  include FileUtils
13
13
 
14
14
  NAME = 'sequel'
15
- VERS = '2.7.1'
15
+ VERS = '2.8.0'
16
16
  CLEAN.include ["**/.*.sw?", "pkg", ".config", "rdoc", "coverage", "www/public/*.html"]
17
17
  RDOC_OPTS = ["--quiet", "--line-numbers", "--inline-source", '--title', \
18
18
  'Sequel: The Database Toolkit for Ruby', '--main', 'README']
@@ -83,26 +83,19 @@ module Sequel
83
83
  # and speed is a priority, you may want to set this to true:
84
84
  #
85
85
  # Sequel.single_threaded = true
86
- #
87
- # Note that some database adapters (e.g. MySQL) have issues with single threaded mode if
88
- # you try to perform more than one query simultaneously. For example, the
89
- # following code will not work well in single threaded mode on MySQL:
90
- #
91
- # DB[:items].each{|i| DB[:nodes].filter(:item_id=>i[:id]).each{|n| puts "#{i} #{n}"}}
92
- #
93
- # Basically, you can't issue another query inside a call to Dataset#each in single
94
- # threaded mode. There is a fairly easy fix, just use Dataset#all inside
95
- # Dataset#each for the outer query:
96
- #
97
- # DB[:items].all{|i| DB[:nodes].filter(:item_id=>i[:id]).each{|n| puts "#{i} #{n}"}}
98
- #
99
- # Dataset#all gets all of the returned objects before calling the block, so the query
100
- # isn't left open. Some of the adapters do this internally, and thus don't have a
101
- # problem issuing queries inside of Dataset#each.
102
86
  def self.single_threaded=(value)
103
87
  Database.single_threaded = value
104
88
  end
105
89
 
90
+ # Set whether to upcase identifiers for all databases by default. By default,
91
+ # Sequel upcases identifiers unless the database folds unquoted identifiers to
92
+ # lower case (MySQL, PostgreSQL, and SQLite).
93
+ #
94
+ # Sequel.upcase_identifiers = false
95
+ def self.upcase_identifiers=(value)
96
+ Database.upcase_identifiers = value
97
+ end
98
+
106
99
  # Always returns false, since ParseTree support has been removed.
107
100
  def self.use_parse_tree
108
101
  false
@@ -32,10 +32,6 @@ module Sequel
32
32
  handle
33
33
  end
34
34
 
35
- def disconnect
36
- @pool.disconnect {|conn| conn.Close}
37
- end
38
-
39
35
  def dataset(opts = nil)
40
36
  ADO::Dataset.new(self, opts)
41
37
  end
@@ -49,20 +45,15 @@ module Sequel
49
45
  end
50
46
  end
51
47
  alias_method :do, :execute
48
+
49
+ private
50
+
51
+ def disconnect_connection(conn)
52
+ conn.Close
53
+ end
52
54
  end
53
55
 
54
56
  class Dataset < Sequel::Dataset
55
- def literal(v)
56
- case v
57
- when Time
58
- literal(v.iso8601)
59
- when Date, DateTime
60
- literal(v.to_s)
61
- else
62
- super
63
- end
64
- end
65
-
66
57
  def fetch_rows(sql)
67
58
  execute(sql) do |s|
68
59
  @columns = s.Fields.extend(Enumerable).map do |column|
@@ -20,16 +20,6 @@ module Sequel
20
20
  dbc
21
21
  end
22
22
 
23
- def disconnect
24
- @pool.disconnect do |conn|
25
- rc = SQLDisconnect(conn)
26
- check_error(rc, "Could not disconnect from database")
27
-
28
- rc = SQLFreeHandle(SQL_HANDLE_DBC, conn)
29
- check_error(rc, "Could not free Database handle")
30
- end
31
- end
32
-
33
23
  def test_connection(server=nil)
34
24
  synchronize(server){|conn|}
35
25
  true
@@ -72,6 +62,14 @@ module Sequel
72
62
  raise DatabaseError, msg
73
63
  end
74
64
  end
65
+
66
+ def disconnect_connection(conn)
67
+ rc = SQLDisconnect(conn)
68
+ check_error(rc, "Could not disconnect from database")
69
+
70
+ rc = SQLFreeHandle(SQL_HANDLE_DBC, conn)
71
+ check_error(rc, "Could not free Database handle")
72
+ end
75
73
  end
76
74
 
77
75
  class Dataset < Sequel::Dataset
@@ -51,10 +51,6 @@ module Sequel
51
51
  ::DBI.connect(dbname, opts[:user], opts[:password])
52
52
  end
53
53
 
54
- def disconnect
55
- @pool.disconnect {|c| c.disconnect}
56
- end
57
-
58
54
  def dataset(opts = nil)
59
55
  DBI::Dataset.new(self, opts)
60
56
  end
@@ -78,6 +74,12 @@ module Sequel
78
74
  def lowercase
79
75
  @lowercase ||= false
80
76
  end
77
+
78
+ private
79
+
80
+ def disconnect_connection(c)
81
+ c.disconnect
82
+ end
81
83
  end
82
84
 
83
85
  class Dataset < Sequel::Dataset
@@ -5,20 +5,10 @@ module Sequel
5
5
  class Database < Sequel::Database
6
6
  set_adapter_scheme :informix
7
7
 
8
- # AUTO_INCREMENT = 'IDENTITY(1,1)'.freeze
9
- #
10
- # def auto_increment_sql
11
- # AUTO_INCREMENT
12
- # end
13
-
14
8
  def connect(server)
15
9
  opts = server_opts(server)
16
10
  ::Informix.connect(opts[:database], opts[:user], opts[:password])
17
11
  end
18
-
19
- def disconnect
20
- @pool.disconnect{|c| c.close}
21
- end
22
12
 
23
13
  def dataset(opts = nil)
24
14
  Sequel::Informix::Dataset.new(self, opts)
@@ -36,9 +26,19 @@ module Sequel
36
26
  synchronize(opts[:server]){|c| yield c.cursor(sql)}
37
27
  end
38
28
  alias_method :query, :execute
29
+
30
+ private
31
+
32
+ def disconnect_connection(c)
33
+ c.close
34
+ end
39
35
  end
40
36
 
41
37
  class Dataset < Sequel::Dataset
38
+ include UnsupportedIntersectExcept
39
+
40
+ SELECT_CLAUSE_ORDER = %w'limit distinct columns from join where having group union order'.freeze
41
+
42
42
  def literal(v)
43
43
  case v
44
44
  when Time
@@ -50,18 +50,6 @@ module Sequel
50
50
  end
51
51
  end
52
52
 
53
- def select_sql(opts = nil)
54
- limit = opts.delete(:limit)
55
- offset = opts.delete(:offset)
56
- sql = super
57
- if limit
58
- limit = "FIRST #{limit}"
59
- offset = offset ? "SKIP #{offset}" : ""
60
- sql.sub!(/^select /i,"SELECT #{offset} #{limit} ")
61
- end
62
- sql
63
- end
64
-
65
53
  def fetch_rows(sql, &block)
66
54
  execute(sql) do |cursor|
67
55
  begin
@@ -72,6 +60,17 @@ module Sequel
72
60
  end
73
61
  self
74
62
  end
63
+
64
+ private
65
+
66
+ def select_clause_order
67
+ SELECT_CLAUSE_ORDER
68
+ end
69
+
70
+ def select_limit_sql(sql, opts)
71
+ sql << " SKIP #{opts[:offset]}" if opts[:offset]
72
+ sql << " FIRST #{opts[:limit]}" if opts[:limit]
73
+ end
75
74
  end
76
75
  end
77
76
  end
@@ -1,4 +1,5 @@
1
1
  require 'java'
2
+ require 'sequel_core/dataset/stored_procedures'
2
3
 
3
4
  module Sequel
4
5
  # Houses Sequel's JDBC support when running on JRuby.
@@ -93,6 +94,37 @@ module Sequel
93
94
  end
94
95
  end
95
96
 
97
+ # Execute the given stored procedure with the give name. If a block is
98
+ # given, the stored procedure should return rows.
99
+ def call_sproc(name, opts = {})
100
+ args = opts[:args] || []
101
+ sql = "{call #{name}(#{args.map{'?'}.join(',')})}"
102
+ synchronize(opts[:server]) do |conn|
103
+ cps = conn.prepareCall(sql)
104
+
105
+ i = 0
106
+ args.each{|arg| set_ps_arg(cps, arg, i+=1)}
107
+
108
+ begin
109
+ if block_given?
110
+ yield cps.executeQuery
111
+ else
112
+ case opts[:type]
113
+ when :insert
114
+ cps.executeUpdate
115
+ last_insert_id(conn, opts)
116
+ else
117
+ cps.executeUpdate
118
+ end
119
+ end
120
+ rescue NativeException, JavaSQL::SQLException => e
121
+ raise_error(e)
122
+ ensure
123
+ cps.close
124
+ end
125
+ end
126
+ end
127
+
96
128
  # Connect to the database using JavaSQL::DriverManager.getConnection.
97
129
  def connect(server)
98
130
  setup_connection(JavaSQL::DriverManager.getConnection(uri(server_opts(server))))
@@ -103,14 +135,10 @@ module Sequel
103
135
  JDBC::Dataset.new(self, opts)
104
136
  end
105
137
 
106
- # Close all adapter connections
107
- def disconnect
108
- @pool.disconnect {|c| c.close}
109
- end
110
-
111
138
  # Execute the given SQL. If a block is given, if should be a SELECT
112
139
  # statement or something else that returns rows.
113
140
  def execute(sql, opts={}, &block)
141
+ return call_sproc(sql, opts, &block) if opts[:sproc]
114
142
  return execute_prepared_statement(sql, opts, &block) if sql.is_one_of?(Symbol, Dataset)
115
143
  log_info(sql)
116
144
  synchronize(opts[:server]) do |conn|
@@ -190,6 +218,11 @@ module Sequel
190
218
 
191
219
  private
192
220
 
221
+ # Close given adapter connections
222
+ def disconnect_connection(c)
223
+ c.close
224
+ end
225
+
193
226
  # Execute the prepared statement. If the provided name is a
194
227
  # dataset, use that as the prepared statement, otherwise use
195
228
  # it as a key to look it up in the prepared_statements hash.
@@ -287,6 +320,8 @@ module Sequel
287
320
  end
288
321
 
289
322
  class Dataset < Sequel::Dataset
323
+ include StoredProcedures
324
+
290
325
  # Use JDBC PreparedStatements instead of emulated ones. Statements
291
326
  # created using #prepare are cached at the connection level to allow
292
327
  # reuse. This also supports bind variables by using unnamed
@@ -313,10 +348,27 @@ module Sequel
313
348
  end
314
349
  end
315
350
 
316
- # Create an unnamed prepared statement and call it. Allows the
317
- # use of bind variables.
318
- def call(type, hash, values=nil, &block)
319
- prepare(type, nil, values).call(hash, &block)
351
+ # Use JDBC CallableStatements to execute stored procedures. Only supported
352
+ # if the underlying database has stored procedure support.
353
+ module StoredProcedureMethods
354
+ include Sequel::Dataset::StoredProcedureMethods
355
+
356
+ private
357
+
358
+ # Execute the database stored procedure with the stored arguments.
359
+ def execute(sql, opts={}, &block)
360
+ super(@sproc_name, {:args=>@sproc_args, :sproc=>true, :type=>sql_query_type}.merge(opts), &block)
361
+ end
362
+
363
+ # Same as execute, explicit due to intricacies of alias and super.
364
+ def execute_dui(sql, opts={}, &block)
365
+ super(@sproc_name, {:args=>@sproc_args, :sproc=>true, :type=>sql_query_type}.merge(opts), &block)
366
+ end
367
+
368
+ # Same as execute, explicit due to intricacies of alias and super.
369
+ def execute_insert(sql, opts={}, &block)
370
+ super(@sproc_name, {:args=>@sproc_args, :sproc=>true, :type=>sql_query_type}.merge(opts), &block)
371
+ end
320
372
  end
321
373
 
322
374
  # Correctly return rows from the database and return them as hashes.
@@ -352,7 +404,7 @@ module Sequel
352
404
 
353
405
  # Create a named prepared statement that is stored in the
354
406
  # database (and connection) for reuse.
355
- def prepare(type, name, values=nil)
407
+ def prepare(type, name=nil, values=nil)
356
408
  ps = to_prepared_statement(type, values)
357
409
  ps.extend(PreparedStatementMethods)
358
410
  if name
@@ -361,6 +413,13 @@ module Sequel
361
413
  end
362
414
  ps
363
415
  end
416
+
417
+ private
418
+
419
+ # Extend the dataset with the JDBC stored procedure methods.
420
+ def prepare_extend_sproc(ds)
421
+ ds.extend(StoredProcedureMethods)
422
+ end
364
423
  end
365
424
  end
366
425
  end
@@ -70,6 +70,7 @@ module Sequel
70
70
  conn = super(conn)
71
71
  conn.extend(Sequel::JDBC::Postgres::AdapterMethods)
72
72
  conn.db = self
73
+ conn.apply_connection_settings
73
74
  conn
74
75
  end
75
76
 
@@ -1,5 +1,6 @@
1
1
  require 'mysql'
2
2
  require 'sequel_core/adapters/shared/mysql'
3
+ require 'sequel_core/dataset/stored_procedures'
3
4
 
4
5
  # Add methods to get columns, yield hashes with symbol keys, and do
5
6
  # type conversion.
@@ -85,6 +86,12 @@ module Sequel
85
86
 
86
87
  set_adapter_scheme :mysql
87
88
 
89
+ # Support stored procedures on MySQL
90
+ def call_sproc(name, opts={}, &block)
91
+ args = opts[:args] || []
92
+ execute("CALL #{name}(#{literal(args) unless args.empty?})", opts.merge(:sproc=>false), &block)
93
+ end
94
+
88
95
  # Connect to the database. In addition to the usual database options,
89
96
  # the following options have effect:
90
97
  #
@@ -125,14 +132,10 @@ module Sequel
125
132
  MySQL::Dataset.new(self, opts)
126
133
  end
127
134
 
128
- # Closes all database connections.
129
- def disconnect
130
- @pool.disconnect {|c| c.close}
131
- end
132
-
133
135
  # Executes the given SQL using an available connection, yielding the
134
136
  # connection if the block is given.
135
137
  def execute(sql, opts={}, &block)
138
+ return call_sproc(sql, opts, &block) if opts[:sproc]
136
139
  return execute_prepared_statement(sql, opts, &block) if Symbol === sql
137
140
  begin
138
141
  synchronize(opts[:server]){|conn| _execute(conn, sql, opts, &block)}
@@ -178,11 +181,19 @@ module Sequel
178
181
  log_info(sql)
179
182
  conn.query(sql)
180
183
  if opts[:type] == :select
181
- r = conn.use_result
182
- begin
183
- yield r
184
- ensure
185
- r.free
184
+ loop do
185
+ begin
186
+ r = conn.use_result
187
+ rescue Mysql::Error
188
+ nil
189
+ else
190
+ begin
191
+ yield r
192
+ ensure
193
+ r.free
194
+ end
195
+ end
196
+ break unless conn.respond_to?(:next_result) && conn.next_result
186
197
  end
187
198
  else
188
199
  yield conn if block_given?
@@ -200,6 +211,11 @@ module Sequel
200
211
  @opts[:database]
201
212
  end
202
213
 
214
+ # Closes given database connection.
215
+ def disconnect_connection(c)
216
+ c.close
217
+ end
218
+
203
219
  # Executes a prepared statement on an available connection. If the
204
220
  # prepared statement already exists for the connection and has the same
205
221
  # SQL, reuse it, otherwise, prepare the new statement. Because of the
@@ -231,11 +247,27 @@ module Sequel
231
247
  # Dataset class for MySQL datasets accessed via the native driver.
232
248
  class Dataset < Sequel::Dataset
233
249
  include Sequel::MySQL::DatasetMethods
250
+ include StoredProcedures
251
+
252
+ # Methods to add to MySQL prepared statement calls without using a
253
+ # real database prepared statement and bound variables.
254
+ module CallableStatementMethods
255
+ # Extend given dataset with this module so subselects inside subselects in
256
+ # prepared statements work.
257
+ def subselect_sql(ds)
258
+ ps = ds.to_prepared_statement(:select)
259
+ ps.extend(CallableStatementMethods)
260
+ ps.prepared_args = prepared_args
261
+ ps.prepared_sql
262
+ end
263
+ end
234
264
 
235
265
  # Methods for MySQL prepared statements using the native driver.
236
266
  module PreparedStatementMethods
237
267
  include Sequel::Dataset::UnnumberedArgumentMapper
238
268
 
269
+ private
270
+
239
271
  # Execute the prepared statement with the bind arguments instead of
240
272
  # the given SQL.
241
273
  def execute(sql, opts={}, &block)
@@ -248,6 +280,34 @@ module Sequel
248
280
  end
249
281
  end
250
282
 
283
+ # Methods for MySQL stored procedures using the native driver.
284
+ module StoredProcedureMethods
285
+ include Sequel::Dataset::StoredProcedureMethods
286
+
287
+ private
288
+
289
+ # Execute the database stored procedure with the stored arguments.
290
+ def execute(sql, opts={}, &block)
291
+ super(@sproc_name, {:args=>@sproc_args, :sproc=>true}.merge(opts), &block)
292
+ end
293
+
294
+ # Same as execute, explicit due to intricacies of alias and super.
295
+ def execute_dui(sql, opts={}, &block)
296
+ super(@sproc_name, {:args=>@sproc_args, :sproc=>true}.merge(opts), &block)
297
+ end
298
+ end
299
+
300
+ # MySQL is different in that it supports prepared statements but not bound
301
+ # variables outside of prepared statements. The default implementation
302
+ # breaks the use of subselects in prepared statements, so extend the
303
+ # temporary prepared statement that this creates with a module that
304
+ # fixes it.
305
+ def call(type, bind_arguments={}, values=nil)
306
+ ps = to_prepared_statement(type, values)
307
+ ps.extend(CallableStatementMethods)
308
+ ps.call(bind_arguments)
309
+ end
310
+
251
311
  # Delete rows matching this dataset
252
312
  def delete(opts = nil)
253
313
  execute_dui(delete_sql(opts)){|c| c.affected_rows}
@@ -281,11 +341,14 @@ module Sequel
281
341
 
282
342
  # Store the given type of prepared statement in the associated database
283
343
  # with the given name.
284
- def prepare(type, name, values=nil)
344
+ def prepare(type, name=nil, values=nil)
285
345
  ps = to_prepared_statement(type, values)
286
346
  ps.extend(PreparedStatementMethods)
287
- ps.prepared_statement_name = name
288
- db.prepared_statements[name] = ps
347
+ if name
348
+ ps.prepared_statement_name = name
349
+ db.prepared_statements[name] = ps
350
+ end
351
+ ps
289
352
  end
290
353
 
291
354
  # Replace (update or insert) the matching row.
@@ -309,6 +372,11 @@ module Sequel
309
372
  def execute_dui(sql, opts={}, &block)
310
373
  super(sql, {:type=>:dui}.merge(opts), &block)
311
374
  end
375
+
376
+ # Extend the dataset with the MySQL stored procedure methods.
377
+ def prepare_extend_sproc(ds)
378
+ ds.extend(StoredProcedureMethods)
379
+ end
312
380
  end
313
381
  end
314
382
  end