sequel 3.29.0 → 3.30.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 +35 -3
- data/Rakefile +2 -1
- data/doc/association_basics.rdoc +11 -0
- data/doc/opening_databases.rdoc +2 -0
- data/doc/release_notes/3.30.0.txt +135 -0
- data/doc/testing.rdoc +17 -3
- data/lib/sequel/adapters/amalgalite.rb +2 -2
- data/lib/sequel/adapters/do/mysql.rb +5 -2
- data/lib/sequel/adapters/ibmdb.rb +2 -2
- data/lib/sequel/adapters/jdbc.rb +126 -43
- data/lib/sequel/adapters/jdbc/as400.rb +11 -3
- data/lib/sequel/adapters/jdbc/db2.rb +2 -1
- data/lib/sequel/adapters/jdbc/derby.rb +44 -19
- data/lib/sequel/adapters/jdbc/h2.rb +32 -19
- data/lib/sequel/adapters/jdbc/hsqldb.rb +21 -17
- data/lib/sequel/adapters/jdbc/jtds.rb +9 -4
- data/lib/sequel/adapters/jdbc/mssql.rb +3 -1
- data/lib/sequel/adapters/jdbc/mysql.rb +2 -1
- data/lib/sequel/adapters/jdbc/oracle.rb +21 -7
- data/lib/sequel/adapters/jdbc/postgresql.rb +3 -2
- data/lib/sequel/adapters/jdbc/sqlite.rb +2 -1
- data/lib/sequel/adapters/jdbc/sqlserver.rb +48 -18
- data/lib/sequel/adapters/mock.rb +2 -1
- data/lib/sequel/adapters/mysql.rb +4 -2
- data/lib/sequel/adapters/mysql2.rb +2 -2
- data/lib/sequel/adapters/odbc/mssql.rb +1 -1
- data/lib/sequel/adapters/openbase.rb +1 -1
- data/lib/sequel/adapters/oracle.rb +6 -6
- data/lib/sequel/adapters/postgres.rb +25 -12
- data/lib/sequel/adapters/shared/access.rb +14 -6
- data/lib/sequel/adapters/shared/db2.rb +36 -13
- data/lib/sequel/adapters/shared/firebird.rb +12 -5
- data/lib/sequel/adapters/shared/informix.rb +11 -3
- data/lib/sequel/adapters/shared/mssql.rb +94 -47
- data/lib/sequel/adapters/shared/mysql.rb +107 -49
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +2 -2
- data/lib/sequel/adapters/shared/oracle.rb +54 -27
- data/lib/sequel/adapters/shared/postgres.rb +65 -26
- data/lib/sequel/adapters/shared/progress.rb +4 -1
- data/lib/sequel/adapters/shared/sqlite.rb +36 -20
- data/lib/sequel/adapters/sqlite.rb +2 -3
- data/lib/sequel/adapters/swift/mysql.rb +3 -2
- data/lib/sequel/adapters/swift/sqlite.rb +2 -2
- data/lib/sequel/adapters/tinytds.rb +14 -8
- data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +7 -4
- data/lib/sequel/database/misc.rb +6 -2
- data/lib/sequel/dataset/graph.rb +33 -7
- data/lib/sequel/dataset/prepared_statements.rb +19 -5
- data/lib/sequel/dataset/sql.rb +611 -201
- data/lib/sequel/model/associations.rb +12 -5
- data/lib/sequel/model/base.rb +20 -5
- data/lib/sequel/plugins/sharding.rb +9 -29
- data/lib/sequel/sql.rb +2 -1
- data/lib/sequel/timezones.rb +14 -4
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/mysql_spec.rb +10 -0
- data/spec/adapters/oracle_spec.rb +1 -1
- data/spec/core/core_sql_spec.rb +3 -1
- data/spec/core/database_spec.rb +42 -0
- data/spec/core/dataset_spec.rb +10 -3
- data/spec/core/mock_adapter_spec.rb +4 -0
- data/spec/core/object_graph_spec.rb +38 -0
- data/spec/extensions/association_autoreloading_spec.rb +1 -10
- data/spec/extensions/association_dependencies_spec.rb +2 -12
- data/spec/extensions/association_pks_spec.rb +35 -39
- data/spec/extensions/caching_spec.rb +23 -50
- data/spec/extensions/class_table_inheritance_spec.rb +30 -82
- data/spec/extensions/composition_spec.rb +18 -13
- data/spec/extensions/hook_class_methods_spec.rb +65 -91
- data/spec/extensions/identity_map_spec.rb +33 -103
- data/spec/extensions/instance_filters_spec.rb +10 -21
- data/spec/extensions/instance_hooks_spec.rb +6 -24
- data/spec/extensions/json_serializer_spec.rb +4 -5
- data/spec/extensions/lazy_attributes_spec.rb +16 -20
- data/spec/extensions/list_spec.rb +17 -39
- data/spec/extensions/many_through_many_spec.rb +135 -277
- data/spec/extensions/migration_spec.rb +18 -15
- data/spec/extensions/named_timezones_spec.rb +1 -1
- data/spec/extensions/nested_attributes_spec.rb +97 -92
- data/spec/extensions/optimistic_locking_spec.rb +9 -20
- data/spec/extensions/prepared_statements_associations_spec.rb +22 -37
- data/spec/extensions/prepared_statements_safe_spec.rb +9 -27
- data/spec/extensions/prepared_statements_spec.rb +11 -30
- data/spec/extensions/prepared_statements_with_pk_spec.rb +6 -13
- data/spec/extensions/pretty_table_spec.rb +1 -6
- data/spec/extensions/rcte_tree_spec.rb +41 -43
- data/spec/extensions/schema_dumper_spec.rb +3 -6
- data/spec/extensions/serialization_spec.rb +20 -32
- data/spec/extensions/sharding_spec.rb +66 -140
- data/spec/extensions/single_table_inheritance_spec.rb +14 -36
- data/spec/extensions/spec_helper.rb +10 -64
- data/spec/extensions/sql_expr_spec.rb +20 -60
- data/spec/extensions/tactical_eager_loading_spec.rb +9 -19
- data/spec/extensions/timestamps_spec.rb +6 -6
- data/spec/extensions/to_dot_spec.rb +1 -2
- data/spec/extensions/touch_spec.rb +13 -14
- data/spec/extensions/tree_spec.rb +11 -26
- data/spec/extensions/update_primary_key_spec.rb +30 -24
- data/spec/extensions/validation_class_methods_spec.rb +30 -51
- data/spec/extensions/validation_helpers_spec.rb +16 -35
- data/spec/integration/dataset_test.rb +16 -4
- data/spec/integration/prepared_statement_test.rb +4 -2
- data/spec/model/eager_loading_spec.rb +16 -0
- data/spec/model/model_spec.rb +15 -1
- data/spec/model/record_spec.rb +60 -0
- metadata +23 -40
data/CHANGELOG
CHANGED
|
@@ -1,3 +1,35 @@
|
|
|
1
|
+
=== 3.30.0 (2011-12-01)
|
|
2
|
+
|
|
3
|
+
* Handle usage of on_duplicate_key_update in MySQL prepared statements (jeremyevans) (#404)
|
|
4
|
+
|
|
5
|
+
* Make after_commit and after_rollback respect :server option (jeremyevans) (#401)
|
|
6
|
+
|
|
7
|
+
* Respect :connect_timeout option in the postgres adapter when using pg (glebpom, jeremyevans) (#402)
|
|
8
|
+
|
|
9
|
+
* Make Dataset#destroy for model datasets respect dataset shard when using a transaction (jeremyevans)
|
|
10
|
+
|
|
11
|
+
* Make :server option to Model#save set the shard to use (jeremyevans)
|
|
12
|
+
|
|
13
|
+
* Move Model#set_server from the sharding plugin to the base plugin (jeremyevans)
|
|
14
|
+
|
|
15
|
+
* Add :graph_alias_base association option for setting base name to use for table aliases when eager graphing (jeremyevans)
|
|
16
|
+
|
|
17
|
+
* Make ILIKE work correctly on Microsoft SQL Server if database/column collation is case sensitive (jfirebaugh) (#398)
|
|
18
|
+
|
|
19
|
+
* When starting a new dataset graph, assume existing selection is the columns to select from the current table (jeremyevans)
|
|
20
|
+
|
|
21
|
+
* Allow specifying nanoseconds and offsets when converting a hash or array to a timestamp (jeremyevans, jfirebaugh) (#395)
|
|
22
|
+
|
|
23
|
+
* Improve performance when converting Java types to ruby types in the jdbc adapter (jeremyevans, jfirebaugh) (#395)
|
|
24
|
+
|
|
25
|
+
* Fix tinytds adapter if DB.identifier_output_method = nil (jeremyevans)
|
|
26
|
+
|
|
27
|
+
* Explicitly order by the row number column when emulating offsets (jfirebaugh) (#393)
|
|
28
|
+
|
|
29
|
+
* Fix Dataset#graph and #eager_graph modifying the receiver if the receiver is already graphed (jeremyevans) (#392)
|
|
30
|
+
|
|
31
|
+
* Change dataset literalization to an append-only-all-the-way-down design (jeremyevans)
|
|
32
|
+
|
|
1
33
|
=== 3.29.0 (2011-11-01)
|
|
2
34
|
|
|
3
35
|
* Allow Model.dataset_module to take a Module instance (jeremyevans)
|
|
@@ -64,7 +96,7 @@
|
|
|
64
96
|
|
|
65
97
|
* Add after_commit, after_rollback, after_destroy_commit, and after_destroy_rollback hooks to Model objects (jeremyevans)
|
|
66
98
|
|
|
67
|
-
* Add after_commit and after_rollback hooks to Database objects (jeremyevans)
|
|
99
|
+
* Add after_commit and after_rollback hooks to Database objects (jeremyevans) (#383)
|
|
68
100
|
|
|
69
101
|
* Support savepoints inside prepared transactions on MySQL (jeremyevans)
|
|
70
102
|
|
|
@@ -184,9 +216,9 @@
|
|
|
184
216
|
|
|
185
217
|
* Fix the db2 adapter so it actually works (jeremyevans)
|
|
186
218
|
|
|
187
|
-
* Add ibmdb adapter for accessing DB2 (roylez, jeremyevans)
|
|
219
|
+
* Add ibmdb adapter for accessing DB2 (roylez, jeremyevans) (#376)
|
|
188
220
|
|
|
189
|
-
* Add much better support for DB2 databases (roylez, jeremyevans)
|
|
221
|
+
* Add much better support for DB2 databases (roylez, jeremyevans) (#376)
|
|
190
222
|
|
|
191
223
|
* Handle SQL::AliasedExpressions and SQL::JoinClauses in Dataset#select_all (jeremyevans)
|
|
192
224
|
|
data/Rakefile
CHANGED
|
@@ -12,7 +12,8 @@ CLEAN.include ["**/.*.sw?", "sequel-*.gem", ".config", "rdoc", "coverage", "www/
|
|
|
12
12
|
|
|
13
13
|
desc "Packages sequel"
|
|
14
14
|
task :package=>[:clean] do |p|
|
|
15
|
-
|
|
15
|
+
load './sequel.gemspec'
|
|
16
|
+
Gem::Builder.new(SEQUEL_GEMSPEC).build
|
|
16
17
|
end
|
|
17
18
|
|
|
18
19
|
desc "Install sequel gem"
|
data/doc/association_basics.rdoc
CHANGED
|
@@ -1329,6 +1329,17 @@ a JOIN USING or NATURAL JOIN for the graph:
|
|
|
1329
1329
|
Artist.one_to_many :albums, :key=>:artist_name,
|
|
1330
1330
|
:graph_only_conditions=>nil, :graph_join_type=>:natural
|
|
1331
1331
|
|
|
1332
|
+
==== :graph_alias_base
|
|
1333
|
+
|
|
1334
|
+
The base name to use for the table alias when eager graphing. Defaults to the name
|
|
1335
|
+
of the association. If the alias name has already been used in the query, Sequel will create
|
|
1336
|
+
a unique alias by appending a numeric suffix (e.g. alias_0, alias_1, ...) until the alias is
|
|
1337
|
+
unique.
|
|
1338
|
+
|
|
1339
|
+
This is mostly useful if you have associations with the same name in many models, and you want
|
|
1340
|
+
to be able to easily tell which table alias corresponds to which association when eagerly
|
|
1341
|
+
graphing multiple associations with the same name.
|
|
1342
|
+
|
|
1332
1343
|
==== :eager_grapher
|
|
1333
1344
|
|
|
1334
1345
|
Sets up a custom grapher to use when eager loading the objects via eager_graph.
|
data/doc/opening_databases.rdoc
CHANGED
|
@@ -342,6 +342,8 @@ The following additional options are supported:
|
|
|
342
342
|
|
|
343
343
|
:charset :: Same as :encoding, :encoding takes precedence
|
|
344
344
|
:encoding :: Set the client_encoding to the given string
|
|
345
|
+
:connect_timeout :: Set the number of seconds to wait for a connection (default 20, only respected
|
|
346
|
+
if using the pg library).
|
|
345
347
|
|
|
346
348
|
=== sqlite
|
|
347
349
|
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
= Dataset Literalization Refactoring
|
|
2
|
+
|
|
3
|
+
* As warned about in the 3.29.0 release notes, dataset literalization
|
|
4
|
+
has been completely refactored. It now uses an append-only design
|
|
5
|
+
which is faster in all cases, about twice as fast for large objects
|
|
6
|
+
and deeply nested structures, and over two orders of magnitude
|
|
7
|
+
faster in some pathological cases.
|
|
8
|
+
|
|
9
|
+
This change should not affect applications, but may affect custom
|
|
10
|
+
extensions or adapters that dealt with literalization of objects.
|
|
11
|
+
Most literalization methods now have a method with an _append
|
|
12
|
+
suffix that does the actual literalization, which takes the sql
|
|
13
|
+
string to append to as the first argument. If you were overriding
|
|
14
|
+
a literalization method, you now probably need to override the
|
|
15
|
+
_append version instead. If you have this literalization method:
|
|
16
|
+
|
|
17
|
+
def foo_sql(bar)
|
|
18
|
+
"BAR #{literal(bar.baz)}"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
You need to change the code to:
|
|
22
|
+
|
|
23
|
+
def foo_sql_append(sql, bar)
|
|
24
|
+
sql << "BAR "
|
|
25
|
+
literal_append(sql, bar.baz)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def foo_sql(bar)
|
|
29
|
+
sql = ""
|
|
30
|
+
foo_sql_append(sql, bar)
|
|
31
|
+
sql
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
If you have questions about modifying your custom adapter or
|
|
35
|
+
extension, please ask on the Google Group or the IRC channel.
|
|
36
|
+
|
|
37
|
+
= New Features
|
|
38
|
+
|
|
39
|
+
* Model#set_server has been added to the base support (it was
|
|
40
|
+
previously only in the sharding plugin), which allows you to
|
|
41
|
+
set the shard on which to save/delete the model instance:
|
|
42
|
+
|
|
43
|
+
foo1.set_server(:server_a).save
|
|
44
|
+
foo2.set_server(:server_a).destroy
|
|
45
|
+
|
|
46
|
+
* Model#save now accepts a :server option that uses set_server
|
|
47
|
+
to set the shard to use. Unlike most other #save options, this
|
|
48
|
+
option persists past the end of the save. Previously, the
|
|
49
|
+
:server option only affected the transaction code, it now
|
|
50
|
+
affects the INSERT/UPDATE statement as well.
|
|
51
|
+
|
|
52
|
+
* When initiating a new dataset graph, any existing selected
|
|
53
|
+
columns is assumed to be the columns to select for the graph from
|
|
54
|
+
the current/master table. Before, there was not a way to specify
|
|
55
|
+
the columns to select from the current/master table.
|
|
56
|
+
|
|
57
|
+
* A :graph_alias_base association option has been added, which is
|
|
58
|
+
used to set the base alias name to use when eager graphing. This
|
|
59
|
+
is mostly useful when cascading eager graphs to dependent
|
|
60
|
+
associations, where multiple associations with the same name in
|
|
61
|
+
different models are being graphed simultaneously.
|
|
62
|
+
|
|
63
|
+
* You can now specify nanoseconds and a timezone offset
|
|
64
|
+
when converting a hash or array to a timestamp. The nanoseconds
|
|
65
|
+
and offset are the 7th and 8th entries in the array, and the :nanos
|
|
66
|
+
and :offset entry in the hash.
|
|
67
|
+
|
|
68
|
+
* The postgres adapter now respects a :connect_timeout option if you
|
|
69
|
+
are using the pg driver.
|
|
70
|
+
|
|
71
|
+
= Other Improvements
|
|
72
|
+
|
|
73
|
+
* Type conversion of Java to Ruby types in the JDBC adapter has been
|
|
74
|
+
made much faster, as conversion method lookup is now
|
|
75
|
+
O(number of columns) instead of
|
|
76
|
+
O(number of columns*number of rows).
|
|
77
|
+
|
|
78
|
+
* Sequel::SQL::Blob literalization is now much faster on adapters that
|
|
79
|
+
use hex encoding, by switching to String#unpack('H*').
|
|
80
|
+
|
|
81
|
+
* Database#after_commit and after_rollback now respect the :server
|
|
82
|
+
option to set the server/shard to use.
|
|
83
|
+
|
|
84
|
+
* Symbol splitting (e.g. for table__column) is now slightly faster.
|
|
85
|
+
|
|
86
|
+
* All adapters now pass the dataset :limit/:offset value through
|
|
87
|
+
Dataset#literal instead of using it verbatim. Note that
|
|
88
|
+
Dataset#limit already called to_i on input strings, so this isn't
|
|
89
|
+
a security issue. However, the previous code broke if you
|
|
90
|
+
provided a Sequel-specific object (e.g. Sequel::SQL::Function) as
|
|
91
|
+
the :limit/:offset value.
|
|
92
|
+
|
|
93
|
+
* Calling graph and eager_graph on an already graphed dataset no
|
|
94
|
+
longer modifies the receiver.
|
|
95
|
+
|
|
96
|
+
* Model#set_server now correctly handles the case where @this is
|
|
97
|
+
already loaded.
|
|
98
|
+
|
|
99
|
+
* Dataset#destroy for model datasets now uses the dataset's shard
|
|
100
|
+
for transactions.
|
|
101
|
+
|
|
102
|
+
* When emulating offset support using ROW_NUMBER (on Microsoft SQL
|
|
103
|
+
Server, DB2, and Oracle), explicitly order by the ROW_NUMBER
|
|
104
|
+
result, as otherwise the results are not guaranteed to be ordered.
|
|
105
|
+
|
|
106
|
+
* Explicitly force a case insensitive collation when emulating ILIKE
|
|
107
|
+
on Microsoft SQL Server. Previously, ILIKE could be case sensitive
|
|
108
|
+
on Microsoft SQL Server if case sensitive collation was the
|
|
109
|
+
database default.
|
|
110
|
+
|
|
111
|
+
* Using on_duplicate_key_update with prepared statements on MySQL now
|
|
112
|
+
works correctly.
|
|
113
|
+
|
|
114
|
+
* The tinytds adapter now works correctly if the
|
|
115
|
+
identifier_output_method is nil.
|
|
116
|
+
|
|
117
|
+
* The plugin/extension specs were cleaned up using the mock adapter.
|
|
118
|
+
|
|
119
|
+
= Backwards Compatibility
|
|
120
|
+
|
|
121
|
+
* In addition to the previously mentioned dataset literalization
|
|
122
|
+
changes, any custom adapters that overrode *_clause_methods
|
|
123
|
+
methods need to be modified to add a method that adds the
|
|
124
|
+
SELECT/UPDATE/INSERT/DELETE. Previously, this was done by default,
|
|
125
|
+
but due to common table expressions and the dataset literalization
|
|
126
|
+
changes, a separate method is now needed.
|
|
127
|
+
|
|
128
|
+
* Dataset#on_duplicate_key_update_sql has been removed from the shared
|
|
129
|
+
mysql adapter.
|
|
130
|
+
|
|
131
|
+
* The :columns dataset option used when inserting is no longer
|
|
132
|
+
literalized in advance.
|
|
133
|
+
|
|
134
|
+
* Dataset#as_sql no longer takes an expression, it just takes the
|
|
135
|
+
alias, and only adds the alias part.
|
data/doc/testing.rdoc
CHANGED
|
@@ -20,9 +20,14 @@ Make sure you are using Sequel 3.29.0 or above when using these examples, as old
|
|
|
20
20
|
|
|
21
21
|
=== RSpec 2
|
|
22
22
|
|
|
23
|
-
class
|
|
24
|
-
around
|
|
25
|
-
|
|
23
|
+
class RSpec::Core::ExampleGroup
|
|
24
|
+
# Setting an around filter globally doesn't appear to work in 2.7 (and maybe other versions),
|
|
25
|
+
# so set one up for each subclass.
|
|
26
|
+
def self.inherited(subclass)
|
|
27
|
+
super
|
|
28
|
+
subclass.around do |example|
|
|
29
|
+
Sequel::Model.db.transaction(:rollback=>:always){example.call}
|
|
30
|
+
end
|
|
26
31
|
end
|
|
27
32
|
end
|
|
28
33
|
|
|
@@ -35,6 +40,15 @@ Make sure you are using Sequel 3.29.0 or above when using these examples, as old
|
|
|
35
40
|
end
|
|
36
41
|
end
|
|
37
42
|
|
|
43
|
+
=== MiniTest::Unit
|
|
44
|
+
|
|
45
|
+
# Must use this class as the base class for your tests
|
|
46
|
+
class SequelTestCase < MiniTest::Unit::TestCase
|
|
47
|
+
def run(*args, &block)
|
|
48
|
+
Sequel::Model.db.transaction(:rollback=>:always){super}
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
38
52
|
== Transactional testing with multiple databases
|
|
39
53
|
|
|
40
54
|
You can use the Sequel.transaction method to run a transaction on multiple databases, rolling all of them back. Instead of:
|
|
@@ -176,8 +176,8 @@ module Sequel
|
|
|
176
176
|
private
|
|
177
177
|
|
|
178
178
|
# Quote the string using the adapter instance method.
|
|
179
|
-
def
|
|
180
|
-
db.synchronize{|c| c.quote(v)}
|
|
179
|
+
def literal_string_append(sql, v)
|
|
180
|
+
db.synchronize{|c| sql << c.quote(v)}
|
|
181
181
|
end
|
|
182
182
|
end
|
|
183
183
|
end
|
|
@@ -26,6 +26,9 @@ module Sequel
|
|
|
26
26
|
# Dataset class for MySQL datasets accessed via DataObjects.
|
|
27
27
|
class Dataset < DataObjects::Dataset
|
|
28
28
|
include Sequel::MySQL::DatasetMethods
|
|
29
|
+
APOS = Dataset::APOS
|
|
30
|
+
APOS_RE = Dataset::APOS_RE
|
|
31
|
+
DOUBLE_APOS = Dataset::DOUBLE_APOS
|
|
29
32
|
|
|
30
33
|
# Use execute_insert to execute the replace_sql.
|
|
31
34
|
def replace(*args)
|
|
@@ -35,8 +38,8 @@ module Sequel
|
|
|
35
38
|
private
|
|
36
39
|
|
|
37
40
|
# do_mysql sets NO_BACKSLASH_ESCAPES, so use standard SQL string escaping
|
|
38
|
-
def
|
|
39
|
-
|
|
41
|
+
def literal_string_append(sql, s)
|
|
42
|
+
sql << APOS << s.gsub(APOS_RE, DOUBLE_APOS) << APOS
|
|
40
43
|
end
|
|
41
44
|
end
|
|
42
45
|
end
|
|
@@ -354,8 +354,8 @@ module Sequel
|
|
|
354
354
|
module CallableStatementMethods
|
|
355
355
|
# Extend given dataset with this module so subselects inside subselects in
|
|
356
356
|
# prepared statements work.
|
|
357
|
-
def
|
|
358
|
-
ps = ds.to_prepared_statement(:select)
|
|
357
|
+
def subselect_sql_append(sql, ds)
|
|
358
|
+
ps = ds.to_prepared_statement(:select).clone(:append_sql=>sql)
|
|
359
359
|
ps.extend(CallableStatementMethods)
|
|
360
360
|
ps = ps.bind(@opts[:bind_vars]) if @opts[:bind_vars]
|
|
361
361
|
ps.prepared_args = prepared_args
|
data/lib/sequel/adapters/jdbc.rb
CHANGED
|
@@ -588,12 +588,6 @@ module Sequel
|
|
|
588
588
|
# double performance when fetching rows.
|
|
589
589
|
attr_accessor :convert_types
|
|
590
590
|
|
|
591
|
-
# Use the convert_types default setting from the database.
|
|
592
|
-
def initialize(db, opts={})
|
|
593
|
-
@convert_types = db.convert_types
|
|
594
|
-
super
|
|
595
|
-
end
|
|
596
|
-
|
|
597
591
|
# Correctly return rows from the database and return them as hashes.
|
|
598
592
|
def fetch_rows(sql, &block)
|
|
599
593
|
execute(sql){|result| process_result_set(result, &block)}
|
|
@@ -613,30 +607,77 @@ module Sequel
|
|
|
613
607
|
end
|
|
614
608
|
|
|
615
609
|
private
|
|
616
|
-
|
|
617
|
-
#
|
|
618
|
-
|
|
610
|
+
|
|
611
|
+
# Cache Java class constants to speed up lookups
|
|
612
|
+
JAVA_SQL_TIMESTAMP = Java::JavaSQL::Timestamp
|
|
613
|
+
JAVA_SQL_TIME = Java::JavaSQL::Time
|
|
614
|
+
JAVA_SQL_DATE = Java::JavaSQL::Date
|
|
615
|
+
JAVA_SQL_BLOB = Java::JavaSQL::Blob
|
|
616
|
+
JAVA_SQL_CLOB = Java::JavaSQL::Clob
|
|
617
|
+
JAVA_BUFFERED_READER = Java::JavaIo::BufferedReader
|
|
618
|
+
JAVA_BIG_DECIMAL = Java::JavaMath::BigDecimal
|
|
619
|
+
JAVA_BYTE_ARRAY = Java::byte[]
|
|
620
|
+
|
|
621
|
+
# Handle type conversions for common Java types.
|
|
622
|
+
class TYPE_TRANSLATOR
|
|
623
|
+
LF = "\n".freeze
|
|
624
|
+
def time(v) Sequel.string_to_time(v.to_string) end
|
|
625
|
+
def date(v) Date.civil(v.getYear + 1900, v.getMonth + 1, v.getDate) end
|
|
626
|
+
def decimal(v) BigDecimal.new(v.to_string) end
|
|
627
|
+
def byte_array(v) Sequel::SQL::Blob.new(String.from_java_bytes(v)) end
|
|
628
|
+
def blob(v) Sequel::SQL::Blob.new(String.from_java_bytes(v.getBytes(1, v.length))) end
|
|
629
|
+
def clob(v) Sequel::SQL::Blob.new(v.getSubString(1, v.length)) end
|
|
630
|
+
def buffered_reader(v)
|
|
631
|
+
lines = ""
|
|
632
|
+
c = false
|
|
633
|
+
while(line = v.read_line) do
|
|
634
|
+
lines << LF if c
|
|
635
|
+
lines << line
|
|
636
|
+
c ||= true
|
|
637
|
+
end
|
|
638
|
+
lines
|
|
639
|
+
end
|
|
640
|
+
end
|
|
641
|
+
TYPE_TRANSLATOR_INSTANCE = tt = TYPE_TRANSLATOR.new
|
|
642
|
+
|
|
643
|
+
# Cache type translator methods so that duplicate Method
|
|
644
|
+
# objects are not created.
|
|
645
|
+
DECIMAL_METHOD = tt.method(:decimal)
|
|
646
|
+
TIME_METHOD = tt.method(:time)
|
|
647
|
+
DATE_METHOD = tt.method(:date)
|
|
648
|
+
BUFFERED_READER_METHOD = tt.method(:buffered_reader)
|
|
649
|
+
BYTE_ARRAY_METHOD = tt.method(:byte_array)
|
|
650
|
+
BLOB_METHOD = tt.method(:blob)
|
|
651
|
+
CLOB_METHOD = tt.method(:clob)
|
|
652
|
+
|
|
653
|
+
# Convert the given Java timestamp to an instance of Sequel.datetime_class.
|
|
654
|
+
def convert_type_timestamp(v)
|
|
655
|
+
db.to_application_timestamp([v.getYear + 1900, v.getMonth + 1, v.getDate, v.getHours, v.getMinutes, v.getSeconds, v.getNanos])
|
|
656
|
+
end
|
|
657
|
+
|
|
658
|
+
# Return a callable object that will convert any value of <tt>v</tt>'s
|
|
659
|
+
# class to a ruby object. If no callable object can handle <tt>v</tt>'s
|
|
660
|
+
# class, return false so that the negative lookup is cached.
|
|
661
|
+
def convert_type_proc(v)
|
|
619
662
|
case v
|
|
620
|
-
when
|
|
621
|
-
|
|
622
|
-
when
|
|
623
|
-
|
|
624
|
-
when
|
|
625
|
-
|
|
626
|
-
when
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
when
|
|
631
|
-
|
|
632
|
-
when
|
|
633
|
-
|
|
634
|
-
when
|
|
635
|
-
|
|
636
|
-
when Java::JavaSQL::Clob
|
|
637
|
-
Sequel::SQL::Blob.new(v.getSubString(1, v.length))
|
|
663
|
+
when JAVA_BIG_DECIMAL
|
|
664
|
+
DECIMAL_METHOD
|
|
665
|
+
when JAVA_SQL_TIMESTAMP
|
|
666
|
+
method(:convert_type_timestamp)
|
|
667
|
+
when JAVA_SQL_TIME
|
|
668
|
+
TIME_METHOD
|
|
669
|
+
when JAVA_SQL_DATE
|
|
670
|
+
DATE_METHOD
|
|
671
|
+
when JAVA_BUFFERED_READER
|
|
672
|
+
BUFFERED_READER_METHOD
|
|
673
|
+
when JAVA_BYTE_ARRAY
|
|
674
|
+
BYTE_ARRAY_METHOD
|
|
675
|
+
when JAVA_SQL_BLOB
|
|
676
|
+
BLOB_METHOD
|
|
677
|
+
when JAVA_SQL_CLOB
|
|
678
|
+
CLOB_METHOD
|
|
638
679
|
else
|
|
639
|
-
|
|
680
|
+
false
|
|
640
681
|
end
|
|
641
682
|
end
|
|
642
683
|
|
|
@@ -647,7 +688,7 @@ module Sequel
|
|
|
647
688
|
|
|
648
689
|
# Split out from fetch rows to allow processing of JDBC result sets
|
|
649
690
|
# that don't come from issuing an SQL string.
|
|
650
|
-
def process_result_set(result)
|
|
691
|
+
def process_result_set(result, &block)
|
|
651
692
|
# get column names
|
|
652
693
|
meta = result.getMetaData
|
|
653
694
|
cols = []
|
|
@@ -659,28 +700,70 @@ module Sequel
|
|
|
659
700
|
columns.delete(rn)
|
|
660
701
|
end
|
|
661
702
|
@columns = columns
|
|
662
|
-
|
|
663
|
-
|
|
703
|
+
ct = @convert_types
|
|
704
|
+
if (ct.nil? ? db.convert_types : ct)
|
|
705
|
+
cols.each{|c| c << nil}
|
|
706
|
+
process_result_set_convert(cols, result, rn, &block)
|
|
707
|
+
else
|
|
708
|
+
process_result_set_no_convert(cols, result, rn, &block)
|
|
709
|
+
end
|
|
710
|
+
ensure
|
|
711
|
+
result.close
|
|
712
|
+
end
|
|
713
|
+
|
|
714
|
+
# Use conversion procs to convert data retrieved
|
|
715
|
+
# from the database. This has been optimized, the algorithm it uses
|
|
716
|
+
# is roughly, for each column value in each row:
|
|
717
|
+
# * check if the value is truthy (not false/nil)
|
|
718
|
+
# * if not truthy, return object
|
|
719
|
+
# * otherwise, see if a conversion method exists for
|
|
720
|
+
# the column. All columns start with a nil conversion proc,
|
|
721
|
+
# since unlike other adapters, Sequel doesn't get the type of
|
|
722
|
+
# the column when parsing the column metadata.
|
|
723
|
+
# * if a conversion proc is not false/nil, call it with the object
|
|
724
|
+
# and return the result.
|
|
725
|
+
# * if a conversion proc has already been looked up and doesn't
|
|
726
|
+
# exist (false value), return object.
|
|
727
|
+
# * if a conversion proc hasn't been looked up yet (nil value),
|
|
728
|
+
# call convert_type_proc to get the conversion method. Cache
|
|
729
|
+
# the result of as the column's conversion proc to speed up
|
|
730
|
+
# later processing. If the conversion proc exists, call it
|
|
731
|
+
# and return the result, otherwise, return the object.
|
|
732
|
+
def process_result_set_convert(cols, result, rn)
|
|
664
733
|
while result.next
|
|
665
734
|
row = {}
|
|
666
|
-
cols.each do |n, i|
|
|
667
|
-
|
|
735
|
+
cols.each do |n, i, p|
|
|
736
|
+
v = result.getObject(i)
|
|
737
|
+
row[n] = if v
|
|
738
|
+
if p
|
|
739
|
+
p.call(v)
|
|
740
|
+
elsif p.nil?
|
|
741
|
+
cols[i-1][2] = p = convert_type_proc(v)
|
|
742
|
+
if p
|
|
743
|
+
p.call(v)
|
|
744
|
+
else
|
|
745
|
+
v
|
|
746
|
+
end
|
|
747
|
+
else
|
|
748
|
+
v
|
|
749
|
+
end
|
|
750
|
+
else
|
|
751
|
+
v
|
|
752
|
+
end
|
|
668
753
|
end
|
|
669
754
|
row.delete(rn) if rn
|
|
670
755
|
yield row
|
|
671
756
|
end
|
|
672
|
-
ensure
|
|
673
|
-
result.close
|
|
674
757
|
end
|
|
675
758
|
|
|
676
|
-
#
|
|
677
|
-
#
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
759
|
+
# Yield rows without calling any conversion procs. This
|
|
760
|
+
# may yield Java values and not ruby values.
|
|
761
|
+
def process_result_set_no_convert(cols, result, rn)
|
|
762
|
+
while result.next
|
|
763
|
+
row = {}
|
|
764
|
+
cols.each{|n, i| row[n] = result.getObject(i)}
|
|
765
|
+
row.delete(rn) if rn
|
|
766
|
+
yield row
|
|
684
767
|
end
|
|
685
768
|
end
|
|
686
769
|
end
|