sequel 3.10.0 → 3.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. data/CHANGELOG +68 -0
  2. data/COPYING +1 -1
  3. data/README.rdoc +87 -27
  4. data/bin/sequel +2 -4
  5. data/doc/association_basics.rdoc +1383 -0
  6. data/doc/dataset_basics.rdoc +106 -0
  7. data/doc/opening_databases.rdoc +45 -16
  8. data/doc/querying.rdoc +210 -0
  9. data/doc/release_notes/3.11.0.txt +254 -0
  10. data/doc/virtual_rows.rdoc +217 -31
  11. data/lib/sequel/adapters/ado.rb +28 -12
  12. data/lib/sequel/adapters/ado/mssql.rb +33 -1
  13. data/lib/sequel/adapters/amalgalite.rb +13 -8
  14. data/lib/sequel/adapters/db2.rb +1 -2
  15. data/lib/sequel/adapters/dbi.rb +7 -4
  16. data/lib/sequel/adapters/do.rb +14 -15
  17. data/lib/sequel/adapters/do/postgres.rb +4 -5
  18. data/lib/sequel/adapters/do/sqlite.rb +9 -0
  19. data/lib/sequel/adapters/firebird.rb +5 -10
  20. data/lib/sequel/adapters/informix.rb +2 -4
  21. data/lib/sequel/adapters/jdbc.rb +111 -49
  22. data/lib/sequel/adapters/jdbc/mssql.rb +1 -2
  23. data/lib/sequel/adapters/jdbc/mysql.rb +11 -0
  24. data/lib/sequel/adapters/jdbc/oracle.rb +4 -7
  25. data/lib/sequel/adapters/jdbc/postgresql.rb +8 -1
  26. data/lib/sequel/adapters/jdbc/sqlite.rb +12 -0
  27. data/lib/sequel/adapters/mysql.rb +14 -5
  28. data/lib/sequel/adapters/odbc.rb +2 -4
  29. data/lib/sequel/adapters/odbc/mssql.rb +2 -4
  30. data/lib/sequel/adapters/openbase.rb +1 -2
  31. data/lib/sequel/adapters/oracle.rb +4 -8
  32. data/lib/sequel/adapters/postgres.rb +4 -11
  33. data/lib/sequel/adapters/shared/mssql.rb +22 -9
  34. data/lib/sequel/adapters/shared/mysql.rb +33 -30
  35. data/lib/sequel/adapters/shared/oracle.rb +0 -5
  36. data/lib/sequel/adapters/shared/postgres.rb +13 -11
  37. data/lib/sequel/adapters/shared/sqlite.rb +56 -10
  38. data/lib/sequel/adapters/sqlite.rb +16 -9
  39. data/lib/sequel/connection_pool.rb +6 -1
  40. data/lib/sequel/connection_pool/single.rb +1 -0
  41. data/lib/sequel/core.rb +6 -1
  42. data/lib/sequel/database.rb +52 -23
  43. data/lib/sequel/database/schema_generator.rb +6 -0
  44. data/lib/sequel/database/schema_methods.rb +5 -5
  45. data/lib/sequel/database/schema_sql.rb +1 -1
  46. data/lib/sequel/dataset.rb +4 -190
  47. data/lib/sequel/dataset/actions.rb +323 -1
  48. data/lib/sequel/dataset/features.rb +18 -2
  49. data/lib/sequel/dataset/graph.rb +7 -0
  50. data/lib/sequel/dataset/misc.rb +119 -0
  51. data/lib/sequel/dataset/mutation.rb +64 -0
  52. data/lib/sequel/dataset/prepared_statements.rb +6 -0
  53. data/lib/sequel/dataset/query.rb +272 -6
  54. data/lib/sequel/dataset/sql.rb +186 -394
  55. data/lib/sequel/model.rb +4 -2
  56. data/lib/sequel/model/associations.rb +31 -14
  57. data/lib/sequel/model/base.rb +32 -13
  58. data/lib/sequel/model/exceptions.rb +8 -4
  59. data/lib/sequel/model/plugins.rb +3 -13
  60. data/lib/sequel/plugins/active_model.rb +26 -7
  61. data/lib/sequel/plugins/instance_filters.rb +98 -0
  62. data/lib/sequel/plugins/many_through_many.rb +1 -1
  63. data/lib/sequel/plugins/optimistic_locking.rb +25 -9
  64. data/lib/sequel/version.rb +1 -1
  65. data/spec/adapters/mssql_spec.rb +26 -0
  66. data/spec/adapters/mysql_spec.rb +33 -4
  67. data/spec/adapters/postgres_spec.rb +24 -1
  68. data/spec/adapters/spec_helper.rb +6 -0
  69. data/spec/adapters/sqlite_spec.rb +28 -0
  70. data/spec/core/connection_pool_spec.rb +17 -5
  71. data/spec/core/database_spec.rb +101 -1
  72. data/spec/core/dataset_spec.rb +42 -4
  73. data/spec/core/schema_spec.rb +13 -0
  74. data/spec/extensions/active_model_spec.rb +34 -11
  75. data/spec/extensions/caching_spec.rb +2 -0
  76. data/spec/extensions/instance_filters_spec.rb +55 -0
  77. data/spec/extensions/spec_helper.rb +2 -0
  78. data/spec/integration/dataset_test.rb +12 -1
  79. data/spec/integration/model_test.rb +12 -0
  80. data/spec/integration/plugin_test.rb +61 -1
  81. data/spec/integration/schema_test.rb +14 -3
  82. data/spec/model/base_spec.rb +27 -0
  83. data/spec/model/plugins_spec.rb +0 -22
  84. data/spec/model/record_spec.rb +32 -1
  85. data/spec/model/spec_helper.rb +2 -0
  86. metadata +14 -3
  87. data/lib/sequel/dataset/convenience.rb +0 -326
