sequel 3.21.0 → 3.39.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.
Files changed (352) hide show
  1. data/CHANGELOG +1061 -3
  2. data/MIT-LICENSE +1 -1
  3. data/README.rdoc +103 -63
  4. data/Rakefile +59 -27
  5. data/bin/sequel +50 -26
  6. data/doc/active_record.rdoc +67 -51
  7. data/doc/advanced_associations.rdoc +189 -75
  8. data/doc/association_basics.rdoc +327 -79
  9. data/doc/cheat_sheet.rdoc +21 -21
  10. data/doc/core_extensions.rdoc +374 -0
  11. data/doc/dataset_basics.rdoc +10 -10
  12. data/doc/dataset_filtering.rdoc +54 -42
  13. data/doc/mass_assignment.rdoc +56 -0
  14. data/doc/migration.rdoc +89 -557
  15. data/doc/model_hooks.rdoc +80 -29
  16. data/doc/object_model.rdoc +547 -0
  17. data/doc/opening_databases.rdoc +114 -53
  18. data/doc/prepared_statements.rdoc +41 -15
  19. data/doc/querying.rdoc +137 -56
  20. data/doc/reflection.rdoc +36 -10
  21. data/doc/release_notes/3.22.0.txt +39 -0
  22. data/doc/release_notes/3.23.0.txt +172 -0
  23. data/doc/release_notes/3.24.0.txt +420 -0
  24. data/doc/release_notes/3.25.0.txt +88 -0
  25. data/doc/release_notes/3.26.0.txt +88 -0
  26. data/doc/release_notes/3.27.0.txt +82 -0
  27. data/doc/release_notes/3.28.0.txt +304 -0
  28. data/doc/release_notes/3.29.0.txt +459 -0
  29. data/doc/release_notes/3.30.0.txt +135 -0
  30. data/doc/release_notes/3.31.0.txt +146 -0
  31. data/doc/release_notes/3.32.0.txt +202 -0
  32. data/doc/release_notes/3.33.0.txt +157 -0
  33. data/doc/release_notes/3.34.0.txt +671 -0
  34. data/doc/release_notes/3.35.0.txt +144 -0
  35. data/doc/release_notes/3.36.0.txt +245 -0
  36. data/doc/release_notes/3.37.0.txt +338 -0
  37. data/doc/release_notes/3.38.0.txt +234 -0
  38. data/doc/release_notes/3.39.0.txt +237 -0
  39. data/doc/schema_modification.rdoc +585 -0
  40. data/doc/sharding.rdoc +99 -8
  41. data/doc/sql.rdoc +154 -112
  42. data/doc/testing.rdoc +169 -0
  43. data/doc/thread_safety.rdoc +17 -0
  44. data/doc/transactions.rdoc +137 -0
  45. data/doc/validations.rdoc +1 -1
  46. data/doc/virtual_rows.rdoc +78 -43
  47. data/lib/sequel/adapters/ado/mssql.rb +18 -6
  48. data/lib/sequel/adapters/ado.rb +40 -18
  49. data/lib/sequel/adapters/amalgalite.rb +17 -9
  50. data/lib/sequel/adapters/db2.rb +175 -86
  51. data/lib/sequel/adapters/dbi.rb +15 -15
  52. data/lib/sequel/adapters/do/mysql.rb +17 -11
  53. data/lib/sequel/adapters/do/postgres.rb +2 -61
  54. data/lib/sequel/adapters/do/sqlite.rb +0 -10
  55. data/lib/sequel/adapters/do.rb +18 -36
  56. data/lib/sequel/adapters/firebird.rb +27 -208
  57. data/lib/sequel/adapters/ibmdb.rb +453 -0
  58. data/lib/sequel/adapters/informix.rb +6 -23
  59. data/lib/sequel/adapters/jdbc/as400.rb +16 -34
  60. data/lib/sequel/adapters/jdbc/db2.rb +56 -0
  61. data/lib/sequel/adapters/jdbc/derby.rb +325 -0
  62. data/lib/sequel/adapters/jdbc/firebird.rb +24 -0
  63. data/lib/sequel/adapters/jdbc/h2.rb +73 -31
  64. data/lib/sequel/adapters/jdbc/hsqldb.rb +184 -0
  65. data/lib/sequel/adapters/jdbc/informix.rb +21 -0
  66. data/lib/sequel/adapters/jdbc/jtds.rb +40 -0
  67. data/lib/sequel/adapters/jdbc/mssql.rb +3 -33
  68. data/lib/sequel/adapters/jdbc/mysql.rb +7 -24
  69. data/lib/sequel/adapters/jdbc/oracle.rb +88 -25
  70. data/lib/sequel/adapters/jdbc/postgresql.rb +77 -52
  71. data/lib/sequel/adapters/jdbc/progress.rb +21 -0
  72. data/lib/sequel/adapters/jdbc/sqlite.rb +20 -10
  73. data/lib/sequel/adapters/jdbc/sqlserver.rb +66 -0
  74. data/lib/sequel/adapters/jdbc/transactions.rb +83 -0
  75. data/lib/sequel/adapters/jdbc.rb +279 -97
  76. data/lib/sequel/adapters/mock.rb +372 -0
  77. data/lib/sequel/adapters/mysql.rb +125 -222
  78. data/lib/sequel/adapters/mysql2.rb +65 -56
  79. data/lib/sequel/adapters/odbc/mssql.rb +17 -9
  80. data/lib/sequel/adapters/odbc.rb +28 -9
  81. data/lib/sequel/adapters/openbase.rb +3 -5
  82. data/lib/sequel/adapters/oracle.rb +349 -53
  83. data/lib/sequel/adapters/postgres.rb +368 -138
  84. data/lib/sequel/adapters/shared/access.rb +32 -9
  85. data/lib/sequel/adapters/shared/db2.rb +343 -0
  86. data/lib/sequel/adapters/shared/firebird.rb +221 -0
  87. data/lib/sequel/adapters/shared/informix.rb +53 -0
  88. data/lib/sequel/adapters/shared/mssql.rb +401 -116
  89. data/lib/sequel/adapters/shared/mysql.rb +424 -89
  90. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +155 -0
  91. data/lib/sequel/adapters/shared/oracle.rb +257 -45
  92. data/lib/sequel/adapters/shared/postgres.rb +675 -279
  93. data/lib/sequel/adapters/shared/progress.rb +5 -8
  94. data/lib/sequel/adapters/shared/sqlite.rb +285 -96
  95. data/lib/sequel/adapters/sqlite.rb +101 -39
  96. data/lib/sequel/adapters/swift/mysql.rb +10 -12
  97. data/lib/sequel/adapters/swift/postgres.rb +13 -79
  98. data/lib/sequel/adapters/swift/sqlite.rb +9 -6
  99. data/lib/sequel/adapters/swift.rb +28 -19
  100. data/lib/sequel/adapters/tinytds.rb +174 -22
  101. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +77 -0
  102. data/lib/sequel/adapters/utils/pg_types.rb +81 -0
  103. data/lib/sequel/adapters/utils/stored_procedures.rb +1 -11
  104. data/lib/sequel/ast_transformer.rb +194 -0
  105. data/lib/sequel/connection_pool/sharded_single.rb +11 -1
  106. data/lib/sequel/connection_pool/sharded_threaded.rb +33 -2
  107. data/lib/sequel/connection_pool/single.rb +5 -0
  108. data/lib/sequel/connection_pool/threaded.rb +43 -14
  109. data/lib/sequel/connection_pool.rb +10 -2
  110. data/lib/sequel/core.rb +143 -11
  111. data/lib/sequel/database/connecting.rb +38 -28
  112. data/lib/sequel/database/dataset.rb +4 -4
  113. data/lib/sequel/database/dataset_defaults.rb +63 -2
  114. data/lib/sequel/database/logging.rb +7 -2
  115. data/lib/sequel/database/misc.rb +190 -46
  116. data/lib/sequel/database/query.rb +272 -110
  117. data/lib/sequel/database/schema_generator.rb +103 -36
  118. data/lib/sequel/database/schema_methods.rb +300 -67
  119. data/lib/sequel/dataset/actions.rb +344 -90
  120. data/lib/sequel/dataset/features.rb +101 -8
  121. data/lib/sequel/dataset/graph.rb +42 -15
  122. data/lib/sequel/dataset/misc.rb +52 -25
  123. data/lib/sequel/dataset/mutation.rb +12 -7
  124. data/lib/sequel/dataset/prepared_statements.rb +68 -30
  125. data/lib/sequel/dataset/query.rb +305 -54
  126. data/lib/sequel/dataset/sql.rb +720 -292
  127. data/lib/sequel/dataset.rb +8 -0
  128. data/lib/sequel/exceptions.rb +4 -0
  129. data/lib/sequel/extensions/_pretty_table.rb +83 -0
  130. data/lib/sequel/extensions/arbitrary_servers.rb +109 -0
  131. data/lib/sequel/extensions/blank.rb +4 -0
  132. data/lib/sequel/extensions/columns_introspection.rb +72 -0
  133. data/lib/sequel/extensions/constraint_validations.rb +451 -0
  134. data/lib/sequel/{core_sql.rb → extensions/core_extensions.rb} +30 -46
  135. data/lib/sequel/extensions/eval_inspect.rb +173 -0
  136. data/lib/sequel/extensions/inflector.rb +4 -0
  137. data/lib/sequel/extensions/looser_typecasting.rb +5 -4
  138. data/lib/sequel/extensions/migration.rb +100 -11
  139. data/lib/sequel/extensions/named_timezones.rb +9 -0
  140. data/lib/sequel/extensions/null_dataset.rb +94 -0
  141. data/lib/sequel/extensions/pagination.rb +4 -0
  142. data/lib/sequel/extensions/pg_array.rb +537 -0
  143. data/lib/sequel/extensions/pg_array_ops.rb +263 -0
  144. data/lib/sequel/extensions/pg_auto_parameterize.rb +175 -0
  145. data/lib/sequel/extensions/pg_hstore.rb +313 -0
  146. data/lib/sequel/extensions/pg_hstore_ops.rb +293 -0
  147. data/lib/sequel/extensions/pg_inet.rb +113 -0
  148. data/lib/sequel/extensions/pg_interval.rb +191 -0
  149. data/lib/sequel/extensions/pg_json.rb +208 -0
  150. data/lib/sequel/extensions/pg_range.rb +512 -0
  151. data/lib/sequel/extensions/pg_range_ops.rb +150 -0
  152. data/lib/sequel/extensions/pg_row.rb +572 -0
  153. data/lib/sequel/extensions/pg_row_ops.rb +182 -0
  154. data/lib/sequel/extensions/pg_statement_cache.rb +317 -0
  155. data/lib/sequel/extensions/pretty_table.rb +17 -72
  156. data/lib/sequel/extensions/query.rb +8 -4
  157. data/lib/sequel/extensions/query_literals.rb +79 -0
  158. data/lib/sequel/extensions/schema_caching.rb +76 -0
  159. data/lib/sequel/extensions/schema_dumper.rb +282 -76
  160. data/lib/sequel/extensions/select_remove.rb +39 -0
  161. data/lib/sequel/extensions/server_block.rb +140 -0
  162. data/lib/sequel/extensions/split_array_nil.rb +65 -0
  163. data/lib/sequel/extensions/sql_expr.rb +8 -110
  164. data/lib/sequel/extensions/string_date_time.rb +4 -0
  165. data/lib/sequel/extensions/thread_local_timezones.rb +10 -4
  166. data/lib/sequel/extensions/to_dot.rb +99 -83
  167. data/lib/sequel/model/associations.rb +1263 -409
  168. data/lib/sequel/model/base.rb +624 -171
  169. data/lib/sequel/model/errors.rb +1 -1
  170. data/lib/sequel/model/exceptions.rb +24 -2
  171. data/lib/sequel/model/inflections.rb +1 -1
  172. data/lib/sequel/model.rb +30 -11
  173. data/lib/sequel/no_core_ext.rb +2 -0
  174. data/lib/sequel/plugins/active_model.rb +13 -1
  175. data/lib/sequel/plugins/association_pks.rb +22 -4
  176. data/lib/sequel/plugins/caching.rb +25 -18
  177. data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
  178. data/lib/sequel/plugins/composition.rb +44 -12
  179. data/lib/sequel/plugins/constraint_validations.rb +198 -0
  180. data/lib/sequel/plugins/dataset_associations.rb +100 -0
  181. data/lib/sequel/plugins/defaults_setter.rb +72 -0
  182. data/lib/sequel/plugins/dirty.rb +214 -0
  183. data/lib/sequel/plugins/eager_each.rb +59 -0
  184. data/lib/sequel/plugins/force_encoding.rb +6 -6
  185. data/lib/sequel/plugins/hook_class_methods.rb +1 -1
  186. data/lib/sequel/plugins/identity_map.rb +134 -15
  187. data/lib/sequel/plugins/instance_filters.rb +10 -0
  188. data/lib/sequel/plugins/instance_hooks.rb +1 -1
  189. data/lib/sequel/plugins/json_serializer.rb +58 -6
  190. data/lib/sequel/plugins/list.rb +13 -2
  191. data/lib/sequel/plugins/many_through_many.rb +103 -51
  192. data/lib/sequel/plugins/many_to_one_pk_lookup.rb +71 -0
  193. data/lib/sequel/plugins/nested_attributes.rb +150 -66
  194. data/lib/sequel/plugins/optimistic_locking.rb +8 -0
  195. data/lib/sequel/plugins/pg_row.rb +121 -0
  196. data/lib/sequel/plugins/pg_typecast_on_load.rb +65 -0
  197. data/lib/sequel/plugins/prepared_statements.rb +167 -0
  198. data/lib/sequel/plugins/prepared_statements_associations.rb +87 -0
  199. data/lib/sequel/plugins/prepared_statements_safe.rb +82 -0
  200. data/lib/sequel/plugins/prepared_statements_with_pk.rb +59 -0
  201. data/lib/sequel/plugins/rcte_tree.rb +31 -17
  202. data/lib/sequel/plugins/schema.rb +8 -3
  203. data/lib/sequel/plugins/serialization.rb +98 -49
  204. data/lib/sequel/plugins/serialization_modification_detection.rb +63 -0
  205. data/lib/sequel/plugins/sharding.rb +21 -54
  206. data/lib/sequel/plugins/single_table_inheritance.rb +5 -3
  207. data/lib/sequel/plugins/static_cache.rb +99 -0
  208. data/lib/sequel/plugins/subclasses.rb +29 -3
  209. data/lib/sequel/plugins/tactical_eager_loading.rb +7 -7
  210. data/lib/sequel/plugins/timestamps.rb +1 -1
  211. data/lib/sequel/plugins/tree.rb +3 -3
  212. data/lib/sequel/plugins/typecast_on_load.rb +9 -12
  213. data/lib/sequel/plugins/update_primary_key.rb +2 -2
  214. data/lib/sequel/plugins/validation_class_methods.rb +1 -1
  215. data/lib/sequel/plugins/validation_helpers.rb +55 -4
  216. data/lib/sequel/plugins/xml_serializer.rb +15 -4
  217. data/lib/sequel/sql.rb +649 -122
  218. data/lib/sequel/timezones.rb +67 -40
  219. data/lib/sequel/version.rb +1 -1
  220. data/spec/adapters/db2_spec.rb +146 -0
  221. data/spec/adapters/firebird_spec.rb +1 -1
  222. data/spec/adapters/mssql_spec.rb +194 -66
  223. data/spec/adapters/mysql_spec.rb +475 -306
  224. data/spec/adapters/oracle_spec.rb +92 -117
  225. data/spec/adapters/postgres_spec.rb +1982 -325
  226. data/spec/adapters/spec_helper.rb +9 -6
  227. data/spec/adapters/sqlite_spec.rb +203 -75
  228. data/spec/core/connection_pool_spec.rb +218 -93
  229. data/spec/core/database_spec.rb +956 -522
  230. data/spec/core/dataset_spec.rb +1631 -1242
  231. data/spec/core/expression_filters_spec.rb +690 -334
  232. data/spec/core/mock_adapter_spec.rb +453 -0
  233. data/spec/core/object_graph_spec.rb +88 -129
  234. data/spec/core/schema_generator_spec.rb +4 -4
  235. data/spec/core/schema_spec.rb +556 -53
  236. data/spec/core/spec_helper.rb +7 -48
  237. data/spec/core_extensions_spec.rb +626 -0
  238. data/spec/extensions/active_model_spec.rb +13 -0
  239. data/spec/extensions/arbitrary_servers_spec.rb +110 -0
  240. data/spec/extensions/association_autoreloading_spec.rb +18 -10
  241. data/spec/extensions/association_dependencies_spec.rb +15 -25
  242. data/spec/extensions/association_pks_spec.rb +66 -32
  243. data/spec/extensions/association_proxies_spec.rb +4 -4
  244. data/spec/extensions/boolean_readers_spec.rb +25 -25
  245. data/spec/extensions/caching_spec.rb +47 -51
  246. data/spec/extensions/class_table_inheritance_spec.rb +31 -83
  247. data/spec/extensions/columns_introspection_spec.rb +91 -0
  248. data/spec/extensions/composition_spec.rb +18 -13
  249. data/spec/extensions/constraint_validations_plugin_spec.rb +196 -0
  250. data/spec/extensions/constraint_validations_spec.rb +316 -0
  251. data/spec/extensions/dataset_associations_spec.rb +199 -0
  252. data/spec/extensions/defaults_setter_spec.rb +88 -0
  253. data/spec/extensions/dirty_spec.rb +155 -0
  254. data/spec/extensions/eager_each_spec.rb +34 -0
  255. data/spec/extensions/eval_inspect_spec.rb +67 -0
  256. data/spec/extensions/force_encoding_spec.rb +4 -2
  257. data/spec/extensions/hook_class_methods_spec.rb +97 -128
  258. data/spec/extensions/identity_map_spec.rb +142 -24
  259. data/spec/extensions/inflector_spec.rb +0 -4
  260. data/spec/extensions/instance_filters_spec.rb +11 -21
  261. data/spec/extensions/instance_hooks_spec.rb +72 -0
  262. data/spec/extensions/json_serializer_spec.rb +49 -12
  263. data/spec/extensions/lazy_attributes_spec.rb +16 -20
  264. data/spec/extensions/list_spec.rb +49 -40
  265. data/spec/extensions/looser_typecasting_spec.rb +7 -7
  266. data/spec/extensions/many_through_many_spec.rb +368 -254
  267. data/spec/extensions/many_to_one_pk_lookup_spec.rb +140 -0
  268. data/spec/extensions/migration_spec.rb +140 -35
  269. data/spec/extensions/named_timezones_spec.rb +29 -11
  270. data/spec/extensions/nested_attributes_spec.rb +268 -89
  271. data/spec/extensions/null_dataset_spec.rb +85 -0
  272. data/spec/extensions/optimistic_locking_spec.rb +24 -21
  273. data/spec/extensions/pg_array_ops_spec.rb +112 -0
  274. data/spec/extensions/pg_array_spec.rb +320 -0
  275. data/spec/extensions/pg_auto_parameterize_spec.rb +65 -0
  276. data/spec/extensions/pg_hstore_ops_spec.rb +140 -0
  277. data/spec/extensions/pg_hstore_spec.rb +194 -0
  278. data/spec/extensions/pg_inet_spec.rb +47 -0
  279. data/spec/extensions/pg_interval_spec.rb +72 -0
  280. data/spec/extensions/pg_json_spec.rb +99 -0
  281. data/spec/extensions/pg_range_ops_spec.rb +56 -0
  282. data/spec/extensions/pg_range_spec.rb +395 -0
  283. data/spec/extensions/pg_row_ops_spec.rb +58 -0
  284. data/spec/extensions/pg_row_plugin_spec.rb +49 -0
  285. data/spec/extensions/pg_row_spec.rb +323 -0
  286. data/spec/extensions/pg_statement_cache_spec.rb +208 -0
  287. data/spec/extensions/pg_typecast_on_load_spec.rb +58 -0
  288. data/spec/extensions/prepared_statements_associations_spec.rb +111 -0
  289. data/spec/extensions/prepared_statements_safe_spec.rb +61 -0
  290. data/spec/extensions/prepared_statements_spec.rb +87 -0
  291. data/spec/extensions/prepared_statements_with_pk_spec.rb +31 -0
  292. data/spec/extensions/pretty_table_spec.rb +7 -6
  293. data/spec/extensions/query_literals_spec.rb +167 -0
  294. data/spec/extensions/query_spec.rb +9 -3
  295. data/spec/extensions/rcte_tree_spec.rb +50 -43
  296. data/spec/extensions/schema_caching_spec.rb +41 -0
  297. data/spec/extensions/schema_dumper_spec.rb +434 -49
  298. data/spec/extensions/schema_spec.rb +30 -49
  299. data/spec/extensions/select_remove_spec.rb +38 -0
  300. data/spec/extensions/serialization_modification_detection_spec.rb +72 -0
  301. data/spec/extensions/serialization_spec.rb +86 -48
  302. data/spec/extensions/server_block_spec.rb +90 -0
  303. data/spec/extensions/sharding_spec.rb +69 -143
  304. data/spec/extensions/single_table_inheritance_spec.rb +23 -29
  305. data/spec/extensions/skip_create_refresh_spec.rb +1 -1
  306. data/spec/extensions/spec_helper.rb +34 -67
  307. data/spec/extensions/split_array_nil_spec.rb +24 -0
  308. data/spec/extensions/sql_expr_spec.rb +29 -60
  309. data/spec/extensions/static_cache_spec.rb +145 -0
  310. data/spec/extensions/subclasses_spec.rb +14 -0
  311. data/spec/extensions/tactical_eager_loading_spec.rb +17 -19
  312. data/spec/extensions/thread_local_timezones_spec.rb +22 -2
  313. data/spec/extensions/timestamps_spec.rb +6 -6
  314. data/spec/extensions/to_dot_spec.rb +8 -11
  315. data/spec/extensions/touch_spec.rb +13 -14
  316. data/spec/extensions/tree_spec.rb +11 -26
  317. data/spec/extensions/typecast_on_load_spec.rb +9 -6
  318. data/spec/extensions/update_primary_key_spec.rb +30 -24
  319. data/spec/extensions/validation_class_methods_spec.rb +58 -67
  320. data/spec/extensions/validation_helpers_spec.rb +31 -37
  321. data/spec/extensions/xml_serializer_spec.rb +29 -4
  322. data/spec/files/transaction_specified_migrations/001_create_alt_basic.rb +4 -0
  323. data/spec/files/transaction_specified_migrations/002_create_basic.rb +4 -0
  324. data/spec/files/transaction_unspecified_migrations/001_create_alt_basic.rb +3 -0
  325. data/spec/files/transaction_unspecified_migrations/002_create_basic.rb +3 -0
  326. data/spec/integration/associations_test.rb +659 -21
  327. data/spec/integration/database_test.rb +11 -5
  328. data/spec/integration/dataset_test.rb +717 -129
  329. data/spec/integration/eager_loader_test.rb +38 -54
  330. data/spec/integration/migrator_test.rb +2 -3
  331. data/spec/integration/model_test.rb +81 -2
  332. data/spec/integration/plugin_test.rb +604 -147
  333. data/spec/integration/prepared_statement_test.rb +272 -128
  334. data/spec/integration/schema_test.rb +367 -57
  335. data/spec/integration/spec_helper.rb +42 -32
  336. data/spec/integration/timezone_test.rb +38 -12
  337. data/spec/integration/transaction_test.rb +183 -8
  338. data/spec/integration/type_test.rb +31 -8
  339. data/spec/model/association_reflection_spec.rb +207 -8
  340. data/spec/model/associations_spec.rb +1206 -693
  341. data/spec/model/base_spec.rb +334 -100
  342. data/spec/model/dataset_methods_spec.rb +45 -27
  343. data/spec/model/eager_loading_spec.rb +828 -692
  344. data/spec/model/hooks_spec.rb +355 -67
  345. data/spec/model/model_spec.rb +251 -179
  346. data/spec/model/plugins_spec.rb +24 -13
  347. data/spec/model/record_spec.rb +506 -232
  348. data/spec/model/spec_helper.rb +16 -77
  349. data/spec/model/validations_spec.rb +38 -2
  350. data/spec/rcov.opts +2 -0
  351. metadata +209 -80
  352. data/spec/core/core_sql_spec.rb +0 -451
