sequel 2.7.1 → 2.8.0

Sign up to get free protection for your applications and to get access to all the features.
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