@@ -26,6 +26,11 @@ module Sequel
26
26
  when 'mssql'
27
27
  Sequel.ts_require 'adapters/shared/mssql'
28
28
  extend Sequel::MSSQL::DatabaseMethods
29
+ def self.dataset(*args)
30
+ ds = super
31
+ ds.extend Sequel::MSSQL::DatasetMethods
32
+ ds
33
+ end
29
34
  end
30
35
  end
31
36
 
@@ -63,17 +68,15 @@ module Sequel
63
68
  end
64
69
 
65
70
  def execute(sql, opts={})
66
- log_info(sql)
67
71
  synchronize(opts[:server]) do |conn|
68
- r = conn.execute(sql)
72
+ r = log_yield(sql){conn.execute(sql)}
69
73
  yield(r) if block_given?
70
74
  r
71
75
  end
72
76
  end
73
77
 
74
78
  def do(sql, opts={})
75
- log_info(sql)
76
- synchronize(opts[:server]){|conn| conn.do(sql)}
79
+ synchronize(opts[:server]){|conn| log_yield(sql){conn.do(sql)}}
77
80
  end
78
81
  alias_method :execute_dui, :do
79
82
 
@@ -66,11 +66,10 @@ module Sequel
66
66
  # Otherwise, the return value is the insert id if opts[:type] is :insert,
67
67
  # or the number of affected rows, otherwise.
68
68
  def execute(sql, opts={})
69
- log_info(sql)
70
69
  synchronize(opts[:server]) do |conn|
71
70
  begin
72
71
  command = conn.create_command(sql)
73
- res = block_given? ? command.execute_reader : command.execute_non_query
72
+ res = log_yield(sql){block_given? ? command.execute_reader : command.execute_non_query}
74
73
  rescue ::DataObjects::Error => e
75
74
  raise_error(e)
76
75
  end
@@ -121,21 +120,23 @@ module Sequel
121
120
  # substitute our own.
122
121
  def begin_transaction(conn)
123
122
  return super if supports_savepoints?