@@ -32,47 +32,96 @@ module Sequel
32
32
  DATABASE_SETUP = {:postgresql=>proc do |db|
33
33
  Sequel.ts_require 'adapters/jdbc/postgresql'
34
34
  db.extend(Sequel::JDBC::Postgres::DatabaseMethods)
35
+ db.dataset_class = Sequel::JDBC::Postgres::Dataset
35
36
  JDBC.load_gem('postgres')
36
37
  org.postgresql.Driver
37
38
  end,
38
39
  :mysql=>proc do |db|
39
40
  Sequel.ts_require 'adapters/jdbc/mysql'
40
41
  db.extend(Sequel::JDBC::MySQL::DatabaseMethods)
42
+ db.extend_datasets Sequel::MySQL::DatasetMethods
41
43
  JDBC.load_gem('mysql')
42
44
  com.mysql.jdbc.Driver
43
45
  end,
44
46
  :sqlite=>proc do |db|
45
47
  Sequel.ts_require 'adapters/jdbc/sqlite'
46
48
  db.extend(Sequel::JDBC::SQLite::DatabaseMethods)
49
+ db.extend_datasets Sequel::SQLite::DatasetMethods
50
+ db.set_integer_booleans
47
51
  JDBC.load_gem('sqlite3')
48
52
  org.sqlite.JDBC
49
53
  end,
50
54
  :oracle=>proc do |db|
51
55
  Sequel.ts_require 'adapters/jdbc/oracle'
52
56
  db.extend(Sequel::JDBC::Oracle::DatabaseMethods)
57
+ db.dataset_class = Sequel::JDBC::Oracle::Dataset
53
58
  Java::oracle.jdbc.driver.OracleDriver
54
59
  end,
55
60
  :sqlserver=>proc do |db|
56
- Sequel.ts_require 'adapters/jdbc/mssql'
57
- db.extend(Sequel::JDBC::MSSQL::DatabaseMethods)
61
+ Sequel.ts_require 'adapters/jdbc/sqlserver'
62
+ db.extend(Sequel::JDBC::SQLServer::DatabaseMethods)
63
+ db.extend_datasets Sequel::MSSQL::DatasetMethods
64
+ db.send(:set_mssql_unicode_strings)
58
65
  com.microsoft.sqlserver.jdbc.SQLServerDriver
59
66
  end,
60
67
  :jtds=>proc do |db|
61
- Sequel.ts_require 'adapters/jdbc/mssql'
62
- db.extend(Sequel::JDBC::MSSQL::DatabaseMethods)
68
+ Sequel.ts_require 'adapters/jdbc/jtds'
69
+ db.extend(Sequel::JDBC::JTDS::DatabaseMethods)
70
+ db.dataset_class = Sequel::JDBC::JTDS::Dataset
71
+ db.send(:set_mssql_unicode_strings)
63
72
  JDBC.load_gem('jtds')
64
73
  Java::net.sourceforge.jtds.jdbc.Driver
65
74
  end,
66
75
  :h2=>proc do |db|
67
76
  Sequel.ts_require 'adapters/jdbc/h2'
68
77
  db.extend(Sequel::JDBC::H2::DatabaseMethods)
78
+ db.dataset_class = Sequel::JDBC::H2::Dataset
69
79
  JDBC.load_gem('h2')
70
80
  org.h2.Driver
71
81
  end,
82
+ :hsqldb=>proc do |db|
83
+ Sequel.ts_require 'adapters/jdbc/hsqldb'
84
+ db.extend(Sequel::JDBC::HSQLDB::DatabaseMethods)
85
+ db.dataset_class = Sequel::JDBC::HSQLDB::Dataset
86
+ # Current gem is 1.8.1.3, but Sequel supports 2.2.5
87
+ org.hsqldb.jdbcDriver
88
+ end,
89
+ :derby=>proc do |db|
90
+ Sequel.ts_require 'adapters/jdbc/derby'
91
+ db.extend(Sequel::JDBC::Derby::DatabaseMethods)
92
+ db.dataset_class = Sequel::JDBC::Derby::Dataset
93
+ JDBC.load_gem('derby')
94
+ org.apache.derby.jdbc.EmbeddedDriver
95
+ end,
72
96
  :as400=>proc do |db|
73
97
  Sequel.ts_require 'adapters/jdbc/as400'
74
98
  db.extend(Sequel::JDBC::AS400::DatabaseMethods)
99
+ db.dataset_class = Sequel::JDBC::AS400::Dataset
75
100
  com.ibm.as400.access.AS400JDBCDriver
101
+ end,
102
+ :"informix-sqli"=>proc do |db|
103
+ Sequel.ts_require 'adapters/jdbc/informix'
104
+ db.extend(Sequel::JDBC::Informix::DatabaseMethods)
105
+ db.extend_datasets Sequel::Informix::DatasetMethods
106
+ com.informix.jdbc.IfxDriver
107
+ end,
108
+ :db2=>proc do |db|
109
+ Sequel.ts_require 'adapters/jdbc/db2'
110
+ db.extend(Sequel::JDBC::DB2::DatabaseMethods)
111
+ db.extend_datasets Sequel::DB2::DatasetMethods
112
+ com.ibm.db2.jcc.DB2Driver
113
+ end,
114
+ :firebirdsql=>proc do |db|
115
+ Sequel.ts_require 'adapters/jdbc/firebird'
116
+ db.extend(Sequel::JDBC::Firebird::DatabaseMethods)
117
+ db.extend_datasets Sequel::Firebird::DatasetMethods
118
+ org.firebirdsql.jdbc.FBDriver
119
+ end,
120
+ :jdbcprogress=>proc do |db|
121
+ Sequel.ts_require 'adapters/jdbc/progress'
122
+ db.extend(Sequel::JDBC::Progress::DatabaseMethods)
123
+ db.extend_datasets Sequel::Progress::DatasetMethods
124
+ com.progress.sql.jdbc.JdbcProgressDriver
76
125
  end
77
126
  }
