activerecord-jdbc-adapter 52.7-java → 60.0-java
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -2
- data/.travis.yml +58 -37
- data/Gemfile +9 -2
- data/README.md +25 -9
- data/Rakefile +1 -1
- data/Rakefile.jdbc +8 -1
- data/activerecord-jdbc-adapter.gemspec +5 -8
- data/lib/arjdbc/abstract/connection_management.rb +7 -0
- data/lib/arjdbc/abstract/core.rb +16 -23
- data/lib/arjdbc/abstract/database_statements.rb +26 -2
- data/lib/arjdbc/abstract/statement_cache.rb +2 -5
- data/lib/arjdbc/abstract/transaction_support.rb +5 -3
- data/lib/arjdbc/db2/column.rb +0 -39
- data/lib/arjdbc/derby/adapter.rb +1 -20
- data/lib/arjdbc/firebird/adapter.rb +0 -21
- data/lib/arjdbc/h2/adapter.rb +0 -15
- data/lib/arjdbc/hsqldb/adapter.rb +0 -14
- data/lib/arjdbc/informix/adapter.rb +0 -23
- data/lib/arjdbc/jdbc/adapter.rb +3 -1
- data/lib/arjdbc/jdbc/adapter_require.rb +3 -1
- data/lib/arjdbc/jdbc/base_ext.rb +3 -1
- data/lib/arjdbc/jdbc/callbacks.rb +2 -0
- data/lib/arjdbc/jdbc/column.rb +2 -0
- data/lib/arjdbc/jdbc/connection.rb +2 -0
- data/lib/arjdbc/jdbc/connection_methods.rb +2 -0
- data/lib/arjdbc/jdbc/error.rb +2 -0
- data/lib/arjdbc/jdbc/extension.rb +2 -0
- data/lib/arjdbc/jdbc/java.rb +3 -1
- data/lib/arjdbc/jdbc/railtie.rb +3 -1
- data/lib/arjdbc/jdbc/rake_tasks.rb +3 -1
- data/lib/arjdbc/jdbc/serialized_attributes_helper.rb +3 -1
- data/lib/arjdbc/jdbc/type_cast.rb +2 -0
- data/lib/arjdbc/jdbc/type_converter.rb +2 -0
- data/lib/arjdbc/mysql/adapter.rb +47 -18
- data/lib/arjdbc/mysql/connection_methods.rb +0 -1
- data/lib/arjdbc/postgresql/adapter.rb +220 -213
- data/lib/arjdbc/postgresql/base/array_decoder.rb +2 -0
- data/lib/arjdbc/postgresql/base/array_encoder.rb +4 -2
- data/lib/arjdbc/postgresql/base/array_parser.rb +4 -2
- data/lib/arjdbc/postgresql/base/pgconn.rb +2 -0
- data/lib/arjdbc/postgresql/column.rb +6 -4
- data/lib/arjdbc/postgresql/connection_methods.rb +0 -1
- data/lib/arjdbc/postgresql/name.rb +2 -0
- data/lib/arjdbc/postgresql/oid_types.rb +2 -0
- data/lib/arjdbc/sqlite3/adapter.rb +175 -180
- data/lib/arjdbc/sqlite3/connection_methods.rb +15 -5
- data/lib/arjdbc/tasks/databases.rake +13 -10
- data/lib/arjdbc/util/quoted_cache.rb +3 -1
- data/lib/arjdbc/util/serialized_attributes.rb +3 -1
- data/lib/arjdbc/util/table_copier.rb +3 -1
- data/lib/arjdbc/version.rb +1 -1
- data/pom.xml +4 -4
- data/rakelib/01-tomcat.rake +2 -2
- data/rakelib/rails.rake +1 -1
- data/src/java/arjdbc/ArJdbcModule.java +5 -5
- data/src/java/arjdbc/jdbc/DriverWrapper.java +1 -9
- data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +434 -701
- data/src/java/arjdbc/mssql/MSSQLRubyJdbcConnection.java +0 -51
- data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +13 -23
- data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +31 -24
- data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +94 -99
- metadata +8 -10
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
ArJdbc::ConnectionMethods.module_eval do
|
3
3
|
def sqlite3_connection(config)
|
4
|
-
config = config.deep_dup
|
5
4
|
config[:adapter_spec] ||= ::ArJdbc::SQLite3
|
6
5
|
config[:adapter_class] = ActiveRecord::ConnectionAdapters::SQLite3Adapter unless config.key?(:adapter_class)
|
7
6
|
|
@@ -23,17 +22,27 @@ ArJdbc::ConnectionMethods.module_eval do
|
|
23
22
|
raise
|
24
23
|
end
|
25
24
|
end
|
26
|
-
|
25
|
+
|
26
|
+
config[:properties] ||= {}
|
27
|
+
|
27
28
|
database = config[:database] # NOTE: "jdbc:sqlite::memory:" syntax is supported
|
28
29
|
config[:url] ||= "jdbc:sqlite:#{database == ':memory:' ? '' : database}"
|
29
30
|
config[:connection_alive_sql] ||= 'SELECT 1'
|
30
31
|
|
32
|
+
if config[:readonly]
|
33
|
+
# See
|
34
|
+
# * http://sqlite.org/c3ref/open.html
|
35
|
+
# * http://sqlite.org/c3ref/c_open_autoproxy.html
|
36
|
+
# => 0x01 = readonly, 0x40 = uri (default in JDBC)
|
37
|
+
config[:properties][:open_mode] = 0x01 | 0x40
|
38
|
+
end
|
39
|
+
|
31
40
|
timeout = config[:timeout]
|
32
41
|
if timeout && timeout.to_s !~ /\A\d+\Z/
|
33
42
|
raise TypeError.new "Timeout must be nil or a number (got: #{timeout})."
|
34
43
|
end
|
35
44
|
|
36
|
-
options =
|
45
|
+
options = config[:properties]
|
37
46
|
options['busy_timeout'] ||= timeout unless timeout.nil?
|
38
47
|
|
39
48
|
jdbc_connection(config)
|
@@ -51,8 +60,9 @@ ArJdbc::ConnectionMethods.module_eval do
|
|
51
60
|
def parse_sqlite3_config!(config)
|
52
61
|
database = ( config[:database] ||= config[:dbfile] )
|
53
62
|
if ':memory:' != database
|
54
|
-
|
55
|
-
|
63
|
+
# make sure to have an absolute path. Ruby and Java don't agree on working directory
|
64
|
+
config[:database] = File.expand_path(database, defined?(Rails.root) ? Rails.root : nil)
|
65
|
+
dirname = File.dirname(config[:database])
|
56
66
|
Dir.mkdir(dirname) unless File.directory?(dirname)
|
57
67
|
end
|
58
68
|
end
|
@@ -5,25 +5,28 @@ module ActiveRecord::Tasks
|
|
5
5
|
DatabaseTasks.module_eval do
|
6
6
|
|
7
7
|
# @override patched to adapt jdbc configuration
|
8
|
-
def each_current_configuration(environment)
|
8
|
+
def each_current_configuration(environment, spec_name = nil)
|
9
9
|
environments = [environment]
|
10
10
|
environments << 'test' if environment == 'development'
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
|
12
|
+
environments.each do |env|
|
13
|
+
ActiveRecord::Base.configurations.configs_for(env_name: env).each do |db_config|
|
14
|
+
next if spec_name && spec_name != db_config.spec_name
|
15
|
+
|
16
|
+
yield adapt_jdbc_config(db_config.config), db_config.spec_name, env unless db_config.config['database'].blank?
|
17
|
+
end
|
15
18
|
end
|
16
19
|
end
|
17
20
|
|
18
21
|
# @override patched to adapt jdbc configuration
|
19
22
|
def each_local_configuration
|
20
|
-
ActiveRecord::Base.configurations.
|
21
|
-
next unless config['database']
|
23
|
+
ActiveRecord::Base.configurations.configs_for.each do |db_config|
|
24
|
+
next unless db_config.config['database']
|
22
25
|
|
23
|
-
if local_database?(config)
|
24
|
-
yield adapt_jdbc_config(config)
|
26
|
+
if local_database?(db_config.config)
|
27
|
+
yield adapt_jdbc_config(db_config.config)
|
25
28
|
else
|
26
|
-
$stderr.puts "This task only modifies local databases. #{config['database']} is on a remote host."
|
29
|
+
$stderr.puts "This task only modifies local databases. #{db_config.config['database']} is on a remote host."
|
27
30
|
end
|
28
31
|
end
|
29
32
|
end
|
@@ -45,4 +48,4 @@ module ActiveRecord::Tasks
|
|
45
48
|
|
46
49
|
end if const_defined?(:MySQLDatabaseTasks)
|
47
50
|
|
48
|
-
end
|
51
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ArJdbc
|
2
4
|
module Util
|
3
5
|
# Gets included into `ActiveRecord::Base` to support sending LOB values
|
@@ -95,4 +97,4 @@ module ArJdbc
|
|
95
97
|
end
|
96
98
|
# @private only due backwards compatibility
|
97
99
|
SerializedAttributesHelper = Util::SerializedAttributes
|
98
|
-
end
|
100
|
+
end
|
data/lib/arjdbc/version.rb
CHANGED
data/pom.xml
CHANGED
@@ -12,7 +12,7 @@
|
|
12
12
|
<url>http://github.com/jruby/activerecord-jdbc-adapter/wiki</url>
|
13
13
|
|
14
14
|
<properties>
|
15
|
-
<jruby.version>9.
|
15
|
+
<jruby.version>9.2.6.0</jruby.version>
|
16
16
|
</properties>
|
17
17
|
|
18
18
|
<issueManagement>
|
@@ -75,7 +75,7 @@
|
|
75
75
|
<dependency>
|
76
76
|
<groupId>org.postgresql</groupId>
|
77
77
|
<artifactId>postgresql</artifactId>
|
78
|
-
<version>42.1.4
|
78
|
+
<version>42.1.4</version>
|
79
79
|
</dependency>
|
80
80
|
</dependencies>
|
81
81
|
|
@@ -103,8 +103,8 @@
|
|
103
103
|
<artifactId>maven-compiler-plugin</artifactId>
|
104
104
|
<version>2.5.1</version>
|
105
105
|
<configuration>
|
106
|
-
<source>1.
|
107
|
-
<target>1.
|
106
|
+
<source>1.8</source>
|
107
|
+
<target>1.8</target>
|
108
108
|
</configuration>
|
109
109
|
</plugin>
|
110
110
|
</plugins>
|
data/rakelib/01-tomcat.rake
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
namespace :'tomcat-jndi' do # contains a FS JNDI impl (for tests)
|
2
2
|
|
3
|
-
TOMCAT_MAVEN_REPO = '
|
3
|
+
TOMCAT_MAVEN_REPO = 'http://repo2.maven.org/maven2/org/apache/tomcat'
|
4
4
|
TOMCAT_VERSION = '7.0.54'
|
5
5
|
|
6
6
|
DOWNLOAD_DIR = File.expand_path('../test/jars', File.dirname(__FILE__))
|
@@ -48,4 +48,4 @@ namespace :'tomcat-jndi' do # contains a FS JNDI impl (for tests)
|
|
48
48
|
rm jar_path if File.exist?(jar_path)
|
49
49
|
end
|
50
50
|
|
51
|
-
end
|
51
|
+
end
|
data/rakelib/rails.rake
CHANGED
@@ -51,7 +51,7 @@ namespace :rails do
|
|
51
51
|
ruby_opts_string += " -C \"#{ar_path}\""
|
52
52
|
ruby_opts_string += " -rbundler/setup"
|
53
53
|
ruby_opts_string += " -rminitest -rminitest/excludes" unless ENV['NO_EXCLUDES'].eql?('true')
|
54
|
-
file_list = ENV["TEST"] ? FileList[ ENV["TEST"]
|
54
|
+
file_list = ENV["TEST"] ? FileList[ ENV["TEST"] ] : test_files_finder.call
|
55
55
|
file_list_string = file_list.map { |fn| "\"#{fn}\"" }.join(' ')
|
56
56
|
# test_loader_code = "-e \"ARGV.each{|f| require f}\"" # :direct
|
57
57
|
option_list = ( ENV["TESTOPTS"] || ENV["TESTOPT"] || ENV["TEST_OPTS"] || '' )
|
@@ -151,7 +151,7 @@ public class ArJdbcModule {
|
|
151
151
|
throw newNativeException(runtime, e);
|
152
152
|
}
|
153
153
|
|
154
|
-
return
|
154
|
+
return context.tru;
|
155
155
|
}
|
156
156
|
|
157
157
|
/**
|
@@ -191,7 +191,7 @@ public class ArJdbcModule {
|
|
191
191
|
}
|
192
192
|
|
193
193
|
// NOTE: probably useless - only to be useful for the pooled runtime mode when jar at WEB-INF/lib
|
194
|
-
static final Map<Ruby, Map<String, Boolean>> loadedDrivers = new WeakHashMap
|
194
|
+
static final Map<Ruby, Map<String, Boolean>> loadedDrivers = new WeakHashMap<>(8);
|
195
195
|
|
196
196
|
private static IRubyObject loadDriver(final ThreadContext context, final IRubyObject self,
|
197
197
|
final String constName) {
|
@@ -202,7 +202,7 @@ public class ArJdbcModule {
|
|
202
202
|
synchronized (ArJdbcModule.class) {
|
203
203
|
loadedMap = loadedDrivers.get(runtime);
|
204
204
|
if ( loadedMap == null ) {
|
205
|
-
loadedMap = new HashMap
|
205
|
+
loadedMap = new HashMap<>(4);
|
206
206
|
loadedDrivers.put(runtime, loadedMap);
|
207
207
|
}
|
208
208
|
}
|
@@ -210,8 +210,8 @@ public class ArJdbcModule {
|
|
210
210
|
|
211
211
|
final Boolean driverLoaded = loadedMap.get(constName);
|
212
212
|
if ( driverLoaded != null ) {
|
213
|
-
if (
|
214
|
-
return
|
213
|
+
if (driverLoaded) return context.fals;
|
214
|
+
return context.nil;
|
215
215
|
}
|
216
216
|
|
217
217
|
try { // require 'jdbc/mysql'
|
@@ -60,15 +60,7 @@ public class DriverWrapper {
|
|
60
60
|
|
61
61
|
private Driver allocateDriver(final Class<? extends Driver> driverClass)
|
62
62
|
throws InstantiationException, IllegalAccessException {
|
63
|
-
|
64
|
-
return driverClass.newInstance();
|
65
|
-
}
|
66
|
-
catch (InstantiationException e) {
|
67
|
-
throw e;
|
68
|
-
}
|
69
|
-
catch (IllegalAccessException e) {
|
70
|
-
throw e;
|
71
|
-
}
|
63
|
+
return driverClass.newInstance();
|
72
64
|
}
|
73
65
|
|
74
66
|
protected static Class<? extends Driver> loadDriver(final Ruby runtime, final String name)
|
@@ -73,7 +73,6 @@ import org.jruby.RubyBoolean;
|
|
73
73
|
import org.jruby.RubyClass;
|
74
74
|
import org.jruby.RubyException;
|
75
75
|
import org.jruby.RubyFixnum;
|
76
|
-
import org.jruby.RubyFloat;
|
77
76
|
import org.jruby.RubyHash;
|
78
77
|
import org.jruby.RubyIO;
|
79
78
|
import org.jruby.RubyInteger;
|
@@ -86,6 +85,7 @@ import org.jruby.RubyTime;
|
|
86
85
|
import org.jruby.anno.JRubyMethod;
|
87
86
|
import org.jruby.exceptions.RaiseException;
|
88
87
|
import org.jruby.ext.bigdecimal.RubyBigDecimal;
|
88
|
+
import org.jruby.ext.date.RubyDate;
|
89
89
|
import org.jruby.javasupport.JavaEmbedUtils;
|
90
90
|
import org.jruby.javasupport.JavaUtil;
|
91
91
|
import org.jruby.runtime.Block;
|
@@ -147,11 +147,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
147
147
|
return JdbcConnection;
|
148
148
|
}
|
149
149
|
|
150
|
-
@Deprecated
|
151
|
-
public static RubyClass getJdbcConnectionClass(final Ruby runtime) {
|
152
|
-
return getConnectionAdapters(runtime).getClass("JdbcConnection");
|
153
|
-
}
|
154
|
-
|
155
150
|
public static RubyClass getJdbcConnection(final Ruby runtime) {
|
156
151
|
return (RubyClass) getConnectionAdapters(runtime).getConstantAt("JdbcConnection");
|
157
152
|
}
|
@@ -231,34 +226,30 @@ public class RubyJdbcConnection extends RubyObject {
|
|
231
226
|
|
232
227
|
@JRubyMethod(name = "transaction_isolation", alias = "get_transaction_isolation")
|
233
228
|
public IRubyObject get_transaction_isolation(final ThreadContext context) {
|
234
|
-
return withConnection(context,
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
return context.runtime.newSymbol(isolationSymbol);
|
240
|
-
}
|
229
|
+
return withConnection(context, connection -> {
|
230
|
+
final int level = connection.getTransactionIsolation();
|
231
|
+
final String isolationSymbol = formatTransactionIsolationLevel(level);
|
232
|
+
if ( isolationSymbol == null ) return context.nil;
|
233
|
+
return context.runtime.newSymbol(isolationSymbol);
|
241
234
|
});
|
242
235
|
}
|
243
236
|
|
244
237
|
@JRubyMethod(name = "transaction_isolation=", alias = "set_transaction_isolation")
|
245
238
|
public IRubyObject set_transaction_isolation(final ThreadContext context, final IRubyObject isolation) {
|
246
|
-
return withConnection(context,
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
}
|
239
|
+
return withConnection(context, connection -> {
|
240
|
+
final int level;
|
241
|
+
if ( isolation.isNil() ) {
|
242
|
+
level = connection.getMetaData().getDefaultTransactionIsolation();
|
243
|
+
}
|
244
|
+
else {
|
245
|
+
level = mapTransactionIsolationLevel(isolation);
|
246
|
+
}
|
255
247
|
|
256
|
-
|
248
|
+
connection.setTransactionIsolation(level);
|
257
249
|
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
}
|
250
|
+
final String isolationSymbol = formatTransactionIsolationLevel(level);
|
251
|
+
if ( isolationSymbol == null ) return context.nil;
|
252
|
+
return context.runtime.newSymbol(isolationSymbol);
|
262
253
|
});
|
263
254
|
}
|
264
255
|
|
@@ -306,31 +297,25 @@ public class RubyJdbcConnection extends RubyObject {
|
|
306
297
|
final IRubyObject[] args) throws SQLException {
|
307
298
|
final IRubyObject isolation = args.length > 0 ? args[0] : null;
|
308
299
|
|
309
|
-
return withConnection(context,
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
supported = level > Connection.TRANSACTION_NONE; // > 0
|
320
|
-
}
|
321
|
-
return context.runtime.newBoolean(supported);
|
300
|
+
return withConnection(context, (Callable<IRubyObject>) connection -> {
|
301
|
+
final DatabaseMetaData metaData = connection.getMetaData();
|
302
|
+
final boolean supported;
|
303
|
+
if ( isolation != null && ! isolation.isNil() ) {
|
304
|
+
final int level = mapTransactionIsolationLevel(isolation);
|
305
|
+
supported = metaData.supportsTransactionIsolationLevel(level);
|
306
|
+
}
|
307
|
+
else {
|
308
|
+
final int level = metaData.getDefaultTransactionIsolation();
|
309
|
+
supported = level > Connection.TRANSACTION_NONE; // > 0
|
322
310
|
}
|
311
|
+
return context.runtime.newBoolean(supported);
|
323
312
|
});
|
324
313
|
}
|
325
314
|
|
326
315
|
@JRubyMethod(name = {"begin", "transaction"}, required = 1) // optional isolation argument for AR-4.0
|
327
316
|
public IRubyObject begin(final ThreadContext context, final IRubyObject isolation) {
|
328
317
|
try { // handleException == false so we can handle setTXIsolation
|
329
|
-
return withConnection(context, false,
|
330
|
-
public IRubyObject call(final Connection connection) throws SQLException {
|
331
|
-
return beginTransaction(context, connection, isolation == context.nil ? null : isolation);
|
332
|
-
}
|
333
|
-
});
|
318
|
+
return withConnection(context, false, connection -> beginTransaction(context, connection, isolation == context.nil ? null : isolation));
|
334
319
|
} catch (SQLException e) {
|
335
320
|
return handleException(context, e);
|
336
321
|
}
|
@@ -339,11 +324,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
339
324
|
@JRubyMethod(name = {"begin", "transaction"}) // optional isolation argument for AR-4.0
|
340
325
|
public IRubyObject begin(final ThreadContext context) {
|
341
326
|
try { // handleException == false so we can handle setTXIsolation
|
342
|
-
return withConnection(context, false,
|
343
|
-
public IRubyObject call(final Connection connection) throws SQLException {
|
344
|
-
return beginTransaction(context, connection, null);
|
345
|
-
}
|
346
|
-
});
|
327
|
+
return withConnection(context, false, connection -> beginTransaction(context, connection, null));
|
347
328
|
} catch (SQLException e) {
|
348
329
|
return handleException(context, e);
|
349
330
|
}
|
@@ -373,8 +354,8 @@ public class RubyJdbcConnection extends RubyObject {
|
|
373
354
|
|
374
355
|
@JRubyMethod(name = "commit")
|
375
356
|
public IRubyObject commit(final ThreadContext context) {
|
376
|
-
final Connection connection = getConnection(true);
|
377
357
|
try {
|
358
|
+
final Connection connection = getConnectionInternal(true);
|
378
359
|
if ( ! connection.getAutoCommit() ) {
|
379
360
|
try {
|
380
361
|
connection.commit();
|
@@ -394,13 +375,13 @@ public class RubyJdbcConnection extends RubyObject {
|
|
394
375
|
|
395
376
|
@JRubyMethod(name = "rollback")
|
396
377
|
public IRubyObject rollback(final ThreadContext context) {
|
397
|
-
final Connection connection = getConnection(true);
|
398
378
|
try {
|
379
|
+
final Connection connection = getConnectionInternal(true);
|
399
380
|
if ( ! connection.getAutoCommit() ) {
|
400
381
|
try {
|
401
382
|
connection.rollback();
|
402
383
|
resetSavepoints(context); // if any
|
403
|
-
return context.
|
384
|
+
return context.tru;
|
404
385
|
} finally {
|
405
386
|
connection.setAutoCommit(true);
|
406
387
|
}
|
@@ -414,11 +395,9 @@ public class RubyJdbcConnection extends RubyObject {
|
|
414
395
|
|
415
396
|
@JRubyMethod(name = "supports_savepoints?")
|
416
397
|
public IRubyObject supports_savepoints_p(final ThreadContext context) throws SQLException {
|
417
|
-
return withConnection(context,
|
418
|
-
|
419
|
-
|
420
|
-
return context.runtime.newBoolean( metaData.supportsSavepoints() );
|
421
|
-
}
|
398
|
+
return withConnection(context, (Callable<IRubyObject>) connection -> {
|
399
|
+
final DatabaseMetaData metaData = connection.getMetaData();
|
400
|
+
return context.runtime.newBoolean( metaData.supportsSavepoints() );
|
422
401
|
});
|
423
402
|
}
|
424
403
|
|
@@ -429,8 +408,8 @@ public class RubyJdbcConnection extends RubyObject {
|
|
429
408
|
|
430
409
|
@JRubyMethod(name = "create_savepoint", required = 1)
|
431
410
|
public IRubyObject create_savepoint(final ThreadContext context, IRubyObject name) {
|
432
|
-
final Connection connection = getConnection(true);
|
433
411
|
try {
|
412
|
+
final Connection connection = getConnectionInternal(true);
|
434
413
|
connection.setAutoCommit(false);
|
435
414
|
|
436
415
|
final Savepoint savepoint ;
|
@@ -458,8 +437,8 @@ public class RubyJdbcConnection extends RubyObject {
|
|
458
437
|
public IRubyObject rollback_savepoint(final ThreadContext context, final IRubyObject name) {
|
459
438
|
if (name == context.nil) throw context.runtime.newArgumentError("nil savepoint name given");
|
460
439
|
|
461
|
-
final Connection connection = getConnection(true);
|
462
440
|
try {
|
441
|
+
final Connection connection = getConnectionInternal(true);
|
463
442
|
Savepoint savepoint = getSavepoints(context).get(name);
|
464
443
|
if ( savepoint == null ) {
|
465
444
|
throw context.runtime.newRuntimeError("could not rollback savepoint: '" + name + "' (not set)");
|
@@ -476,7 +455,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
476
455
|
public IRubyObject release_savepoint(final ThreadContext context, final IRubyObject name) {
|
477
456
|
if (name == context.nil) throw context.runtime.newArgumentError("nil savepoint name given");
|
478
457
|
|
479
|
-
final Connection connection = getConnection(true);
|
480
458
|
try {
|
481
459
|
Object savepoint = getSavepoints(context).remove(name);
|
482
460
|
|
@@ -487,6 +465,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
487
465
|
savepoint = ((IRubyObject) savepoint).toJava(Savepoint.class);
|
488
466
|
}
|
489
467
|
|
468
|
+
final Connection connection = getConnectionInternal(true);
|
490
469
|
releaseSavepoint(connection, (Savepoint) savepoint);
|
491
470
|
return context.nil;
|
492
471
|
}
|
@@ -525,7 +504,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
525
504
|
}
|
526
505
|
|
527
506
|
@SuppressWarnings("unchecked")
|
528
|
-
private
|
507
|
+
private Map<IRubyObject, Savepoint> getSavepoints(final boolean init) {
|
529
508
|
if ( hasInternalVariable("savepoints") ) {
|
530
509
|
return (Map<IRubyObject, Savepoint>) getInternalVariable("savepoints");
|
531
510
|
}
|
@@ -545,13 +524,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
545
524
|
return false;
|
546
525
|
}
|
547
526
|
|
548
|
-
@Deprecated // second argument is now mandatory - only kept for compatibility
|
549
|
-
@JRubyMethod(required = 1)
|
550
|
-
public final IRubyObject initialize(final ThreadContext context, final IRubyObject config) {
|
551
|
-
doInitialize(context, config, context.nil);
|
552
|
-
return this;
|
553
|
-
}
|
554
|
-
|
555
527
|
@JRubyMethod(required = 2)
|
556
528
|
public final IRubyObject initialize(final ThreadContext context, final IRubyObject config, final IRubyObject adapter) {
|
557
529
|
doInitialize(context, config, adapter);
|
@@ -559,12 +531,17 @@ public class RubyJdbcConnection extends RubyObject {
|
|
559
531
|
}
|
560
532
|
|
561
533
|
protected void doInitialize(final ThreadContext context, final IRubyObject config, final IRubyObject adapter) {
|
562
|
-
this.config = config;
|
534
|
+
this.config = config;
|
535
|
+
this.adapter = adapter;
|
563
536
|
|
564
537
|
this.jndi = setupConnectionFactory(context);
|
565
538
|
this.lazy = jndi; // JNDIs are lazy by default otherwise eager
|
566
539
|
try {
|
567
|
-
|
540
|
+
if (adapter == null || adapter == context.nil) {
|
541
|
+
warn(context, "adapter not set, please pass adapter on JdbcConnection#initialize(config, adapter)");
|
542
|
+
}
|
543
|
+
|
544
|
+
if (!lazy) setConnection(newConnection());
|
568
545
|
}
|
569
546
|
catch (SQLException e) {
|
570
547
|
String message = e.getMessage();
|
@@ -575,7 +552,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
575
552
|
IRubyObject value = getConfigValue(context, "configure_connection");
|
576
553
|
if ( value == context.nil ) this.configureConnection = true;
|
577
554
|
else {
|
578
|
-
this.configureConnection = value != context.
|
555
|
+
this.configureConnection = value != context.fals;
|
579
556
|
}
|
580
557
|
|
581
558
|
IRubyObject jdbcFetchSize = getConfigValue(context, "jdbc_fetch_size");
|
@@ -586,7 +563,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
586
563
|
|
587
564
|
@JRubyMethod(name = "adapter")
|
588
565
|
public IRubyObject adapter(final ThreadContext context) {
|
589
|
-
final IRubyObject adapter = getAdapter();
|
590
566
|
return adapter == null ? context.nil : adapter;
|
591
567
|
}
|
592
568
|
|
@@ -601,43 +577,9 @@ public class RubyJdbcConnection extends RubyObject {
|
|
601
577
|
return factory;
|
602
578
|
}
|
603
579
|
|
604
|
-
/**
|
605
|
-
* Called during <code>initialize</code> after the connection factory
|
606
|
-
* has been set to check if we can connect and/or perform any initialization
|
607
|
-
* necessary.
|
608
|
-
* <br/>
|
609
|
-
* NOTE: connection has not been configured at this point,
|
610
|
-
* nor should we retry - we're creating a brand new JDBC connection
|
611
|
-
*
|
612
|
-
* @param context
|
613
|
-
* @return connection
|
614
|
-
*/
|
615
|
-
@Deprecated
|
616
|
-
@JRubyMethod(name = "init_connection")
|
617
|
-
public synchronized IRubyObject init_connection(final ThreadContext context) {
|
618
|
-
try {
|
619
|
-
return initConnection(context);
|
620
|
-
}
|
621
|
-
catch (SQLException e) {
|
622
|
-
return handleException(context, e); // throws
|
623
|
-
}
|
624
|
-
}
|
625
|
-
|
626
|
-
private IRubyObject initConnection(final ThreadContext context) throws SQLException {
|
627
|
-
final IRubyObject adapter = getAdapter(); // self.adapter
|
628
|
-
if ( adapter == null || adapter == context.nil ) {
|
629
|
-
warn(context, "adapter not set, please pass adapter on JdbcConnection#initialize(config, adapter)");
|
630
|
-
}
|
631
|
-
|
632
|
-
if ( ! lazy ) setConnection( newConnection() );
|
633
|
-
|
634
|
-
return context.nil;
|
635
|
-
}
|
636
|
-
|
637
580
|
private void configureConnection() {
|
638
581
|
if ( ! configureConnection ) return; // return false;
|
639
582
|
|
640
|
-
final IRubyObject adapter = getAdapter(); // self.adapter
|
641
583
|
if ( adapter != null && ! adapter.isNil() ) {
|
642
584
|
if ( adapter.respondsTo("configure_connection") ) {
|
643
585
|
final ThreadContext context = getRuntime().getCurrentContext();
|
@@ -659,7 +601,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
659
601
|
|
660
602
|
@JRubyMethod(name = "jdbc_connection", alias = "connection", required = 1)
|
661
603
|
public final IRubyObject connection(final ThreadContext context, final IRubyObject unwrap) {
|
662
|
-
if ( unwrap == context.nil || unwrap == context.
|
604
|
+
if ( unwrap == context.nil || unwrap == context.fals ) {
|
663
605
|
return connection(context);
|
664
606
|
}
|
665
607
|
Connection connection = connectionImpl(context);
|
@@ -695,18 +637,25 @@ public class RubyJdbcConnection extends RubyObject {
|
|
695
637
|
|
696
638
|
@JRubyMethod(name = "active?", alias = "valid?")
|
697
639
|
public RubyBoolean active_p(final ThreadContext context) {
|
698
|
-
if ( ! connected ) return context.
|
699
|
-
if (
|
640
|
+
if ( ! connected ) return context.fals;
|
641
|
+
if (jndi) {
|
700
642
|
// for JNDI the data-source / pool is supposed to
|
701
643
|
// manage connections for us thus no valid check!
|
702
644
|
boolean active = getConnectionFactory() != null;
|
703
645
|
return context.runtime.newBoolean( active );
|
704
646
|
}
|
705
|
-
final Connection connection = getConnection();
|
706
|
-
if ( connection == null ) return context.
|
647
|
+
final Connection connection = getConnection(false);
|
648
|
+
if ( connection == null ) return context.fals; // unlikely
|
707
649
|
return context.runtime.newBoolean( isConnectionValid(context, connection) );
|
708
650
|
}
|
709
651
|
|
652
|
+
@JRubyMethod(name = "really_valid?")
|
653
|
+
public RubyBoolean really_valid_p(final ThreadContext context) {
|
654
|
+
final Connection connection = getConnection(true);
|
655
|
+
if (connection == null) return context.fals;
|
656
|
+
return context.runtime.newBoolean(isConnectionValid(context, connection));
|
657
|
+
}
|
658
|
+
|
710
659
|
@JRubyMethod(name = "disconnect!")
|
711
660
|
public synchronized IRubyObject disconnect(final ThreadContext context) {
|
712
661
|
setConnection(null); connected = false;
|
@@ -727,41 +676,40 @@ public class RubyJdbcConnection extends RubyObject {
|
|
727
676
|
|
728
677
|
private void connectImpl(final boolean forceConnection) throws SQLException {
|
729
678
|
setConnection( forceConnection ? newConnection() : null );
|
730
|
-
if (forceConnection)
|
731
|
-
if (getConnectionImpl() == null) throw new SQLException("Didn't get a connection. Wrong URL?");
|
732
|
-
configureConnection();
|
733
|
-
}
|
679
|
+
if ( forceConnection ) configureConnection();
|
734
680
|
}
|
735
681
|
|
736
682
|
@JRubyMethod(name = "read_only?")
|
737
683
|
public IRubyObject is_read_only(final ThreadContext context) {
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
return context.runtime.newBoolean(
|
684
|
+
try {
|
685
|
+
final Connection connection = getConnectionInternal(false);
|
686
|
+
if (connection != null) {
|
687
|
+
return context.runtime.newBoolean(connection.isReadOnly());
|
742
688
|
}
|
743
|
-
|
689
|
+
} catch (SQLException e) {
|
690
|
+
return handleException(context, e);
|
744
691
|
}
|
745
692
|
return context.nil;
|
746
693
|
}
|
747
694
|
|
748
695
|
@JRubyMethod(name = "read_only=")
|
749
696
|
public IRubyObject set_read_only(final ThreadContext context, final IRubyObject flag) {
|
750
|
-
final Connection connection = getConnection(true);
|
751
697
|
try {
|
698
|
+
final Connection connection = getConnectionInternal(true);
|
752
699
|
connection.setReadOnly( flag.isTrue() );
|
753
700
|
return context.runtime.newBoolean( connection.isReadOnly() );
|
701
|
+
} catch (SQLException e) {
|
702
|
+
return handleException(context, e);
|
754
703
|
}
|
755
|
-
catch (SQLException e) { return handleException(context, e); }
|
756
704
|
}
|
757
705
|
|
758
706
|
@JRubyMethod(name = { "open?" /* "conn?" */ })
|
759
707
|
public IRubyObject open_p(final ThreadContext context) {
|
760
|
-
|
708
|
+
try {
|
709
|
+
final Connection connection = getConnectionInternal(false);
|
761
710
|
|
762
|
-
|
711
|
+
if (connection == null) return context.fals;
|
763
712
|
|
764
|
-
try {
|
765
713
|
// NOTE: isClosed method generally cannot be called to determine
|
766
714
|
// whether a connection to a database is valid or invalid ...
|
767
715
|
return context.runtime.newBoolean(!connection.isClosed());
|
@@ -774,10 +722,10 @@ public class RubyJdbcConnection extends RubyObject {
|
|
774
722
|
public IRubyObject close(final ThreadContext context) {
|
775
723
|
final Connection connection = getConnection(false);
|
776
724
|
|
777
|
-
if (connection == null) return context.
|
725
|
+
if (connection == null) return context.fals;
|
778
726
|
|
779
727
|
try {
|
780
|
-
if (connection.isClosed()) return context.
|
728
|
+
if (connection.isClosed()) return context.fals;
|
781
729
|
|
782
730
|
setConnection(null); // does connection.close();
|
783
731
|
} catch (Exception e) {
|
@@ -787,69 +735,65 @@ public class RubyJdbcConnection extends RubyObject {
|
|
787
735
|
|
788
736
|
// ActiveRecord expects a closed connection to not try and re-open a connection
|
789
737
|
// whereas JNDI expects that.
|
790
|
-
if (!
|
738
|
+
if (!jndi) disconnect(context);
|
791
739
|
|
792
|
-
return context.
|
740
|
+
return context.tru;
|
793
741
|
}
|
794
742
|
|
795
743
|
@JRubyMethod(name = "database_name")
|
796
744
|
public IRubyObject database_name(final ThreadContext context) {
|
797
|
-
return withConnection(context,
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
if ( name == null ) return context.nil;
|
803
|
-
}
|
804
|
-
return context.runtime.newString(name);
|
745
|
+
return withConnection(context, connection -> {
|
746
|
+
String name = connection.getCatalog();
|
747
|
+
if ( name == null ) {
|
748
|
+
name = connection.getMetaData().getUserName();
|
749
|
+
if ( name == null ) return context.nil;
|
805
750
|
}
|
751
|
+
return context.runtime.newString(name);
|
806
752
|
});
|
807
753
|
}
|
808
754
|
|
809
755
|
@JRubyMethod(name = "execute", required = 1)
|
810
756
|
public IRubyObject execute(final ThreadContext context, final IRubyObject sql) {
|
811
757
|
final String query = sqlString(sql);
|
812
|
-
return withConnection(context,
|
813
|
-
|
814
|
-
|
815
|
-
|
816
|
-
statement = createStatement(context, connection);
|
817
|
-
|
818
|
-
// For DBs that do support multiple statements, lets return the last result set
|
819
|
-
// to be consistent with AR
|
820
|
-
boolean hasResultSet = doExecute(statement, query);
|
821
|
-
int updateCount = statement.getUpdateCount();
|
758
|
+
return withConnection(context, connection -> {
|
759
|
+
Statement statement = null;
|
760
|
+
try {
|
761
|
+
statement = createStatement(context, connection);
|
822
762
|
|
823
|
-
|
824
|
-
|
763
|
+
// For DBs that do support multiple statements, lets return the last result set
|
764
|
+
// to be consistent with AR
|
765
|
+
boolean hasResultSet = doExecute(statement, query);
|
766
|
+
int updateCount = statement.getUpdateCount();
|
825
767
|
|
826
|
-
|
768
|
+
IRubyObject result = context.nil; // If no results, return nil
|
769
|
+
ResultSet resultSet;
|
827
770
|
|
828
|
-
|
829
|
-
resultSet = statement.getResultSet();
|
771
|
+
while (hasResultSet || updateCount != -1) {
|
830
772
|
|
831
|
-
|
832
|
-
|
833
|
-
// this shouldn't be an issue in most cases since we're only getting 1 result set anyways
|
834
|
-
result = mapExecuteResult(context, connection, resultSet);
|
835
|
-
resultSet.close();
|
836
|
-
} else {
|
837
|
-
result = context.runtime.newFixnum(updateCount);
|
838
|
-
}
|
773
|
+
if (hasResultSet) {
|
774
|
+
resultSet = statement.getResultSet();
|
839
775
|
|
840
|
-
//
|
841
|
-
|
842
|
-
|
776
|
+
// Unfortunately the result set gets closed when getMoreResults()
|
777
|
+
// is called, so we have to process the result sets as we get them
|
778
|
+
// this shouldn't be an issue in most cases since we're only getting 1 result set anyways
|
779
|
+
result = mapExecuteResult(context, connection, resultSet);
|
780
|
+
resultSet.close();
|
781
|
+
} else {
|
782
|
+
result = context.runtime.newFixnum(updateCount);
|
843
783
|
}
|
844
784
|
|
845
|
-
|
846
|
-
|
847
|
-
|
848
|
-
debugErrorSQL(context, query);
|
849
|
-
throw e;
|
850
|
-
} finally {
|
851
|
-
close(statement);
|
785
|
+
// Check to see if there is another result set
|
786
|
+
hasResultSet = statement.getMoreResults();
|
787
|
+
updateCount = statement.getUpdateCount();
|
852
788
|
}
|
789
|
+
|
790
|
+
return result;
|
791
|
+
|
792
|
+
} catch (final SQLException e) {
|
793
|
+
debugErrorSQL(context, query);
|
794
|
+
throw e;
|
795
|
+
} finally {
|
796
|
+
close(statement);
|
853
797
|
}
|
854
798
|
});
|
855
799
|
}
|
@@ -888,106 +832,62 @@ public class RubyJdbcConnection extends RubyObject {
|
|
888
832
|
return mapQueryResult(context, connection, resultSet);
|
889
833
|
}
|
890
834
|
|
891
|
-
private static String[] createStatementPk(IRubyObject pk) {
|
892
|
-
String[] statementPk;
|
893
|
-
if (pk instanceof RubyArray) {
|
894
|
-
RubyArray ary = (RubyArray) pk;
|
895
|
-
int size = ary.size();
|
896
|
-
statementPk = new String[size];
|
897
|
-
for (int i = 0; i < size; i++) {
|
898
|
-
statementPk[i] = sqlString(ary.eltInternal(i));
|
899
|
-
}
|
900
|
-
} else {
|
901
|
-
statementPk = new String[] { sqlString(pk) };
|
902
|
-
}
|
903
|
-
return statementPk;
|
904
|
-
}
|
905
|
-
|
906
835
|
/**
|
907
836
|
* Executes an INSERT SQL statement
|
908
837
|
* @param context
|
909
838
|
* @param sql
|
910
|
-
* @param pk Rails PK
|
911
839
|
* @return ActiveRecord::Result
|
912
840
|
* @throws SQLException
|
913
841
|
*/
|
914
|
-
@JRubyMethod(name = "
|
915
|
-
public IRubyObject
|
916
|
-
return withConnection(context,
|
917
|
-
|
918
|
-
|
919
|
-
|
920
|
-
try {
|
921
|
-
|
922
|
-
statement = createStatement(context, connection);
|
923
|
-
|
924
|
-
if (pk == context.nil || pk == context.fals || !supportsGeneratedKeys(connection)) {
|
925
|
-
statement.executeUpdate(query, Statement.RETURN_GENERATED_KEYS);
|
926
|
-
} else {
|
927
|
-
statement.executeUpdate(query, createStatementPk(pk));
|
928
|
-
}
|
842
|
+
@JRubyMethod(name = "execute_insert", required = 1)
|
843
|
+
public IRubyObject execute_insert(final ThreadContext context, final IRubyObject sql) {
|
844
|
+
return withConnection(context, connection -> {
|
845
|
+
Statement statement = null;
|
846
|
+
final String query = sqlString(sql);
|
847
|
+
try {
|
929
848
|
|
930
|
-
|
849
|
+
statement = createStatement(context, connection);
|
850
|
+
statement.executeUpdate(query, Statement.RETURN_GENERATED_KEYS);
|
851
|
+
return mapGeneratedKeys(context, connection, statement);
|
931
852
|
|
932
|
-
|
933
|
-
|
934
|
-
|
935
|
-
|
936
|
-
|
937
|
-
}
|
853
|
+
} catch (final SQLException e) {
|
854
|
+
debugErrorSQL(context, query);
|
855
|
+
throw e;
|
856
|
+
} finally {
|
857
|
+
close(statement);
|
938
858
|
}
|
939
859
|
});
|
940
860
|
}
|
941
861
|
|
942
|
-
@Deprecated
|
943
|
-
@JRubyMethod(name = "execute_insert", required = 1)
|
944
|
-
public IRubyObject execute_insert(final ThreadContext context, final IRubyObject sql) {
|
945
|
-
return execute_insert_pk(context, sql, context.nil);
|
946
|
-
}
|
947
|
-
|
948
862
|
/**
|
949
863
|
* Executes an INSERT SQL statement using a prepared statement
|
950
864
|
* @param context
|
951
865
|
* @param sql
|
952
866
|
* @param binds RubyArray of values to be bound to the query
|
953
|
-
* @param pk Rails PK
|
954
867
|
* @return ActiveRecord::Result
|
955
868
|
* @throws SQLException
|
956
869
|
*/
|
957
|
-
@JRubyMethod(name = "
|
958
|
-
public IRubyObject
|
959
|
-
|
960
|
-
|
961
|
-
|
962
|
-
|
963
|
-
final String query = sqlString(sql);
|
964
|
-
try {
|
965
|
-
if (pk == context.nil || pk == context.fals || !supportsGeneratedKeys(connection)) {
|
966
|
-
statement = connection.prepareStatement(query, Statement.RETURN_GENERATED_KEYS);
|
967
|
-
} else {
|
968
|
-
statement = connection.prepareStatement(query, createStatementPk(pk));
|
969
|
-
}
|
870
|
+
@JRubyMethod(name = "execute_insert", required = 2)
|
871
|
+
public IRubyObject execute_insert(final ThreadContext context, final IRubyObject sql, final IRubyObject binds) {
|
872
|
+
return withConnection(context, connection -> {
|
873
|
+
PreparedStatement statement = null;
|
874
|
+
final String query = sqlString(sql);
|
875
|
+
try {
|
970
876
|
|
971
|
-
|
972
|
-
|
973
|
-
|
877
|
+
statement = connection.prepareStatement(query, Statement.RETURN_GENERATED_KEYS);
|
878
|
+
setStatementParameters(context, connection, statement, (RubyArray) binds);
|
879
|
+
statement.executeUpdate();
|
880
|
+
return mapGeneratedKeys(context, connection, statement);
|
974
881
|
|
975
|
-
|
976
|
-
|
977
|
-
|
978
|
-
|
979
|
-
|
980
|
-
}
|
882
|
+
} catch (final SQLException e) {
|
883
|
+
debugErrorSQL(context, query);
|
884
|
+
throw e;
|
885
|
+
} finally {
|
886
|
+
close(statement);
|
981
887
|
}
|
982
888
|
});
|
983
889
|
}
|
984
890
|
|
985
|
-
@Deprecated
|
986
|
-
@JRubyMethod(name = "execute_insert", required = 2)
|
987
|
-
public IRubyObject execute_insert(final ThreadContext context, final IRubyObject binds, final IRubyObject sql) {
|
988
|
-
return execute_insert_pk(context, sql, binds, context.nil);
|
989
|
-
}
|
990
|
-
|
991
891
|
/**
|
992
892
|
* Executes an UPDATE (DELETE) SQL statement
|
993
893
|
* @param context
|
@@ -997,22 +897,20 @@ public class RubyJdbcConnection extends RubyObject {
|
|
997
897
|
*/
|
998
898
|
@JRubyMethod(name = {"execute_update", "execute_delete"}, required = 1)
|
999
899
|
public IRubyObject execute_update(final ThreadContext context, final IRubyObject sql) {
|
1000
|
-
return withConnection(context,
|
1001
|
-
|
1002
|
-
|
1003
|
-
final String query = sqlString(sql);
|
900
|
+
return withConnection(context, (Callable<IRubyObject>) connection -> {
|
901
|
+
Statement statement = null;
|
902
|
+
final String query = sqlString(sql);
|
1004
903
|
|
1005
|
-
|
1006
|
-
|
904
|
+
try {
|
905
|
+
statement = createStatement(context, connection);
|
1007
906
|
|
1008
|
-
|
1009
|
-
|
1010
|
-
|
1011
|
-
|
1012
|
-
|
1013
|
-
|
1014
|
-
|
1015
|
-
}
|
907
|
+
final int rowCount = statement.executeUpdate(query);
|
908
|
+
return context.runtime.newFixnum(rowCount);
|
909
|
+
} catch (final SQLException e) {
|
910
|
+
debugErrorSQL(context, query);
|
911
|
+
throw e;
|
912
|
+
} finally {
|
913
|
+
close(statement);
|
1016
914
|
}
|
1017
915
|
});
|
1018
916
|
}
|
@@ -1028,21 +926,19 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1028
926
|
*/
|
1029
927
|
@JRubyMethod(name = {"execute_prepared_update", "execute_prepared_delete"}, required = 2)
|
1030
928
|
public IRubyObject execute_prepared_update(final ThreadContext context, final IRubyObject sql, final IRubyObject binds) {
|
1031
|
-
return withConnection(context,
|
1032
|
-
|
1033
|
-
|
1034
|
-
|
1035
|
-
|
1036
|
-
|
1037
|
-
|
1038
|
-
|
1039
|
-
|
1040
|
-
|
1041
|
-
|
1042
|
-
|
1043
|
-
|
1044
|
-
close(statement);
|
1045
|
-
}
|
929
|
+
return withConnection(context, (Callable<IRubyObject>) connection -> {
|
930
|
+
PreparedStatement statement = null;
|
931
|
+
final String query = sqlString(sql);
|
932
|
+
try {
|
933
|
+
statement = connection.prepareStatement(query);
|
934
|
+
setStatementParameters(context, connection, statement, (RubyArray) binds);
|
935
|
+
final int rowCount = statement.executeUpdate();
|
936
|
+
return context.runtime.newFixnum(rowCount);
|
937
|
+
} catch (final SQLException e) {
|
938
|
+
debugErrorSQL(context, query);
|
939
|
+
throw e;
|
940
|
+
} finally {
|
941
|
+
close(statement);
|
1046
942
|
}
|
1047
943
|
});
|
1048
944
|
}
|
@@ -1089,50 +985,48 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1089
985
|
|
1090
986
|
private IRubyObject doExecuteQueryRaw(final ThreadContext context,
|
1091
987
|
final String query, final int maxRows, final Block block, final RubyArray binds) {
|
1092
|
-
return withConnection(context,
|
1093
|
-
|
1094
|
-
|
1095
|
-
|
1096
|
-
|
1097
|
-
|
1098
|
-
|
1099
|
-
|
1100
|
-
|
1101
|
-
|
1102
|
-
|
1103
|
-
|
1104
|
-
|
1105
|
-
|
1106
|
-
|
1107
|
-
|
1108
|
-
}
|
988
|
+
return withConnection(context, connection -> {
|
989
|
+
Statement statement = null; boolean hasResult;
|
990
|
+
try {
|
991
|
+
if ( binds == null || binds.isEmpty()) { // plain statement
|
992
|
+
statement = createStatement(context, connection);
|
993
|
+
statement.setMaxRows(maxRows); // zero means there is no limit
|
994
|
+
hasResult = statement.execute(query);
|
995
|
+
}
|
996
|
+
else {
|
997
|
+
final PreparedStatement prepStatement;
|
998
|
+
statement = prepStatement = connection.prepareStatement(query);
|
999
|
+
if (fetchSize != 0) statement.setFetchSize(fetchSize);
|
1000
|
+
statement.setMaxRows(maxRows); // zero means there is no limit
|
1001
|
+
setStatementParameters(context, connection, prepStatement, binds);
|
1002
|
+
hasResult = prepStatement.execute();
|
1003
|
+
}
|
1109
1004
|
|
1110
|
-
|
1111
|
-
if (hasResult) {
|
1112
|
-
// yield(id1, name1) ... row 1 result data
|
1113
|
-
// yield(id2, name2) ... row 2 result data
|
1114
|
-
return yieldResultRows(context, connection, statement.getResultSet(), block);
|
1115
|
-
}
|
1116
|
-
return context.nil;
|
1117
|
-
}
|
1005
|
+
if (block.isGiven()) {
|
1118
1006
|
if (hasResult) {
|
1119
|
-
|
1007
|
+
// yield(id1, name1) ... row 1 result data
|
1008
|
+
// yield(id2, name2) ... row 2 result data
|
1009
|
+
return yieldResultRows(context, connection, statement.getResultSet(), block);
|
1120
1010
|
}
|
1121
|
-
return context.
|
1011
|
+
return context.nil;
|
1122
1012
|
}
|
1123
|
-
|
1124
|
-
|
1125
|
-
throw e;
|
1126
|
-
}
|
1127
|
-
finally {
|
1128
|
-
close(statement);
|
1013
|
+
if (hasResult) {
|
1014
|
+
return mapToRawResult(context, connection, statement.getResultSet(), false);
|
1129
1015
|
}
|
1016
|
+
return context.runtime.newEmptyArray();
|
1017
|
+
}
|
1018
|
+
catch (final SQLException e) {
|
1019
|
+
debugErrorSQL(context, query);
|
1020
|
+
throw e;
|
1021
|
+
}
|
1022
|
+
finally {
|
1023
|
+
close(statement);
|
1130
1024
|
}
|
1131
1025
|
});
|
1132
1026
|
}
|
1133
1027
|
|
1134
1028
|
protected static String sqlString(final IRubyObject sql) {
|
1135
|
-
return sql
|
1029
|
+
return sql.convertToString().decodeString();
|
1136
1030
|
}
|
1137
1031
|
|
1138
1032
|
/**
|
@@ -1145,26 +1039,24 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1145
1039
|
*/
|
1146
1040
|
@JRubyMethod(required = 1)
|
1147
1041
|
public IRubyObject execute_query(final ThreadContext context, final IRubyObject sql) {
|
1148
|
-
return withConnection(context,
|
1149
|
-
|
1150
|
-
|
1151
|
-
|
1152
|
-
|
1153
|
-
statement = createStatement(context, connection);
|
1042
|
+
return withConnection(context, connection -> {
|
1043
|
+
Statement statement = null;
|
1044
|
+
final String query = sqlString(sql);
|
1045
|
+
try {
|
1046
|
+
statement = createStatement(context, connection);
|
1154
1047
|
|
1155
|
-
|
1156
|
-
|
1157
|
-
|
1158
|
-
|
1048
|
+
// At least until AR 5.1 #exec_query still gets called for things that don't return results in some cases :(
|
1049
|
+
if (statement.execute(query)) {
|
1050
|
+
return mapQueryResult(context, connection, statement.getResultSet());
|
1051
|
+
}
|
1159
1052
|
|
1160
|
-
|
1053
|
+
return newEmptyResult(context);
|
1161
1054
|
|
1162
|
-
|
1163
|
-
|
1164
|
-
|
1165
|
-
|
1166
|
-
|
1167
|
-
}
|
1055
|
+
} catch (final SQLException e) {
|
1056
|
+
debugErrorSQL(context, query);
|
1057
|
+
throw e;
|
1058
|
+
} finally {
|
1059
|
+
close(statement);
|
1168
1060
|
}
|
1169
1061
|
});
|
1170
1062
|
}
|
@@ -1177,13 +1069,11 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1177
1069
|
*/
|
1178
1070
|
@JRubyMethod(required = 1)
|
1179
1071
|
public IRubyObject prepare_statement(final ThreadContext context, final IRubyObject sql) {
|
1180
|
-
return withConnection(context,
|
1181
|
-
|
1182
|
-
|
1183
|
-
|
1184
|
-
|
1185
|
-
return JavaUtil.convertJavaToRuby(context.runtime, statement);
|
1186
|
-
}
|
1072
|
+
return withConnection(context, connection -> {
|
1073
|
+
final String query = sql.convertToString().getUnicodeValue();
|
1074
|
+
PreparedStatement statement = connection.prepareStatement(query);
|
1075
|
+
if (fetchSize != 0) statement.setFetchSize(fetchSize);
|
1076
|
+
return JavaUtil.convertJavaToRuby(context.runtime, statement);
|
1187
1077
|
});
|
1188
1078
|
}
|
1189
1079
|
|
@@ -1206,40 +1096,40 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1206
1096
|
@JRubyMethod(required = 3)
|
1207
1097
|
public IRubyObject execute_prepared_query(final ThreadContext context, final IRubyObject sql,
|
1208
1098
|
final IRubyObject binds, final IRubyObject cachedStatement) {
|
1209
|
-
return withConnection(context,
|
1210
|
-
|
1211
|
-
|
1212
|
-
|
1213
|
-
PreparedStatement statement = null;
|
1099
|
+
return withConnection(context, connection -> {
|
1100
|
+
final boolean cached = !(cachedStatement == null || cachedStatement.isNil());
|
1101
|
+
String query = null;
|
1102
|
+
PreparedStatement statement = null;
|
1214
1103
|
|
1215
|
-
|
1216
|
-
|
1217
|
-
|
1218
|
-
|
1219
|
-
|
1220
|
-
|
1221
|
-
|
1104
|
+
try {
|
1105
|
+
if (cached) {
|
1106
|
+
statement = (PreparedStatement) JavaEmbedUtils.rubyToJava(cachedStatement);
|
1107
|
+
} else {
|
1108
|
+
query = sql.convertToString().getUnicodeValue();
|
1109
|
+
statement = connection.prepareStatement(query);
|
1110
|
+
if (fetchSize != 0) statement.setFetchSize(fetchSize);
|
1111
|
+
}
|
1222
1112
|
|
1223
|
-
|
1113
|
+
setStatementParameters(context, connection, statement, (RubyArray) binds);
|
1224
1114
|
|
1225
|
-
|
1226
|
-
|
1227
|
-
|
1228
|
-
|
1115
|
+
if (statement.execute()) {
|
1116
|
+
ResultSet resultSet = statement.getResultSet();
|
1117
|
+
IRubyObject results = mapQueryResult(context, connection, resultSet);
|
1118
|
+
resultSet.close();
|
1229
1119
|
|
1230
|
-
|
1231
|
-
|
1232
|
-
|
1233
|
-
|
1234
|
-
|
1235
|
-
|
1236
|
-
|
1237
|
-
|
1238
|
-
|
1239
|
-
|
1240
|
-
|
1241
|
-
|
1242
|
-
|
1120
|
+
return results;
|
1121
|
+
} else {
|
1122
|
+
return newEmptyResult(context);
|
1123
|
+
}
|
1124
|
+
} catch (final SQLException e) {
|
1125
|
+
if (query == null) query = sql.convertToString().getUnicodeValue();
|
1126
|
+
debugErrorSQL(context, query);
|
1127
|
+
throw e;
|
1128
|
+
} finally {
|
1129
|
+
if ( cached ) {
|
1130
|
+
statement.clearParameters();
|
1131
|
+
} else {
|
1132
|
+
close(statement);
|
1243
1133
|
}
|
1244
1134
|
}
|
1245
1135
|
});
|
@@ -1251,35 +1141,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1251
1141
|
return mapToResult(context, connection, resultSet, columns);
|
1252
1142
|
}
|
1253
1143
|
|
1254
|
-
/**
|
1255
|
-
* @deprecated please do not use this method
|
1256
|
-
*/
|
1257
|
-
@Deprecated // only used by Oracle adapter - also it's really a bad idea
|
1258
|
-
@JRubyMethod(name = "execute_id_insert", required = 2)
|
1259
|
-
public IRubyObject execute_id_insert(final ThreadContext context, final IRubyObject sql, final IRubyObject id) {
|
1260
|
-
final Ruby runtime = context.runtime;
|
1261
|
-
|
1262
|
-
callMethod("warn", RubyString.newUnicodeString(runtime, "DEPRECATED: execute_id_insert(sql, id) will be removed"));
|
1263
|
-
|
1264
|
-
return withConnection(context, new Callable<IRubyObject>() {
|
1265
|
-
public IRubyObject call(final Connection connection) throws SQLException {
|
1266
|
-
PreparedStatement statement = null;
|
1267
|
-
final String insertSQL = sql.convertToString().getUnicodeValue();
|
1268
|
-
try {
|
1269
|
-
statement = connection.prepareStatement(insertSQL);
|
1270
|
-
statement.setLong(1, RubyNumeric.fix2long(id));
|
1271
|
-
statement.executeUpdate();
|
1272
|
-
}
|
1273
|
-
catch (final SQLException e) {
|
1274
|
-
debugErrorSQL(context, insertSQL);
|
1275
|
-
throw e;
|
1276
|
-
}
|
1277
|
-
finally { close(statement); }
|
1278
|
-
return id;
|
1279
|
-
}
|
1280
|
-
});
|
1281
|
-
}
|
1282
|
-
|
1283
1144
|
@JRubyMethod(name = "supported_data_types")
|
1284
1145
|
public IRubyObject supported_data_types(final ThreadContext context) throws SQLException {
|
1285
1146
|
final Connection connection = getConnection(true);
|
@@ -1303,12 +1164,10 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1303
1164
|
protected static final int PRIMARY_KEYS_COLUMN_NAME = 4;
|
1304
1165
|
|
1305
1166
|
private List<RubyString> primaryKeys(final ThreadContext context, final String tableName) {
|
1306
|
-
return withConnection(context,
|
1307
|
-
|
1308
|
-
|
1309
|
-
|
1310
|
-
return primaryKeys(context, connection, table);
|
1311
|
-
}
|
1167
|
+
return withConnection(context, connection -> {
|
1168
|
+
final String _tableName = caseConvertIdentifierForJdbc(connection, tableName);
|
1169
|
+
final TableName table = extractTableName(connection, null, null, _tableName);
|
1170
|
+
return primaryKeys(context, connection, table);
|
1312
1171
|
});
|
1313
1172
|
}
|
1314
1173
|
|
@@ -1316,7 +1175,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1316
1175
|
final Connection connection, final TableName table) throws SQLException {
|
1317
1176
|
final DatabaseMetaData metaData = connection.getMetaData();
|
1318
1177
|
ResultSet resultSet = null;
|
1319
|
-
final List<RubyString> keyNames = new ArrayList
|
1178
|
+
final List<RubyString> keyNames = new ArrayList<>();
|
1320
1179
|
try {
|
1321
1180
|
resultSet = metaData.getPrimaryKeys(table.catalog, table.schema, table.name);
|
1322
1181
|
final Ruby runtime = context.runtime;
|
@@ -1330,26 +1189,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1330
1189
|
return keyNames;
|
1331
1190
|
}
|
1332
1191
|
|
1333
|
-
@Deprecated //@JRubyMethod(name = "tables")
|
1334
|
-
public IRubyObject tables(ThreadContext context) {
|
1335
|
-
return tables(context, null, null, null, TABLE_TYPE);
|
1336
|
-
}
|
1337
|
-
|
1338
|
-
@Deprecated //@JRubyMethod(name = "tables")
|
1339
|
-
public IRubyObject tables(ThreadContext context, IRubyObject catalog) {
|
1340
|
-
return tables(context, toStringOrNull(catalog), null, null, TABLE_TYPE);
|
1341
|
-
}
|
1342
|
-
|
1343
|
-
@Deprecated //@JRubyMethod(name = "tables")
|
1344
|
-
public IRubyObject tables(ThreadContext context, IRubyObject catalog, IRubyObject schemaPattern) {
|
1345
|
-
return tables(context, toStringOrNull(catalog), toStringOrNull(schemaPattern), null, TABLE_TYPE);
|
1346
|
-
}
|
1347
|
-
|
1348
|
-
@Deprecated //@JRubyMethod(name = "tables")
|
1349
|
-
public IRubyObject tables(ThreadContext context, IRubyObject catalog, IRubyObject schemaPattern, IRubyObject tablePattern) {
|
1350
|
-
return tables(context, toStringOrNull(catalog), toStringOrNull(schemaPattern), toStringOrNull(tablePattern), TABLE_TYPE);
|
1351
|
-
}
|
1352
|
-
|
1353
1192
|
@JRubyMethod(name = "tables", required = 0, optional = 4)
|
1354
1193
|
public IRubyObject tables(final ThreadContext context, final IRubyObject[] args) {
|
1355
1194
|
switch ( args.length ) {
|
@@ -1367,11 +1206,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1367
1206
|
|
1368
1207
|
protected IRubyObject tables(final ThreadContext context,
|
1369
1208
|
final String catalog, final String schemaPattern, final String tablePattern, final String[] types) {
|
1370
|
-
return withConnection(context,
|
1371
|
-
public IRubyObject call(final Connection connection) throws SQLException {
|
1372
|
-
return matchTables(context, connection, catalog, schemaPattern, tablePattern, types, false);
|
1373
|
-
}
|
1374
|
-
});
|
1209
|
+
return withConnection(context, connection -> matchTables(context, connection, catalog, schemaPattern, tablePattern, types, false));
|
1375
1210
|
}
|
1376
1211
|
|
1377
1212
|
protected String[] getTableTypes() {
|
@@ -1401,40 +1236,36 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1401
1236
|
|
1402
1237
|
protected IRubyObject tableExists(final ThreadContext context,
|
1403
1238
|
final String defaultSchema, final String tableName) {
|
1404
|
-
return withConnection(context,
|
1405
|
-
|
1406
|
-
|
1407
|
-
return context.runtime.newBoolean( tableExists(context, connection, components) );
|
1408
|
-
}
|
1239
|
+
return withConnection(context, connection -> {
|
1240
|
+
final TableName components = extractTableName(connection, defaultSchema, tableName);
|
1241
|
+
return context.runtime.newBoolean( tableExists(context, connection, components) );
|
1409
1242
|
});
|
1410
1243
|
}
|
1411
1244
|
|
1412
1245
|
@JRubyMethod(name = {"columns", "columns_internal"}, required = 1, optional = 2)
|
1413
1246
|
public RubyArray columns_internal(final ThreadContext context, final IRubyObject[] args)
|
1414
1247
|
throws SQLException {
|
1415
|
-
return withConnection(context,
|
1416
|
-
|
1417
|
-
|
1418
|
-
|
1419
|
-
|
1420
|
-
|
1421
|
-
|
1422
|
-
final String defaultSchema = args.length > 2 ? toStringOrNull(args[2]) : null;
|
1423
|
-
|
1424
|
-
final TableName components;
|
1425
|
-
components = extractTableName(connection, catalog, defaultSchema, tableName);
|
1248
|
+
return withConnection(context, connection -> {
|
1249
|
+
ResultSet columns = null;
|
1250
|
+
try {
|
1251
|
+
final String tableName = args[0].toString();
|
1252
|
+
// optionals (NOTE: catalog argumnet was never used before 1.3.0) :
|
1253
|
+
final String catalog = args.length > 1 ? toStringOrNull(args[1]) : null;
|
1254
|
+
final String defaultSchema = args.length > 2 ? toStringOrNull(args[2]) : null;
|
1426
1255
|
|
1427
|
-
|
1428
|
-
|
1429
|
-
}
|
1256
|
+
final TableName components;
|
1257
|
+
components = extractTableName(connection, catalog, defaultSchema, tableName);
|
1430
1258
|
|
1431
|
-
|
1432
|
-
|
1433
|
-
return mapColumnsResult(context, metaData, components, columns);
|
1434
|
-
}
|
1435
|
-
finally {
|
1436
|
-
close(columns);
|
1259
|
+
if ( ! tableExists(context, connection, components) ) {
|
1260
|
+
throw new SQLException("table: " + tableName + " does not exist");
|
1437
1261
|
}
|
1262
|
+
|
1263
|
+
final DatabaseMetaData metaData = connection.getMetaData();
|
1264
|
+
columns = metaData.getColumns(components.catalog, components.schema, components.name, null);
|
1265
|
+
return mapColumnsResult(context, metaData, components, columns);
|
1266
|
+
}
|
1267
|
+
finally {
|
1268
|
+
close(columns);
|
1438
1269
|
}
|
1439
1270
|
});
|
1440
1271
|
}
|
@@ -1464,70 +1295,68 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1464
1295
|
* should filter the return from this method instead.
|
1465
1296
|
*/
|
1466
1297
|
protected IRubyObject indexes(final ThreadContext context, final String tableName, final String name, final String schemaName) {
|
1467
|
-
return withConnection(context,
|
1468
|
-
|
1469
|
-
|
1470
|
-
final RubyClass IndexDefinition = getIndexDefinition(context);
|
1298
|
+
return withConnection(context, (Callable<IRubyObject>) connection -> {
|
1299
|
+
final Ruby runtime = context.runtime;
|
1300
|
+
final RubyClass IndexDefinition = getIndexDefinition(context);
|
1471
1301
|
|
1472
|
-
|
1473
|
-
|
1474
|
-
|
1302
|
+
String _tableName = caseConvertIdentifierForJdbc(connection, tableName);
|
1303
|
+
String _schemaName = caseConvertIdentifierForJdbc(connection, schemaName);
|
1304
|
+
final TableName table = extractTableName(connection, null, _schemaName, _tableName);
|
1475
1305
|
|
1476
|
-
|
1306
|
+
final List<RubyString> primaryKeys = primaryKeys(context, connection, table);
|
1477
1307
|
|
1478
|
-
|
1479
|
-
|
1480
|
-
|
1481
|
-
|
1482
|
-
|
1483
|
-
|
1484
|
-
|
1485
|
-
while ( indexInfoSet.next() ) {
|
1486
|
-
String indexName = indexInfoSet.getString(INDEX_INFO_NAME);
|
1487
|
-
if ( indexName == null ) continue;
|
1488
|
-
RubyArray currentColumns = null;
|
1308
|
+
ResultSet indexInfoSet = null;
|
1309
|
+
final RubyArray indexes = RubyArray.newArray(runtime, 8);
|
1310
|
+
try {
|
1311
|
+
final DatabaseMetaData metaData = connection.getMetaData();
|
1312
|
+
indexInfoSet = metaData.getIndexInfo(table.catalog, table.schema, table.name, false, true);
|
1313
|
+
String currentIndex = null;
|
1489
1314
|
|
1490
|
-
|
1315
|
+
while ( indexInfoSet.next() ) {
|
1316
|
+
String indexName = indexInfoSet.getString(INDEX_INFO_NAME);
|
1317
|
+
if ( indexName == null ) continue;
|
1318
|
+
RubyArray currentColumns = null;
|
1491
1319
|
|
1492
|
-
|
1493
|
-
final RubyString rubyColumnName = cachedString(
|
1494
|
-
context, caseConvertIdentifierForRails(metaData, columnName)
|
1495
|
-
);
|
1496
|
-
if ( primaryKeys.contains(rubyColumnName) ) continue;
|
1320
|
+
indexName = caseConvertIdentifierForRails(metaData, indexName);
|
1497
1321
|
|
1498
|
-
|
1499
|
-
|
1500
|
-
|
1322
|
+
final String columnName = indexInfoSet.getString(INDEX_INFO_COLUMN_NAME);
|
1323
|
+
final RubyString rubyColumnName = cachedString(
|
1324
|
+
context, caseConvertIdentifierForRails(metaData, columnName)
|
1325
|
+
);
|
1326
|
+
if ( primaryKeys.contains(rubyColumnName) ) continue;
|
1501
1327
|
|
1502
|
-
|
1503
|
-
|
1328
|
+
// We are working on a new index
|
1329
|
+
if ( ! indexName.equals(currentIndex) ) {
|
1330
|
+
currentIndex = indexName;
|
1504
1331
|
|
1505
|
-
|
1332
|
+
String indexTableName = indexInfoSet.getString(INDEX_INFO_TABLE_NAME);
|
1333
|
+
indexTableName = caseConvertIdentifierForRails(metaData, indexTableName);
|
1506
1334
|
|
1507
|
-
|
1508
|
-
cachedString(context, indexTableName), // table_name
|
1509
|
-
cachedString(context, indexName), // index_name
|
1510
|
-
nonUnique ? runtime.getFalse() : runtime.getTrue(), // unique
|
1511
|
-
currentColumns = RubyArray.newArray(runtime, 4) // [] column names
|
1512
|
-
// orders, (since AR 3.2) where, type, using (AR 4.0)
|
1513
|
-
};
|
1335
|
+
final boolean nonUnique = indexInfoSet.getBoolean(INDEX_INFO_NON_UNIQUE);
|
1514
1336
|
|
1515
|
-
|
1516
|
-
|
1337
|
+
IRubyObject[] args = new IRubyObject[] {
|
1338
|
+
cachedString(context, indexTableName), // table_name
|
1339
|
+
cachedString(context, indexName), // index_name
|
1340
|
+
nonUnique ? context.fals : context.tru, // unique
|
1341
|
+
currentColumns = RubyArray.newArray(runtime, 4) // [] column names
|
1342
|
+
// orders, (since AR 3.2) where, type, using (AR 4.0)
|
1343
|
+
};
|
1517
1344
|
|
1518
|
-
|
1519
|
-
if ( currentColumns != null ) currentColumns.append(rubyColumnName);
|
1345
|
+
indexes.append( IndexDefinition.newInstance(context, args, Block.NULL_BLOCK) ); // IndexDefinition.new
|
1520
1346
|
}
|
1521
1347
|
|
1522
|
-
|
1348
|
+
// one or more columns can be associated with an index
|
1349
|
+
if ( currentColumns != null ) currentColumns.append(rubyColumnName);
|
1350
|
+
}
|
1351
|
+
|
1352
|
+
return indexes;
|
1523
1353
|
|
1524
|
-
|
1525
|
-
}
|
1354
|
+
} finally { close(indexInfoSet); }
|
1526
1355
|
});
|
1527
1356
|
}
|
1528
1357
|
|
1529
1358
|
protected RubyClass getIndexDefinition(final ThreadContext context) {
|
1530
|
-
final RubyClass adapterClass =
|
1359
|
+
final RubyClass adapterClass = adapter.getMetaClass();
|
1531
1360
|
IRubyObject IDef = adapterClass.getConstantAt("IndexDefinition");
|
1532
1361
|
return IDef != null ? (RubyClass) IDef : getIndexDefinition(context.runtime);
|
1533
1362
|
}
|
@@ -1538,57 +1367,55 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1538
1367
|
}
|
1539
1368
|
|
1540
1369
|
protected IRubyObject foreignKeys(final ThreadContext context, final String tableName, final String schemaName, final String catalog) {
|
1541
|
-
return withConnection(context,
|
1542
|
-
|
1543
|
-
|
1544
|
-
final RubyClass FKDefinition = getForeignKeyDefinition(context);
|
1370
|
+
return withConnection(context, (Callable<IRubyObject>) connection -> {
|
1371
|
+
final Ruby runtime = context.runtime;
|
1372
|
+
final RubyClass FKDefinition = getForeignKeyDefinition(context);
|
1545
1373
|
|
1546
|
-
|
1547
|
-
|
1548
|
-
|
1374
|
+
String _tableName = caseConvertIdentifierForJdbc(connection, tableName);
|
1375
|
+
String _schemaName = caseConvertIdentifierForJdbc(connection, schemaName);
|
1376
|
+
final TableName table = extractTableName(connection, catalog, _schemaName, _tableName);
|
1549
1377
|
|
1550
|
-
|
1551
|
-
|
1552
|
-
|
1553
|
-
|
1554
|
-
|
1378
|
+
ResultSet fkInfoSet = null;
|
1379
|
+
final List<IRubyObject> fKeys = new ArrayList<>(8);
|
1380
|
+
try {
|
1381
|
+
final DatabaseMetaData metaData = connection.getMetaData();
|
1382
|
+
fkInfoSet = metaData.getImportedKeys(table.catalog, table.schema, table.name);
|
1555
1383
|
|
1556
|
-
|
1557
|
-
|
1384
|
+
while ( fkInfoSet.next() ) {
|
1385
|
+
final RubyHash options = RubyHash.newHash(runtime);
|
1558
1386
|
|
1559
|
-
|
1560
|
-
|
1561
|
-
|
1562
|
-
|
1563
|
-
|
1387
|
+
String fkName = fkInfoSet.getString("FK_NAME");
|
1388
|
+
if (fkName != null) {
|
1389
|
+
fkName = caseConvertIdentifierForRails(metaData, fkName);
|
1390
|
+
options.put(runtime.newSymbol("name"), fkName);
|
1391
|
+
}
|
1564
1392
|
|
1565
|
-
|
1566
|
-
|
1393
|
+
String columnName = fkInfoSet.getString("FKCOLUMN_NAME");
|
1394
|
+
options.put(runtime.newSymbol("column"), caseConvertIdentifierForRails(metaData, columnName));
|
1567
1395
|
|
1568
|
-
|
1569
|
-
|
1396
|
+
columnName = fkInfoSet.getString("PKCOLUMN_NAME");
|
1397
|
+
options.put(runtime.newSymbol("primary_key"), caseConvertIdentifierForRails(metaData, columnName));
|
1570
1398
|
|
1571
|
-
|
1572
|
-
|
1399
|
+
String fkTableName = fkInfoSet.getString("FKTABLE_NAME");
|
1400
|
+
fkTableName = caseConvertIdentifierForRails(metaData, fkTableName);
|
1573
1401
|
|
1574
|
-
|
1575
|
-
|
1402
|
+
String pkTableName = fkInfoSet.getString("PKTABLE_NAME");
|
1403
|
+
pkTableName = caseConvertIdentifierForRails(metaData, pkTableName);
|
1576
1404
|
|
1577
|
-
|
1578
|
-
|
1405
|
+
final String onDelete = extractForeignKeyRule( fkInfoSet.getInt("DELETE_RULE") );
|
1406
|
+
if ( onDelete != null ) options.op_aset(context, runtime.newSymbol("on_delete"), runtime.newSymbol(onDelete));
|
1579
1407
|
|
1580
|
-
|
1581
|
-
|
1408
|
+
final String onUpdate = extractForeignKeyRule( fkInfoSet.getInt("UPDATE_RULE") );
|
1409
|
+
if ( onUpdate != null ) options.op_aset(context, runtime.newSymbol("on_update"), runtime.newSymbol(onUpdate));
|
1582
1410
|
|
1583
|
-
|
1584
|
-
|
1585
|
-
|
1586
|
-
|
1411
|
+
IRubyObject from_table = cachedString(context, fkTableName);
|
1412
|
+
IRubyObject to_table = cachedString(context, pkTableName);
|
1413
|
+
fKeys.add( FKDefinition.newInstance(context, from_table, to_table, options, Block.NULL_BLOCK) ); // ForeignKeyDefinition.new
|
1414
|
+
}
|
1587
1415
|
|
1588
|
-
|
1416
|
+
return runtime.newArray(fKeys);
|
1589
1417
|
|
1590
|
-
|
1591
|
-
}
|
1418
|
+
} finally { close(fkInfoSet); }
|
1592
1419
|
});
|
1593
1420
|
}
|
1594
1421
|
|
@@ -1603,7 +1430,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1603
1430
|
}
|
1604
1431
|
|
1605
1432
|
protected RubyClass getForeignKeyDefinition(final ThreadContext context) {
|
1606
|
-
final RubyClass adapterClass =
|
1433
|
+
final RubyClass adapterClass = adapter.getMetaClass();
|
1607
1434
|
IRubyObject FKDef = adapterClass.getConstantAt("ForeignKeyDefinition");
|
1608
1435
|
return FKDef != null ? (RubyClass) FKDef : getForeignKeyDefinition(context.runtime);
|
1609
1436
|
}
|
@@ -1611,42 +1438,34 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1611
1438
|
|
1612
1439
|
@JRubyMethod(name = "supports_foreign_keys?")
|
1613
1440
|
public IRubyObject supports_foreign_keys_p(final ThreadContext context) throws SQLException {
|
1614
|
-
return withConnection(context,
|
1615
|
-
|
1616
|
-
|
1617
|
-
return context.runtime.newBoolean( metaData.supportsIntegrityEnhancementFacility() );
|
1618
|
-
}
|
1441
|
+
return withConnection(context, (Callable<IRubyObject>) connection -> {
|
1442
|
+
final DatabaseMetaData metaData = connection.getMetaData();
|
1443
|
+
return context.runtime.newBoolean( metaData.supportsIntegrityEnhancementFacility() );
|
1619
1444
|
});
|
1620
1445
|
}
|
1621
1446
|
|
1622
1447
|
@JRubyMethod(name = "supports_views?")
|
1623
1448
|
public IRubyObject supports_views_p(final ThreadContext context) throws SQLException {
|
1624
|
-
return withConnection(context,
|
1625
|
-
|
1626
|
-
|
1627
|
-
|
1628
|
-
|
1629
|
-
|
1630
|
-
|
1631
|
-
return context.runtime.newBoolean( true );
|
1632
|
-
}
|
1449
|
+
return withConnection(context, (Callable<IRubyObject>) connection -> {
|
1450
|
+
final DatabaseMetaData metaData = connection.getMetaData();
|
1451
|
+
final ResultSet tableTypes = metaData.getTableTypes();
|
1452
|
+
try {
|
1453
|
+
while ( tableTypes.next() ) {
|
1454
|
+
if ( "VIEW".equalsIgnoreCase( tableTypes.getString(1) ) ) {
|
1455
|
+
return context.runtime.newBoolean( true );
|
1633
1456
|
}
|
1634
1457
|
}
|
1635
|
-
finally {
|
1636
|
-
close(tableTypes);
|
1637
|
-
}
|
1638
|
-
return context.runtime.newBoolean( false );
|
1639
1458
|
}
|
1459
|
+
finally {
|
1460
|
+
close(tableTypes);
|
1461
|
+
}
|
1462
|
+
return context.runtime.newBoolean( false );
|
1640
1463
|
});
|
1641
1464
|
}
|
1642
1465
|
|
1643
1466
|
@JRubyMethod(name = "with_jdbc_connection", alias = "with_connection_retry_guard", frame = true)
|
1644
1467
|
public IRubyObject with_jdbc_connection(final ThreadContext context, final Block block) {
|
1645
|
-
return withConnection(context,
|
1646
|
-
public IRubyObject call(final Connection connection) throws SQLException {
|
1647
|
-
return block.call(context, convertJavaToRuby(connection));
|
1648
|
-
}
|
1649
|
-
});
|
1468
|
+
return withConnection(context, connection -> block.call(context, convertJavaToRuby(connection)));
|
1650
1469
|
}
|
1651
1470
|
|
1652
1471
|
/*
|
@@ -1707,24 +1526,22 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1707
1526
|
// TODO: Fix this, the columns don't have the info needed to handle this anymore
|
1708
1527
|
// currently commented out so that it will compile
|
1709
1528
|
|
1710
|
-
return withConnection(context,
|
1711
|
-
|
1712
|
-
|
1713
|
-
|
1714
|
-
|
1715
|
-
|
1716
|
-
|
1717
|
-
setBlobParameter(context, connection, statement, 1, value, column, Types.BLOB);
|
1718
|
-
}
|
1719
|
-
else { // clob
|
1720
|
-
setClobParameter(context, connection, statement, 1, value, column, Types.CLOB);
|
1721
|
-
}
|
1722
|
-
setStatementParameter(context, context.runtime, connection, statement, 2, idValue, idColumn);
|
1723
|
-
*/
|
1724
|
-
return statement.executeUpdate();
|
1529
|
+
return withConnection(context, connection -> {
|
1530
|
+
PreparedStatement statement = null;
|
1531
|
+
try {
|
1532
|
+
statement = connection.prepareStatement(sql);
|
1533
|
+
/*
|
1534
|
+
if ( binary ) { // blob
|
1535
|
+
setBlobParameter(context, connection, statement, 1, value, column, Types.BLOB);
|
1725
1536
|
}
|
1726
|
-
|
1537
|
+
else { // clob
|
1538
|
+
setClobParameter(context, connection, statement, 1, value, column, Types.CLOB);
|
1539
|
+
}
|
1540
|
+
setStatementParameter(context, context.runtime, connection, statement, 2, idValue, idColumn);
|
1541
|
+
*/
|
1542
|
+
return statement.executeUpdate();
|
1727
1543
|
}
|
1544
|
+
finally { close(statement); }
|
1728
1545
|
});
|
1729
1546
|
}
|
1730
1547
|
|
@@ -1780,7 +1597,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1780
1597
|
final IRubyObject self, final IRubyObject config, final Block block) {
|
1781
1598
|
final IRubyObject ds_or_name = rawDataSourceOrName(context, config);
|
1782
1599
|
|
1783
|
-
if ( ds_or_name == null ) return context.
|
1600
|
+
if ( ds_or_name == null ) return context.fals;
|
1784
1601
|
|
1785
1602
|
final javax.sql.DataSource dataSource;
|
1786
1603
|
final Object dsOrName = ds_or_name.toJava(Object.class);
|
@@ -1836,7 +1653,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1836
1653
|
}
|
1837
1654
|
}
|
1838
1655
|
|
1839
|
-
if ( configValue == null || configValue == context.nil || configValue ==
|
1656
|
+
if ( configValue == null || configValue == context.nil || configValue == context.fals ) {
|
1840
1657
|
return null;
|
1841
1658
|
}
|
1842
1659
|
return configValue;
|
@@ -1859,13 +1676,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1859
1676
|
}
|
1860
1677
|
}
|
1861
1678
|
|
1862
|
-
@Deprecated
|
1863
|
-
@JRubyMethod(name = "setup_jdbc_factory", visibility = Visibility.PROTECTED)
|
1864
|
-
public IRubyObject set_driver_factory(final ThreadContext context) {
|
1865
|
-
setDriverFactory(context);
|
1866
|
-
return get_connection_factory(context.runtime);
|
1867
|
-
}
|
1868
|
-
|
1869
1679
|
private ConnectionFactory setDriverFactory(final ThreadContext context) {
|
1870
1680
|
|
1871
1681
|
final IRubyObject url = getConfigValue(context, "url");
|
@@ -1965,12 +1775,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1965
1775
|
return props;
|
1966
1776
|
}
|
1967
1777
|
|
1968
|
-
@JRubyMethod(name = "setup_jndi_factory", visibility = Visibility.PROTECTED)
|
1969
|
-
public IRubyObject set_data_source_factory(final ThreadContext context) {
|
1970
|
-
setDataSourceFactory(context);
|
1971
|
-
return get_connection_factory(context.runtime);
|
1972
|
-
}
|
1973
|
-
|
1974
1778
|
private ConnectionFactory setDataSourceFactory(final ThreadContext context) {
|
1975
1779
|
final javax.sql.DataSource dataSource; final String lookupName;
|
1976
1780
|
IRubyObject value = getConfigValue(context, "data_source");
|
@@ -1992,28 +1796,10 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1992
1796
|
private static volatile boolean defaultConfigJndi;
|
1993
1797
|
private static transient ConnectionFactory defaultConnectionFactory;
|
1994
1798
|
|
1995
|
-
/**
|
1996
|
-
* Sets the connection factory from the available configuration.
|
1997
|
-
* @param context
|
1998
|
-
* @see #initialize
|
1999
|
-
*/
|
2000
|
-
@Deprecated
|
2001
|
-
@JRubyMethod(name = "setup_connection_factory", visibility = Visibility.PROTECTED)
|
2002
|
-
public IRubyObject setup_connection_factory(final ThreadContext context) {
|
2003
|
-
setupConnectionFactory(context);
|
2004
|
-
return get_connection_factory(context.runtime);
|
2005
|
-
}
|
2006
|
-
|
2007
|
-
private IRubyObject get_connection_factory(final Ruby runtime) {
|
2008
|
-
return JavaUtil.convertJavaToRuby(runtime, connectionFactory);
|
2009
|
-
}
|
2010
|
-
|
2011
1799
|
/**
|
2012
1800
|
* @return whether the connection factory is JNDI based
|
2013
1801
|
*/
|
2014
1802
|
private boolean setupConnectionFactory(final ThreadContext context) {
|
2015
|
-
final IRubyObject config = getConfig();
|
2016
|
-
|
2017
1803
|
if ( defaultConfig == null ) {
|
2018
1804
|
synchronized(RubyJdbcConnection.class) {
|
2019
1805
|
if ( defaultConfig == null ) {
|
@@ -2045,18 +1831,17 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2045
1831
|
|
2046
1832
|
@JRubyMethod(name = "jndi?", alias = "jndi_connection?")
|
2047
1833
|
public RubyBoolean jndi_p(final ThreadContext context) {
|
2048
|
-
return context.runtime.newBoolean(
|
1834
|
+
return context.runtime.newBoolean(jndi);
|
2049
1835
|
}
|
2050
1836
|
|
2051
1837
|
protected boolean isJndi() { return this.jndi; }
|
2052
1838
|
|
2053
1839
|
@JRubyMethod(name = "config")
|
2054
|
-
public IRubyObject config() { return
|
1840
|
+
public IRubyObject config() { return config; }
|
2055
1841
|
|
2056
1842
|
public IRubyObject getConfig() { return this.config; }
|
2057
1843
|
|
2058
1844
|
protected final IRubyObject getConfigValue(final ThreadContext context, final String key) {
|
2059
|
-
final IRubyObject config = getConfig();
|
2060
1845
|
final RubySymbol keySym = context.runtime.newSymbol(key);
|
2061
1846
|
if ( config instanceof RubyHash ) {
|
2062
1847
|
final IRubyObject value = ((RubyHash) config).fastARef(keySym);
|
@@ -2067,7 +1852,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2067
1852
|
|
2068
1853
|
protected final IRubyObject setConfigValue(final ThreadContext context,
|
2069
1854
|
final String key, final IRubyObject value) {
|
2070
|
-
final IRubyObject config = getConfig();
|
2071
1855
|
final RubySymbol keySym = context.runtime.newSymbol(key);
|
2072
1856
|
if ( config instanceof RubyHash ) {
|
2073
1857
|
return ((RubyHash) config).op_aset(context, keySym, value);
|
@@ -2077,7 +1861,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2077
1861
|
|
2078
1862
|
protected final IRubyObject setConfigValueIfNotSet(final ThreadContext context,
|
2079
1863
|
final String key, final IRubyObject value) {
|
2080
|
-
final IRubyObject config = getConfig();
|
2081
1864
|
final RubySymbol keySym = context.runtime.newSymbol(key);
|
2082
1865
|
if ( config instanceof RubyHash ) {
|
2083
1866
|
final IRubyObject setValue = ((RubyHash) config).fastARef(keySym);
|
@@ -2097,7 +1880,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2097
1880
|
protected final IRubyObject getAdapter() { return this.adapter; }
|
2098
1881
|
|
2099
1882
|
protected RubyClass getJdbcColumnClass(final ThreadContext context) {
|
2100
|
-
return (RubyClass)
|
1883
|
+
return (RubyClass) adapter.callMethod(context, "jdbc_column_class");
|
2101
1884
|
}
|
2102
1885
|
|
2103
1886
|
protected ConnectionFactory getConnectionFactory() throws RaiseException {
|
@@ -2309,7 +2092,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2309
2092
|
@JRubyMethod(name = "raw_date_time?", meta = true)
|
2310
2093
|
public static IRubyObject useRawDateTime(final ThreadContext context, final IRubyObject self) {
|
2311
2094
|
if ( rawDateTime == null ) return context.nil;
|
2312
|
-
return context.runtime.newBoolean(
|
2095
|
+
return context.runtime.newBoolean(rawDateTime);
|
2313
2096
|
}
|
2314
2097
|
|
2315
2098
|
@JRubyMethod(name = "raw_date_time=", meta = true)
|
@@ -2323,17 +2106,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2323
2106
|
return value;
|
2324
2107
|
}
|
2325
2108
|
|
2326
|
-
/**
|
2327
|
-
* @return AR::Type-casted value
|
2328
|
-
* @since 1.3.18
|
2329
|
-
*/
|
2330
|
-
@Deprecated
|
2331
|
-
protected static IRubyObject typeCastFromDatabase(final ThreadContext context,
|
2332
|
-
final IRubyObject adapter, final RubySymbol typeName, final RubyString value) {
|
2333
|
-
final IRubyObject type = adapter.callMethod(context, "lookup_cast_type", typeName);
|
2334
|
-
return type.callMethod(context, "deserialize", value);
|
2335
|
-
}
|
2336
|
-
|
2337
2109
|
protected IRubyObject dateToRuby(final ThreadContext context,
|
2338
2110
|
final Ruby runtime, final ResultSet resultSet, final int column)
|
2339
2111
|
throws SQLException {
|
@@ -2344,11 +2116,11 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2344
2116
|
return resultSet.wasNull() ? context.nil : RubyString.newEmptyString(runtime);
|
2345
2117
|
}
|
2346
2118
|
|
2347
|
-
if ( rawDateTime != null && rawDateTime
|
2119
|
+
if ( rawDateTime != null && rawDateTime) {
|
2348
2120
|
return RubyString.newString(runtime, DateTimeUtils.dateToString(value));
|
2349
2121
|
}
|
2350
2122
|
|
2351
|
-
return DateTimeUtils.newDateAsTime(context, value,
|
2123
|
+
return DateTimeUtils.newDateAsTime(context, value, null).callMethod(context, "to_date");
|
2352
2124
|
}
|
2353
2125
|
|
2354
2126
|
protected IRubyObject timeToRuby(final ThreadContext context,
|
@@ -2360,7 +2132,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2360
2132
|
return resultSet.wasNull() ? context.nil : RubyString.newEmptyString(runtime);
|
2361
2133
|
}
|
2362
2134
|
|
2363
|
-
if ( rawDateTime != null && rawDateTime
|
2135
|
+
if ( rawDateTime != null && rawDateTime) {
|
2364
2136
|
return RubyString.newString(runtime, DateTimeUtils.timeToString(value));
|
2365
2137
|
}
|
2366
2138
|
|
@@ -2376,7 +2148,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2376
2148
|
return resultSet.wasNull() ? context.nil : RubyString.newEmptyString(runtime);
|
2377
2149
|
}
|
2378
2150
|
|
2379
|
-
if ( rawDateTime != null && rawDateTime
|
2151
|
+
if ( rawDateTime != null && rawDateTime) {
|
2380
2152
|
return RubyString.newString(runtime, DateTimeUtils.timestampToString(value));
|
2381
2153
|
}
|
2382
2154
|
|
@@ -2388,19 +2160,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2388
2160
|
return DateTimeUtils.newTime(context, value, getDefaultTimeZone(context));
|
2389
2161
|
}
|
2390
2162
|
|
2391
|
-
@Deprecated
|
2392
|
-
protected static RubyString timestampToRubyString(final Ruby runtime, String value) {
|
2393
|
-
// Timestamp's format: yyyy-mm-dd hh:mm:ss.fffffffff
|
2394
|
-
String suffix; // assumes java.sql.Timestamp internals :
|
2395
|
-
if ( value.endsWith( suffix = " 00:00:00.0" ) ) {
|
2396
|
-
value = value.substring( 0, value.length() - suffix.length() );
|
2397
|
-
}
|
2398
|
-
else if ( value.endsWith( suffix = ".0" ) ) {
|
2399
|
-
value = value.substring( 0, value.length() - suffix.length() );
|
2400
|
-
}
|
2401
|
-
return RubyString.newUnicodeString(runtime, value);
|
2402
|
-
}
|
2403
|
-
|
2404
2163
|
protected static Boolean rawBoolean;
|
2405
2164
|
static {
|
2406
2165
|
final String booleanRaw = SafePropertyAccessor.getProperty("arjdbc.boolean.raw");
|
@@ -2412,7 +2171,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2412
2171
|
@JRubyMethod(name = "raw_boolean?", meta = true)
|
2413
2172
|
public static IRubyObject useRawBoolean(final ThreadContext context, final IRubyObject self) {
|
2414
2173
|
if ( rawBoolean == null ) return context.nil;
|
2415
|
-
return context.runtime.newBoolean(
|
2174
|
+
return context.runtime.newBoolean(rawBoolean);
|
2416
2175
|
}
|
2417
2176
|
|
2418
2177
|
@JRubyMethod(name = "raw_boolean=", meta = true)
|
@@ -2444,13 +2203,13 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2444
2203
|
protected IRubyObject booleanToRuby(final ThreadContext context,
|
2445
2204
|
final Ruby runtime, final ResultSet resultSet, final int column)
|
2446
2205
|
throws SQLException {
|
2447
|
-
if ( rawBoolean != null && rawBoolean
|
2206
|
+
if ( rawBoolean != null && rawBoolean) {
|
2448
2207
|
final String value = resultSet.getString(column);
|
2449
2208
|
if ( value == null /* && resultSet.wasNull() */ ) return context.nil;
|
2450
2209
|
return RubyString.newUnicodeString(runtime, value);
|
2451
2210
|
}
|
2452
2211
|
final boolean value = resultSet.getBoolean(column);
|
2453
|
-
if (
|
2212
|
+
if (!value && resultSet.wasNull()) return context.nil;
|
2454
2213
|
return runtime.newBoolean(value);
|
2455
2214
|
}
|
2456
2215
|
|
@@ -2668,7 +2427,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2668
2427
|
}
|
2669
2428
|
}
|
2670
2429
|
|
2671
|
-
protected static final Map<String, Integer> JDBC_TYPE_FOR = new HashMap
|
2430
|
+
protected static final Map<String, Integer> JDBC_TYPE_FOR = new HashMap<>(32, 1);
|
2672
2431
|
static {
|
2673
2432
|
JDBC_TYPE_FOR.put("string", Types.VARCHAR);
|
2674
2433
|
JDBC_TYPE_FOR.put("text", Types.CLOB);
|
@@ -2710,7 +2469,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2710
2469
|
final String internedType = internedTypeFor(context, attribute);
|
2711
2470
|
final Integer sqlType = jdbcTypeFor(internedType);
|
2712
2471
|
if ( sqlType != null ) {
|
2713
|
-
return sqlType
|
2472
|
+
return sqlType;
|
2714
2473
|
}
|
2715
2474
|
|
2716
2475
|
return Types.OTHER; // -1 as well as 0 are used in Types
|
@@ -2888,11 +2647,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2888
2647
|
statement.setTimestamp(index, timestamp, getCalendar(dateTime.getZone()));
|
2889
2648
|
}
|
2890
2649
|
|
2891
|
-
@Deprecated
|
2892
|
-
protected static Timestamp convertToTimestamp(final RubyFloat value) {
|
2893
|
-
return DateTimeUtils.convertToTimestamp(value);
|
2894
|
-
}
|
2895
|
-
|
2896
2650
|
protected static Calendar getCalendar(final DateTimeZone zone) { // final java.util.Date hint
|
2897
2651
|
if (DateTimeZone.UTC == zone) return getCalendarUTC();
|
2898
2652
|
if (DateTimeZone.getDefault() == zone) return new GregorianCalendar();
|
@@ -2938,6 +2692,12 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2938
2692
|
value = value.callMethod(context, "to_date");
|
2939
2693
|
}
|
2940
2694
|
|
2695
|
+
if (value instanceof RubyDate) {
|
2696
|
+
RubyDate rubyDate = (RubyDate) value;
|
2697
|
+
statement.setDate(index, rubyDate.toJava(Date.class));
|
2698
|
+
return;
|
2699
|
+
}
|
2700
|
+
|
2941
2701
|
// NOTE: assuming Date#to_s does right ...
|
2942
2702
|
statement.setDate(index, Date.valueOf(value.toString()));
|
2943
2703
|
}
|
@@ -2976,7 +2736,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2976
2736
|
// For some reason the driver doesn't like "character varying" as a type
|
2977
2737
|
if ( type.eql(context.runtime.newSymbol("string")) ) return "varchar";
|
2978
2738
|
|
2979
|
-
final RubyHash nativeTypes = (RubyHash)
|
2739
|
+
final RubyHash nativeTypes = (RubyHash) adapter.callMethod(context, "native_database_types");
|
2980
2740
|
// e.g. `integer: { name: 'integer' }`
|
2981
2741
|
final RubyHash typeInfo = (RubyHash) nativeTypes.op_aref(context, type);
|
2982
2742
|
|
@@ -3037,16 +2797,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
3037
2797
|
}
|
3038
2798
|
|
3039
2799
|
/**
|
3040
|
-
*
|
3041
|
-
* @return connection
|
3042
|
-
* @throws <code>ActiveRecord::ConnectionNotEstablished</code>, <code>ActiveRecord::JDBCError</code>
|
3043
|
-
*/
|
3044
|
-
protected Connection getConnection() throws RaiseException {
|
3045
|
-
return getConnection(false);
|
3046
|
-
}
|
3047
|
-
|
3048
|
-
/**
|
3049
|
-
* @see #getConnection()
|
2800
|
+
* Returns a connection (might cause a reconnect if there's none).
|
3050
2801
|
* @param required set to true if a connection is required to exists (e.g. on commit)
|
3051
2802
|
* @return connection
|
3052
2803
|
* @throws <code>ActiveRecord::ConnectionNotEstablished</code> if disconnected
|
@@ -3061,17 +2812,15 @@ public class RubyJdbcConnection extends RubyObject {
|
|
3061
2812
|
}
|
3062
2813
|
}
|
3063
2814
|
|
3064
|
-
|
2815
|
+
protected Connection getConnectionInternal(final boolean required) throws SQLException {
|
3065
2816
|
Connection connection = getConnectionImpl();
|
3066
|
-
if (
|
3067
|
-
if (
|
3068
|
-
|
3069
|
-
|
2817
|
+
if (connection == null && required) {
|
2818
|
+
if (!connected) handleNotConnected(); // raise ConnectionNotEstablished
|
2819
|
+
synchronized (this) {
|
2820
|
+
connection = getConnectionImpl();
|
2821
|
+
if ( connection == null ) {
|
2822
|
+
connectImpl(true); // throws SQLException
|
3070
2823
|
connection = getConnectionImpl();
|
3071
|
-
if ( connection == null ) {
|
3072
|
-
connectImpl( true ); // throws SQLException
|
3073
|
-
connection = getConnectionImpl();
|
3074
|
-
}
|
3075
2824
|
}
|
3076
2825
|
}
|
3077
2826
|
}
|
@@ -3202,7 +2951,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
3202
2951
|
try {
|
3203
2952
|
tablesSet = metaData.getTables(catalog, _schemaPattern, _tablePattern, types);
|
3204
2953
|
if ( checkExistsOnly ) { // only check if given table exists
|
3205
|
-
return tablesSet.next() ? context.
|
2954
|
+
return tablesSet.next() ? context.tru : null;
|
3206
2955
|
}
|
3207
2956
|
else {
|
3208
2957
|
return mapTables(context, connection, catalog, _schemaPattern, _tablePattern, tablesSet);
|
@@ -3211,15 +2960,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
3211
2960
|
finally { close(tablesSet); }
|
3212
2961
|
}
|
3213
2962
|
|
3214
|
-
@Deprecated
|
3215
|
-
protected IRubyObject matchTables(final Ruby runtime,
|
3216
|
-
final Connection connection,
|
3217
|
-
final String catalog, final String schemaPattern,
|
3218
|
-
final String tablePattern, final String[] types,
|
3219
|
-
final boolean checkExistsOnly) throws SQLException {
|
3220
|
-
return matchTables(runtime.getCurrentContext(), connection, catalog, schemaPattern, tablePattern, types, checkExistsOnly);
|
3221
|
-
}
|
3222
|
-
|
3223
2963
|
// NOTE java.sql.DatabaseMetaData.getTables :
|
3224
2964
|
protected final static int TABLES_TABLE_CAT = 1;
|
3225
2965
|
protected final static int TABLES_TABLE_SCHEM = 2;
|
@@ -3307,7 +3047,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
3307
3047
|
final String tabName = results.getString(TABLE_NAME);
|
3308
3048
|
final RubyString tableName = cachedString(context, caseConvertIdentifierForRails(metaData, tabName));
|
3309
3049
|
|
3310
|
-
final IRubyObject type_metadata =
|
3050
|
+
final IRubyObject type_metadata = adapter.callMethod(context, "fetch_type_metadata", sqlType);
|
3311
3051
|
|
3312
3052
|
// (name, default, sql_type_metadata = nil, null = true, table_name = nil, default_function = nil, collation = nil, comment: nil)
|
3313
3053
|
final IRubyObject[] args = new IRubyObject[] {
|
@@ -3323,7 +3063,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
3323
3063
|
ResultSet primaryKeys = null;
|
3324
3064
|
try {
|
3325
3065
|
primaryKeys = metaData.getPrimaryKeys(components.catalog, components.schema, components.name);
|
3326
|
-
final List<String> primaryKeyNames = new ArrayList
|
3066
|
+
final List<String> primaryKeyNames = new ArrayList<>(4);
|
3327
3067
|
while ( primaryKeys.next() ) {
|
3328
3068
|
primaryKeyNames.add( primaryKeys.getString(COLUMN_NAME) );
|
3329
3069
|
}
|
@@ -3372,7 +3112,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
3372
3112
|
// not have and auto-generated ID column :
|
3373
3113
|
boolean next = genKeys.next() && genKeys.getMetaData().getColumnCount() > 0;
|
3374
3114
|
// singleResult == null - guess if only single key returned
|
3375
|
-
if ( singleResult == null || singleResult
|
3115
|
+
if ( singleResult == null || singleResult) {
|
3376
3116
|
if ( next ) {
|
3377
3117
|
firstKey = mapGeneratedKey(runtime, genKeys);
|
3378
3118
|
if ( singleResult != null || ! genKeys.next() ) {
|
@@ -3405,7 +3145,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
3405
3145
|
if (supportsGeneratedKeys == null) {
|
3406
3146
|
supportsGeneratedKeys = this.supportsGeneratedKeys = connection.getMetaData().supportsGetGeneratedKeys();
|
3407
3147
|
}
|
3408
|
-
return supportsGeneratedKeys
|
3148
|
+
return supportsGeneratedKeys;
|
3409
3149
|
}
|
3410
3150
|
|
3411
3151
|
/**
|
@@ -3437,8 +3177,8 @@ public class RubyJdbcConnection extends RubyObject {
|
|
3437
3177
|
final ColumnData[] columns = extractColumns(context, connection, resultSet, false);
|
3438
3178
|
|
3439
3179
|
final Ruby runtime = context.runtime;
|
3440
|
-
final IRubyObject[] blockArgs = new IRubyObject[columns.length];
|
3441
3180
|
while ( resultSet.next() ) {
|
3181
|
+
final IRubyObject[] blockArgs = new IRubyObject[columns.length];
|
3442
3182
|
for ( int i = 0; i < columns.length; i++ ) {
|
3443
3183
|
final ColumnData column = columns[i];
|
3444
3184
|
blockArgs[i] = jdbcToRuby(context, runtime, column.index, column.type, resultSet);
|
@@ -3464,16 +3204,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
3464
3204
|
return setupColumns(context, connection, resultSet.getMetaData(), downCase);
|
3465
3205
|
}
|
3466
3206
|
|
3467
|
-
/**
|
3468
|
-
* @deprecated use {@link #extractColumns(ThreadContext, Connection, ResultSet, boolean)}
|
3469
|
-
*/
|
3470
|
-
@Deprecated
|
3471
|
-
protected ColumnData[] extractColumns(final Ruby runtime,
|
3472
|
-
final Connection connection, final ResultSet resultSet,
|
3473
|
-
final boolean downCase) throws SQLException {
|
3474
|
-
return extractColumns(runtime.getCurrentContext(), connection, resultSet, downCase);
|
3475
|
-
}
|
3476
|
-
|
3477
3207
|
protected <T> T withConnection(final ThreadContext context, final Callable<T> block)
|
3478
3208
|
throws RaiseException {
|
3479
3209
|
try {
|
@@ -3579,13 +3309,12 @@ public class RubyJdbcConnection extends RubyObject {
|
|
3579
3309
|
}
|
3580
3310
|
|
3581
3311
|
protected boolean isTransient(final Exception exception) {
|
3582
|
-
|
3583
|
-
return false;
|
3312
|
+
return exception instanceof SQLTransientException;
|
3584
3313
|
}
|
3585
3314
|
|
3586
3315
|
protected boolean isRecoverable(final Exception exception) {
|
3587
|
-
|
3588
|
-
|
3316
|
+
return exception instanceof SQLRecoverableException;
|
3317
|
+
// exception instanceof SQLException; // pre JDBC 4.0 drivers?
|
3589
3318
|
}
|
3590
3319
|
|
3591
3320
|
private static Throwable getCause(Throwable exception) {
|
@@ -3743,6 +3472,11 @@ public class RubyJdbcConnection extends RubyObject {
|
|
3743
3472
|
return Result.newInstance(context, columnsToArray(context, columns), rows, Block.NULL_BLOCK); // Result.new
|
3744
3473
|
}
|
3745
3474
|
|
3475
|
+
protected static IRubyObject newEmptyResult(final ThreadContext context) {
|
3476
|
+
final RubyClass Result = getResult(context.runtime);
|
3477
|
+
return Result.newInstance(context, RubyArray.newEmptyArray(context.runtime), RubyArray.newEmptyArray(context.runtime), Block.NULL_BLOCK); // Result.new
|
3478
|
+
}
|
3479
|
+
|
3746
3480
|
private static RubyArray columnsToArray(ThreadContext context, ColumnData[] columns) {
|
3747
3481
|
final IRubyObject[] cols = new IRubyObject[columns.length];
|
3748
3482
|
|
@@ -3995,7 +3729,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
3995
3729
|
public static void debugStackTrace(final ThreadContext context, final Throwable e) {
|
3996
3730
|
if ( debug || ( context != null && context.runtime.isDebug() ) ) {
|
3997
3731
|
final PrintStream out = context != null ? context.runtime.getOut() : System.out;
|
3998
|
-
if ( debugStackTrace == null || debugStackTrace
|
3732
|
+
if ( debugStackTrace == null || debugStackTrace) {
|
3999
3733
|
e.printStackTrace(out);
|
4000
3734
|
}
|
4001
3735
|
else {
|
@@ -4011,8 +3745,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
4011
3745
|
private static boolean driverUsedLogged;
|
4012
3746
|
|
4013
3747
|
private void logDriverUsed(final Connection connection) {
|
4014
|
-
if (
|
4015
|
-
if ( driverUsedLogged ) return;
|
3748
|
+
if (debug && !driverUsedLogged) {
|
4016
3749
|
driverUsedLogged = true;
|
4017
3750
|
try {
|
4018
3751
|
final DatabaseMetaData meta = connection.getMetaData();
|