124
- log_info(TRANSACTION_BEGIN)
125
- t = ::DataObjects::Transaction.create_for_uri(uri)
126
- t.instance_variable_get(:@connection).close
127
- t.instance_variable_set(:@connection, conn)
128
- t.begin
129
- t
123
+ log_yield(TRANSACTION_BEGIN) do
124
+ t = ::DataObjects::Transaction.create_for_uri(uri)
125
+ t.instance_variable_get(:@connection).close
126
+ t.instance_variable_set(:@connection, conn)
127
+ t.begin
128
+ t
129
+ end
130
130
  end
131
131
 
132
132
  # DataObjects requires transactions be prepared before being
133
133
  # committed, so we do that.
134
134
  def commit_transaction(t)
135
135
  return super if supports_savepoints?
136
- log_info(TRANSACTION_ROLLBACK)
137
- t.prepare
138
- t.commit
136
+ log_yield(TRANSACTION_ROLLBACK) do
137
+ t.prepare
138
+ t.commit
139
+ end
139
140
  end
140
141
 
141
142
  # Method to call on a statement object to execute SQL that does
@@ -151,15 +152,13 @@ module Sequel
151
152
 
152
153
  # Execute SQL on the connection by creating a command first
153
154
  def log_connection_execute(conn, sql)
154
- log_info(sql)
155
- conn.create_command(sql).execute_non_query
155
+ log_yield(sql){conn.create_command(sql).execute_non_query}
156
156
  end
157
157
 
158
158
  # We use the transactions rollback method to rollback.
159
159
  def rollback_transaction(t)
160
160
  return super if supports_savepoints?
161
- log_info(TRANSACTION_COMMIT)
162
- t.rollback
161
+ log_yield(TRANSACTION_COMMIT){t.rollback}
163
162
  end
164
163
 
165
164
  # Allow extending the given connection when it is first created.
@@ -19,13 +19,12 @@ module Sequel
19
19
  begin
20
20
  if block_given?
21
21
  begin
22
- reader = command.execute_reader
23
- yield(reader)
22
+ yield(reader = @db.log_yield(sql){command.execute_reader})
24
23
  ensure
25
24
  reader.close if reader
26
25
  end
27
26
  else
28
- command.execute_non_query
27
+ @db.log_yield(sql){command.execute_non_query}
29
28
  end
30
29
  rescue ::DataObjects::Error => e
31
30
  raise_error(e)
@@ -64,9 +63,9 @@ module Sequel
64
63
  # Run the INSERT sql on the database and return the primary key
65
64
  # for the record.
66
65
  def execute_insert(sql, opts={})
67
- log_info(sql)
68
66
  synchronize(opts[:server]) do |conn|
69
- conn.create_command(sql).execute_non_query
67
+ com = conn.create_command(sql)
68
+ log_yield(sql){com.execute_non_query}
70
69
  insert_result(conn, opts[:table], opts[:values])
71
70
  end
72
71
  end
@@ -20,6 +20,15 @@ module Sequel
20
20
  o = super
21
21
  uri == 'sqlite3::memory:' ? o.merge(:max_connections=>1) : o
22
22
  end
23
+
24
+ # Execute the connection pragmas on the connection
25
+ def setup_connection(conn)
26
+ connection_pragmas.each do |s|
27
+ com = conn.create_command(s)
28
+ log_yield(s){com.execute_non_query}
29
+ end
30
+ super
31
+ end
23
32
  end
24
33
 
25
34
  # Dataset class for SQLite datasets accessed via DataObjects.
@@ -43,15 +43,13 @@ module Sequel
43
43
  end
44
44
 
45
45
  def execute(sql, opts={})
46
- log_info(sql)
47
46
  begin
48
47
  synchronize(opts[:server]) do |conn|
49
- r = conn.execute(sql)
48
+ r = log_yield(sql){conn.execute(sql)}
50
49
  yield(r) if block_given?
51
50
  r
52
51
  end
53
52
  rescue => e