78
127
 
@@ -101,13 +150,15 @@ module Sequel
101
150
  # True by default, can be set to false to roughly double performance when
102
151
  # fetching rows.
103
152
  attr_accessor :convert_types
104
-
153
+
105
154
  # Call the DATABASE_SETUP proc directly after initialization,
106
155
  # so the object always uses sub adapter specific code. Also,
107
156
  # raise an error immediately if the connection doesn't have a
108
157
  # uri, since JDBC requires one.
109
158
  def initialize(opts)
110
159
  super
160
+ @connection_prepared_statements = {}
161
+ @connection_prepared_statements_mutex = Mutex.new
111
162
  @convert_types = typecast_value_boolean(@opts.fetch(:convert_types, true))
112
163
  raise(Error, "No connection string specified") unless uri
113
164
 
@@ -158,8 +209,9 @@ module Sequel
158
209
  args = [uri(opts)]
159
210
  args.concat([opts[:user], opts[:password]]) if opts[:user] && opts[:password]
160
211
  begin
212
+ JavaSQL::DriverManager.setLoginTimeout(opts[:login_timeout]) if opts[:login_timeout]
161
213
  JavaSQL::DriverManager.getConnection(*args)
162
- rescue => e
214
+ rescue JavaSQL::SQLException, NativeException, StandardError => e
163
215
  raise e unless driver
