activerecord-jdbc-alt-adapter 52.6.0-java → 60.0.0-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +0 -2
- data/.travis.yml +58 -37
- data/Gemfile +9 -2
- data/README.md +30 -14
- data/Rakefile +1 -1
- data/Rakefile.jdbc +8 -1
- data/activerecord-jdbc-adapter.gemspec +5 -8
- data/activerecord-jdbc-alt-adapter.gemspec +5 -8
- data/lib/arel/visitors/sqlserver.rb +33 -23
- data/lib/arjdbc/abstract/connection_management.rb +7 -0
- data/lib/arjdbc/abstract/core.rb +16 -23
- data/lib/arjdbc/abstract/database_statements.rb +24 -0
- 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/mssql.rb +3 -1
- data/lib/arjdbc/mssql/adapter.rb +105 -36
- data/lib/arjdbc/mssql/column.rb +5 -1
- data/lib/arjdbc/mssql/connection_methods.rb +8 -2
- data/lib/arjdbc/mssql/database_limits.rb +2 -0
- data/lib/arjdbc/mssql/database_statements.rb +43 -5
- data/lib/arjdbc/mssql/errors.rb +2 -0
- data/lib/arjdbc/mssql/explain_support.rb +3 -1
- data/lib/arjdbc/mssql/extensions/attribute_methods.rb +5 -1
- data/lib/arjdbc/mssql/extensions/calculations.rb +2 -0
- data/lib/arjdbc/mssql/quoting.rb +38 -0
- data/lib/arjdbc/mssql/schema_creation.rb +24 -2
- data/lib/arjdbc/mssql/schema_definitions.rb +10 -0
- data/lib/arjdbc/mssql/schema_dumper.rb +2 -0
- data/lib/arjdbc/mssql/schema_statements.rb +63 -21
- data/lib/arjdbc/mssql/transaction.rb +2 -0
- data/lib/arjdbc/mssql/types.rb +2 -0
- data/lib/arjdbc/mssql/types/binary_types.rb +2 -0
- data/lib/arjdbc/mssql/types/date_and_time_types.rb +2 -0
- data/lib/arjdbc/mssql/types/deprecated_types.rb +2 -0
- data/lib/arjdbc/mssql/types/numeric_types.rb +2 -0
- data/lib/arjdbc/mssql/types/string_types.rb +2 -0
- data/lib/arjdbc/mssql/utils.rb +2 -0
- data/lib/arjdbc/mysql/adapter.rb +47 -18
- 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/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 -4
- data/lib/arjdbc/tasks/databases.rake +13 -10
- data/lib/arjdbc/tasks/mssql_database_tasks.rb +49 -5
- 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/src/java/arjdbc/ArJdbcModule.java +5 -5
- data/src/java/arjdbc/jdbc/DriverWrapper.java +1 -9
- data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +406 -629
- data/src/java/arjdbc/mssql/MSSQLRubyJdbcConnection.java +37 -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
- data/src/java/arjdbc/util/DateTimeUtils.java +12 -4
- metadata +8 -16
|
@@ -23,17 +23,27 @@ ArJdbc::ConnectionMethods.module_eval do
|
|
|
23
23
|
raise
|
|
24
24
|
end
|
|
25
25
|
end
|
|
26
|
-
|
|
26
|
+
|
|
27
|
+
config[:properties] ||= {}
|
|
28
|
+
|
|
27
29
|
database = config[:database] # NOTE: "jdbc:sqlite::memory:" syntax is supported
|
|
28
30
|
config[:url] ||= "jdbc:sqlite:#{database == ':memory:' ? '' : database}"
|
|
29
31
|
config[:connection_alive_sql] ||= 'SELECT 1'
|
|
30
32
|
|
|
33
|
+
if config[:readonly]
|
|
34
|
+
# See
|
|
35
|
+
# * http://sqlite.org/c3ref/open.html
|
|
36
|
+
# * http://sqlite.org/c3ref/c_open_autoproxy.html
|
|
37
|
+
# => 0x01 = readonly, 0x40 = uri (default in JDBC)
|
|
38
|
+
config[:properties][:open_mode] = 0x01 | 0x40
|
|
39
|
+
end
|
|
40
|
+
|
|
31
41
|
timeout = config[:timeout]
|
|
32
42
|
if timeout && timeout.to_s !~ /\A\d+\Z/
|
|
33
43
|
raise TypeError.new "Timeout must be nil or a number (got: #{timeout})."
|
|
34
44
|
end
|
|
35
45
|
|
|
36
|
-
options =
|
|
46
|
+
options = config[:properties]
|
|
37
47
|
options['busy_timeout'] ||= timeout unless timeout.nil?
|
|
38
48
|
|
|
39
49
|
jdbc_connection(config)
|
|
@@ -51,8 +61,9 @@ ArJdbc::ConnectionMethods.module_eval do
|
|
|
51
61
|
def parse_sqlite3_config!(config)
|
|
52
62
|
database = ( config[:database] ||= config[:dbfile] )
|
|
53
63
|
if ':memory:' != database
|
|
54
|
-
|
|
55
|
-
|
|
64
|
+
# make sure to have an absolute path. Ruby and Java don't agree on working directory
|
|
65
|
+
config[:database] = File.expand_path(database, defined?(Rails.root) ? Rails.root : nil)
|
|
66
|
+
dirname = File.dirname(config[:database])
|
|
56
67
|
Dir.mkdir(dirname) unless File.directory?(dirname)
|
|
57
68
|
end
|
|
58
69
|
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,17 +1,37 @@
|
|
|
1
|
+
require 'active_record/tasks/database_tasks'
|
|
2
|
+
|
|
1
3
|
require 'arjdbc/tasks/jdbc_database_tasks'
|
|
2
4
|
|
|
3
5
|
module ArJdbc
|
|
4
6
|
module Tasks
|
|
5
7
|
class MSSQLDatabaseTasks < JdbcDatabaseTasks
|
|
8
|
+
delegate :clear_active_connections!, to: ActiveRecord::Base
|
|
9
|
+
|
|
10
|
+
def create
|
|
11
|
+
establish_master_connection
|
|
12
|
+
connection.create_database(configuration['database'])
|
|
13
|
+
establish_connection configuration
|
|
14
|
+
rescue ActiveRecord::StatementInvalid => error
|
|
15
|
+
case error.message
|
|
16
|
+
when /database .* already exists/i
|
|
17
|
+
raise ActiveRecord::Tasks::DatabaseAlreadyExists
|
|
18
|
+
else
|
|
19
|
+
raise
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def drop
|
|
24
|
+
establish_master_connection
|
|
25
|
+
connection.drop_database configuration['database']
|
|
26
|
+
end
|
|
6
27
|
|
|
7
28
|
def purge
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
establish_connection(test)
|
|
12
|
-
connection.recreate_database(test_database)
|
|
29
|
+
clear_active_connections!
|
|
30
|
+
drop
|
|
31
|
+
create
|
|
13
32
|
end
|
|
14
33
|
|
|
34
|
+
|
|
15
35
|
def structure_dump(filename)
|
|
16
36
|
config = config_from_url_if_needed
|
|
17
37
|
`smoscript -s #{config['host']} -d #{config['database']} -u #{config['username']} -p #{config['password']} -f #{filename} -A -U`
|
|
@@ -24,6 +44,10 @@ module ArJdbc
|
|
|
24
44
|
|
|
25
45
|
private
|
|
26
46
|
|
|
47
|
+
def establish_master_connection
|
|
48
|
+
establish_connection configuration.merge('database' => 'master')
|
|
49
|
+
end
|
|
50
|
+
|
|
27
51
|
def config_from_url_if_needed
|
|
28
52
|
config = self.config
|
|
29
53
|
if config['url'] && ! config.key?('database')
|
|
@@ -42,5 +66,25 @@ module ArJdbc
|
|
|
42
66
|
end
|
|
43
67
|
|
|
44
68
|
end
|
|
69
|
+
|
|
70
|
+
module DatabaseTasksMSSQL
|
|
71
|
+
extend ActiveSupport::Concern
|
|
72
|
+
|
|
73
|
+
module ClassMethods
|
|
74
|
+
|
|
75
|
+
def check_protected_environments!
|
|
76
|
+
super
|
|
77
|
+
rescue ActiveRecord::JDBCError => error
|
|
78
|
+
case error.message
|
|
79
|
+
when /cannot open database .* requested by the login/i
|
|
80
|
+
else
|
|
81
|
+
raise
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
ActiveRecord::Tasks::DatabaseTasks.send :include, DatabaseTasksMSSQL
|
|
45
89
|
end
|
|
46
90
|
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
|
|
@@ -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
|
-
supported = metaData.supportsTransactionIsolationLevel(level);
|
|
316
|
-
}
|
|
317
|
-
else {
|
|
318
|
-
final int level = metaData.getDefaultTransactionIsolation();
|
|
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);
|
|
322
306
|
}
|
|
307
|
+
else {
|
|
308
|
+
final int level = metaData.getDefaultTransactionIsolation();
|
|
309
|
+
supported = level > Connection.TRANSACTION_NONE; // > 0
|
|
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;
|
|
@@ -735,33 +684,35 @@ public class RubyJdbcConnection extends RubyObject {
|
|
|
735
684
|
|
|
736
685
|
@JRubyMethod(name = "read_only?")
|
|
737
686
|
public IRubyObject is_read_only(final ThreadContext context) {
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
return context.runtime.newBoolean(
|
|
687
|
+
try {
|
|
688
|
+
final Connection connection = getConnectionInternal(false);
|
|
689
|
+
if (connection != null) {
|
|
690
|
+
return context.runtime.newBoolean(connection.isReadOnly());
|
|
742
691
|
}
|
|
743
|
-
|
|
692
|
+
} catch (SQLException e) {
|
|
693
|
+
return handleException(context, e);
|
|
744
694
|
}
|
|
745
695
|
return context.nil;
|
|
746
696
|
}
|
|
747
697
|
|
|
748
698
|
@JRubyMethod(name = "read_only=")
|
|
749
699
|
public IRubyObject set_read_only(final ThreadContext context, final IRubyObject flag) {
|
|
750
|
-
final Connection connection = getConnection(true);
|
|
751
700
|
try {
|
|
701
|
+
final Connection connection = getConnectionInternal(true);
|
|
752
702
|
connection.setReadOnly( flag.isTrue() );
|
|
753
703
|
return context.runtime.newBoolean( connection.isReadOnly() );
|
|
704
|
+
} catch (SQLException e) {
|
|
705
|
+
return handleException(context, e);
|
|
754
706
|
}
|
|
755
|
-
catch (SQLException e) { return handleException(context, e); }
|
|
756
707
|
}
|
|
757
708
|
|
|
758
709
|
@JRubyMethod(name = { "open?" /* "conn?" */ })
|
|
759
710
|
public IRubyObject open_p(final ThreadContext context) {
|
|
760
|
-
|
|
711
|
+
try {
|
|
712
|
+
final Connection connection = getConnectionInternal(false);
|
|
761
713
|
|
|
762
|
-
|
|
714
|
+
if (connection == null) return context.fals;
|
|
763
715
|
|
|
764
|
-
try {
|
|
765
716
|
// NOTE: isClosed method generally cannot be called to determine
|
|
766
717
|
// whether a connection to a database is valid or invalid ...
|
|
767
718
|
return context.runtime.newBoolean(!connection.isClosed());
|
|
@@ -774,10 +725,10 @@ public class RubyJdbcConnection extends RubyObject {
|
|
|
774
725
|
public IRubyObject close(final ThreadContext context) {
|
|
775
726
|
final Connection connection = getConnection(false);
|
|
776
727
|
|
|
777
|
-
if (connection == null) return context.
|
|
728
|
+
if (connection == null) return context.fals;
|
|
778
729
|
|
|
779
730
|
try {
|
|
780
|
-
if (connection.isClosed()) return context.
|
|
731
|
+
if (connection.isClosed()) return context.fals;
|
|
781
732
|
|
|
782
733
|
setConnection(null); // does connection.close();
|
|
783
734
|
} catch (Exception e) {
|
|
@@ -787,69 +738,65 @@ public class RubyJdbcConnection extends RubyObject {
|
|
|
787
738
|
|
|
788
739
|
// ActiveRecord expects a closed connection to not try and re-open a connection
|
|
789
740
|
// whereas JNDI expects that.
|
|
790
|
-
if (!
|
|
741
|
+
if (!jndi) disconnect(context);
|
|
791
742
|
|
|
792
|
-
return context.
|
|
743
|
+
return context.tru;
|
|
793
744
|
}
|
|
794
745
|
|
|
795
746
|
@JRubyMethod(name = "database_name")
|
|
796
747
|
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);
|
|
748
|
+
return withConnection(context, connection -> {
|
|
749
|
+
String name = connection.getCatalog();
|
|
750
|
+
if ( name == null ) {
|
|
751
|
+
name = connection.getMetaData().getUserName();
|
|
752
|
+
if ( name == null ) return context.nil;
|
|
805
753
|
}
|
|
754
|
+
return context.runtime.newString(name);
|
|
806
755
|
});
|
|
807
756
|
}
|
|
808
757
|
|
|
809
758
|
@JRubyMethod(name = "execute", required = 1)
|
|
810
759
|
public IRubyObject execute(final ThreadContext context, final IRubyObject sql) {
|
|
811
760
|
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();
|
|
761
|
+
return withConnection(context, connection -> {
|
|
762
|
+
Statement statement = null;
|
|
763
|
+
try {
|
|
764
|
+
statement = createStatement(context, connection);
|
|
822
765
|
|
|
823
|
-
|
|
824
|
-
|
|
766
|
+
// For DBs that do support multiple statements, lets return the last result set
|
|
767
|
+
// to be consistent with AR
|
|
768
|
+
boolean hasResultSet = doExecute(statement, query);
|
|
769
|
+
int updateCount = statement.getUpdateCount();
|
|
825
770
|
|
|
826
|
-
|
|
771
|
+
IRubyObject result = context.nil; // If no results, return nil
|
|
772
|
+
ResultSet resultSet;
|
|
827
773
|
|
|
828
|
-
|
|
829
|
-
resultSet = statement.getResultSet();
|
|
774
|
+
while (hasResultSet || updateCount != -1) {
|
|
830
775
|
|
|
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
|
-
}
|
|
776
|
+
if (hasResultSet) {
|
|
777
|
+
resultSet = statement.getResultSet();
|
|
839
778
|
|
|
840
|
-
//
|
|
841
|
-
|
|
842
|
-
|
|
779
|
+
// Unfortunately the result set gets closed when getMoreResults()
|
|
780
|
+
// is called, so we have to process the result sets as we get them
|
|
781
|
+
// this shouldn't be an issue in most cases since we're only getting 1 result set anyways
|
|
782
|
+
result = mapExecuteResult(context, connection, resultSet);
|
|
783
|
+
resultSet.close();
|
|
784
|
+
} else {
|
|
785
|
+
result = context.runtime.newFixnum(updateCount);
|
|
843
786
|
}
|
|
844
787
|
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
debugErrorSQL(context, query);
|
|
849
|
-
throw e;
|
|
850
|
-
} finally {
|
|
851
|
-
close(statement);
|
|
788
|
+
// Check to see if there is another result set
|
|
789
|
+
hasResultSet = statement.getMoreResults();
|
|
790
|
+
updateCount = statement.getUpdateCount();
|
|
852
791
|
}
|
|
792
|
+
|
|
793
|
+
return result;
|
|
794
|
+
|
|
795
|
+
} catch (final SQLException e) {
|
|
796
|
+
debugErrorSQL(context, query);
|
|
797
|
+
throw e;
|
|
798
|
+
} finally {
|
|
799
|
+
close(statement);
|
|
853
800
|
}
|
|
854
801
|
});
|
|
855
802
|
}
|
|
@@ -928,7 +875,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
|
928
875
|
}
|
|
929
876
|
|
|
930
877
|
return mapGeneratedKeys(context, connection, statement);
|
|
931
|
-
|
|
932
878
|
} catch (final SQLException e) {
|
|
933
879
|
debugErrorSQL(context, query);
|
|
934
880
|
throw e;
|
|
@@ -971,7 +917,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
|
971
917
|
setStatementParameters(context, connection, statement, (RubyArray) binds);
|
|
972
918
|
statement.executeUpdate();
|
|
973
919
|
return mapGeneratedKeys(context, connection, statement);
|
|
974
|
-
|
|
975
920
|
} catch (final SQLException e) {
|
|
976
921
|
debugErrorSQL(context, query);
|
|
977
922
|
throw e;
|
|
@@ -997,22 +942,20 @@ public class RubyJdbcConnection extends RubyObject {
|
|
|
997
942
|
*/
|
|
998
943
|
@JRubyMethod(name = {"execute_update", "execute_delete"}, required = 1)
|
|
999
944
|
public IRubyObject execute_update(final ThreadContext context, final IRubyObject sql) {
|
|
1000
|
-
return withConnection(context,
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
final String query = sqlString(sql);
|
|
945
|
+
return withConnection(context, (Callable<IRubyObject>) connection -> {
|
|
946
|
+
Statement statement = null;
|
|
947
|
+
final String query = sqlString(sql);
|
|
1004
948
|
|
|
1005
|
-
|
|
1006
|
-
|
|
949
|
+
try {
|
|
950
|
+
statement = createStatement(context, connection);
|
|
1007
951
|
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
}
|
|
952
|
+
final int rowCount = statement.executeUpdate(query);
|
|
953
|
+
return context.runtime.newFixnum(rowCount);
|
|
954
|
+
} catch (final SQLException e) {
|
|
955
|
+
debugErrorSQL(context, query);
|
|
956
|
+
throw e;
|
|
957
|
+
} finally {
|
|
958
|
+
close(statement);
|
|
1016
959
|
}
|
|
1017
960
|
});
|
|
1018
961
|
}
|
|
@@ -1028,21 +971,19 @@ public class RubyJdbcConnection extends RubyObject {
|
|
|
1028
971
|
*/
|
|
1029
972
|
@JRubyMethod(name = {"execute_prepared_update", "execute_prepared_delete"}, required = 2)
|
|
1030
973
|
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
|
-
}
|
|
974
|
+
return withConnection(context, (Callable<IRubyObject>) connection -> {
|
|
975
|
+
PreparedStatement statement = null;
|
|
976
|
+
final String query = sqlString(sql);
|
|
977
|
+
try {
|
|
978
|
+
statement = connection.prepareStatement(query);
|
|
979
|
+
setStatementParameters(context, connection, statement, (RubyArray) binds);
|
|
980
|
+
final int rowCount = statement.executeUpdate();
|
|
981
|
+
return context.runtime.newFixnum(rowCount);
|
|
982
|
+
} catch (final SQLException e) {
|
|
983
|
+
debugErrorSQL(context, query);
|
|
984
|
+
throw e;
|
|
985
|
+
} finally {
|
|
986
|
+
close(statement);
|
|
1046
987
|
}
|
|
1047
988
|
});
|
|
1048
989
|
}
|
|
@@ -1089,50 +1030,48 @@ public class RubyJdbcConnection extends RubyObject {
|
|
|
1089
1030
|
|
|
1090
1031
|
private IRubyObject doExecuteQueryRaw(final ThreadContext context,
|
|
1091
1032
|
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
|
-
}
|
|
1033
|
+
return withConnection(context, connection -> {
|
|
1034
|
+
Statement statement = null; boolean hasResult;
|
|
1035
|
+
try {
|
|
1036
|
+
if ( binds == null || binds.isEmpty()) { // plain statement
|
|
1037
|
+
statement = createStatement(context, connection);
|
|
1038
|
+
statement.setMaxRows(maxRows); // zero means there is no limit
|
|
1039
|
+
hasResult = statement.execute(query);
|
|
1040
|
+
}
|
|
1041
|
+
else {
|
|
1042
|
+
final PreparedStatement prepStatement;
|
|
1043
|
+
statement = prepStatement = connection.prepareStatement(query);
|
|
1044
|
+
if (fetchSize != 0) statement.setFetchSize(fetchSize);
|
|
1045
|
+
statement.setMaxRows(maxRows); // zero means there is no limit
|
|
1046
|
+
setStatementParameters(context, connection, prepStatement, binds);
|
|
1047
|
+
hasResult = prepStatement.execute();
|
|
1048
|
+
}
|
|
1109
1049
|
|
|
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
|
-
}
|
|
1050
|
+
if (block.isGiven()) {
|
|
1118
1051
|
if (hasResult) {
|
|
1119
|
-
|
|
1052
|
+
// yield(id1, name1) ... row 1 result data
|
|
1053
|
+
// yield(id2, name2) ... row 2 result data
|
|
1054
|
+
return yieldResultRows(context, connection, statement.getResultSet(), block);
|
|
1120
1055
|
}
|
|
1121
|
-
return context.
|
|
1056
|
+
return context.nil;
|
|
1122
1057
|
}
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
throw e;
|
|
1126
|
-
}
|
|
1127
|
-
finally {
|
|
1128
|
-
close(statement);
|
|
1058
|
+
if (hasResult) {
|
|
1059
|
+
return mapToRawResult(context, connection, statement.getResultSet(), false);
|
|
1129
1060
|
}
|
|
1061
|
+
return context.runtime.newEmptyArray();
|
|
1062
|
+
}
|
|
1063
|
+
catch (final SQLException e) {
|
|
1064
|
+
debugErrorSQL(context, query);
|
|
1065
|
+
throw e;
|
|
1066
|
+
}
|
|
1067
|
+
finally {
|
|
1068
|
+
close(statement);
|
|
1130
1069
|
}
|
|
1131
1070
|
});
|
|
1132
1071
|
}
|
|
1133
1072
|
|
|
1134
1073
|
protected static String sqlString(final IRubyObject sql) {
|
|
1135
|
-
return sql
|
|
1074
|
+
return sql.convertToString().decodeString();
|
|
1136
1075
|
}
|
|
1137
1076
|
|
|
1138
1077
|
/**
|
|
@@ -1145,26 +1084,24 @@ public class RubyJdbcConnection extends RubyObject {
|
|
|
1145
1084
|
*/
|
|
1146
1085
|
@JRubyMethod(required = 1)
|
|
1147
1086
|
public IRubyObject execute_query(final ThreadContext context, final IRubyObject sql) {
|
|
1148
|
-
return withConnection(context,
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
statement = createStatement(context, connection);
|
|
1087
|
+
return withConnection(context, connection -> {
|
|
1088
|
+
Statement statement = null;
|
|
1089
|
+
final String query = sqlString(sql);
|
|
1090
|
+
try {
|
|
1091
|
+
statement = createStatement(context, connection);
|
|
1154
1092
|
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1093
|
+
// At least until AR 5.1 #exec_query still gets called for things that don't return results in some cases :(
|
|
1094
|
+
if (statement.execute(query)) {
|
|
1095
|
+
return mapQueryResult(context, connection, statement.getResultSet());
|
|
1096
|
+
}
|
|
1159
1097
|
|
|
1160
|
-
|
|
1098
|
+
return newEmptyResult(context);
|
|
1161
1099
|
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
}
|
|
1100
|
+
} catch (final SQLException e) {
|
|
1101
|
+
debugErrorSQL(context, query);
|
|
1102
|
+
throw e;
|
|
1103
|
+
} finally {
|
|
1104
|
+
close(statement);
|
|
1168
1105
|
}
|
|
1169
1106
|
});
|
|
1170
1107
|
}
|
|
@@ -1177,13 +1114,11 @@ public class RubyJdbcConnection extends RubyObject {
|
|
|
1177
1114
|
*/
|
|
1178
1115
|
@JRubyMethod(required = 1)
|
|
1179
1116
|
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
|
-
}
|
|
1117
|
+
return withConnection(context, connection -> {
|
|
1118
|
+
final String query = sql.convertToString().getUnicodeValue();
|
|
1119
|
+
PreparedStatement statement = connection.prepareStatement(query);
|
|
1120
|
+
if (fetchSize != 0) statement.setFetchSize(fetchSize);
|
|
1121
|
+
return JavaUtil.convertJavaToRuby(context.runtime, statement);
|
|
1187
1122
|
});
|
|
1188
1123
|
}
|
|
1189
1124
|
|
|
@@ -1206,40 +1141,40 @@ public class RubyJdbcConnection extends RubyObject {
|
|
|
1206
1141
|
@JRubyMethod(required = 3)
|
|
1207
1142
|
public IRubyObject execute_prepared_query(final ThreadContext context, final IRubyObject sql,
|
|
1208
1143
|
final IRubyObject binds, final IRubyObject cachedStatement) {
|
|
1209
|
-
return withConnection(context,
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
PreparedStatement statement = null;
|
|
1144
|
+
return withConnection(context, connection -> {
|
|
1145
|
+
final boolean cached = !(cachedStatement == null || cachedStatement.isNil());
|
|
1146
|
+
String query = null;
|
|
1147
|
+
PreparedStatement statement = null;
|
|
1214
1148
|
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1149
|
+
try {
|
|
1150
|
+
if (cached) {
|
|
1151
|
+
statement = (PreparedStatement) JavaEmbedUtils.rubyToJava(cachedStatement);
|
|
1152
|
+
} else {
|
|
1153
|
+
query = sql.convertToString().getUnicodeValue();
|
|
1154
|
+
statement = connection.prepareStatement(query);
|
|
1155
|
+
if (fetchSize != 0) statement.setFetchSize(fetchSize);
|
|
1156
|
+
}
|
|
1222
1157
|
|
|
1223
|
-
|
|
1158
|
+
setStatementParameters(context, connection, statement, (RubyArray) binds);
|
|
1224
1159
|
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1160
|
+
if (statement.execute()) {
|
|
1161
|
+
ResultSet resultSet = statement.getResultSet();
|
|
1162
|
+
IRubyObject results = mapQueryResult(context, connection, resultSet);
|
|
1163
|
+
resultSet.close();
|
|
1229
1164
|
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1165
|
+
return results;
|
|
1166
|
+
} else {
|
|
1167
|
+
return newEmptyResult(context);
|
|
1168
|
+
}
|
|
1169
|
+
} catch (final SQLException e) {
|
|
1170
|
+
if (query == null) query = sql.convertToString().getUnicodeValue();
|
|
1171
|
+
debugErrorSQL(context, query);
|
|
1172
|
+
throw e;
|
|
1173
|
+
} finally {
|
|
1174
|
+
if ( cached ) {
|
|
1175
|
+
statement.clearParameters();
|
|
1176
|
+
} else {
|
|
1177
|
+
close(statement);
|
|
1243
1178
|
}
|
|
1244
1179
|
}
|
|
1245
1180
|
});
|
|
@@ -1251,35 +1186,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
|
1251
1186
|
return mapToResult(context, connection, resultSet, columns);
|
|
1252
1187
|
}
|
|
1253
1188
|
|
|
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
1189
|
@JRubyMethod(name = "supported_data_types")
|
|
1284
1190
|
public IRubyObject supported_data_types(final ThreadContext context) throws SQLException {
|
|
1285
1191
|
final Connection connection = getConnection(true);
|
|
@@ -1303,12 +1209,10 @@ public class RubyJdbcConnection extends RubyObject {
|
|
|
1303
1209
|
protected static final int PRIMARY_KEYS_COLUMN_NAME = 4;
|
|
1304
1210
|
|
|
1305
1211
|
private List<RubyString> primaryKeys(final ThreadContext context, final String tableName) {
|
|
1306
|
-
return withConnection(context,
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
return primaryKeys(context, connection, table);
|
|
1311
|
-
}
|
|
1212
|
+
return withConnection(context, connection -> {
|
|
1213
|
+
final String _tableName = caseConvertIdentifierForJdbc(connection, tableName);
|
|
1214
|
+
final TableName table = extractTableName(connection, null, null, _tableName);
|
|
1215
|
+
return primaryKeys(context, connection, table);
|
|
1312
1216
|
});
|
|
1313
1217
|
}
|
|
1314
1218
|
|
|
@@ -1316,7 +1220,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
|
1316
1220
|
final Connection connection, final TableName table) throws SQLException {
|
|
1317
1221
|
final DatabaseMetaData metaData = connection.getMetaData();
|
|
1318
1222
|
ResultSet resultSet = null;
|
|
1319
|
-
final List<RubyString> keyNames = new ArrayList
|
|
1223
|
+
final List<RubyString> keyNames = new ArrayList<>();
|
|
1320
1224
|
try {
|
|
1321
1225
|
resultSet = metaData.getPrimaryKeys(table.catalog, table.schema, table.name);
|
|
1322
1226
|
final Ruby runtime = context.runtime;
|
|
@@ -1330,26 +1234,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
|
1330
1234
|
return keyNames;
|
|
1331
1235
|
}
|
|
1332
1236
|
|
|
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
1237
|
@JRubyMethod(name = "tables", required = 0, optional = 4)
|
|
1354
1238
|
public IRubyObject tables(final ThreadContext context, final IRubyObject[] args) {
|
|
1355
1239
|
switch ( args.length ) {
|
|
@@ -1367,11 +1251,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
|
1367
1251
|
|
|
1368
1252
|
protected IRubyObject tables(final ThreadContext context,
|
|
1369
1253
|
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
|
-
});
|
|
1254
|
+
return withConnection(context, connection -> matchTables(context, connection, catalog, schemaPattern, tablePattern, types, false));
|
|
1375
1255
|
}
|
|
1376
1256
|
|
|
1377
1257
|
protected String[] getTableTypes() {
|
|
@@ -1401,40 +1281,36 @@ public class RubyJdbcConnection extends RubyObject {
|
|
|
1401
1281
|
|
|
1402
1282
|
protected IRubyObject tableExists(final ThreadContext context,
|
|
1403
1283
|
final String defaultSchema, final String tableName) {
|
|
1404
|
-
return withConnection(context,
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
return context.runtime.newBoolean( tableExists(context, connection, components) );
|
|
1408
|
-
}
|
|
1284
|
+
return withConnection(context, connection -> {
|
|
1285
|
+
final TableName components = extractTableName(connection, defaultSchema, tableName);
|
|
1286
|
+
return context.runtime.newBoolean( tableExists(context, connection, components) );
|
|
1409
1287
|
});
|
|
1410
1288
|
}
|
|
1411
1289
|
|
|
1412
1290
|
@JRubyMethod(name = {"columns", "columns_internal"}, required = 1, optional = 2)
|
|
1413
1291
|
public RubyArray columns_internal(final ThreadContext context, final IRubyObject[] args)
|
|
1414
1292
|
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);
|
|
1293
|
+
return withConnection(context, connection -> {
|
|
1294
|
+
ResultSet columns = null;
|
|
1295
|
+
try {
|
|
1296
|
+
final String tableName = args[0].toString();
|
|
1297
|
+
// optionals (NOTE: catalog argumnet was never used before 1.3.0) :
|
|
1298
|
+
final String catalog = args.length > 1 ? toStringOrNull(args[1]) : null;
|
|
1299
|
+
final String defaultSchema = args.length > 2 ? toStringOrNull(args[2]) : null;
|
|
1426
1300
|
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
}
|
|
1301
|
+
final TableName components;
|
|
1302
|
+
components = extractTableName(connection, catalog, defaultSchema, tableName);
|
|
1430
1303
|
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
return mapColumnsResult(context, metaData, components, columns);
|
|
1434
|
-
}
|
|
1435
|
-
finally {
|
|
1436
|
-
close(columns);
|
|
1304
|
+
if ( ! tableExists(context, connection, components) ) {
|
|
1305
|
+
throw new SQLException("table: " + tableName + " does not exist");
|
|
1437
1306
|
}
|
|
1307
|
+
|
|
1308
|
+
final DatabaseMetaData metaData = connection.getMetaData();
|
|
1309
|
+
columns = metaData.getColumns(components.catalog, components.schema, components.name, null);
|
|
1310
|
+
return mapColumnsResult(context, metaData, components, columns);
|
|
1311
|
+
}
|
|
1312
|
+
finally {
|
|
1313
|
+
close(columns);
|
|
1438
1314
|
}
|
|
1439
1315
|
});
|
|
1440
1316
|
}
|
|
@@ -1464,70 +1340,68 @@ public class RubyJdbcConnection extends RubyObject {
|
|
|
1464
1340
|
* should filter the return from this method instead.
|
|
1465
1341
|
*/
|
|
1466
1342
|
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);
|
|
1471
|
-
|
|
1472
|
-
String _tableName = caseConvertIdentifierForJdbc(connection, tableName);
|
|
1473
|
-
String _schemaName = caseConvertIdentifierForJdbc(connection, schemaName);
|
|
1474
|
-
final TableName table = extractTableName(connection, null, _schemaName, _tableName);
|
|
1343
|
+
return withConnection(context, (Callable<IRubyObject>) connection -> {
|
|
1344
|
+
final Ruby runtime = context.runtime;
|
|
1345
|
+
final RubyClass IndexDefinition = getIndexDefinition(context);
|
|
1475
1346
|
|
|
1476
|
-
|
|
1347
|
+
String _tableName = caseConvertIdentifierForJdbc(connection, tableName);
|
|
1348
|
+
String _schemaName = caseConvertIdentifierForJdbc(connection, schemaName);
|
|
1349
|
+
final TableName table = extractTableName(connection, null, _schemaName, _tableName);
|
|
1477
1350
|
|
|
1478
|
-
|
|
1479
|
-
final RubyArray indexes = RubyArray.newArray(runtime, 8);
|
|
1480
|
-
try {
|
|
1481
|
-
final DatabaseMetaData metaData = connection.getMetaData();
|
|
1482
|
-
indexInfoSet = metaData.getIndexInfo(table.catalog, table.schema, table.name, false, true);
|
|
1483
|
-
String currentIndex = null;
|
|
1484
|
-
RubyArray currentColumns = null;
|
|
1351
|
+
final List<RubyString> primaryKeys = primaryKeys(context, connection, table);
|
|
1485
1352
|
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1353
|
+
ResultSet indexInfoSet = null;
|
|
1354
|
+
final RubyArray indexes = RubyArray.newArray(runtime, 8);
|
|
1355
|
+
try {
|
|
1356
|
+
final DatabaseMetaData metaData = connection.getMetaData();
|
|
1357
|
+
indexInfoSet = metaData.getIndexInfo(table.catalog, table.schema, table.name, false, true);
|
|
1358
|
+
String currentIndex = null;
|
|
1489
1359
|
|
|
1490
|
-
|
|
1360
|
+
while ( indexInfoSet.next() ) {
|
|
1361
|
+
String indexName = indexInfoSet.getString(INDEX_INFO_NAME);
|
|
1362
|
+
if ( indexName == null ) continue;
|
|
1363
|
+
RubyArray currentColumns = null;
|
|
1491
1364
|
|
|
1492
|
-
|
|
1493
|
-
final RubyString rubyColumnName = cachedString(
|
|
1494
|
-
context, caseConvertIdentifierForRails(metaData, columnName)
|
|
1495
|
-
);
|
|
1496
|
-
if ( primaryKeys.contains(rubyColumnName) ) continue;
|
|
1365
|
+
indexName = caseConvertIdentifierForRails(metaData, indexName);
|
|
1497
1366
|
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1367
|
+
final String columnName = indexInfoSet.getString(INDEX_INFO_COLUMN_NAME);
|
|
1368
|
+
final RubyString rubyColumnName = cachedString(
|
|
1369
|
+
context, caseConvertIdentifierForRails(metaData, columnName)
|
|
1370
|
+
);
|
|
1371
|
+
if ( primaryKeys.contains(rubyColumnName) ) continue;
|
|
1501
1372
|
|
|
1502
|
-
|
|
1503
|
-
|
|
1373
|
+
// We are working on a new index
|
|
1374
|
+
if ( ! indexName.equals(currentIndex) ) {
|
|
1375
|
+
currentIndex = indexName;
|
|
1504
1376
|
|
|
1505
|
-
|
|
1377
|
+
String indexTableName = indexInfoSet.getString(INDEX_INFO_TABLE_NAME);
|
|
1378
|
+
indexTableName = caseConvertIdentifierForRails(metaData, indexTableName);
|
|
1506
1379
|
|
|
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
|
-
};
|
|
1380
|
+
final boolean nonUnique = indexInfoSet.getBoolean(INDEX_INFO_NON_UNIQUE);
|
|
1514
1381
|
|
|
1515
|
-
|
|
1516
|
-
|
|
1382
|
+
IRubyObject[] args = new IRubyObject[] {
|
|
1383
|
+
cachedString(context, indexTableName), // table_name
|
|
1384
|
+
cachedString(context, indexName), // index_name
|
|
1385
|
+
nonUnique ? context.fals : context.tru, // unique
|
|
1386
|
+
currentColumns = RubyArray.newArray(runtime, 4) // [] column names
|
|
1387
|
+
// orders, (since AR 3.2) where, type, using (AR 4.0)
|
|
1388
|
+
};
|
|
1517
1389
|
|
|
1518
|
-
|
|
1519
|
-
if ( currentColumns != null ) currentColumns.append(rubyColumnName);
|
|
1390
|
+
indexes.append( IndexDefinition.newInstance(context, args, Block.NULL_BLOCK) ); // IndexDefinition.new
|
|
1520
1391
|
}
|
|
1521
1392
|
|
|
1522
|
-
|
|
1393
|
+
// one or more columns can be associated with an index
|
|
1394
|
+
if ( currentColumns != null ) currentColumns.append(rubyColumnName);
|
|
1395
|
+
}
|
|
1523
1396
|
|
|
1524
|
-
|
|
1525
|
-
|
|
1397
|
+
return indexes;
|
|
1398
|
+
|
|
1399
|
+
} finally { close(indexInfoSet); }
|
|
1526
1400
|
});
|
|
1527
1401
|
}
|
|
1528
1402
|
|
|
1529
1403
|
protected RubyClass getIndexDefinition(final ThreadContext context) {
|
|
1530
|
-
final RubyClass adapterClass =
|
|
1404
|
+
final RubyClass adapterClass = adapter.getMetaClass();
|
|
1531
1405
|
IRubyObject IDef = adapterClass.getConstantAt("IndexDefinition");
|
|
1532
1406
|
return IDef != null ? (RubyClass) IDef : getIndexDefinition(context.runtime);
|
|
1533
1407
|
}
|
|
@@ -1538,57 +1412,55 @@ public class RubyJdbcConnection extends RubyObject {
|
|
|
1538
1412
|
}
|
|
1539
1413
|
|
|
1540
1414
|
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);
|
|
1415
|
+
return withConnection(context, (Callable<IRubyObject>) connection -> {
|
|
1416
|
+
final Ruby runtime = context.runtime;
|
|
1417
|
+
final RubyClass FKDefinition = getForeignKeyDefinition(context);
|
|
1545
1418
|
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1419
|
+
String _tableName = caseConvertIdentifierForJdbc(connection, tableName);
|
|
1420
|
+
String _schemaName = caseConvertIdentifierForJdbc(connection, schemaName);
|
|
1421
|
+
final TableName table = extractTableName(connection, catalog, _schemaName, _tableName);
|
|
1549
1422
|
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1423
|
+
ResultSet fkInfoSet = null;
|
|
1424
|
+
final List<IRubyObject> fKeys = new ArrayList<>(8);
|
|
1425
|
+
try {
|
|
1426
|
+
final DatabaseMetaData metaData = connection.getMetaData();
|
|
1427
|
+
fkInfoSet = metaData.getImportedKeys(table.catalog, table.schema, table.name);
|
|
1555
1428
|
|
|
1556
|
-
|
|
1557
|
-
|
|
1429
|
+
while ( fkInfoSet.next() ) {
|
|
1430
|
+
final RubyHash options = RubyHash.newHash(runtime);
|
|
1558
1431
|
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1432
|
+
String fkName = fkInfoSet.getString("FK_NAME");
|
|
1433
|
+
if (fkName != null) {
|
|
1434
|
+
fkName = caseConvertIdentifierForRails(metaData, fkName);
|
|
1435
|
+
options.put(runtime.newSymbol("name"), fkName);
|
|
1436
|
+
}
|
|
1564
1437
|
|
|
1565
|
-
|
|
1566
|
-
|
|
1438
|
+
String columnName = fkInfoSet.getString("FKCOLUMN_NAME");
|
|
1439
|
+
options.put(runtime.newSymbol("column"), caseConvertIdentifierForRails(metaData, columnName));
|
|
1567
1440
|
|
|
1568
|
-
|
|
1569
|
-
|
|
1441
|
+
columnName = fkInfoSet.getString("PKCOLUMN_NAME");
|
|
1442
|
+
options.put(runtime.newSymbol("primary_key"), caseConvertIdentifierForRails(metaData, columnName));
|
|
1570
1443
|
|
|
1571
|
-
|
|
1572
|
-
|
|
1444
|
+
String fkTableName = fkInfoSet.getString("FKTABLE_NAME");
|
|
1445
|
+
fkTableName = caseConvertIdentifierForRails(metaData, fkTableName);
|
|
1573
1446
|
|
|
1574
|
-
|
|
1575
|
-
|
|
1447
|
+
String pkTableName = fkInfoSet.getString("PKTABLE_NAME");
|
|
1448
|
+
pkTableName = caseConvertIdentifierForRails(metaData, pkTableName);
|
|
1576
1449
|
|
|
1577
|
-
|
|
1578
|
-
|
|
1450
|
+
final String onDelete = extractForeignKeyRule( fkInfoSet.getInt("DELETE_RULE") );
|
|
1451
|
+
if ( onDelete != null ) options.op_aset(context, runtime.newSymbol("on_delete"), runtime.newSymbol(onDelete));
|
|
1579
1452
|
|
|
1580
|
-
|
|
1581
|
-
|
|
1453
|
+
final String onUpdate = extractForeignKeyRule( fkInfoSet.getInt("UPDATE_RULE") );
|
|
1454
|
+
if ( onUpdate != null ) options.op_aset(context, runtime.newSymbol("on_update"), runtime.newSymbol(onUpdate));
|
|
1582
1455
|
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1456
|
+
IRubyObject from_table = cachedString(context, fkTableName);
|
|
1457
|
+
IRubyObject to_table = cachedString(context, pkTableName);
|
|
1458
|
+
fKeys.add( FKDefinition.newInstance(context, from_table, to_table, options, Block.NULL_BLOCK) ); // ForeignKeyDefinition.new
|
|
1459
|
+
}
|
|
1587
1460
|
|
|
1588
|
-
|
|
1461
|
+
return runtime.newArray(fKeys);
|
|
1589
1462
|
|
|
1590
|
-
|
|
1591
|
-
}
|
|
1463
|
+
} finally { close(fkInfoSet); }
|
|
1592
1464
|
});
|
|
1593
1465
|
}
|
|
1594
1466
|
|
|
@@ -1603,7 +1475,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
|
1603
1475
|
}
|
|
1604
1476
|
|
|
1605
1477
|
protected RubyClass getForeignKeyDefinition(final ThreadContext context) {
|
|
1606
|
-
final RubyClass adapterClass =
|
|
1478
|
+
final RubyClass adapterClass = adapter.getMetaClass();
|
|
1607
1479
|
IRubyObject FKDef = adapterClass.getConstantAt("ForeignKeyDefinition");
|
|
1608
1480
|
return FKDef != null ? (RubyClass) FKDef : getForeignKeyDefinition(context.runtime);
|
|
1609
1481
|
}
|
|
@@ -1611,42 +1483,34 @@ public class RubyJdbcConnection extends RubyObject {
|
|
|
1611
1483
|
|
|
1612
1484
|
@JRubyMethod(name = "supports_foreign_keys?")
|
|
1613
1485
|
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
|
-
}
|
|
1486
|
+
return withConnection(context, (Callable<IRubyObject>) connection -> {
|
|
1487
|
+
final DatabaseMetaData metaData = connection.getMetaData();
|
|
1488
|
+
return context.runtime.newBoolean( metaData.supportsIntegrityEnhancementFacility() );
|
|
1619
1489
|
});
|
|
1620
1490
|
}
|
|
1621
1491
|
|
|
1622
1492
|
@JRubyMethod(name = "supports_views?")
|
|
1623
1493
|
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
|
-
}
|
|
1494
|
+
return withConnection(context, (Callable<IRubyObject>) connection -> {
|
|
1495
|
+
final DatabaseMetaData metaData = connection.getMetaData();
|
|
1496
|
+
final ResultSet tableTypes = metaData.getTableTypes();
|
|
1497
|
+
try {
|
|
1498
|
+
while ( tableTypes.next() ) {
|
|
1499
|
+
if ( "VIEW".equalsIgnoreCase( tableTypes.getString(1) ) ) {
|
|
1500
|
+
return context.runtime.newBoolean( true );
|
|
1633
1501
|
}
|
|
1634
1502
|
}
|
|
1635
|
-
finally {
|
|
1636
|
-
close(tableTypes);
|
|
1637
|
-
}
|
|
1638
|
-
return context.runtime.newBoolean( false );
|
|
1639
1503
|
}
|
|
1504
|
+
finally {
|
|
1505
|
+
close(tableTypes);
|
|
1506
|
+
}
|
|
1507
|
+
return context.runtime.newBoolean( false );
|
|
1640
1508
|
});
|
|
1641
1509
|
}
|
|
1642
1510
|
|
|
1643
1511
|
@JRubyMethod(name = "with_jdbc_connection", alias = "with_connection_retry_guard", frame = true)
|
|
1644
1512
|
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
|
-
});
|
|
1513
|
+
return withConnection(context, connection -> block.call(context, convertJavaToRuby(connection)));
|
|
1650
1514
|
}
|
|
1651
1515
|
|
|
1652
1516
|
/*
|
|
@@ -1707,24 +1571,22 @@ public class RubyJdbcConnection extends RubyObject {
|
|
|
1707
1571
|
// TODO: Fix this, the columns don't have the info needed to handle this anymore
|
|
1708
1572
|
// currently commented out so that it will compile
|
|
1709
1573
|
|
|
1710
|
-
return withConnection(context,
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
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();
|
|
1574
|
+
return withConnection(context, connection -> {
|
|
1575
|
+
PreparedStatement statement = null;
|
|
1576
|
+
try {
|
|
1577
|
+
statement = connection.prepareStatement(sql);
|
|
1578
|
+
/*
|
|
1579
|
+
if ( binary ) { // blob
|
|
1580
|
+
setBlobParameter(context, connection, statement, 1, value, column, Types.BLOB);
|
|
1581
|
+
}
|
|
1582
|
+
else { // clob
|
|
1583
|
+
setClobParameter(context, connection, statement, 1, value, column, Types.CLOB);
|
|
1725
1584
|
}
|
|
1726
|
-
|
|
1585
|
+
setStatementParameter(context, context.runtime, connection, statement, 2, idValue, idColumn);
|
|
1586
|
+
*/
|
|
1587
|
+
return statement.executeUpdate();
|
|
1727
1588
|
}
|
|
1589
|
+
finally { close(statement); }
|
|
1728
1590
|
});
|
|
1729
1591
|
}
|
|
1730
1592
|
|
|
@@ -1780,7 +1642,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
|
1780
1642
|
final IRubyObject self, final IRubyObject config, final Block block) {
|
|
1781
1643
|
final IRubyObject ds_or_name = rawDataSourceOrName(context, config);
|
|
1782
1644
|
|
|
1783
|
-
if ( ds_or_name == null ) return context.
|
|
1645
|
+
if ( ds_or_name == null ) return context.fals;
|
|
1784
1646
|
|
|
1785
1647
|
final javax.sql.DataSource dataSource;
|
|
1786
1648
|
final Object dsOrName = ds_or_name.toJava(Object.class);
|
|
@@ -1836,7 +1698,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
|
1836
1698
|
}
|
|
1837
1699
|
}
|
|
1838
1700
|
|
|
1839
|
-
if ( configValue == null || configValue == context.nil || configValue ==
|
|
1701
|
+
if ( configValue == null || configValue == context.nil || configValue == context.fals ) {
|
|
1840
1702
|
return null;
|
|
1841
1703
|
}
|
|
1842
1704
|
return configValue;
|
|
@@ -1859,13 +1721,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
|
1859
1721
|
}
|
|
1860
1722
|
}
|
|
1861
1723
|
|
|
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
1724
|
private ConnectionFactory setDriverFactory(final ThreadContext context) {
|
|
1870
1725
|
|
|
1871
1726
|
final IRubyObject url = getConfigValue(context, "url");
|
|
@@ -1965,12 +1820,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
|
1965
1820
|
return props;
|
|
1966
1821
|
}
|
|
1967
1822
|
|
|
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
1823
|
private ConnectionFactory setDataSourceFactory(final ThreadContext context) {
|
|
1975
1824
|
final javax.sql.DataSource dataSource; final String lookupName;
|
|
1976
1825
|
IRubyObject value = getConfigValue(context, "data_source");
|
|
@@ -1992,28 +1841,10 @@ public class RubyJdbcConnection extends RubyObject {
|
|
|
1992
1841
|
private static volatile boolean defaultConfigJndi;
|
|
1993
1842
|
private static transient ConnectionFactory defaultConnectionFactory;
|
|
1994
1843
|
|
|
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
1844
|
/**
|
|
2012
1845
|
* @return whether the connection factory is JNDI based
|
|
2013
1846
|
*/
|
|
2014
1847
|
private boolean setupConnectionFactory(final ThreadContext context) {
|
|
2015
|
-
final IRubyObject config = getConfig();
|
|
2016
|
-
|
|
2017
1848
|
if ( defaultConfig == null ) {
|
|
2018
1849
|
synchronized(RubyJdbcConnection.class) {
|
|
2019
1850
|
if ( defaultConfig == null ) {
|
|
@@ -2045,18 +1876,17 @@ public class RubyJdbcConnection extends RubyObject {
|
|
|
2045
1876
|
|
|
2046
1877
|
@JRubyMethod(name = "jndi?", alias = "jndi_connection?")
|
|
2047
1878
|
public RubyBoolean jndi_p(final ThreadContext context) {
|
|
2048
|
-
return context.runtime.newBoolean(
|
|
1879
|
+
return context.runtime.newBoolean(jndi);
|
|
2049
1880
|
}
|
|
2050
1881
|
|
|
2051
1882
|
protected boolean isJndi() { return this.jndi; }
|
|
2052
1883
|
|
|
2053
1884
|
@JRubyMethod(name = "config")
|
|
2054
|
-
public IRubyObject config() { return
|
|
1885
|
+
public IRubyObject config() { return config; }
|
|
2055
1886
|
|
|
2056
1887
|
public IRubyObject getConfig() { return this.config; }
|
|
2057
1888
|
|
|
2058
1889
|
protected final IRubyObject getConfigValue(final ThreadContext context, final String key) {
|
|
2059
|
-
final IRubyObject config = getConfig();
|
|
2060
1890
|
final RubySymbol keySym = context.runtime.newSymbol(key);
|
|
2061
1891
|
if ( config instanceof RubyHash ) {
|
|
2062
1892
|
final IRubyObject value = ((RubyHash) config).fastARef(keySym);
|
|
@@ -2067,7 +1897,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
|
2067
1897
|
|
|
2068
1898
|
protected final IRubyObject setConfigValue(final ThreadContext context,
|
|
2069
1899
|
final String key, final IRubyObject value) {
|
|
2070
|
-
final IRubyObject config = getConfig();
|
|
2071
1900
|
final RubySymbol keySym = context.runtime.newSymbol(key);
|
|
2072
1901
|
if ( config instanceof RubyHash ) {
|
|
2073
1902
|
return ((RubyHash) config).op_aset(context, keySym, value);
|
|
@@ -2077,7 +1906,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
|
2077
1906
|
|
|
2078
1907
|
protected final IRubyObject setConfigValueIfNotSet(final ThreadContext context,
|
|
2079
1908
|
final String key, final IRubyObject value) {
|
|
2080
|
-
final IRubyObject config = getConfig();
|
|
2081
1909
|
final RubySymbol keySym = context.runtime.newSymbol(key);
|
|
2082
1910
|
if ( config instanceof RubyHash ) {
|
|
2083
1911
|
final IRubyObject setValue = ((RubyHash) config).fastARef(keySym);
|
|
@@ -2097,7 +1925,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
|
2097
1925
|
protected final IRubyObject getAdapter() { return this.adapter; }
|
|
2098
1926
|
|
|
2099
1927
|
protected RubyClass getJdbcColumnClass(final ThreadContext context) {
|
|
2100
|
-
return (RubyClass)
|
|
1928
|
+
return (RubyClass) adapter.callMethod(context, "jdbc_column_class");
|
|
2101
1929
|
}
|
|
2102
1930
|
|
|
2103
1931
|
protected ConnectionFactory getConnectionFactory() throws RaiseException {
|
|
@@ -2309,7 +2137,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
|
2309
2137
|
@JRubyMethod(name = "raw_date_time?", meta = true)
|
|
2310
2138
|
public static IRubyObject useRawDateTime(final ThreadContext context, final IRubyObject self) {
|
|
2311
2139
|
if ( rawDateTime == null ) return context.nil;
|
|
2312
|
-
return context.runtime.newBoolean(
|
|
2140
|
+
return context.runtime.newBoolean(rawDateTime);
|
|
2313
2141
|
}
|
|
2314
2142
|
|
|
2315
2143
|
@JRubyMethod(name = "raw_date_time=", meta = true)
|
|
@@ -2323,17 +2151,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
|
2323
2151
|
return value;
|
|
2324
2152
|
}
|
|
2325
2153
|
|
|
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
2154
|
protected IRubyObject dateToRuby(final ThreadContext context,
|
|
2338
2155
|
final Ruby runtime, final ResultSet resultSet, final int column)
|
|
2339
2156
|
throws SQLException {
|
|
@@ -2344,11 +2161,11 @@ public class RubyJdbcConnection extends RubyObject {
|
|
|
2344
2161
|
return resultSet.wasNull() ? context.nil : RubyString.newEmptyString(runtime);
|
|
2345
2162
|
}
|
|
2346
2163
|
|
|
2347
|
-
if ( rawDateTime != null && rawDateTime
|
|
2164
|
+
if ( rawDateTime != null && rawDateTime) {
|
|
2348
2165
|
return RubyString.newString(runtime, DateTimeUtils.dateToString(value));
|
|
2349
2166
|
}
|
|
2350
2167
|
|
|
2351
|
-
return DateTimeUtils.newDateAsTime(context, value,
|
|
2168
|
+
return DateTimeUtils.newDateAsTime(context, value, null).callMethod(context, "to_date");
|
|
2352
2169
|
}
|
|
2353
2170
|
|
|
2354
2171
|
protected IRubyObject timeToRuby(final ThreadContext context,
|
|
@@ -2360,7 +2177,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
|
2360
2177
|
return resultSet.wasNull() ? context.nil : RubyString.newEmptyString(runtime);
|
|
2361
2178
|
}
|
|
2362
2179
|
|
|
2363
|
-
if ( rawDateTime != null && rawDateTime
|
|
2180
|
+
if ( rawDateTime != null && rawDateTime) {
|
|
2364
2181
|
return RubyString.newString(runtime, DateTimeUtils.timeToString(value));
|
|
2365
2182
|
}
|
|
2366
2183
|
|
|
@@ -2376,7 +2193,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
|
2376
2193
|
return resultSet.wasNull() ? context.nil : RubyString.newEmptyString(runtime);
|
|
2377
2194
|
}
|
|
2378
2195
|
|
|
2379
|
-
if ( rawDateTime != null && rawDateTime
|
|
2196
|
+
if ( rawDateTime != null && rawDateTime) {
|
|
2380
2197
|
return RubyString.newString(runtime, DateTimeUtils.timestampToString(value));
|
|
2381
2198
|
}
|
|
2382
2199
|
|
|
@@ -2388,19 +2205,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
|
2388
2205
|
return DateTimeUtils.newTime(context, value, getDefaultTimeZone(context));
|
|
2389
2206
|
}
|
|
2390
2207
|
|
|
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
2208
|
protected static Boolean rawBoolean;
|
|
2405
2209
|
static {
|
|
2406
2210
|
final String booleanRaw = SafePropertyAccessor.getProperty("arjdbc.boolean.raw");
|
|
@@ -2412,7 +2216,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
|
2412
2216
|
@JRubyMethod(name = "raw_boolean?", meta = true)
|
|
2413
2217
|
public static IRubyObject useRawBoolean(final ThreadContext context, final IRubyObject self) {
|
|
2414
2218
|
if ( rawBoolean == null ) return context.nil;
|
|
2415
|
-
return context.runtime.newBoolean(
|
|
2219
|
+
return context.runtime.newBoolean(rawBoolean);
|
|
2416
2220
|
}
|
|
2417
2221
|
|
|
2418
2222
|
@JRubyMethod(name = "raw_boolean=", meta = true)
|
|
@@ -2444,13 +2248,13 @@ public class RubyJdbcConnection extends RubyObject {
|
|
|
2444
2248
|
protected IRubyObject booleanToRuby(final ThreadContext context,
|
|
2445
2249
|
final Ruby runtime, final ResultSet resultSet, final int column)
|
|
2446
2250
|
throws SQLException {
|
|
2447
|
-
if ( rawBoolean != null && rawBoolean
|
|
2251
|
+
if ( rawBoolean != null && rawBoolean) {
|
|
2448
2252
|
final String value = resultSet.getString(column);
|
|
2449
2253
|
if ( value == null /* && resultSet.wasNull() */ ) return context.nil;
|
|
2450
2254
|
return RubyString.newUnicodeString(runtime, value);
|
|
2451
2255
|
}
|
|
2452
2256
|
final boolean value = resultSet.getBoolean(column);
|
|
2453
|
-
if (
|
|
2257
|
+
if (!value && resultSet.wasNull()) return context.nil;
|
|
2454
2258
|
return runtime.newBoolean(value);
|
|
2455
2259
|
}
|
|
2456
2260
|
|
|
@@ -2668,7 +2472,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
|
2668
2472
|
}
|
|
2669
2473
|
}
|
|
2670
2474
|
|
|
2671
|
-
protected static final Map<String, Integer> JDBC_TYPE_FOR = new HashMap
|
|
2475
|
+
protected static final Map<String, Integer> JDBC_TYPE_FOR = new HashMap<>(32, 1);
|
|
2672
2476
|
static {
|
|
2673
2477
|
JDBC_TYPE_FOR.put("string", Types.VARCHAR);
|
|
2674
2478
|
JDBC_TYPE_FOR.put("text", Types.CLOB);
|
|
@@ -2710,7 +2514,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
|
2710
2514
|
final String internedType = internedTypeFor(context, attribute);
|
|
2711
2515
|
final Integer sqlType = jdbcTypeFor(internedType);
|
|
2712
2516
|
if ( sqlType != null ) {
|
|
2713
|
-
return sqlType
|
|
2517
|
+
return sqlType;
|
|
2714
2518
|
}
|
|
2715
2519
|
|
|
2716
2520
|
return Types.OTHER; // -1 as well as 0 are used in Types
|
|
@@ -2897,11 +2701,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
|
2897
2701
|
statement.setTimestamp(index, timestamp, getCalendar(dateTime.getZone()));
|
|
2898
2702
|
}
|
|
2899
2703
|
|
|
2900
|
-
@Deprecated
|
|
2901
|
-
protected static Timestamp convertToTimestamp(final RubyFloat value) {
|
|
2902
|
-
return DateTimeUtils.convertToTimestamp(value);
|
|
2903
|
-
}
|
|
2904
|
-
|
|
2905
2704
|
protected static Calendar getCalendar(final DateTimeZone zone) { // final java.util.Date hint
|
|
2906
2705
|
if (DateTimeZone.UTC == zone) return getCalendarUTC();
|
|
2907
2706
|
if (DateTimeZone.getDefault() == zone) return new GregorianCalendar();
|
|
@@ -2947,9 +2746,14 @@ public class RubyJdbcConnection extends RubyObject {
|
|
|
2947
2746
|
value = value.callMethod(context, "to_date");
|
|
2948
2747
|
}
|
|
2949
2748
|
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2749
|
+
if (value instanceof RubyDate) {
|
|
2750
|
+
RubyDate rubyDate = (RubyDate) value;
|
|
2751
|
+
statement.setDate(index, rubyDate.toJava(Date.class));
|
|
2752
|
+
return;
|
|
2753
|
+
}
|
|
2754
|
+
|
|
2755
|
+
// NOTE: assuming Date#to_s does right ...
|
|
2756
|
+
statement.setDate(index, Date.valueOf(value.toString()));
|
|
2953
2757
|
}
|
|
2954
2758
|
|
|
2955
2759
|
protected void setBooleanParameter(final ThreadContext context,
|
|
@@ -2986,7 +2790,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
|
2986
2790
|
// For some reason the driver doesn't like "character varying" as a type
|
|
2987
2791
|
if ( type.eql(context.runtime.newSymbol("string")) ) return "varchar";
|
|
2988
2792
|
|
|
2989
|
-
final RubyHash nativeTypes = (RubyHash)
|
|
2793
|
+
final RubyHash nativeTypes = (RubyHash) adapter.callMethod(context, "native_database_types");
|
|
2990
2794
|
// e.g. `integer: { name: 'integer' }`
|
|
2991
2795
|
final RubyHash typeInfo = (RubyHash) nativeTypes.op_aref(context, type);
|
|
2992
2796
|
|
|
@@ -3047,16 +2851,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
|
3047
2851
|
}
|
|
3048
2852
|
|
|
3049
2853
|
/**
|
|
3050
|
-
*
|
|
3051
|
-
* @return connection
|
|
3052
|
-
* @throws <code>ActiveRecord::ConnectionNotEstablished</code>, <code>ActiveRecord::JDBCError</code>
|
|
3053
|
-
*/
|
|
3054
|
-
protected Connection getConnection() throws RaiseException {
|
|
3055
|
-
return getConnection(false);
|
|
3056
|
-
}
|
|
3057
|
-
|
|
3058
|
-
/**
|
|
3059
|
-
* @see #getConnection()
|
|
2854
|
+
* Returns a connection (might cause a reconnect if there's none).
|
|
3060
2855
|
* @param required set to true if a connection is required to exists (e.g. on commit)
|
|
3061
2856
|
* @return connection
|
|
3062
2857
|
* @throws <code>ActiveRecord::ConnectionNotEstablished</code> if disconnected
|
|
@@ -3071,17 +2866,15 @@ public class RubyJdbcConnection extends RubyObject {
|
|
|
3071
2866
|
}
|
|
3072
2867
|
}
|
|
3073
2868
|
|
|
3074
|
-
|
|
2869
|
+
protected Connection getConnectionInternal(final boolean required) throws SQLException {
|
|
3075
2870
|
Connection connection = getConnectionImpl();
|
|
3076
|
-
if (
|
|
3077
|
-
if (
|
|
3078
|
-
|
|
3079
|
-
|
|
2871
|
+
if (connection == null && required) {
|
|
2872
|
+
if (!connected) handleNotConnected(); // raise ConnectionNotEstablished
|
|
2873
|
+
synchronized (this) {
|
|
2874
|
+
connection = getConnectionImpl();
|
|
2875
|
+
if ( connection == null ) {
|
|
2876
|
+
connectImpl(true); // throws SQLException
|
|
3080
2877
|
connection = getConnectionImpl();
|
|
3081
|
-
if ( connection == null ) {
|
|
3082
|
-
connectImpl( true ); // throws SQLException
|
|
3083
|
-
connection = getConnectionImpl();
|
|
3084
|
-
}
|
|
3085
2878
|
}
|
|
3086
2879
|
}
|
|
3087
2880
|
}
|
|
@@ -3212,7 +3005,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
|
3212
3005
|
try {
|
|
3213
3006
|
tablesSet = metaData.getTables(catalog, _schemaPattern, _tablePattern, types);
|
|
3214
3007
|
if ( checkExistsOnly ) { // only check if given table exists
|
|
3215
|
-
return tablesSet.next() ? context.
|
|
3008
|
+
return tablesSet.next() ? context.tru : null;
|
|
3216
3009
|
}
|
|
3217
3010
|
else {
|
|
3218
3011
|
return mapTables(context, connection, catalog, _schemaPattern, _tablePattern, tablesSet);
|
|
@@ -3221,15 +3014,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
|
3221
3014
|
finally { close(tablesSet); }
|
|
3222
3015
|
}
|
|
3223
3016
|
|
|
3224
|
-
@Deprecated
|
|
3225
|
-
protected IRubyObject matchTables(final Ruby runtime,
|
|
3226
|
-
final Connection connection,
|
|
3227
|
-
final String catalog, final String schemaPattern,
|
|
3228
|
-
final String tablePattern, final String[] types,
|
|
3229
|
-
final boolean checkExistsOnly) throws SQLException {
|
|
3230
|
-
return matchTables(runtime.getCurrentContext(), connection, catalog, schemaPattern, tablePattern, types, checkExistsOnly);
|
|
3231
|
-
}
|
|
3232
|
-
|
|
3233
3017
|
// NOTE java.sql.DatabaseMetaData.getTables :
|
|
3234
3018
|
protected final static int TABLES_TABLE_CAT = 1;
|
|
3235
3019
|
protected final static int TABLES_TABLE_SCHEM = 2;
|
|
@@ -3318,7 +3102,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
|
3318
3102
|
final String tabName = results.getString(TABLE_NAME);
|
|
3319
3103
|
final RubyString tableName = cachedString(context, caseConvertIdentifierForRails(metaData, tabName));
|
|
3320
3104
|
|
|
3321
|
-
final IRubyObject type_metadata =
|
|
3105
|
+
final IRubyObject type_metadata = adapter.callMethod(context, "fetch_type_metadata", sqlType);
|
|
3322
3106
|
|
|
3323
3107
|
// (name, default, sql_type_metadata = nil, null = true, table_name = nil, default_function = nil, collation = nil, comment: nil)
|
|
3324
3108
|
final IRubyObject[] args = new IRubyObject[] {
|
|
@@ -3334,7 +3118,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
|
3334
3118
|
ResultSet primaryKeys = null;
|
|
3335
3119
|
try {
|
|
3336
3120
|
primaryKeys = metaData.getPrimaryKeys(components.catalog, components.schema, components.name);
|
|
3337
|
-
final List<String> primaryKeyNames = new ArrayList
|
|
3121
|
+
final List<String> primaryKeyNames = new ArrayList<>(4);
|
|
3338
3122
|
while ( primaryKeys.next() ) {
|
|
3339
3123
|
primaryKeyNames.add( primaryKeys.getString(COLUMN_NAME) );
|
|
3340
3124
|
}
|
|
@@ -3383,7 +3167,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
|
3383
3167
|
// not have and auto-generated ID column :
|
|
3384
3168
|
boolean next = genKeys.next() && genKeys.getMetaData().getColumnCount() > 0;
|
|
3385
3169
|
// singleResult == null - guess if only single key returned
|
|
3386
|
-
if ( singleResult == null || singleResult
|
|
3170
|
+
if ( singleResult == null || singleResult) {
|
|
3387
3171
|
if ( next ) {
|
|
3388
3172
|
firstKey = mapGeneratedKey(runtime, genKeys);
|
|
3389
3173
|
if ( singleResult != null || ! genKeys.next() ) {
|
|
@@ -3416,7 +3200,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
|
3416
3200
|
if (supportsGeneratedKeys == null) {
|
|
3417
3201
|
supportsGeneratedKeys = this.supportsGeneratedKeys = connection.getMetaData().supportsGetGeneratedKeys();
|
|
3418
3202
|
}
|
|
3419
|
-
return supportsGeneratedKeys
|
|
3203
|
+
return supportsGeneratedKeys;
|
|
3420
3204
|
}
|
|
3421
3205
|
|
|
3422
3206
|
/**
|
|
@@ -3448,8 +3232,8 @@ public class RubyJdbcConnection extends RubyObject {
|
|
|
3448
3232
|
final ColumnData[] columns = extractColumns(context, connection, resultSet, false);
|
|
3449
3233
|
|
|
3450
3234
|
final Ruby runtime = context.runtime;
|
|
3451
|
-
final IRubyObject[] blockArgs = new IRubyObject[columns.length];
|
|
3452
3235
|
while ( resultSet.next() ) {
|
|
3236
|
+
final IRubyObject[] blockArgs = new IRubyObject[columns.length];
|
|
3453
3237
|
for ( int i = 0; i < columns.length; i++ ) {
|
|
3454
3238
|
final ColumnData column = columns[i];
|
|
3455
3239
|
blockArgs[i] = jdbcToRuby(context, runtime, column.index, column.type, resultSet);
|
|
@@ -3475,16 +3259,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
|
3475
3259
|
return setupColumns(context, connection, resultSet.getMetaData(), downCase);
|
|
3476
3260
|
}
|
|
3477
3261
|
|
|
3478
|
-
/**
|
|
3479
|
-
* @deprecated use {@link #extractColumns(ThreadContext, Connection, ResultSet, boolean)}
|
|
3480
|
-
*/
|
|
3481
|
-
@Deprecated
|
|
3482
|
-
protected ColumnData[] extractColumns(final Ruby runtime,
|
|
3483
|
-
final Connection connection, final ResultSet resultSet,
|
|
3484
|
-
final boolean downCase) throws SQLException {
|
|
3485
|
-
return extractColumns(runtime.getCurrentContext(), connection, resultSet, downCase);
|
|
3486
|
-
}
|
|
3487
|
-
|
|
3488
3262
|
protected <T> T withConnection(final ThreadContext context, final Callable<T> block)
|
|
3489
3263
|
throws RaiseException {
|
|
3490
3264
|
try {
|
|
@@ -3590,13 +3364,12 @@ public class RubyJdbcConnection extends RubyObject {
|
|
|
3590
3364
|
}
|
|
3591
3365
|
|
|
3592
3366
|
protected boolean isTransient(final Exception exception) {
|
|
3593
|
-
|
|
3594
|
-
return false;
|
|
3367
|
+
return exception instanceof SQLTransientException;
|
|
3595
3368
|
}
|
|
3596
3369
|
|
|
3597
3370
|
protected boolean isRecoverable(final Exception exception) {
|
|
3598
|
-
|
|
3599
|
-
|
|
3371
|
+
return exception instanceof SQLRecoverableException;
|
|
3372
|
+
// exception instanceof SQLException; // pre JDBC 4.0 drivers?
|
|
3600
3373
|
}
|
|
3601
3374
|
|
|
3602
3375
|
private static Throwable getCause(Throwable exception) {
|
|
@@ -3754,6 +3527,11 @@ public class RubyJdbcConnection extends RubyObject {
|
|
|
3754
3527
|
return Result.newInstance(context, columnsToArray(context, columns), rows, Block.NULL_BLOCK); // Result.new
|
|
3755
3528
|
}
|
|
3756
3529
|
|
|
3530
|
+
protected static IRubyObject newEmptyResult(final ThreadContext context) {
|
|
3531
|
+
final RubyClass Result = getResult(context.runtime);
|
|
3532
|
+
return Result.newInstance(context, RubyArray.newEmptyArray(context.runtime), RubyArray.newEmptyArray(context.runtime), Block.NULL_BLOCK); // Result.new
|
|
3533
|
+
}
|
|
3534
|
+
|
|
3757
3535
|
private static RubyArray columnsToArray(ThreadContext context, ColumnData[] columns) {
|
|
3758
3536
|
final IRubyObject[] cols = new IRubyObject[columns.length];
|
|
3759
3537
|
|
|
@@ -4006,7 +3784,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
|
4006
3784
|
public static void debugStackTrace(final ThreadContext context, final Throwable e) {
|
|
4007
3785
|
if ( debug || ( context != null && context.runtime.isDebug() ) ) {
|
|
4008
3786
|
final PrintStream out = context != null ? context.runtime.getOut() : System.out;
|
|
4009
|
-
if ( debugStackTrace == null || debugStackTrace
|
|
3787
|
+
if ( debugStackTrace == null || debugStackTrace) {
|
|
4010
3788
|
e.printStackTrace(out);
|
|
4011
3789
|
}
|
|
4012
3790
|
else {
|
|
@@ -4022,8 +3800,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
|
4022
3800
|
private static boolean driverUsedLogged;
|
|
4023
3801
|
|
|
4024
3802
|
private void logDriverUsed(final Connection connection) {
|
|
4025
|
-
if (
|
|
4026
|
-
if ( driverUsedLogged ) return;
|
|
3803
|
+
if (debug && !driverUsedLogged) {
|
|
4027
3804
|
driverUsedLogged = true;
|
|
4028
3805
|
try {
|
|
4029
3806
|
final DatabaseMetaData meta = connection.getMetaData();
|