54
- log_info(e.message)
55
53
  raise_error(e, :classes=>[Fb::Error])
56
54
  end
57
55
  end
@@ -105,14 +103,12 @@ module Sequel
105
103
  end
106
104
 
107
105
  def begin_transaction(conn)
108
- log_info(TRANSACTION_BEGIN)
109
- conn.transaction
106
+ log_yield(TRANSACTION_BEGIN){conn.transaction}
110
107
  conn
111
108
  end
112
109
 
113
110
  def commit_transaction(conn)
114
- log_info(TRANSACTION_COMMIT)
115
- conn.commit
111
+ log_yield(TRANSACTION_COMMIT){conn.commit}
116
112
  end
117
113
 
118
114
  def create_sequence_sql(name, opts={})
@@ -160,7 +156,7 @@ module Sequel
160
156
  events = opts[:events] ? Array(opts[:events]) : [:insert, :update, :delete]
161
157
  whence = opts[:after] ? 'AFTER' : 'BEFORE'
162
158
  inactive = opts[:inactive] ? 'INACTIVE' : 'ACTIVE'
163
- position = opts[:position] ? opts[:position] : 0
159
+ position = opts.fetch(:position, 0)
164
160
  sql = <<-end_sql
165
161
  CREATE TRIGGER #{quote_identifier(name)} for #{quote_identifier(table)}
166
162
  #{inactive} #{whence} #{events.map{|e| e.to_s.upcase}.join(' OR ')} position #{position}
@@ -187,8 +183,7 @@ module Sequel
187
183
  end
188
184
 
189
185
  def rollback_transaction(conn)
190
- log_info(TRANSACTION_ROLLBACK)
191
- conn.rollback
186
+ log_yield(TRANSACTION_ROLLBACK){conn.rollback}
192
187
  end
193
188
 
194
189
  def type_literal_generic_string(column)
@@ -18,14 +18,12 @@ module Sequel
18
18
 
19
19
  # Returns number of rows affected
20
20
  def execute_dui(sql, opts={})
21
- log_info(sql)
22
- synchronize(opts[:server]){|c| c.immediate(sql)}
21
+ synchronize(opts[:server]){|c| log_yield(sql){c.immediate(sql)}}
23
22
  end
24
23
  alias_method :do, :execute_dui
25
24
 
26
25
  def execute(sql, opts={})
27
- log_info(sql)
28
- synchronize(opts[:server]){|c| yield c.cursor(sql)}
26
+ synchronize(opts[:server]){|c| yield log_yield(sql){c.cursor(sql)}}
29
27
  end
30
28
  alias_method :query, :execute
31
29
 
@@ -3,24 +3,6 @@ Sequel.require 'adapters/utils/stored_procedures'
3
3
 
4
4
  module Sequel
5
5
  # Houses Sequel's JDBC support when running on JRuby.
6
- # Support for individual database types is done using sub adapters.
7
- # PostgreSQL, MySQL, SQLite, Oracle, and MSSQL all have relatively good support,
8
- # close the the level supported by the native adapter.
9
- # PostgreSQL, MySQL, SQLite can load necessary support using
10
- # the jdbc-* gem, if it is installed, though they will work if you
11
- # have the correct .jar in your CLASSPATH. Oracle and MSSQL should
12
- # load the necessary support if you have the .jar in your CLASSPATH.
13
- # For all other databases, the Java class should be loaded manually
14
- # before calling Sequel.connect.
15
- #
16
- # Note that when using a JDBC adapter, the best way to use Sequel
17
- # is via Sequel.connect, NOT Sequel.jdbc. Use the JDBC connection
18
- # string when connecting, which will be in a different format than
19
- # the native connection string. The connection string should start
20
- # with 'jdbc:'. For PostgreSQL, use 'jdbc:postgresql:', and for
21
- # SQLite you do not need 2 preceding slashes for the database name
22
- # (use no preceding slashes for a relative path, and one preceding
23
- # slash for an absolute path).
24
6
  module JDBC