164
216
  # If the DriverManager can't get the connection - use the connect
165
217
  # method of the driver. (This happens under Tomcat for instance)
@@ -170,8 +222,10 @@ module Sequel
170
222
  end
171
223
  opts[:jdbc_properties].each{|k,v| props.setProperty(k.to_s, v)} if opts[:jdbc_properties]
172
224
  begin
173
- driver.new.connect(args[0], props)
174
- rescue => e2
225
+ c = driver.new.connect(args[0], props)
226
+ raise(Sequel::DatabaseError, 'driver.new.connect returned nil: probably bad JDBC connection string') unless c
227
+ c
228
+ rescue JavaSQL::SQLException, NativeException, StandardError => e2
175
229
  e.message << "\n#{e2.class.name}: #{e2.message}"
176
230
  raise e
177
231
  end
@@ -180,11 +234,6 @@ module Sequel
180
234
  setup_connection(conn)
181
235
  end
182
236
 
183
- # Return instances of JDBC::Dataset with the given opts.
184
- def dataset(opts = nil)
185
- JDBC::Dataset.new(self, opts)
186
- end
187
-
188
237
  # Execute the given SQL. If a block is given, if should be a SELECT
189
238
  # statement or something else that returns rows.
190
239
  def execute(sql, opts={}, &block)
