sequel 2.3.0 → 2.4.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 +16 -0
- data/README +4 -1
- data/Rakefile +17 -19
- data/doc/prepared_statements.rdoc +104 -0
- data/doc/sharding.rdoc +113 -0
- data/lib/sequel_core/adapters/ado.rb +24 -17
- data/lib/sequel_core/adapters/db2.rb +30 -33
- data/lib/sequel_core/adapters/dbi.rb +15 -13
- data/lib/sequel_core/adapters/informix.rb +13 -14
- data/lib/sequel_core/adapters/jdbc.rb +243 -60
- data/lib/sequel_core/adapters/jdbc/mysql.rb +32 -24
- data/lib/sequel_core/adapters/jdbc/postgresql.rb +32 -2
- data/lib/sequel_core/adapters/jdbc/sqlite.rb +16 -20
- data/lib/sequel_core/adapters/mysql.rb +164 -76
- data/lib/sequel_core/adapters/odbc.rb +21 -34
- data/lib/sequel_core/adapters/openbase.rb +10 -7
- data/lib/sequel_core/adapters/oracle.rb +17 -23
- data/lib/sequel_core/adapters/postgres.rb +246 -35
- data/lib/sequel_core/adapters/shared/mssql.rb +106 -0
- data/lib/sequel_core/adapters/shared/mysql.rb +34 -26
- data/lib/sequel_core/adapters/shared/postgres.rb +82 -38
- data/lib/sequel_core/adapters/shared/sqlite.rb +48 -16
- data/lib/sequel_core/adapters/sqlite.rb +141 -44
- data/lib/sequel_core/connection_pool.rb +85 -63
- data/lib/sequel_core/database.rb +46 -17
- data/lib/sequel_core/dataset.rb +21 -40
- data/lib/sequel_core/dataset/convenience.rb +3 -3
- data/lib/sequel_core/dataset/prepared_statements.rb +218 -0
- data/lib/sequel_core/exceptions.rb +0 -12
- data/lib/sequel_model/base.rb +1 -2
- data/lib/sequel_model/plugins.rb +1 -1
- data/spec/adapters/ado_spec.rb +32 -3
- data/spec/adapters/mysql_spec.rb +7 -8
- data/spec/integration/prepared_statement_test.rb +106 -0
- data/spec/sequel_core/connection_pool_spec.rb +105 -3
- data/spec/sequel_core/database_spec.rb +41 -3
- data/spec/sequel_core/dataset_spec.rb +117 -7
- data/spec/sequel_core/spec_helper.rb +2 -2
- data/spec/sequel_model/model_spec.rb +0 -6
- data/spec/sequel_model/spec_helper.rb +1 -1
- metadata +11 -6
- data/lib/sequel_core/adapters/adapter_skeleton.rb +0 -54
- data/lib/sequel_core/adapters/odbc_mssql.rb +0 -106
@@ -2,52 +2,60 @@ require 'sequel_core/adapters/shared/mysql'
|
|
2
2
|
|
3
3
|
module Sequel
|
4
4
|
module JDBC
|
5
|
+
# Database and Dataset instance methods for MySQL specific
|
6
|
+
# support via JDBC.
|
5
7
|
module MySQL
|
8
|
+
# Database instance methods for MySQL databases accessed via JDBC.
|
6
9
|
module DatabaseMethods
|
7
10
|
include Sequel::MySQL::DatabaseMethods
|
8
11
|
|
12
|
+
# Return instance of Sequel::JDBC::MySQL::Dataset with the given opts.
|
9
13
|
def dataset(opts=nil)
|
10
14
|
Sequel::JDBC::MySQL::Dataset.new(self, opts)
|
11
15
|
end
|
12
16
|
|
13
|
-
def execute_insert(sql)
|
14
|
-
begin
|
15
|
-
log_info(sql)
|
16
|
-
@pool.hold do |conn|
|
17
|
-
stmt = conn.createStatement
|
18
|
-
begin
|
19
|
-
stmt.executeUpdate(sql)
|
20
|
-
rs = stmt.executeQuery('SELECT LAST_INSERT_ID()')
|
21
|
-
rs.next
|
22
|
-
rs.getInt(1)
|
23
|
-
rescue NativeException, JavaSQL::SQLException => e
|
24
|
-
raise Error, e.message
|
25
|
-
ensure
|
26
|
-
stmt.close
|
27
|
-
end
|
28
|
-
end
|
29
|
-
rescue NativeException, JavaSQL::SQLException => e
|
30
|
-
raise Error, "#{sql}\r\n#{e.message}"
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
17
|
private
|
35
18
|
|
19
|
+
# The database name for the given database. Need to parse it out
|
20
|
+
# of the connection string, since the JDBC does no parsing on the
|
21
|
+
# given connection string by default.
|
36
22
|
def database_name
|
37
23
|
u = URI.parse(uri.sub(/\Ajdbc:/, ''))
|
38
24
|
(m = /\/(.*)/.match(u.path)) && m[1]
|
39
25
|
end
|
26
|
+
|
27
|
+
# Get the last inserted id using LAST_INSERT_ID().
|
28
|
+
def last_insert_id(conn, opts={})
|
29
|
+
stmt = conn.createStatement
|
30
|
+
begin
|
31
|
+
rs = stmt.executeQuery('SELECT LAST_INSERT_ID()')
|
32
|
+
rs.next
|
33
|
+
rs.getInt(1)
|
34
|
+
ensure
|
35
|
+
stmt.close
|
36
|
+
end
|
37
|
+
end
|
40
38
|
end
|
41
|
-
|
39
|
+
|
40
|
+
# Dataset class for MySQL datasets accessed via JDBC.
|
42
41
|
class Dataset < JDBC::Dataset
|
43
42
|
include Sequel::MySQL::DatasetMethods
|
44
43
|
|
44
|
+
# Use execute_insert to execute the insert_sql.
|
45
45
|
def insert(*values)
|
46
|
-
|
46
|
+
execute_insert(insert_sql(*values))
|
47
47
|
end
|
48
48
|
|
49
|
+
# Use execute_insert to execute the replace_sql.
|
49
50
|
def replace(*args)
|
50
|
-
|
51
|
+
execute_insert(replace_sql(*args))
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
# Call execute_insert on the database.
|
57
|
+
def execute_insert(sql, opts={})
|
58
|
+
@db.execute_insert(sql, {:server=>@opts[:server] || :default}.merge(opts))
|
51
59
|
end
|
52
60
|
end
|
53
61
|
end
|
@@ -4,12 +4,18 @@ module Sequel
|
|
4
4
|
Postgres::CONVERTED_EXCEPTIONS << NativeException
|
5
5
|
|
6
6
|
module JDBC
|
7
|
+
# Adapter, Database, and Dataset support for accessing a PostgreSQL
|
8
|
+
# database via JDBC.
|
7
9
|
module Postgres
|
10
|
+
# Methods to add to the JDBC adapter/connection to allow it to work
|
11
|
+
# with the shared PostgreSQL code.
|
8
12
|
module AdapterMethods
|
9
13
|
include Sequel::Postgres::AdapterMethods
|
10
14
|
|
11
|
-
|
12
|
-
|
15
|
+
# Give the JDBC adapter a direct execute method, which creates
|
16
|
+
# a statement with the given sql and executes it.
|
17
|
+
def execute(sql, args=nil)
|
18
|
+
method = block_given? ? :executeQuery : :execute
|
13
19
|
stmt = createStatement
|
14
20
|
begin
|
15
21
|
rows = stmt.send(method, sql)
|
@@ -21,6 +27,9 @@ module Sequel
|
|
21
27
|
end
|
22
28
|
end
|
23
29
|
|
30
|
+
private
|
31
|
+
|
32
|
+
# JDBC specific method of getting specific values from a result set.
|
24
33
|
def result_set_values(r, *vals)
|
25
34
|
return if r.nil?
|
26
35
|
r.next
|
@@ -34,22 +43,43 @@ module Sequel
|
|
34
43
|
end
|
35
44
|
end
|
36
45
|
|
46
|
+
# Methods to add to Database instances that access PostgreSQL via
|
47
|
+
# JDBC.
|
37
48
|
module DatabaseMethods
|
38
49
|
include Sequel::Postgres::DatabaseMethods
|
39
50
|
|
51
|
+
# Return instance of Sequel::JDBC::Postgres::Dataset with the given opts.
|
40
52
|
def dataset(opts=nil)
|
41
53
|
Sequel::JDBC::Postgres::Dataset.new(self, opts)
|
42
54
|
end
|
43
55
|
|
56
|
+
# Run the INSERT sql on the database and return the primary key
|
57
|
+
# for the record.
|
58
|
+
def execute_insert(sql, opts={})
|
59
|
+
super(sql, {:type=>:insert}.merge(opts))
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
# Extend the adapter with the JDBC PostgreSQL AdapterMethods
|
44
65
|
def setup_connection(conn)
|
66
|
+
conn = super(conn)
|
45
67
|
conn.extend(Sequel::JDBC::Postgres::AdapterMethods)
|
46
68
|
conn
|
47
69
|
end
|
70
|
+
|
71
|
+
# Call insert_result with the table and values specified in the opts.
|
72
|
+
def last_insert_id(conn, opts)
|
73
|
+
insert_result(conn, opts[:table], opts[:values])
|
74
|
+
end
|
48
75
|
end
|
49
76
|
|
77
|
+
# Dataset subclass used for datasets that connect to PostgreSQL via JDBC.
|
50
78
|
class Dataset < JDBC::Dataset
|
51
79
|
include Sequel::Postgres::DatasetMethods
|
52
80
|
|
81
|
+
# Convert Java::JavaSql::Timestamps correctly, and handle SQL::Blobs
|
82
|
+
# correctly.
|
53
83
|
def literal(v)
|
54
84
|
case v
|
55
85
|
when SQL::Blob
|
@@ -2,43 +2,39 @@ require 'sequel_core/adapters/shared/sqlite'
|
|
2
2
|
|
3
3
|
module Sequel
|
4
4
|
module JDBC
|
5
|
+
# Database and Dataset support for SQLite databases accessed via JDBC.
|
5
6
|
module SQLite
|
7
|
+
# Instance methods for SQLite Database objects accessed via JDBC.
|
6
8
|
module DatabaseMethods
|
7
9
|
include Sequel::SQLite::DatabaseMethods
|
8
10
|
|
11
|
+
# Return Sequel::JDBC::SQLite::Dataset object with the given opts.
|
9
12
|
def dataset(opts=nil)
|
10
13
|
Sequel::JDBC::SQLite::Dataset.new(self, opts)
|
11
14
|
end
|
12
15
|
|
13
|
-
|
16
|
+
private
|
17
|
+
|
18
|
+
# Use last_insert_rowid() to get the last inserted id.
|
19
|
+
def last_insert_id(conn, opts={})
|
20
|
+
stmt = conn.createStatement
|
14
21
|
begin
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
rs = stmt.executeQuery('SELECT last_insert_rowid()')
|
21
|
-
rs.next
|
22
|
-
rs.getInt(1)
|
23
|
-
rescue NativeException, JavaSQL::SQLException => e
|
24
|
-
raise Error, e.message
|
25
|
-
ensure
|
26
|
-
stmt.close
|
27
|
-
end
|
28
|
-
end
|
29
|
-
rescue NativeException, JavaSQL::SQLException => e
|
30
|
-
raise Error, "#{sql}\r\n#{e.message}"
|
22
|
+
rs = stmt.executeQuery('SELECT last_insert_rowid()')
|
23
|
+
rs.next
|
24
|
+
rs.getInt(1)
|
25
|
+
ensure
|
26
|
+
stmt.close
|
31
27
|
end
|
32
28
|
end
|
33
29
|
|
34
|
-
|
35
|
-
|
30
|
+
# Default to a single connection for a memory database.
|
36
31
|
def connection_pool_default_options
|
37
32
|
o = super
|
38
33
|
uri == 'jdbc:sqlite::memory:' ? o.merge(:max_connections=>1) : o
|
39
34
|
end
|
40
35
|
end
|
41
|
-
|
36
|
+
|
37
|
+
# Dataset class for SQLite datasets accessed via JDBC.
|
42
38
|
class Dataset < JDBC::Dataset
|
43
39
|
include Sequel::SQLite::DatasetMethods
|
44
40
|
end
|
@@ -1,8 +1,10 @@
|
|
1
1
|
require 'mysql'
|
2
2
|
require 'sequel_core/adapters/shared/mysql'
|
3
3
|
|
4
|
-
#
|
4
|
+
# Add methods to get columns, yield hashes with symbol keys, and do
|
5
|
+
# type conversion.
|
5
6
|
class Mysql::Result
|
7
|
+
# Mapping of type numbers to conversion methods.
|
6
8
|
MYSQL_TYPES = {
|
7
9
|
0 => :to_d, # MYSQL_TYPE_DECIMAL
|
8
10
|
1 => :to_i, # MYSQL_TYPE_TINY
|
@@ -32,21 +34,8 @@ class Mysql::Result
|
|
32
34
|
# 254 => :to_s, # MYSQL_TYPE_STRING
|
33
35
|
# 255 => :to_s # MYSQL_TYPE_GEOMETRY
|
34
36
|
}
|
35
|
-
|
36
|
-
|
37
|
-
if v
|
38
|
-
if type == 1 && Sequel.convert_tinyint_to_bool
|
39
|
-
# We special case tinyint here to avoid adding
|
40
|
-
# a method to an ancestor of Fixnum
|
41
|
-
v.to_i == 0 ? false : true
|
42
|
-
else
|
43
|
-
(t = MYSQL_TYPES[type]) ? v.send(t) : v
|
44
|
-
end
|
45
|
-
else
|
46
|
-
nil
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
37
|
+
|
38
|
+
# Return an array of column name symbols for this result set.
|
50
39
|
def columns(with_table = nil)
|
51
40
|
unless @columns
|
52
41
|
@column_types = []
|
@@ -58,18 +47,7 @@ class Mysql::Result
|
|
58
47
|
@columns
|
59
48
|
end
|
60
49
|
|
61
|
-
|
62
|
-
c = columns
|
63
|
-
while row = fetch_row
|
64
|
-
c.each_with_index do |f, i|
|
65
|
-
if (t = MYSQL_TYPES[@column_types[i]]) && (v = row[i])
|
66
|
-
row[i] = v.send(t)
|
67
|
-
end
|
68
|
-
end
|
69
|
-
yield row
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
50
|
+
# yield a hash with symbol keys and type converted values.
|
73
51
|
def sequel_each_hash(with_table = nil)
|
74
52
|
c = columns
|
75
53
|
while row = fetch_row
|
@@ -79,86 +57,104 @@ class Mysql::Result
|
|
79
57
|
end
|
80
58
|
end
|
81
59
|
|
60
|
+
private
|
61
|
+
|
62
|
+
# Convert the type of v using the method in MYSQL_TYPES[type].
|
63
|
+
def convert_type(v, type)
|
64
|
+
if v
|
65
|
+
if type == 1 && Sequel.convert_tinyint_to_bool
|
66
|
+
# We special case tinyint here to avoid adding
|
67
|
+
# a method to an ancestor of Fixnum
|
68
|
+
v.to_i == 0 ? false : true
|
69
|
+
else
|
70
|
+
(t = MYSQL_TYPES[type]) ? v.send(t) : v
|
71
|
+
end
|
72
|
+
else
|
73
|
+
nil
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
82
77
|
end
|
83
78
|
|
84
79
|
module Sequel
|
85
|
-
|
80
|
+
# Module for holding all MySQL-related classes and modules for Sequel.
|
81
|
+
module MySQL
|
82
|
+
# Database class for MySQL databases used with Sequel.
|
86
83
|
class Database < Sequel::Database
|
87
84
|
include Sequel::MySQL::DatabaseMethods
|
88
85
|
|
89
86
|
set_adapter_scheme :mysql
|
90
|
-
|
91
|
-
|
87
|
+
|
88
|
+
# Connect to the database. In addition to the usual database options,
|
89
|
+
# the following options have effect:
|
90
|
+
#
|
91
|
+
# * :encoding, :charset - Set all the related character sets for this
|
92
|
+
# connection (connection, client, database, server, and results).
|
93
|
+
# * :socket - Use a unix socket file instead of connecting via TCP/IP.
|
94
|
+
def connect(server)
|
95
|
+
opts = server_opts(server)
|
92
96
|
conn = Mysql.init
|
93
97
|
conn.options(Mysql::OPT_LOCAL_INFILE, "client")
|
94
98
|
conn.real_connect(
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
99
|
+
opts[:host] || 'localhost',
|
100
|
+
opts[:user],
|
101
|
+
opts[:password],
|
102
|
+
opts[:database],
|
103
|
+
opts[:port],
|
104
|
+
opts[:socket],
|
101
105
|
Mysql::CLIENT_MULTI_RESULTS +
|
102
106
|
Mysql::CLIENT_MULTI_STATEMENTS +
|
103
107
|
Mysql::CLIENT_COMPRESS
|
104
108
|
)
|
105
109
|
conn.query_with_result = false
|
106
|
-
if encoding =
|
110
|
+
if encoding = opts[:encoding] || opts[:charset]
|
107
111
|
conn.query("set character_set_connection = '#{encoding}'")
|
108
112
|
conn.query("set character_set_client = '#{encoding}'")
|
109
113
|
conn.query("set character_set_database = '#{encoding}'")
|
110
114
|
conn.query("set character_set_server = '#{encoding}'")
|
111
115
|
conn.query("set character_set_results = '#{encoding}'")
|
112
116
|
end
|
117
|
+
conn.meta_eval{attr_accessor :prepared_statements}
|
118
|
+
conn.prepared_statements = {}
|
113
119
|
conn.reconnect = true
|
114
120
|
conn
|
115
121
|
end
|
116
122
|
|
123
|
+
# Returns instance of Sequel::MySQL::Dataset with the given options.
|
117
124
|
def dataset(opts = nil)
|
118
125
|
MySQL::Dataset.new(self, opts)
|
119
126
|
end
|
120
|
-
|
127
|
+
|
128
|
+
# Closes all database connections.
|
121
129
|
def disconnect
|
122
130
|
@pool.disconnect {|c| c.close}
|
123
131
|
end
|
124
|
-
|
125
|
-
|
132
|
+
|
133
|
+
# Executes the given SQL using an available connection, yielding the
|
134
|
+
# connection if the block is given.
|
135
|
+
def execute(sql, opts={}, &block)
|
136
|
+
return execute_prepared_statement(sql, opts, &block) if Symbol === sql
|
126
137
|
begin
|
127
|
-
|
128
|
-
@pool.hold do |conn|
|
129
|
-
conn.query(sql)
|
130
|
-
block[conn] if block
|
131
|
-
end
|
138
|
+
synchronize(opts[:server]){|conn| _execute(conn, sql, opts, &block)}
|
132
139
|
rescue Mysql::Error => e
|
133
140
|
raise Error.new(e.message)
|
134
141
|
end
|
135
142
|
end
|
136
|
-
|
137
|
-
def execute_select(sql, &block)
|
138
|
-
execute(sql) do |c|
|
139
|
-
r = c.use_result
|
140
|
-
begin
|
141
|
-
block[r]
|
142
|
-
ensure
|
143
|
-
r.free
|
144
|
-
end
|
145
|
-
end
|
146
|
-
end
|
147
143
|
|
148
|
-
|
149
|
-
|
144
|
+
# Return the version of the MySQL server two which we are connecting.
|
145
|
+
def server_version(server=nil)
|
146
|
+
@server_version ||= (synchronize(server){|conn| conn.server_version if conn.respond_to?(:server_version)} || super)
|
150
147
|
end
|
151
148
|
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
end
|
149
|
+
# Return an array of symbols specifying table names in the current database.
|
150
|
+
def tables(server=nil)
|
151
|
+
synchronize(server){|conn| conn.list_tables.map {|t| t.to_sym}}
|
156
152
|
end
|
157
153
|
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
return yield(conn) if @transactions.include?
|
154
|
+
# Support single level transactions on MySQL.
|
155
|
+
def transaction(server=nil)
|
156
|
+
synchronize(server) do |conn|
|
157
|
+
return yield(conn) if @transactions.include?(Thread.current)
|
162
158
|
log_info(SQL_BEGIN)
|
163
159
|
conn.query(SQL_BEGIN)
|
164
160
|
begin
|
@@ -180,34 +176,103 @@ module Sequel
|
|
180
176
|
|
181
177
|
private
|
182
178
|
|
179
|
+
# Execute the given SQL on the given connection. If the :type
|
180
|
+
# option is :select, yield the result of the query, otherwise
|
181
|
+
# yield the connection if a block is given.
|
182
|
+
def _execute(conn, sql, opts)
|
183
|
+
log_info(sql)
|
184
|
+
conn.query(sql)
|
185
|
+
if opts[:type] == :select
|
186
|
+
r = conn.use_result
|
187
|
+
begin
|
188
|
+
yield r
|
189
|
+
ensure
|
190
|
+
r.free
|
191
|
+
end
|
192
|
+
else
|
193
|
+
yield conn if block_given?
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
# MySQL doesn't need the connection pool to convert exceptions.
|
183
198
|
def connection_pool_default_options
|
184
199
|
super.merge(:pool_convert_exceptions=>false)
|
185
200
|
end
|
186
201
|
|
202
|
+
# The database name when using the native adapter is always stored in
|
203
|
+
# the :database option.
|
187
204
|
def database_name
|
188
205
|
@opts[:database]
|
189
206
|
end
|
207
|
+
|
208
|
+
# Executes a prepared statement on an available connection. If the
|
209
|
+
# prepared statement already exists for the connection and has the same
|
210
|
+
# SQL, reuse it, otherwise, prepare the new statement. Because of the
|
211
|
+
# usual MySQL stupidity, we are forced to name arguments via separate
|
212
|
+
# SET queries. Use @sequel_arg_N (for N starting at 1) for these
|
213
|
+
# arguments.
|
214
|
+
def execute_prepared_statement(ps_name, opts, &block)
|
215
|
+
args = opts[:arguments]
|
216
|
+
ps = prepared_statements[ps_name]
|
217
|
+
sql = ps.prepared_sql
|
218
|
+
synchronize(opts[:server]) do |conn|
|
219
|
+
unless conn.prepared_statements[ps_name] == sql
|
220
|
+
conn.prepared_statements[ps_name] = sql
|
221
|
+
s = "PREPARE #{ps_name} FROM '#{::Mysql.quote(sql)}'"
|
222
|
+
log_info(s)
|
223
|
+
conn.query(s)
|
224
|
+
end
|
225
|
+
i = 0
|
226
|
+
args.each do |arg|
|
227
|
+
s = "SET @sequel_arg_#{i+=1} = #{literal(arg)}"
|
228
|
+
log_info(s)
|
229
|
+
conn.query(s)
|
230
|
+
end
|
231
|
+
_execute(conn, "EXECUTE #{ps_name}#{" USING #{(1..i).map{|j| "@sequel_arg_#{j}"}.join(', ')}" unless i == 0}", opts, &block)
|
232
|
+
end
|
233
|
+
end
|
190
234
|
end
|
191
|
-
|
235
|
+
|
236
|
+
# Dataset class for MySQL datasets accessed via the native driver.
|
192
237
|
class Dataset < Sequel::Dataset
|
193
238
|
include Sequel::MySQL::DatasetMethods
|
194
|
-
|
239
|
+
|
240
|
+
# Methods for MySQL prepared statements using the native driver.
|
241
|
+
module PreparedStatementMethods
|
242
|
+
include Sequel::Dataset::UnnumberedArgumentMapper
|
243
|
+
|
244
|
+
# Execute the prepared statement with the bind arguments instead of
|
245
|
+
# the given SQL.
|
246
|
+
def execute(sql, opts={}, &block)
|
247
|
+
super(prepared_statement_name, {:arguments=>bind_arguments}.merge(opts), &block)
|
248
|
+
end
|
249
|
+
|
250
|
+
# Same as execute, explicit due to intricacies of alias and super.
|
251
|
+
def execute_dui(sql, opts={}, &block)
|
252
|
+
super(prepared_statement_name, {:arguments=>bind_arguments}.merge(opts), &block)
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
# Delete rows matching this dataset
|
195
257
|
def delete(opts = nil)
|
196
|
-
|
258
|
+
execute_dui(delete_sql(opts)){|c| c.affected_rows}
|
197
259
|
end
|
198
|
-
|
260
|
+
|
261
|
+
# Yield all rows matching this dataset
|
199
262
|
def fetch_rows(sql)
|
200
|
-
|
263
|
+
execute(sql) do |r|
|
201
264
|
@columns = r.columns
|
202
265
|
r.sequel_each_hash {|row| yield row}
|
203
266
|
end
|
204
267
|
self
|
205
268
|
end
|
206
|
-
|
269
|
+
|
270
|
+
# Insert a new value into this dataset
|
207
271
|
def insert(*values)
|
208
|
-
|
272
|
+
execute_dui(insert_sql(*values)){|c| c.insert_id}
|
209
273
|
end
|
210
274
|
|
275
|
+
# Handle correct quoting of strings using ::MySQL.quote.
|
211
276
|
def literal(v)
|
212
277
|
case v
|
213
278
|
when LiteralString
|
@@ -219,12 +284,35 @@ module Sequel
|
|
219
284
|
end
|
220
285
|
end
|
221
286
|
|
287
|
+
# Store the given type of prepared statement in the associated database
|
288
|
+
# with the given name.
|
289
|
+
def prepare(type, name, values=nil)
|
290
|
+
ps = to_prepared_statement(type, values)
|
291
|
+
ps.extend(PreparedStatementMethods)
|
292
|
+
ps.prepared_statement_name = name
|
293
|
+
db.prepared_statements[name] = ps
|
294
|
+
end
|
295
|
+
|
296
|
+
# Replace (update or insert) the matching row.
|
222
297
|
def replace(*args)
|
223
|
-
|
298
|
+
execute_dui(replace_sql(*args)){|c| c.insert_id}
|
224
299
|
end
|
225
300
|
|
301
|
+
# Update the matching rows.
|
226
302
|
def update(*args)
|
227
|
-
|
303
|
+
execute_dui(update_sql(*args)){|c| c.affected_rows}
|
304
|
+
end
|
305
|
+
|
306
|
+
private
|
307
|
+
|
308
|
+
# Set the :type option to :select if it hasn't been set.
|
309
|
+
def execute(sql, opts={}, &block)
|
310
|
+
super(sql, {:type=>:select}.merge(opts), &block)
|
311
|
+
end
|
312
|
+
|
313
|
+
# Set the :type option to :dui if it hasn't been set.
|
314
|
+
def execute_dui(sql, opts={}, &block)
|
315
|
+
super(sql, {:type=>:dui}.merge(opts), &block)
|
228
316
|
end
|
229
317
|
end
|
230
318
|
end
|