25
7
  # Make it accesing the java.lang hierarchy more ruby friendly.
26
8
  module JavaLang
@@ -31,6 +13,19 @@ module Sequel
31
13
  module JavaSQL
32
14
  include_package 'java.sql'
33
15
  end
16
+
17
+ # Make it accesing the javax.naming hierarchy more ruby friendly.
18
+ module JavaxNaming
19
+ include_package 'javax.naming'
20
+ end
21
+
22
+ # Used to identify a jndi connection and to extract the jndi
23
+ # resource name.
24
+ JNDI_URI_REGEXP = /\Ajdbc:jndi:(.+)/
25
+
26
+ # The types to check for 0 scale to transform :decimal types
27
+ # to :integer.
28
+ DECIMAL_TYPE_RE = /number|numeric|decimal/io
34
29
 
35
30
  # Contains procs keyed on sub adapter type that extend the
36
31
  # given database object so it supports the correct database type.
@@ -62,6 +57,12 @@ module Sequel
62
57
  db.extend(Sequel::JDBC::MSSQL::DatabaseMethods)
63
58
  com.microsoft.sqlserver.jdbc.SQLServerDriver
64
59
  end,
60
+ :jtds=>proc do |db|
61
+ Sequel.ts_require 'adapters/jdbc/mssql'
62
+ db.extend(Sequel::JDBC::MSSQL::DatabaseMethods)
63
+ JDBC.load_gem('jtds')
64
+ Java::net.sourceforge.jtds.jdbc.Driver
65
+ end,
65
66
  :h2=>proc do |db|
66
67
  Sequel.ts_require 'adapters/jdbc/h2'
67
68
  db.extend(Sequel::JDBC::H2::DatabaseMethods)
@@ -93,6 +94,9 @@ module Sequel
93
94
  # The type of database we are connecting to
94
95
  attr_reader :database_type
95
96
 
97
+ # The Java database driver we are using
98
+ attr_reader :driver
99
+
96
100
  # Whether to convert some Java types to ruby types when retrieving rows.
97
101
  # True by default, can be set to false to roughly double performance when
98
102
  # fetching rows.
@@ -104,11 +108,14 @@ module Sequel
104
108
  # uri, since JDBC requires one.
105
109
  def initialize(opts)
106
110
  super
107
- @convert_types = @opts.include?(:convert_types) ? typecast_value_boolean(@opts[:convert_types]) : true
111
+ @convert_types = typecast_value_boolean(@opts.fetch(:convert_types, true))
108
112
  raise(Error, "No connection string specified") unless uri
109
- if match = /\Ajdbc:([^:]+)/.match(uri) and prok = DATABASE_SETUP[match[1].to_sym]
110
- prok.call(self)
111
- end
113
+
114
+ resolved_uri = jndi? ? get_uri_from_jndi : uri
115
+
116
+ if match = /\Ajdbc:([^:]+)/.match(resolved_uri) and prok = DATABASE_SETUP[match[1].to_sym]
117
+ @driver = prok.call(self)
118
+ end
112
119
  end
113
120
 
114
121
  # Execute the given stored procedure with the give name. If a block is
@@ -124,14 +131,14 @@ module Sequel
124
131
 
125
132
  begin
126
133
  if block_given?
127
- yield cps.executeQuery
134
+ yield log_yield(sql){cps.executeQuery}
128
135
  else
129
136
  case opts[:type]
130
137
  when :insert
131
- cps.executeUpdate
138
+ log_yield(sql){cps.executeUpdate}
132
139
  last_insert_id(conn, opts)
133
140
  else
134
- cps.executeUpdate
141
+ log_yield(sql){cps.executeUpdate}
135
142
  end
136
143
  end
137
144
  rescue NativeException, JavaSQL::SQLException => e
@@ -141,12 +148,29 @@ module Sequel
141
148
  end
142
149
  end
143
150
  end
