sequel 2.7.1 → 2.8.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +56 -0
- data/README +1 -0
- data/Rakefile +1 -1
- data/lib/sequel_core.rb +9 -16
- data/lib/sequel_core/adapters/ado.rb +6 -15
- data/lib/sequel_core/adapters/db2.rb +8 -10
- data/lib/sequel_core/adapters/dbi.rb +6 -4
- data/lib/sequel_core/adapters/informix.rb +21 -22
- data/lib/sequel_core/adapters/jdbc.rb +69 -10
- data/lib/sequel_core/adapters/jdbc/postgresql.rb +1 -0
- data/lib/sequel_core/adapters/mysql.rb +81 -13
- data/lib/sequel_core/adapters/odbc.rb +32 -4
- data/lib/sequel_core/adapters/openbase.rb +6 -5
- data/lib/sequel_core/adapters/oracle.rb +23 -7
- data/lib/sequel_core/adapters/postgres.rb +42 -32
- data/lib/sequel_core/adapters/shared/mssql.rb +37 -62
- data/lib/sequel_core/adapters/shared/mysql.rb +22 -7
- data/lib/sequel_core/adapters/shared/oracle.rb +27 -48
- data/lib/sequel_core/adapters/shared/postgres.rb +64 -43
- data/lib/sequel_core/adapters/shared/progress.rb +31 -0
- data/lib/sequel_core/adapters/shared/sqlite.rb +15 -4
- data/lib/sequel_core/adapters/sqlite.rb +6 -14
- data/lib/sequel_core/connection_pool.rb +47 -13
- data/lib/sequel_core/database.rb +60 -35
- data/lib/sequel_core/database/schema.rb +4 -4
- data/lib/sequel_core/dataset.rb +12 -3
- data/lib/sequel_core/dataset/convenience.rb +4 -13
- data/lib/sequel_core/dataset/prepared_statements.rb +30 -28
- data/lib/sequel_core/dataset/sql.rb +144 -85
- data/lib/sequel_core/dataset/stored_procedures.rb +75 -0
- data/lib/sequel_core/dataset/unsupported.rb +31 -0
- data/lib/sequel_core/exceptions.rb +6 -0
- data/lib/sequel_core/schema/generator.rb +4 -3
- data/lib/sequel_core/schema/sql.rb +41 -23
- data/lib/sequel_core/sql.rb +29 -1
- data/lib/sequel_model/associations.rb +1 -1
- data/lib/sequel_model/record.rb +31 -28
- data/spec/adapters/mysql_spec.rb +37 -4
- data/spec/adapters/oracle_spec.rb +26 -4
- data/spec/adapters/sqlite_spec.rb +7 -0
- data/spec/integration/prepared_statement_test.rb +24 -0
- data/spec/integration/schema_test.rb +1 -1
- data/spec/sequel_core/connection_pool_spec.rb +49 -2
- data/spec/sequel_core/core_sql_spec.rb +9 -2
- data/spec/sequel_core/database_spec.rb +64 -14
- data/spec/sequel_core/dataset_spec.rb +105 -7
- data/spec/sequel_core/schema_spec.rb +40 -12
- data/spec/sequel_core/spec_helper.rb +1 -0
- data/spec/sequel_model/spec_helper.rb +1 -0
- 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
data/Rakefile
CHANGED
@@ -12,7 +12,7 @@ require "fileutils"
|
|
12
12
|
include FileUtils
|
13
13
|
|
14
14
|
NAME = 'sequel'
|
15
|
-
VERS = '2.
|
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']
|
data/lib/sequel_core.rb
CHANGED
@@ -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
|
-
#
|
317
|
-
#
|
318
|
-
|
319
|
-
|
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
|
@@ -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
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
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
|
-
|
288
|
-
|
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
|