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