144
-
151
+
145
152
  # Connect to the database using JavaSQL::DriverManager.getConnection.
146
153
  def connect(server)
147
- args = [uri(server_opts(server))]
148
- args.concat([opts[:user], opts[:password]]) if opts[:user] && opts[:password]
149
- setup_connection(JavaSQL::DriverManager.getConnection(*args))
154
+ opts = server_opts(server)
155
+ conn = if jndi?
156
+ get_connection_from_jndi
157
+ else
158
+ args = [uri(opts)]
159
+ args.concat([opts[:user], opts[:password]]) if opts[:user] && opts[:password]
160
+ begin
161
+ JavaSQL::DriverManager.getConnection(*args)
162
+ rescue
163
+ # If the DriverManager can't get the connection - use the connect
164
+ # method of the driver. (This happens under Tomcat for instance)
165
+ props = java.util.Properties.new
166
+ if opts && opts[:user] && opts[:password]
167
+ props.setProperty("user", opts[:user])
168
+ props.setProperty("password", opts[:password])
169
+ end
170
+ driver.new.connect(args[0], props)
171
+ end
172
+ end
173
+ setup_connection(conn)
150
174
  end
151
175
 
152
176
  # Return instances of JDBC::Dataset with the given opts.
@@ -159,21 +183,26 @@ module Sequel
159
183
  def execute(sql, opts={}, &block)
160
184
  return call_sproc(sql, opts, &block) if opts[:sproc]
161
185
  return execute_prepared_statement(sql, opts, &block) if [Symbol, Dataset].any?{|c| sql.is_a?(c)}
162
- log_info(sql)
163
186
  synchronize(opts[:server]) do |conn|
164
187
  stmt = conn.createStatement
165
188
  begin
166
189
  if block_given?
167
- yield stmt.executeQuery(sql)
190
+ yield log_yield(sql){stmt.executeQuery(sql)}
168
191
  else
169
192
  case opts[:type]
170
193
  when :ddl
171
- stmt.execute(sql)
194
+ log_yield(sql){stmt.execute(sql)}
172
195
  when :insert
173
- stmt.executeUpdate(sql)
196
+ log_yield(sql) do
197
+ if requires_return_generated_keys?
198
+ stmt.executeUpdate(sql, JavaSQL::Statement.RETURN_GENERATED_KEYS)
199
+ else
200
+ stmt.executeUpdate(sql)
201
+ end
202
+ end
174
203
  last_insert_id(conn, opts.merge(:stmt=>stmt))
175
204
  else
176
- stmt.executeUpdate(sql)
205
+ log_yield(sql){stmt.executeUpdate(sql)}
177
206
  end
178
207
  end
179
208
  rescue NativeException, JavaSQL::SQLException => e
@@ -235,9 +264,14 @@ module Sequel
235
264
  ur = opts[:uri] || opts[:url] || opts[:database]
236
265
  ur =~ /^\Ajdbc:/ ? ur : "jdbc:#{ur}"
237
266
  end
267
+
268
+ # Whether or not JNDI is being used for this connection.
269
+ def jndi?
270
+ !!(uri =~ JNDI_URI_REGEXP)
271
+ end
238
272
 
239
273
  private
240
-
274
+
241
275
  # JDBC uses a statement object to execute SQL on the database
242
276
  def begin_transaction(conn)
243
277
  conn = conn.createStatement unless supports_savepoints?
@@ -269,29 +303,25 @@ module Sequel
269
303
  if name and cps = conn.prepared_statements[name] and cps[0] == sql
270
304
  cps = cps[1]
271
305
  else
