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.
- 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
|