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