272
- if cps
273
- log_info("Closing #{name}")
274
- cps[1].close
275
- end
276
- log_info("Preparing#{" #{name}:" if name} #{sql}")
277
- cps = conn.prepareStatement(sql)
306
+ log_yield("Closing #{name}"){cps[1].close} if cps
307
+ cps = log_yield("Preparing#{" #{name}:" if name} #{sql}"){conn.prepareStatement(sql)}
278
308
  conn.prepared_statements[name] = [sql, cps] if name
279
309
  end
280
310
  i = 0
281
311
  args.each{|arg| set_ps_arg(cps, arg, i+=1)}
282
- log_info("Executing#{" #{name}" if name}", args)
312
+ msg = "Executing#{" #{name}" if name}"
283
313
  begin
284
314
  if block_given?
285
- yield cps.executeQuery
315
+ yield log_yield(msg, args){cps.executeQuery}
286
316
  else
287
317
  case opts[:type]
288
318
  when :ddl
289
- cps.execute
319
+ log_yield(msg, args){cps.execute}
290
320
  when :insert
291
- cps.executeUpdate
321
+ log_yield(msg, args){cps.executeUpdate}
292
322
  last_insert_id(conn, opts.merge(:prepared=>true))
293
323
  else
294
- cps.executeUpdate
324
+ log_yield(msg, args){cps.executeUpdate}
295
325
  end
296
326
  end
297
327
  rescue NativeException, JavaSQL::SQLException => e
@@ -301,7 +331,21 @@ module Sequel
301
331
  end
302
332
  end
303
333
  end
334
+
335
+ # Gets the JDBC connection uri from the JNDI resource.
336
+ def get_uri_from_jndi
337
+ conn = get_connection_from_jndi
338
+ conn.meta_data.url
339
+ ensure
340
+ conn.close if conn
341
+ end
304
342
 
343
+ # Gets the connection from JNDI.
344
+ def get_connection_from_jndi
345
+ jndi_name = JNDI_URI_REGEXP.match(uri)[1]
346
+ JavaxNaming::InitialContext.new.lookup(jndi_name).connection
347
+ end
348
+
305
349
  # Support fractional seconds for Time objects used in bound variables
306
350
  def java_sql_timestamp(time)
307
351
  millis = time.to_i * 1000
@@ -319,7 +363,14 @@ module Sequel
319
363
 
320
364
  # Yield the metadata for this database
321
365
  def metadata(*args, &block)
322
- synchronize{|c| metadata_dataset.send(:process_result_set, c.getMetaData.send(*args), &block)}
366
+ synchronize do |c|
367
+ result = c.getMetaData.send(*args)
368
+ begin
369
+ metadata_dataset.send(:process_result_set, result, &block)
370
+ ensure
371
+ result.close
372
+ end
373
+ end
323
374
  end
324
375
 
325
376
  # Treat SQLExceptions with a "Connection Error" SQLState as disconnects
@@ -388,7 +439,11 @@ module Sequel
388
439
  pks << h[:column_name]
389
440
  end
390
441
  metadata(:getColumns, nil, schema, table, nil) do |h|
391
- ts << [m.call(h[:column_name]), {: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]}]
442
+ 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]}
443
+ if s[:db_type] =~ DECIMAL_TYPE_RE && s[:scale] == 0
444
+ s[:type] = :integer
445
+ end
446
+ ts << [m.call(h[:column_name]), s]
392
447
  end
393
448
  ts
394
449
  end
@@ -397,6 +452,13 @@ module Sequel
397
452
  def transaction_statement_object(conn)
398
453
  conn.createStatement
399
454
  end
455
+
456
+ # This method determines whether or not to add
457
+ # Statement.RETURN_GENERATED_KEYS as an argument when inserting rows.
458
+ # Sub-adapters that require this should override this method.
459
+ def requires_return_generated_keys?
460
+ false
461
+ end
400
462
  end
401
463
 
402
464
  class Dataset < Sequel::Dataset
@@ -498,7 +560,7 @@ module Sequel
498
560
  when Java::byte[]
499
561
  Sequel::SQL::Blob.new(String.from_java_bytes(v))
500
562
  when Java::JavaSQL::Blob
501
- convert_type(v.getBytes(0, v.length))
563
+ convert_type(v.getBytes(1, v.length))
502
564
  else
503
565
  v
504
566
  end