@@ -246,12 +295,14 @@ module Sequel
246
295
  indexes
247
296
  end
248
297
 
298
+ # Whether or not JNDI is being used for this connection.
299
+ def jndi?
300
+ !!(uri =~ JNDI_URI_REGEXP)
301
+ end
302
+
249
303
  # All tables in this database
250
304
  def tables(opts={})
251
- ts = []
252
- m = output_identifier_meth
253
- metadata(:getTables, nil, nil, nil, ['TABLE'].to_java(:string)){|h| ts << m.call(h[:table_name])}
254
- ts
305
+ get_tables('TABLE', opts)
255
306
  end
256
307
 
257
308
  # The uri for this connection. You can specify the uri
@@ -264,18 +315,31 @@ module Sequel
264
315
  ur =~ /^\Ajdbc:/ ? ur : "jdbc:#{ur}"
265
316
  end
266
317
 
267
- # Whether or not JNDI is being used for this connection.
268
- def jndi?
269
- !!(uri =~ JNDI_URI_REGEXP)
318
+ # All views in this database
319
+ def views(opts={})
320
+ get_tables('VIEW', opts)
270
321
  end
271
-
322
+
272
323
  private
273
324
 
274
- # Close given adapter connections
325
+ # Yield the native prepared statements hash for the given connection
326
+ # to the block in a thread-safe manner.
327
+ def cps_sync(conn, &block)
328
+ @connection_prepared_statements_mutex.synchronize{yield(@connection_prepared_statements[conn] ||= {})}
329
+ end
330
+
331
+ # Close given adapter connections, and delete any related prepared statements.
275
332
  def disconnect_connection(c)
