sequel 3.10.0 → 3.11.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 +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?
|