sequel 3.10.0 → 3.11.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +68 -0
- data/COPYING +1 -1
- data/README.rdoc +87 -27
- data/bin/sequel +2 -4
- data/doc/association_basics.rdoc +1383 -0
- data/doc/dataset_basics.rdoc +106 -0
- data/doc/opening_databases.rdoc +45 -16
- data/doc/querying.rdoc +210 -0
- data/doc/release_notes/3.11.0.txt +254 -0
- data/doc/virtual_rows.rdoc +217 -31
- data/lib/sequel/adapters/ado.rb +28 -12
- data/lib/sequel/adapters/ado/mssql.rb +33 -1
- data/lib/sequel/adapters/amalgalite.rb +13 -8
- data/lib/sequel/adapters/db2.rb +1 -2
- data/lib/sequel/adapters/dbi.rb +7 -4
- data/lib/sequel/adapters/do.rb +14 -15
- data/lib/sequel/adapters/do/postgres.rb +4 -5
- data/lib/sequel/adapters/do/sqlite.rb +9 -0
- data/lib/sequel/adapters/firebird.rb +5 -10
- data/lib/sequel/adapters/informix.rb +2 -4
- data/lib/sequel/adapters/jdbc.rb +111 -49
- data/lib/sequel/adapters/jdbc/mssql.rb +1 -2
- data/lib/sequel/adapters/jdbc/mysql.rb +11 -0
- data/lib/sequel/adapters/jdbc/oracle.rb +4 -7
- data/lib/sequel/adapters/jdbc/postgresql.rb +8 -1
- data/lib/sequel/adapters/jdbc/sqlite.rb +12 -0
- data/lib/sequel/adapters/mysql.rb +14 -5
- data/lib/sequel/adapters/odbc.rb +2 -4
- data/lib/sequel/adapters/odbc/mssql.rb +2 -4
- data/lib/sequel/adapters/openbase.rb +1 -2
- data/lib/sequel/adapters/oracle.rb +4 -8
- data/lib/sequel/adapters/postgres.rb +4 -11
- data/lib/sequel/adapters/shared/mssql.rb +22 -9
- data/lib/sequel/adapters/shared/mysql.rb +33 -30
- data/lib/sequel/adapters/shared/oracle.rb +0 -5
- data/lib/sequel/adapters/shared/postgres.rb +13 -11
- data/lib/sequel/adapters/shared/sqlite.rb +56 -10
- data/lib/sequel/adapters/sqlite.rb +16 -9
- data/lib/sequel/connection_pool.rb +6 -1
- data/lib/sequel/connection_pool/single.rb +1 -0
- data/lib/sequel/core.rb +6 -1
- data/lib/sequel/database.rb +52 -23
- data/lib/sequel/database/schema_generator.rb +6 -0
- data/lib/sequel/database/schema_methods.rb +5 -5
- data/lib/sequel/database/schema_sql.rb +1 -1
- data/lib/sequel/dataset.rb +4 -190
- data/lib/sequel/dataset/actions.rb +323 -1
- data/lib/sequel/dataset/features.rb +18 -2
- data/lib/sequel/dataset/graph.rb +7 -0
- data/lib/sequel/dataset/misc.rb +119 -0
- data/lib/sequel/dataset/mutation.rb +64 -0
- data/lib/sequel/dataset/prepared_statements.rb +6 -0
- data/lib/sequel/dataset/query.rb +272 -6
- data/lib/sequel/dataset/sql.rb +186 -394
- data/lib/sequel/model.rb +4 -2
- data/lib/sequel/model/associations.rb +31 -14
- data/lib/sequel/model/base.rb +32 -13
- data/lib/sequel/model/exceptions.rb +8 -4
- data/lib/sequel/model/plugins.rb +3 -13
- data/lib/sequel/plugins/active_model.rb +26 -7
- data/lib/sequel/plugins/instance_filters.rb +98 -0
- data/lib/sequel/plugins/many_through_many.rb +1 -1
- data/lib/sequel/plugins/optimistic_locking.rb +25 -9
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/mssql_spec.rb +26 -0
- data/spec/adapters/mysql_spec.rb +33 -4
- data/spec/adapters/postgres_spec.rb +24 -1
- data/spec/adapters/spec_helper.rb +6 -0
- data/spec/adapters/sqlite_spec.rb +28 -0
- data/spec/core/connection_pool_spec.rb +17 -5
- data/spec/core/database_spec.rb +101 -1
- data/spec/core/dataset_spec.rb +42 -4
- data/spec/core/schema_spec.rb +13 -0
- data/spec/extensions/active_model_spec.rb +34 -11
- data/spec/extensions/caching_spec.rb +2 -0
- data/spec/extensions/instance_filters_spec.rb +55 -0
- data/spec/extensions/spec_helper.rb +2 -0
- data/spec/integration/dataset_test.rb +12 -1
- data/spec/integration/model_test.rb +12 -0
- data/spec/integration/plugin_test.rb +61 -1
- data/spec/integration/schema_test.rb +14 -3
- data/spec/model/base_spec.rb +27 -0
- data/spec/model/plugins_spec.rb +0 -22
- data/spec/model/record_spec.rb +32 -1
- data/spec/model/spec_helper.rb +2 -0
- metadata +14 -3
- data/lib/sequel/dataset/convenience.rb +0 -326
data/doc/virtual_rows.rdoc
CHANGED
@@ -1,29 +1,227 @@
|
|
1
1
|
= Virtual Row Blocks
|
2
2
|
|
3
|
-
Dataset methods filter, order, and select all take blocks that
|
4
|
-
instances of Sequel::SQL::VirtualRow (if the block takes an argument), or
|
5
|
-
are evaluated in the context of an instance of Sequel::SQL::VirtualRow. These are referred to as
|
3
|
+
Dataset methods filter, order, and select all take blocks that are referred to as
|
6
4
|
virtual row blocks. Many other dataset methods pass the blocks
|
7
5
|
they are given into one of those three methods, so there are actually
|
8
|
-
many Sequel methods that take virtual row blocks.
|
6
|
+
many Sequel::Dataset methods that take virtual row blocks.
|
9
7
|
|
10
|
-
|
11
|
-
|
12
|
-
|
8
|
+
== Why Virtual Rows
|
9
|
+
|
10
|
+
Virtual Rows were created to work around the issue that some parts of
|
11
|
+
Sequel's standard DSL could not be used on ruby 1.9. For example, the
|
12
|
+
following Sequel code works on ruby 1.8, but not ruby 1.9:
|
13
|
+
|
14
|
+
dataset.filter(:a > :b[:c])
|
15
|
+
# WHERE a > b(c)
|
16
|
+
|
17
|
+
This code does not work on ruby 1.9 for two reasons. First, Symbol#>
|
18
|
+
(like other inequality methods) is already defined in ruby 1.9, so Sequel
|
19
|
+
does not override it to return an SQL inequality expression. Second, Symbol#[]
|
20
|
+
is already defined on ruby 1.9, so Sequel does not override it to return an
|
21
|
+
SQL function expression.
|
22
|
+
|
23
|
+
Prior to the introduction of virtual rows, the way to handle this was
|
24
|
+
to use the methods that work on both ruby 1.8 and ruby 1.9:
|
25
|
+
|
26
|
+
dataset.filter(:a.identifier > :b.sql_function(:c))
|
27
|
+
# WHERE a > b(c)
|
28
|
+
|
29
|
+
However, that code is a little verbose. The virtual row DSL makes such code
|
30
|
+
more concise:
|
31
|
+
|
32
|
+
dataset.filter{a > b(c)}
|
33
|
+
|
34
|
+
Another use of virtual rows is when you turn off Sequel's core extensions off
|
35
|
+
using the SEQUEL_NO_CORE_EXTENSIONS constant or environment variable. With
|
36
|
+
the core extensions turned off, much of the standard Sequel DSL is not
|
37
|
+
available. For example, you are no longer able to do:
|
38
|
+
|
39
|
+
dataset.filter(:a & (:b | ~:c))
|
40
|
+
# WHERE a AND (b OR NOT c)
|
41
|
+
|
42
|
+
Because Symbol#&, Symbol#| and Symbol#~ are not defined when the core
|
43
|
+
extensions are turned off. However, with virtual rows allow almost the same
|
44
|
+
syntax even without the core extensions:
|
45
|
+
|
46
|
+
dataset.filter{a & (b | ~c)}
|
47
|
+
|
48
|
+
== Regular Procs vs Instance Evaled Procs
|
49
|
+
|
50
|
+
Virtual row blocks behave differently depending on whether the block accepts
|
51
|
+
an argument. If the block accepts an argument, it is called with an instance
|
52
|
+
of Sequel::SQL::VirtualRow. If it does not accept an argument, it is
|
53
|
+
evaluated in the context of an instance of Sequel::SQL::VirtualRow.
|
13
54
|
|
14
55
|
ds = DB[:items]
|
15
|
-
|
16
|
-
ds.filter{
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
ds.
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
56
|
+
# Regular proc
|
57
|
+
ds.filter{|o| o.column > 1}
|
58
|
+
# WHERE column > 1
|
59
|
+
|
60
|
+
# Instance-evaled proc
|
61
|
+
ds.filter{column > 1}
|
62
|
+
# WHERE column > 1
|
63
|
+
|
64
|
+
If you aren't familiar with the difference between regular blocks and instance
|
65
|
+
evaled blocks, you should probably consult a general ruby reference, but briefly,
|
66
|
+
with regular procs, methods called without an explicit receiver inside the
|
67
|
+
proc call the method on the receiver in the surrounding scope, while instance
|
68
|
+
evaled procs call the method on the receiver of the instance_eval call. However,
|
69
|
+
in both cases, local variables available in the surrounding scope will be available
|
70
|
+
inside the proc. If that doesn't make sense, maybe this example will help:
|
71
|
+
|
72
|
+
def self.a
|
73
|
+
42
|
74
|
+
end
|
75
|
+
b = 32
|
76
|
+
|
77
|
+
# Regular proc
|
78
|
+
ds.filter{|o| o.c > a - b}
|
79
|
+
# WHERE c > 10
|
80
|
+
|
81
|
+
# Instance-evaled proc
|
82
|
+
ds.filter{c > a - b}
|
83
|
+
# WHERE c > (a - 32)
|
84
|
+
|
85
|
+
There are two related differences here. First is the usage of "o.c" vs "c",
|
86
|
+
and second is the difference between the the use of "a". In the regular proc,
|
87
|
+
you couldn't call c without an explicit receiver in the proc, unless the self of the
|
88
|
+
surrounding scope responded to it. For a, note how ruby calls the method on
|
89
|
+
the receiver of the surrounding scope in the regular proc, which returns an integer,
|
90
|
+
and does the substraction before Sequel gets access to it. In the instance evaled
|
91
|
+
proc, calling a without a receiver calls the a method on the VirtualRow instance.
|
92
|
+
For b, note that it operates the same in both cases, as it is a local variable.
|
93
|
+
|
94
|
+
Basically, the choice for whether to use a regular proc or an instance evaled proc is
|
95
|
+
completely up to you. The same things can be accomplished with both.
|
96
|
+
Instance evaled procs tend to produce shorter code, but by modifying the scope
|
97
|
+
can be more difficult for a new user to understand. That being said, I usually
|
98
|
+
use instance evaled procs unless I need to call methods on the receiver of the
|
99
|
+
surrounding scope inside the proc.
|
100
|
+
|
101
|
+
== Local Variables vs Method Calls
|
102
|
+
|
103
|
+
If you have a method that accepts 0 arguments and has the same name as a local
|
104
|
+
variable, you can call it with () to differentiate the method call from the
|
105
|
+
local variable access. This is mostly useful in instance_evaled procs:
|
106
|
+
|
107
|
+
b = 32
|
108
|
+
ds.filter{b() > b}
|
109
|
+
# WHERE b > 32
|
110
|
+
|
111
|
+
== VirtualRow Methods
|
112
|
+
|
113
|
+
VirtualRow is a class that returns SQL::Identifiers, SQL::QualifiedIdentifiers,
|
114
|
+
SQL::Functions, or SQL::WindowFunctions depending on how it is called.
|
115
|
+
|
116
|
+
== SQL::Identifiers - Regular columns
|
117
|
+
|
118
|
+
SQL::Identifiers can be thought of as regular column references in SQL,
|
119
|
+
not qualified by any table. You get an SQL::Identifier if the method is called
|
120
|
+
without a block or arguments, and doesn't have a double underscore in the method
|
121
|
+
name:
|
122
|
+
|
123
|
+
ds.filter{|o| o.column > 1}
|
124
|
+
ds.filter{column > 1}
|
125
|
+
# WHERE column > 1
|
126
|
+
|
127
|
+
== SQL::QualifiedIdentifiers - Qualified columns
|
128
|
+
|
129
|
+
SQL::QualifiedIdentifiers can be thought of as column references in SQL that
|
130
|
+
are qualified to a specific table. You get an SQL::QualifiedIdentifier if
|
131
|
+
the method is called without a block or arguments, and has a double underscore
|
132
|
+
in the method name:
|
133
|
+
|
134
|
+
ds.filter{|o| o.table__column > 1}
|
135
|
+
ds.filter{table__column > 1}
|
136
|
+
# WHERE table.column > 1
|
137
|
+
|
138
|
+
Using the double underscore for SQL::QualifiedIdentifiers was done to make
|
139
|
+
usage very similar to using symbols, which also translate the double underscore
|
140
|
+
into a qualified column.
|
141
|
+
|
142
|
+
== SQL::Functions - SQL function calls
|
143
|
+
|
144
|
+
SQL::Functions can be thought of as function calls in SQL. You get a simple
|
145
|
+
function call if you call a method with arguments and without a block:
|
146
|
+
|
147
|
+
ds.filter{|o| o.function(1) > 1}
|
148
|
+
ds.filter{function(1) > 1}
|
149
|
+
# WHERE function(1) > 1
|
150
|
+
|
151
|
+
To call a SQL function with multiple arguments, just use those arguments in
|
152
|
+
your function call:
|
153
|
+
|
154
|
+
ds.filter{|o| o.function(1, o.a) > 1}
|
155
|
+
ds.filter{function(1, a) > 1}
|
156
|
+
# WHERE function(1, a) > 1
|
157
|
+
|
158
|
+
If the SQL function does not accept any arguments, you need to provide an empty
|
159
|
+
block to the method to distinguish it from a call that will produce an
|
160
|
+
SQL::Identifier:
|
161
|
+
|
162
|
+
ds.select{|o| o.version{}}
|
163
|
+
ds.select{version{}}
|
164
|
+
# SELECT version()
|
165
|
+
|
166
|
+
To use the SQL wildcard (*) as the sole argument in a function call (most often
|
167
|
+
used with the count function), you should provide :* as the sole argument to
|
168
|
+
the method, and provide an empty block to the method:
|
169
|
+
|
170
|
+
ds.select{|o| o.count(:*){}}
|
171
|
+
ds.select{count(:*){}}
|
172
|
+
# SELECT count(*)
|
173
|
+
|
174
|
+
To append the DISTINCT keyword before the method arguments, you need to make
|
175
|
+
:distinct the first argument of the method call, and provide an empty block to
|
176
|
+
the method:
|
177
|
+
|
178
|
+
ds.select{|o| o.count(:distinct, o.col1){}}
|
179
|
+
ds.select{count(:distinct, col1){}}
|
180
|
+
# SELECT count(DISTINCT col1)
|
181
|
+
|
182
|
+
To use multiple columns with the DISTINCT keyword, use multiple arguments in
|
183
|
+
the method call:
|
184
|
+
|
185
|
+
ds.select{|o| o.count(:distinct, o.col1, o.col2){}}
|
186
|
+
ds.select{count(:distinct, col1, col2){}}
|
187
|
+
# SELECT count(DISTINCT col1, col2)
|
188
|
+
|
189
|
+
== SQL::WindowFunctions - SQL window function calls
|
190
|
+
|
191
|
+
SQL::WindowFunctions can be thought of as calls to SQL window functions. Not
|
192
|
+
all databases support them, but they are very helpful for certain types of
|
193
|
+
queries. To use them, you need to make :over the first argument of the method
|
194
|
+
call, with an optional hash as the second argument: Here are some examples of use:
|
195
|
+
|
196
|
+
ds.select{|o| o.rank(:over){}}
|
197
|
+
ds.select{rank(:over){}}
|
198
|
+
# SELECT rank() OVER ()
|
199
|
+
|
200
|
+
ds.select{|o| o.count(:over, :*=>true){}}
|
201
|
+
ds.select{count(:over, :*=>true){}}
|
202
|
+
# SELECT count(*) OVER ()
|
203
|
+
|
204
|
+
ds.select{|o| o.sum(:over, :args=>o.col1, :partition=>o.col2, :order=>o.col3){}}
|
205
|
+
ds.select{sum(:over, :args=>col1, :partition=>col2, :order=>col3){}}
|
206
|
+
# SELECT sum(col1) OVER (PARTITION BY col2 ORDER BY col3)
|
207
|
+
|
208
|
+
== Returning multiple values
|
209
|
+
|
210
|
+
It's common when using select and order virtual row blocks to want to
|
211
|
+
return multiple values. If you want to do that, you just need to return a single
|
212
|
+
array:
|
213
|
+
|
214
|
+
ds.select{|o| [o.column1, o.sum(o.column2).as(o.sum)]}
|
215
|
+
ds.select{[column1, sum(column2).as(sum)]}
|
216
|
+
# SELECT column1, sum(column2) AS sum
|
217
|
+
|
218
|
+
Note that if you forget the array brackets, you'll end up with a syntax error:
|
219
|
+
|
220
|
+
# Invalid ruby syntax
|
221
|
+
ds.select{|o| o.column1, o.sum(o.column2).as(o.sum)}
|
222
|
+
ds.select{column1, sum(column2).as(sum)}
|
223
|
+
|
224
|
+
== Alternative Description of the VirtualRow method call rules
|
27
225
|
|
28
226
|
* If a block is given:
|
29
227
|
* The block is currently not called. This may change in a future version.
|
@@ -45,15 +243,3 @@ Basically, the rules are:
|
|
45
243
|
SQL::QualifiedIdentifier with the table and column.
|
46
244
|
* Otherwise, create an SQL::Identifier with the name of the
|
47
245
|
method.
|
48
|
-
|
49
|
-
If you use a virtual row block that doesn't take an argument,
|
50
|
-
the block is instance_evaled, so you can't reference methods
|
51
|
-
in the enclosing scope. If you need to call methods of the
|
52
|
-
enclosing scope, you should assign the results to local variables
|
53
|
-
before the block, or just make the block take an argument and use
|
54
|
-
that. If you want to create identifiers or qualified identifiers
|
55
|
-
with the same name as existing local variables, make sure ruby
|
56
|
-
knows it is a method call instead of a local variable reference
|
57
|
-
by not ommiting the parentheses at the end of the method call.
|
58
|
-
If you want to return multiple arguments (common for select and
|
59
|
-
order), have the block return an array of arguments.
|
data/lib/sequel/adapters/ado.rb
CHANGED
@@ -16,16 +16,26 @@ module Sequel
|
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
-
#
|
19
|
+
# In addition to the usual database options,
|
20
20
|
# the following options have an effect:
|
21
21
|
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
28
|
-
#
|
22
|
+
# :command_timeout :: Sets the time in seconds to wait while attempting
|
23
|
+
# to execute a command before cancelling the attempt and generating
|
24
|
+
# an error. Specifically, it sets the ADO CommandTimeout property.
|
25
|
+
# If this property is not set, the default of 30 seconds is used.
|
26
|
+
# :driver :: The driver to use in the ADO connection string. If not provided, a default
|
27
|
+
# of "SQL Server" is used.
|
28
|
+
# :conn_string :: The full ADO connection string. If this is provided,
|
29
|
+
# the usual options are ignored.
|
30
|
+
# :provider :: Sets the Provider of this ADO connection (for example, "SQLOLEDB").
|
31
|
+
# If you don't specify a provider, the default one used by WIN32OLE
|
32
|
+
# has major problems, such as creating a new native database connection
|
33
|
+
# for every query, which breaks things such as temporary tables.
|
34
|
+
#
|
35
|
+
# Pay special attention to the :provider option, as without specifying a provider,
|
36
|
+
# many things will be broken. The SQLNCLI10 provider appears to work well if you
|
37
|
+
# are connecting to Microsoft SQL Server, but it is not the default as that would
|
38
|
+
# break backwards compatability.
|
29
39
|
def connect(server)
|
30
40
|
opts = server_opts(server)
|
31
41
|
s = opts[:conn_string] || "driver=#{opts[:driver]};server=#{opts[:host]};database=#{opts[:database]}#{";uid=#{opts[:user]};pwd=#{opts[:password]}" if opts[:user]}"
|
@@ -41,10 +51,9 @@ module Sequel
|
|
41
51
|
end
|
42
52
|
|
43
53
|
def execute(sql, opts={})
|
44
|
-
log_info(sql)
|
45
54
|
synchronize(opts[:server]) do |conn|
|
46
55
|
begin
|
47
|
-
r = conn.Execute(sql)
|
56
|
+
r = log_yield(sql){conn.Execute(sql)}
|
48
57
|
yield(r) if block_given?
|
49
58
|
rescue ::WIN32OLERuntimeError => e
|
50
59
|
raise_error(e)
|
@@ -56,9 +65,11 @@ module Sequel
|
|
56
65
|
|
57
66
|
private
|
58
67
|
|
59
|
-
# The ADO adapter doesn't support transactions, since it
|
60
|
-
#
|
68
|
+
# The ADO adapter's default provider doesn't support transactions, since it
|
69
|
+
# creates a new native connection for each query. So Sequel only attempts
|
70
|
+
# to use transactions if an explicit :provider is given.
|
61
71
|
def _transaction(conn)
|
72
|
+
return super if opts[:provider]
|
62
73
|
th = Thread.current
|
63
74
|
begin
|
64
75
|
@transactions << th
|
@@ -81,6 +92,11 @@ module Sequel
|
|
81
92
|
s.getRows.transpose.each{|r| yield cols.inject({}){|m,c| m[c] = r.shift; m}} unless s.eof
|
82
93
|
end
|
83
94
|
end
|
95
|
+
|
96
|
+
# ADO returns nil for all for delete and update statements.
|
97
|
+
def provides_accurate_rows_matched?
|
98
|
+
false
|
99
|
+
end
|
84
100
|
end
|
85
101
|
end
|
86
102
|
end
|
@@ -7,11 +7,36 @@ module Sequel
|
|
7
7
|
module MSSQL
|
8
8
|
module DatabaseMethods
|
9
9
|
include Sequel::MSSQL::DatabaseMethods
|
10
|
+
# Query to use to get the number of rows affected by an update or
|
11
|
+
# delete query.
|
12
|
+
ROWS_AFFECTED = "SELECT @@ROWCOUNT AS AffectedRows"
|
10
13
|
|
11
14
|
# Return instance of Sequel::ADO::MSSQL::Dataset with the given opts.
|
12
15
|
def dataset(opts=nil)
|
13
16
|
Sequel::ADO::MSSQL::Dataset.new(self, opts)
|
14
17
|
end
|
18
|
+
|
19
|
+
# Just execute so it doesn't attempt to return the number of rows modified.
|
20
|
+
def execute_ddl(sql, opts={})
|
21
|
+
execute(sql, opts)
|
22
|
+
end
|
23
|
+
alias execute_insert execute_ddl
|
24
|
+
|
25
|
+
# Issue a separate query to get the rows modified. ADO appears to
|
26
|
+
# use pass by reference with an integer variable, which is obviously
|
27
|
+
# not supported directly in ruby, and I'm not aware of a workaround.
|
28
|
+
def execute_dui(sql, opts={})
|
29
|
+
return super unless @opts[:provider]
|
30
|
+
synchronize(opts[:server]) do |conn|
|
31
|
+
begin
|
32
|
+
log_yield(sql){conn.Execute(sql)}
|
33
|
+
res = log_yield(ROWS_AFFECTED){conn.Execute(ROWS_AFFECTED)}
|
34
|
+
res.getRows.transpose.each{|r| return r.shift}
|
35
|
+
rescue ::WIN32OLERuntimeError => e
|
36
|
+
raise_error(e)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
15
40
|
end
|
16
41
|
|
17
42
|
class Dataset < ADO::Dataset
|
@@ -19,11 +44,18 @@ module Sequel
|
|
19
44
|
|
20
45
|
# Use a nasty hack of multiple SQL statements in the same call and
|
21
46
|
# having the last one return the most recently inserted id. This
|
22
|
-
# is necessary as ADO
|
47
|
+
# is necessary as ADO's default :provider uses a separate native
|
48
|
+
# connection for each query.
|
23
49
|
def insert(*values)
|
24
50
|
return super if @opts[:sql]
|
25
51
|
with_sql("SET NOCOUNT ON; #{insert_sql(*values)}; SELECT CAST(SCOPE_IDENTITY() AS INTEGER)").single_value
|
26
52
|
end
|
53
|
+
|
54
|
+
# If you use a better :provider option for the database, you can get an
|
55
|
+
# accurate number of rows matched.
|
56
|
+
def provides_accurate_rows_matched?
|
57
|
+
!!db.opts[:provider]
|
58
|
+
end
|
27
59
|
end
|
28
60
|
end
|
29
61
|
end
|
@@ -84,37 +84,42 @@ module Sequel
|
|
84
84
|
|
85
85
|
# Run the given SQL with the given arguments. Returns nil.
|
86
86
|
def execute_ddl(sql, opts={})
|
87
|
-
_execute(sql, opts){|conn| conn.execute_batch(sql)
|
87
|
+
_execute(sql, opts){|conn| log_yield(sql){conn.execute_batch(sql)}}
|
88
88
|
nil
|
89
89
|
end
|
90
90
|
|
91
91
|
# Run the given SQL with the given arguments and return the number of changed rows.
|
92
92
|
def execute_dui(sql, opts={})
|
93
|
-
_execute(sql, opts){|conn| conn.execute_batch(sql); conn.row_changes}
|
93
|
+
_execute(sql, opts){|conn| log_yield(sql){conn.execute_batch(sql)}; conn.row_changes}
|
94
94
|
end
|
95
95
|
|
96
96
|
# Run the given SQL with the given arguments and return the last inserted row id.
|
97
97
|
def execute_insert(sql, opts={})
|
98
|
-
_execute(sql, opts){|conn| conn.execute_batch(sql); conn.last_insert_rowid}
|
98
|
+
_execute(sql, opts){|conn| log_yield(sql){conn.execute_batch(sql)}; conn.last_insert_rowid}
|
99
99
|
end
|
100
100
|
|
101
101
|
# Run the given SQL with the given arguments and yield each row.
|
102
|
-
def execute(sql, opts={}
|
103
|
-
_execute(sql, opts)
|
102
|
+
def execute(sql, opts={})
|
103
|
+
_execute(sql, opts) do |conn|
|
104
|
+
begin
|
105
|
+
yield(stmt = log_yield(sql){conn.prepare(sql)})
|
106
|
+
ensure
|
107
|
+
stmt.close if stmt
|
108
|
+
end
|
109
|
+
end
|
104
110
|
end
|
105
111
|
|
106
112
|
# Run the given SQL with the given arguments and return the first value of the first row.
|
107
113
|
def single_value(sql, opts={})
|
108
|
-
_execute(sql, opts){|conn| conn.first_value_from(sql)}
|
114
|
+
_execute(sql, opts){|conn| log_yield(sql){conn.first_value_from(sql)}}
|
109
115
|
end
|
110
116
|
|
111
117
|
private
|
112
118
|
|
113
|
-
#
|
119
|
+
# Yield an available connection. Rescue
|
114
120
|
# any Amalgalite::Errors and turn them into DatabaseErrors.
|
115
121
|
def _execute(sql, opts)
|
116
122
|
begin
|
117
|
-
log_info(sql)
|
118
123
|
synchronize(opts[:server]){|conn| yield conn}
|
119
124
|
rescue ::Amalgalite::Error, ::Amalgalite::SQLite3::Error => e
|
120
125
|
raise_error(e)
|
data/lib/sequel/adapters/db2.rb
CHANGED
@@ -33,13 +33,12 @@ module Sequel
|
|
33
33
|
end
|
34
34
|
|
35
35
|
def execute(sql, opts={})
|
36
|
-
log_info(sql)
|
37
36
|
synchronize(opts[:server]) do |conn|
|
38
37
|
rc, sth = SQLAllocHandle(SQL_HANDLE_STMT, @handle)
|
39
38
|
check_error(rc, "Could not allocate statement")
|
40
39
|
|
41
40
|
begin
|
42
|
-
rc = SQLExecDirect(sth, sql)
|
41
|
+
rc = log_yield(sql){SQLExecDirect(sth, sql)}
|
43
42
|
check_error(rc, "Could not execute statement")
|
44
43
|
|
45
44
|
yield(sth) if block_given?
|