333
+ @connection_prepared_statements_mutex.synchronize{@connection_prepared_statements.delete(c)}
276
334
  c.close
277
335
  end
278
336
 
337
+ # Raise a disconnect error if the SQL state of the cause of the exception indicates so.
338
+ def disconnect_error?(exception, opts)
339
+ cause = exception.respond_to?(:cause) ? exception.cause : exception
340
+ super || (cause.respond_to?(:getSQLState) && cause.getSQLState =~ /^08/)
341
+ end
342
+
279
343
  # Execute the prepared statement. If the provided name is a
280
344
  # dataset, use that as the prepared statement, otherwise use
281
345
  # it as a key to look it up in the prepared_statements hash.
@@ -289,20 +353,25 @@ module Sequel
289
353
  ps = name
290
354
  name = ps.prepared_statement_name
291
355
  else
292
- ps = prepared_statements[name]
356
+ ps = prepared_statement(name)
293
357
  end
294
358
  sql = ps.prepared_sql
295
359
  synchronize(opts[:server]) do |conn|
296
- if name and cps = conn.prepared_statements[name] and cps[0] == sql
360
+ if name and cps = cps_sync(conn){|cpsh| cpsh[name]} and cps[0] == sql
297
361
  cps = cps[1]
298
362
  else
299
- log_yield("Closing #{name}"){cps[1].close} if cps
300
- cps = log_yield("Preparing#{" #{name}:" if name} #{sql}"){conn.prepareStatement(sql)}
301
- conn.prepared_statements[name] = [sql, cps] if name
363
+ log_yield("CLOSE #{name}"){cps[1].close} if cps
364
+ cps = log_yield("PREPARE#{" #{name}:" if name} #{sql}"){conn.prepareStatement(sql)}
365
+ cps_sync(conn){|cpsh| cpsh[name] = [sql, cps]} if name
302
366
  end
303
367
  i = 0
304
368
  args.each{|arg| set_ps_arg(cps, arg, i+=1)}
305
- msg = "Executing#{" #{name}" if name}"
369
+ msg = "EXECUTE#{" #{name}" if name}"
370
+ if ps.log_sql
371
+ msg << " ("
372
+ msg << sql
373
+ msg << ")"
374
+ end
306
375
  begin
307
376
  if block_given?
308
377
  yield log_yield(msg, args){cps.executeQuery}
@@ -325,6 +394,12 @@ module Sequel
325
394
  end
326
395
  end
327
396
 
397
+ # Gets the connection from JNDI.
398
+ def get_connection_from_jndi
399
+ jndi_name = JNDI_URI_REGEXP.match(uri)[1]
400
+ JavaxNaming::InitialContext.new.lookup(jndi_name).connection
401
+ end
402
+
328
403
  # Gets the JDBC connection uri from the JNDI resource.
329
404
  def get_uri_from_jndi
330
405
  conn = get_connection_from_jndi
@@ -333,12 +408,14 @@ module Sequel
333
408
  conn.close if conn
334
409
  end
335
410
 
336
- # Gets the connection from JNDI.
337
- def get_connection_from_jndi
338
- jndi_name = JNDI_URI_REGEXP.match(uri)[1]
339
- JavaxNaming::InitialContext.new.lookup(jndi_name).connection
411
+ # Backbone of the tables and views support.
412
+ def get_tables(type, opts)
413
+ ts = []
414
+ m = output_identifier_meth
415
+ metadata(:getTables, nil, nil, nil, [type].to_java(:string)){|h| ts << m.call(h[:table_name])}
416
+ ts
340
417
  end
341
-
418
+
342
419
  # Support Date objects used in bound variables
343
420
  def java_sql_date(date)
344
421
  java.sql.Date.new(Time.local(date.year, date.month, date.day).to_i * 1000)
@@ -354,7 +431,8 @@ module Sequel
354
431
  # Support fractional seconds for Time objects used in bound variables
355
432
  def java_sql_timestamp(time)
356
433
  ts = java.sql.Timestamp.new(time.to_i * 1000)
357
- ts.setNanos(RUBY_VERSION >= '1.9.0' ? time.nsec : time.usec * 1000)
434
+ # Work around jruby 1.6 ruby 1.9 mode bug
435
+ ts.setNanos((RUBY_VERSION >= '1.9.0' && time.nsec != 0) ? time.nsec : time.usec * 1000)
358
436
  ts
359
437
  end
360
438
 
@@ -383,12 +461,6 @@ module Sequel
383
461
  end
384
462
  end
385
463
 
386
- # Treat SQLExceptions with a "Connection Error" SQLState as disconnects
387
- def raise_error(exception, opts={})
388
- cause = exception.respond_to?(:cause) ? exception.cause : exception
389
- super(exception, {:disconnect => cause.respond_to?(:getSQLState) && cause.getSQLState =~ /^08/}.merge(opts))
390
- end
391
-
392
464
  # Java being java, you need to specify the type of each argument
393
465
  # for the prepared statement, and bind it individually. This
394
466
  # guesses which JDBC method to use, and hopefully JRuby will convert
@@ -405,8 +477,8 @@ module Sequel
405
477
  cps.setDouble(i, arg)
406
478
  when TrueClass, FalseClass
407
479
  cps.setBoolean(i, arg)
408
- when nil
409
- cps.setNull(i, JavaSQL::Types::NULL)
480
+ when NilClass
481
+ set_ps_arg_nil(cps, i)
410
482
  when DateTime
411
483
  cps.setTimestamp(i, java_sql_datetime(arg))
412
484
  when Date
@@ -421,22 +493,22 @@ module Sequel
421
493
  cps.setObject(i, arg)
422
494
  end
423
495
  end
496
+
497
+ # Use setString with a nil value by default, but this doesn't work on all subadapters.
498
+ def set_ps_arg_nil(cps, i)
499
+ cps.setString(i, nil)
500
+ end
424
501
 
425
- # Add a prepared_statements accessor to the connection,
426
- # and set it to an empty hash. This is used to store
427
- # adapter specific prepared statements.
502
+ # Return the connection. Used to do configuration on the
503
+ # connection object before adding it to the connection pool.
428
504
  def setup_connection(conn)
429
- class << conn
430
- attr_accessor :prepared_statements
431
- end
432
- conn.prepared_statements = {}
433
505
  conn
434
506
  end
435
507
 
436
508
  # Parse the table schema for the given table.
437
509
  def schema_parse_table(table, opts={})
438
- m = output_identifier_meth
439
- im = input_identifier_meth
510
+ m = output_identifier_meth(opts[:dataset])
511
+ im = input_identifier_meth(opts[:dataset])
440
512
  ds = dataset
441
513
  schema, table = schema_and_table(table)
442
514
  schema ||= opts[:schema]
@@ -444,9 +516,11 @@ module Sequel
444
516
  table = im.call(table)
445
517
  pks, ts = [], []
446
518
  metadata(:getPrimaryKeys, nil, schema, table) do |h|
519
+ next if schema_parse_table_skip?(h, schema)
447
520
  pks << h[:column_name]
448
521
  end
449
522
  metadata(:getColumns, nil, schema, table, nil) do |h|
523
+ next if schema_parse_table_skip?(h, schema)
450
524
  s = {:type=>schema_column_type(h[:type_name]), :db_type=>h[:type_name], :default=>(h[:column_def] == '' ? nil : h[:column_def]), :allow_null=>(h[:nullable] != 0), :primary_key=>pks.include?(h[:column_name]), :column_size=>h[:column_size], :scale=>h[:decimal_digits]}
451
525
  if s[:db_type] =~ DECIMAL_TYPE_RE && s[:scale] == 0
452
526
  s[:type] = :integer
@@ -456,6 +530,12 @@ module Sequel
456
530
  ts
457
531
  end
458
532
 
533
+ # Whether schema_parse_table should skip the given row when
534
+ # parsing the schema.
535
+ def schema_parse_table_skip?(h, schema)
536
+ h[:table_schem] == 'INFORMATION_SCHEMA'
537
+ end
538
+
459
539
  # Yield a new statement object, and ensure that it is closed before returning.
460
540
  def statement(conn)
461
541
  stmt = conn.createStatement
@@ -476,6 +556,8 @@ module Sequel
476
556
 
477
557
  class Dataset < Sequel::Dataset
478
558
  include StoredProcedures
559
+
560
+ Database::DatasetClass = self
479
561
 
480
562
  # Use JDBC PreparedStatements instead of emulated ones. Statements
481
563
  # created using #prepare are cached at the connection level to allow
@@ -489,17 +571,17 @@ module Sequel
489
571
  # Execute the prepared SQL using the stored type and
490
572
  # arguments derived from the hash passed to call.
491
573
  def execute(sql, opts={}, &block)
492
- super(self, {:arguments=>bind_arguments, :type=>sql_query_type}.merge(opts), &block)
574
+ super(self, {:arguments=>bind_arguments}.merge(opts), &block)
493
575
  end
494
576
 
495
577
  # Same as execute, explicit due to intricacies of alias and super.
496
578
  def execute_dui(sql, opts={}, &block)
497
- super(self, {:arguments=>bind_arguments, :type=>sql_query_type}.merge(opts), &block)
579
+ super(self, {:arguments=>bind_arguments}.merge(opts), &block)
498
580
  end
499
581
 
500
582
  # Same as execute, explicit due to intricacies of alias and super.
501
583
  def execute_insert(sql, opts={}, &block)
502
- super(self, {:arguments=>bind_arguments, :type=>sql_query_type}.merge(opts), &block)
584
+ super(self, {:arguments=>bind_arguments, :type=>:insert}.merge(opts), &block)
503
585
  end
504
586
  end
505
587
 
@@ -512,17 +594,17 @@ module Sequel
512
594
 
513
595
  # Execute the database stored procedure with the stored arguments.
514
596
  def execute(sql, opts={}, &block)
515
- super(@sproc_name, {:args=>@sproc_args, :sproc=>true, :type=>sql_query_type}.merge(opts), &block)
597
+ super(@sproc_name, {:args=>@sproc_args, :sproc=>true}.merge(opts), &block)
516
598
  end
517
599
 
518
600
  # Same as execute, explicit due to intricacies of alias and super.
519
601
  def execute_dui(sql, opts={}, &block)
520
- super(@sproc_name, {:args=>@sproc_args, :sproc=>true, :type=>sql_query_type}.merge(opts), &block)
602
+ super(@sproc_name, {:args=>@sproc_args, :sproc=>true}.merge(opts), &block)
521
603
  end
522
604
 
523
605
  # Same as execute, explicit due to intricacies of alias and super.
524
606
  def execute_insert(sql, opts={}, &block)
525
- super(@sproc_name, {:args=>@sproc_args, :sproc=>true, :type=>sql_query_type}.merge(opts), &block)
607
+ super(@sproc_name, {:args=>@sproc_args, :sproc=>true, :type=>:insert}.merge(opts), &block)
526
608
  end
527
609
  end
528
610
 
@@ -530,13 +612,7 @@ module Sequel
530
612
  # Uses the database's setting by default, can be set to false to roughly
531
613
  # double performance when fetching rows.
532
614
  attr_accessor :convert_types
533
-
534
- # Use the convert_types default setting from the database
535
- def initialize(db, opts={})
536
- @convert_types = db.convert_types
537
- super
538
- end
539
-
615
+
540
616
  # Correctly return rows from the database and return them as hashes.
541
617
  def fetch_rows(sql, &block)
542
618
  execute(sql){|result| process_result_set(result, &block)}
@@ -550,32 +626,88 @@ module Sequel
550
626
  ps.extend(PreparedStatementMethods)
551
627
  if name
552
628
  ps.prepared_statement_name = name
553
- db.prepared_statements[name] = ps
629
+ db.set_prepared_statement(name, ps)
554
630
  end
555
631
  ps
556
632
  end
557
633
 
558
634
  private
559
-
560
- # Convert the type. Used for converting Java types to ruby types.
561
- def convert_type(v)
635
+
636
+ # Cache Java class constants to speed up lookups
637
+ JAVA_SQL_TIMESTAMP = Java::JavaSQL::Timestamp
638
+ JAVA_SQL_TIME = Java::JavaSQL::Time
639
+ JAVA_SQL_DATE = Java::JavaSQL::Date
640
+ JAVA_SQL_BLOB = Java::JavaSQL::Blob
641
+ JAVA_SQL_CLOB = Java::JavaSQL::Clob
642
+ JAVA_BUFFERED_READER = Java::JavaIo::BufferedReader
643
+ JAVA_BIG_DECIMAL = Java::JavaMath::BigDecimal
644
+ JAVA_BYTE_ARRAY = Java::byte[]
645
+ JAVA_UUID = Java::JavaUtil::UUID
646
+
647
+ # Handle type conversions for common Java types.
648
+ class TYPE_TRANSLATOR
649
+ LF = "\n".freeze
650
+ def time(v) Sequel.string_to_time("#{v.to_string}.#{sprintf('%03i', v.getTime.divmod(1000).last)}") end
651
+ def date(v) Date.civil(v.getYear + 1900, v.getMonth + 1, v.getDate) end
652
+ def decimal(v) BigDecimal.new(v.to_string) end
653
+ def byte_array(v) Sequel::SQL::Blob.new(String.from_java_bytes(v)) end
654
+ def blob(v) Sequel::SQL::Blob.new(String.from_java_bytes(v.getBytes(1, v.length))) end
655
+ def clob(v) Sequel::SQL::Blob.new(v.getSubString(1, v.length)) end
656
+ def buffered_reader(v)
657
+ lines = ""
658
+ c = false
659
+ while(line = v.read_line) do
660
+ lines << LF if c
661
+ lines << line
662
+ c ||= true
663
+ end
664
+ lines
665
+ end
666
+ def uuid(v) v.to_string end
667
+ end
668
+ TYPE_TRANSLATOR_INSTANCE = tt = TYPE_TRANSLATOR.new
669
+
670
+ # Cache type translator methods so that duplicate Method
671
+ # objects are not created.
672
+ DECIMAL_METHOD = tt.method(:decimal)
673
+ TIME_METHOD = tt.method(:time)
674
+ DATE_METHOD = tt.method(:date)
675
+ BUFFERED_READER_METHOD = tt.method(:buffered_reader)
676
+ BYTE_ARRAY_METHOD = tt.method(:byte_array)
677
+ BLOB_METHOD = tt.method(:blob)
678
+ CLOB_METHOD = tt.method(:clob)
679
+ UUID_METHOD = tt.method(:uuid)
680
+
681
+ # Convert the given Java timestamp to an instance of Sequel.datetime_class.
682
+ def convert_type_timestamp(v)
683
+ db.to_application_timestamp([v.getYear + 1900, v.getMonth + 1, v.getDate, v.getHours, v.getMinutes, v.getSeconds, v.getNanos])
684
+ end
685
+
686
+ # Return a callable object that will convert any value of <tt>v</tt>'s
687
+ # class to a ruby object. If no callable object can handle <tt>v</tt>'s
688
+ # class, return false so that the negative lookup is cached.
689
+ def convert_type_proc(v)
562
690
  case v
563
- when Java::JavaSQL::Timestamp, Java::JavaSQL::Time
564
- Sequel.database_to_application_timestamp(v.to_string)
565
- when Java::JavaSQL::Date
566
- Sequel.string_to_date(v.to_string)
567
- when Java::JavaIo::BufferedReader
568
- lines = []
569
- while(line = v.read_line) do lines << line end
570
- lines.join("\n")
571
- when Java::JavaMath::BigDecimal
572
- BigDecimal.new(v.to_string)
573
- when Java::byte[]
574
- Sequel::SQL::Blob.new(String.from_java_bytes(v))
575
- when Java::JavaSQL::Blob
576
- convert_type(v.getBytes(1, v.length))
691
+ when JAVA_BIG_DECIMAL
692
+ DECIMAL_METHOD
693
+ when JAVA_SQL_TIMESTAMP
694
+ method(:convert_type_timestamp)
695
+ when JAVA_SQL_TIME
696
+ TIME_METHOD
697
+ when JAVA_SQL_DATE
698
+ DATE_METHOD
699
+ when JAVA_BUFFERED_READER
700
+ BUFFERED_READER_METHOD
701
+ when JAVA_BYTE_ARRAY
702
+ BYTE_ARRAY_METHOD
703
+ when JAVA_SQL_BLOB
704
+ BLOB_METHOD
705
+ when JAVA_SQL_CLOB
706
+ CLOB_METHOD
707
+ when JAVA_UUID
708
+ UUID_METHOD
577
709
  else
578
- v
710
+ false
579
711
  end
580
712
  end
581
713
 
@@ -586,32 +718,82 @@ module Sequel
586
718
 
587
719
  # Split out from fetch rows to allow processing of JDBC result sets
588
720
  # that don't come from issuing an SQL string.
589
- def process_result_set(result)
721
+ def process_result_set(result, &block)
590
722
  # get column names
591
723
  meta = result.getMetaData
592
724
  cols = []
593
725
  i = 0
594
726
  meta.getColumnCount.times{cols << [output_identifier(meta.getColumnLabel(i+=1)), i]}
595
- @columns = cols.map{|c| c.at(0)}
596
- blk = result_set_object_getter
597
- # get rows
727
+ columns = cols.map{|c| c.at(0)}
728
+ if opts[:offset] && offset_returns_row_number_column?
729
+ rn = row_number_column
730
+ columns.delete(rn)
731
+ end
732
+ @columns = columns
733
+ ct = @convert_types
734
+ if (ct.nil? ? db.convert_types : ct)
735
+ cols.each{|c| c << nil}
736
+ process_result_set_convert(cols, result, rn, &block)
737
+ else
738
+ process_result_set_no_convert(cols, result, rn, &block)
739
+ end
740
+ ensure
741
+ result.close
742
+ end
743
+
744
+ # Use conversion procs to convert data retrieved
745
+ # from the database. This has been optimized, the algorithm it uses
746
+ # is roughly, for each column value in each row:
747
+ # * check if the value is truthy (not false/nil)
748
+ # * if not truthy, return object
749
+ # * otherwise, see if a conversion method exists for
750
+ # the column. All columns start with a nil conversion proc,
751
+ # since unlike other adapters, Sequel doesn't get the type of
752
+ # the column when parsing the column metadata.
753
+ # * if a conversion proc is not false/nil, call it with the object
754
+ # and return the result.
755
+ # * if a conversion proc has already been looked up and doesn't
756
+ # exist (false value), return object.
757
+ # * if a conversion proc hasn't been looked up yet (nil value),
758
+ # call convert_type_proc to get the conversion method. Cache
759
+ # the result of as the column's conversion proc to speed up
760
+ # later processing. If the conversion proc exists, call it
761
+ # and return the result, otherwise, return the object.
762
+ def process_result_set_convert(cols, result, rn)
598
763
  while result.next
599
764
  row = {}
600
- cols.each do |n, i|
601
- row[n] = blk.call(result, n, i)
765
+ cols.each do |n, i, p|
766
+ v = result.getObject(i)
767
+ row[n] = if v
768
+ if p
769
+ p.call(v)
770
+ elsif p.nil?
771
+ cols[i-1][2] = p = convert_type_proc(v)
772
+ if p
773
+ p.call(v)
774
+ else
775
+ v
776
+ end
777
+ else
778
+ v
779
+ end
780
+ else
781
+ v
782
+ end
602
783
  end
784
+ row.delete(rn) if rn
603
785
  yield row
604
786
  end
605
787
  end
606
788
 
607
- # Proc that takes the ResultSet and an integer field number and returns
608
- # the object for that field. Respects the @convert_types setting to
609
- # convert Java types to ruby types.
610
- def result_set_object_getter
611
- if @convert_types
612
- lambda {|result, n, i| convert_type(result.getObject(i))}
613
- else
614
- lambda {|result, n, i| result.getObject(i)}
789
+ # Yield rows without calling any conversion procs. This
790
+ # may yield Java values and not ruby values.
791
+ def process_result_set_no_convert(cols, result, rn)
792
+ while result.next
793
+ row = {}
794
+ cols.each{|n, i| row[n] = result.getObject(i)}
795
+ row.delete(rn) if rn
796
+ yield row
615
797
  end
616
798
  end
617
799
  end