activerecord-jdbc-alt-adapter 52.2.3-java → 60.1.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 +3 -0
- data/.travis.yml +80 -52
- data/Gemfile +10 -3
- data/README.md +55 -37
- data/Rakefile +31 -5
- data/Rakefile.jdbc +8 -1
- data/activerecord-jdbc-adapter.gemspec +6 -9
- data/activerecord-jdbc-alt-adapter.gemspec +6 -9
- data/lib/arel/visitors/sqlserver.rb +33 -23
- data/lib/arjdbc/abstract/connection_management.rb +7 -0
- data/lib/arjdbc/abstract/core.rb +17 -24
- data/lib/arjdbc/abstract/database_statements.rb +31 -20
- 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.rb +0 -4
- 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 +3 -5
- 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 +112 -46
- data/lib/arjdbc/mssql/column.rb +5 -1
- data/lib/arjdbc/mssql/connection_methods.rb +13 -2
- data/lib/arjdbc/mssql/database_limits.rb +2 -0
- data/lib/arjdbc/mssql/database_statements.rb +44 -6
- 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/mysql/connection_methods.rb +13 -7
- data/lib/arjdbc/postgresql/adapter.rb +240 -214
- 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 +11 -6
- data/lib/arjdbc/postgresql/connection_methods.rb +3 -1
- data/lib/arjdbc/postgresql/name.rb +2 -0
- data/lib/arjdbc/postgresql/oid_types.rb +3 -1
- data/lib/arjdbc/sqlite3/adapter.rb +188 -180
- data/lib/arjdbc/sqlite3/connection_methods.rb +16 -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/rakelib/02-test.rake +0 -2
- data/rakelib/rails.rake +1 -1
- data/src/java/arjdbc/ArJdbcModule.java +5 -5
- data/src/java/arjdbc/jdbc/DriverWrapper.java +1 -9
- data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +468 -637
- data/src/java/arjdbc/mssql/MSSQLRubyJdbcConnection.java +319 -38
- data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +13 -23
- data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +44 -31
- data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +94 -99
- data/src/java/arjdbc/util/DateTimeUtils.java +34 -12
- metadata +7 -17
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
ArJdbc::ConnectionMethods.module_eval do
|
3
3
|
def sqlite3_connection(config)
|
4
|
+
config = config.deep_dup
|
4
5
|
config[:adapter_spec] ||= ::ArJdbc::SQLite3
|
5
6
|
config[:adapter_class] = ActiveRecord::ConnectionAdapters::SQLite3Adapter unless config.key?(:adapter_class)
|
6
7
|
|
@@ -22,17 +23,27 @@ ArJdbc::ConnectionMethods.module_eval do
|
|
22
23
|
raise
|
23
24
|
end
|
24
25
|
end
|
25
|
-
|
26
|
+
|
27
|
+
config[:properties] ||= {}
|
28
|
+
|
26
29
|
database = config[:database] # NOTE: "jdbc:sqlite::memory:" syntax is supported
|
27
30
|
config[:url] ||= "jdbc:sqlite:#{database == ':memory:' ? '' : database}"
|
28
31
|
config[:connection_alive_sql] ||= 'SELECT 1'
|
29
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
|
+
|
30
41
|
timeout = config[:timeout]
|
31
42
|
if timeout && timeout.to_s !~ /\A\d+\Z/
|
32
43
|
raise TypeError.new "Timeout must be nil or a number (got: #{timeout})."
|
33
44
|
end
|
34
45
|
|
35
|
-
options =
|
46
|
+
options = config[:properties]
|
36
47
|
options['busy_timeout'] ||= timeout unless timeout.nil?
|
37
48
|
|
38
49
|
jdbc_connection(config)
|
@@ -50,8 +61,9 @@ ArJdbc::ConnectionMethods.module_eval do
|
|
50
61
|
def parse_sqlite3_config!(config)
|
51
62
|
database = ( config[:database] ||= config[:dbfile] )
|
52
63
|
if ':memory:' != database
|
53
|
-
|
54
|
-
|
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])
|
55
67
|
Dir.mkdir(dirname) unless File.directory?(dirname)
|
56
68
|
end
|
57
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 = 'https://repo1.maven.org/maven2/org/apache/tomcat'
|
4
4
|
TOMCAT_VERSION = '7.0.54'
|
5
5
|
|
6
6
|
DOWNLOAD_DIR = File.expand_path('../test/jars', File.dirname(__FILE__))
|
@@ -48,4 +48,4 @@ namespace :'tomcat-jndi' do # contains a FS JNDI impl (for tests)
|
|
48
48
|
rm jar_path if File.exist?(jar_path)
|
49
49
|
end
|
50
50
|
|
51
|
-
end
|
51
|
+
end
|
data/rakelib/02-test.rake
CHANGED
@@ -76,8 +76,6 @@ end
|
|
76
76
|
test_task_for adapter, :desc => "Run tests against #{adapter} (ensure driver is on class-path)"
|
77
77
|
end
|
78
78
|
|
79
|
-
#test_task_for :MSSQL, :name => 'test_sqlserver', :driver => nil, :database_name => 'MS-SQL using SQLJDBC'
|
80
|
-
|
81
79
|
test_task_for :AS400, :desc => "Run tests against AS400 (DB2) (ensure driver is on class-path)",
|
82
80
|
:files => FileList["test/db2*_test.rb"] + FileList["test/db/db2/*_test.rb"]
|
83
81
|
|
data/rakelib/rails.rake
CHANGED
@@ -57,7 +57,7 @@ namespace :rails do
|
|
57
57
|
ruby_opts_string += " -C \"#{ar_path}\""
|
58
58
|
ruby_opts_string += " -rbundler/setup"
|
59
59
|
ruby_opts_string += " -rminitest -rminitest/excludes" unless ENV['NO_EXCLUDES'].eql?('true')
|
60
|
-
file_list = ENV["TEST"] ? FileList[ ENV["TEST"] ] : test_files_finder.call
|
60
|
+
file_list = ENV["TEST"] ? FileList[ ENV["TEST"].split(',') ] : test_files_finder.call
|
61
61
|
file_list_string = file_list.map { |fn| "\"#{fn}\"" }.join(' ')
|
62
62
|
# test_loader_code = "-e \"ARGV.each{|f| require f}\"" # :direct
|
63
63
|
option_list = ( ENV["TESTOPTS"] || ENV["TESTOPT"] || ENV["TEST_OPTS"] || '' )
|
@@ -151,7 +151,7 @@ public class ArJdbcModule {
|
|
151
151
|
throw newNativeException(runtime, e);
|
152
152
|
}
|
153
153
|
|
154
|
-
return
|
154
|
+
return context.tru;
|
155
155
|
}
|
156
156
|
|
157
157
|
/**
|
@@ -191,7 +191,7 @@ public class ArJdbcModule {
|
|
191
191
|
}
|
192
192
|
|
193
193
|
// NOTE: probably useless - only to be useful for the pooled runtime mode when jar at WEB-INF/lib
|
194
|
-
static final Map<Ruby, Map<String, Boolean>> loadedDrivers = new WeakHashMap
|
194
|
+
static final Map<Ruby, Map<String, Boolean>> loadedDrivers = new WeakHashMap<>(8);
|
195
195
|
|
196
196
|
private static IRubyObject loadDriver(final ThreadContext context, final IRubyObject self,
|
197
197
|
final String constName) {
|
@@ -202,7 +202,7 @@ public class ArJdbcModule {
|
|
202
202
|
synchronized (ArJdbcModule.class) {
|
203
203
|
loadedMap = loadedDrivers.get(runtime);
|
204
204
|
if ( loadedMap == null ) {
|
205
|
-
loadedMap = new HashMap
|
205
|
+
loadedMap = new HashMap<>(4);
|
206
206
|
loadedDrivers.put(runtime, loadedMap);
|
207
207
|
}
|
208
208
|
}
|
@@ -210,8 +210,8 @@ public class ArJdbcModule {
|
|
210
210
|
|
211
211
|
final Boolean driverLoaded = loadedMap.get(constName);
|
212
212
|
if ( driverLoaded != null ) {
|
213
|
-
if (
|
214
|
-
return
|
213
|
+
if (driverLoaded) return context.fals;
|
214
|
+
return context.nil;
|
215
215
|
}
|
216
216
|
|
217
217
|
try { // require 'jdbc/mysql'
|
@@ -60,15 +60,7 @@ public class DriverWrapper {
|
|
60
60
|
|
61
61
|
private Driver allocateDriver(final Class<? extends Driver> driverClass)
|
62
62
|
throws InstantiationException, IllegalAccessException {
|
63
|
-
|
64
|
-
return driverClass.newInstance();
|
65
|
-
}
|
66
|
-
catch (InstantiationException e) {
|
67
|
-
throw e;
|
68
|
-
}
|
69
|
-
catch (IllegalAccessException e) {
|
70
|
-
throw e;
|
71
|
-
}
|
63
|
+
return driverClass.newInstance();
|
72
64
|
}
|
73
65
|
|
74
66
|
protected static Class<? extends Driver> loadDriver(final Ruby runtime, final String name)
|
@@ -73,7 +73,6 @@ import org.jruby.RubyBoolean;
|
|
73
73
|
import org.jruby.RubyClass;
|
74
74
|
import org.jruby.RubyException;
|
75
75
|
import org.jruby.RubyFixnum;
|
76
|
-
import org.jruby.RubyFloat;
|
77
76
|
import org.jruby.RubyHash;
|
78
77
|
import org.jruby.RubyIO;
|
79
78
|
import org.jruby.RubyInteger;
|
@@ -86,6 +85,7 @@ import org.jruby.RubyTime;
|
|
86
85
|
import org.jruby.anno.JRubyMethod;
|
87
86
|
import org.jruby.exceptions.RaiseException;
|
88
87
|
import org.jruby.ext.bigdecimal.RubyBigDecimal;
|
88
|
+
import org.jruby.ext.date.RubyDate;
|
89
89
|
import org.jruby.javasupport.JavaEmbedUtils;
|
90
90
|
import org.jruby.javasupport.JavaUtil;
|
91
91
|
import org.jruby.runtime.Block;
|
@@ -147,11 +147,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
147
147
|
return JdbcConnection;
|
148
148
|
}
|
149
149
|
|
150
|
-
@Deprecated
|
151
|
-
public static RubyClass getJdbcConnectionClass(final Ruby runtime) {
|
152
|
-
return getConnectionAdapters(runtime).getClass("JdbcConnection");
|
153
|
-
}
|
154
|
-
|
155
150
|
public static RubyClass getJdbcConnection(final Ruby runtime) {
|
156
151
|
return (RubyClass) getConnectionAdapters(runtime).getConstantAt("JdbcConnection");
|
157
152
|
}
|
@@ -231,34 +226,30 @@ public class RubyJdbcConnection extends RubyObject {
|
|
231
226
|
|
232
227
|
@JRubyMethod(name = "transaction_isolation", alias = "get_transaction_isolation")
|
233
228
|
public IRubyObject get_transaction_isolation(final ThreadContext context) {
|
234
|
-
return withConnection(context,
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
return context.runtime.newSymbol(isolationSymbol);
|
240
|
-
}
|
229
|
+
return withConnection(context, connection -> {
|
230
|
+
final int level = connection.getTransactionIsolation();
|
231
|
+
final String isolationSymbol = formatTransactionIsolationLevel(level);
|
232
|
+
if ( isolationSymbol == null ) return context.nil;
|
233
|
+
return context.runtime.newSymbol(isolationSymbol);
|
241
234
|
});
|
242
235
|
}
|
243
236
|
|
244
237
|
@JRubyMethod(name = "transaction_isolation=", alias = "set_transaction_isolation")
|
245
238
|
public IRubyObject set_transaction_isolation(final ThreadContext context, final IRubyObject isolation) {
|
246
|
-
return withConnection(context,
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
}
|
239
|
+
return withConnection(context, connection -> {
|
240
|
+
final int level;
|
241
|
+
if ( isolation.isNil() ) {
|
242
|
+
level = connection.getMetaData().getDefaultTransactionIsolation();
|
243
|
+
}
|
244
|
+
else {
|
245
|
+
level = mapTransactionIsolationLevel(isolation);
|
246
|
+
}
|
255
247
|
|
256
|
-
|
248
|
+
connection.setTransactionIsolation(level);
|
257
249
|
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
}
|
250
|
+
final String isolationSymbol = formatTransactionIsolationLevel(level);
|
251
|
+
if ( isolationSymbol == null ) return context.nil;
|
252
|
+
return context.runtime.newSymbol(isolationSymbol);
|
262
253
|
});
|
263
254
|
}
|
264
255
|
|
@@ -306,31 +297,25 @@ public class RubyJdbcConnection extends RubyObject {
|
|
306
297
|
final IRubyObject[] args) throws SQLException {
|
307
298
|
final IRubyObject isolation = args.length > 0 ? args[0] : null;
|
308
299
|
|
309
|
-
return withConnection(context,
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
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,7 +465,8 @@ public class RubyJdbcConnection extends RubyObject {
|
|
487
465
|
savepoint = ((IRubyObject) savepoint).toJava(Savepoint.class);
|
488
466
|
}
|
489
467
|
|
490
|
-
connection
|
468
|
+
final Connection connection = getConnectionInternal(true);
|
469
|
+
releaseSavepoint(connection, (Savepoint) savepoint);
|
491
470
|
return context.nil;
|
492
471
|
}
|
493
472
|
catch (SQLException e) {
|
@@ -495,6 +474,11 @@ public class RubyJdbcConnection extends RubyObject {
|
|
495
474
|
}
|
496
475
|
}
|
497
476
|
|
477
|
+
// MSSQL doesn't support releasing savepoints so we make it possible to override the actual release action
|
478
|
+
protected void releaseSavepoint(final Connection connection, final Savepoint savepoint) throws SQLException {
|
479
|
+
connection.releaseSavepoint(savepoint);
|
480
|
+
}
|
481
|
+
|
498
482
|
protected static RuntimeException newSavepointNotSetError(final ThreadContext context, final IRubyObject name, final String op) {
|
499
483
|
RubyClass StatementInvalid = ActiveRecord(context).getClass("StatementInvalid");
|
500
484
|
return context.runtime.newRaiseException(StatementInvalid, "could not " + op + " savepoint: '" + name + "' (not set)");
|
@@ -520,7 +504,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
520
504
|
}
|
521
505
|
|
522
506
|
@SuppressWarnings("unchecked")
|
523
|
-
private
|
507
|
+
private Map<IRubyObject, Savepoint> getSavepoints(final boolean init) {
|
524
508
|
if ( hasInternalVariable("savepoints") ) {
|
525
509
|
return (Map<IRubyObject, Savepoint>) getInternalVariable("savepoints");
|
526
510
|
}
|
@@ -540,13 +524,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
540
524
|
return false;
|
541
525
|
}
|
542
526
|
|
543
|
-
@Deprecated // second argument is now mandatory - only kept for compatibility
|
544
|
-
@JRubyMethod(required = 1)
|
545
|
-
public final IRubyObject initialize(final ThreadContext context, final IRubyObject config) {
|
546
|
-
doInitialize(context, config, context.nil);
|
547
|
-
return this;
|
548
|
-
}
|
549
|
-
|
550
527
|
@JRubyMethod(required = 2)
|
551
528
|
public final IRubyObject initialize(final ThreadContext context, final IRubyObject config, final IRubyObject adapter) {
|
552
529
|
doInitialize(context, config, adapter);
|
@@ -554,12 +531,17 @@ public class RubyJdbcConnection extends RubyObject {
|
|
554
531
|
}
|
555
532
|
|
556
533
|
protected void doInitialize(final ThreadContext context, final IRubyObject config, final IRubyObject adapter) {
|
557
|
-
this.config = config;
|
534
|
+
this.config = config;
|
535
|
+
this.adapter = adapter;
|
558
536
|
|
559
537
|
this.jndi = setupConnectionFactory(context);
|
560
538
|
this.lazy = jndi; // JNDIs are lazy by default otherwise eager
|
561
539
|
try {
|
562
|
-
|
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());
|
563
545
|
}
|
564
546
|
catch (SQLException e) {
|
565
547
|
String message = e.getMessage();
|
@@ -570,7 +552,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
570
552
|
IRubyObject value = getConfigValue(context, "configure_connection");
|
571
553
|
if ( value == context.nil ) this.configureConnection = true;
|
572
554
|
else {
|
573
|
-
this.configureConnection = value != context.
|
555
|
+
this.configureConnection = value != context.fals;
|
574
556
|
}
|
575
557
|
|
576
558
|
IRubyObject jdbcFetchSize = getConfigValue(context, "jdbc_fetch_size");
|
@@ -581,7 +563,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
581
563
|
|
582
564
|
@JRubyMethod(name = "adapter")
|
583
565
|
public IRubyObject adapter(final ThreadContext context) {
|
584
|
-
final IRubyObject adapter = getAdapter();
|
585
566
|
return adapter == null ? context.nil : adapter;
|
586
567
|
}
|
587
568
|
|
@@ -596,43 +577,9 @@ public class RubyJdbcConnection extends RubyObject {
|
|
596
577
|
return factory;
|
597
578
|
}
|
598
579
|
|
599
|
-
/**
|
600
|
-
* Called during <code>initialize</code> after the connection factory
|
601
|
-
* has been set to check if we can connect and/or perform any initialization
|
602
|
-
* necessary.
|
603
|
-
* <br/>
|
604
|
-
* NOTE: connection has not been configured at this point,
|
605
|
-
* nor should we retry - we're creating a brand new JDBC connection
|
606
|
-
*
|
607
|
-
* @param context
|
608
|
-
* @return connection
|
609
|
-
*/
|
610
|
-
@Deprecated
|
611
|
-
@JRubyMethod(name = "init_connection")
|
612
|
-
public synchronized IRubyObject init_connection(final ThreadContext context) {
|
613
|
-
try {
|
614
|
-
return initConnection(context);
|
615
|
-
}
|
616
|
-
catch (SQLException e) {
|
617
|
-
return handleException(context, e); // throws
|
618
|
-
}
|
619
|
-
}
|
620
|
-
|
621
|
-
private IRubyObject initConnection(final ThreadContext context) throws SQLException {
|
622
|
-
final IRubyObject adapter = getAdapter(); // self.adapter
|
623
|
-
if ( adapter == null || adapter == context.nil ) {
|
624
|
-
warn(context, "adapter not set, please pass adapter on JdbcConnection#initialize(config, adapter)");
|
625
|
-
}
|
626
|
-
|
627
|
-
if ( ! lazy ) setConnection( newConnection() );
|
628
|
-
|
629
|
-
return context.nil;
|
630
|
-
}
|
631
|
-
|
632
580
|
private void configureConnection() {
|
633
581
|
if ( ! configureConnection ) return; // return false;
|
634
582
|
|
635
|
-
final IRubyObject adapter = getAdapter(); // self.adapter
|
636
583
|
if ( adapter != null && ! adapter.isNil() ) {
|
637
584
|
if ( adapter.respondsTo("configure_connection") ) {
|
638
585
|
final ThreadContext context = getRuntime().getCurrentContext();
|
@@ -654,7 +601,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
654
601
|
|
655
602
|
@JRubyMethod(name = "jdbc_connection", alias = "connection", required = 1)
|
656
603
|
public final IRubyObject connection(final ThreadContext context, final IRubyObject unwrap) {
|
657
|
-
if ( unwrap == context.nil || unwrap == context.
|
604
|
+
if ( unwrap == context.nil || unwrap == context.fals ) {
|
658
605
|
return connection(context);
|
659
606
|
}
|
660
607
|
Connection connection = connectionImpl(context);
|
@@ -690,18 +637,25 @@ public class RubyJdbcConnection extends RubyObject {
|
|
690
637
|
|
691
638
|
@JRubyMethod(name = "active?", alias = "valid?")
|
692
639
|
public RubyBoolean active_p(final ThreadContext context) {
|
693
|
-
if ( ! connected ) return context.
|
694
|
-
if (
|
640
|
+
if ( ! connected ) return context.fals;
|
641
|
+
if (jndi) {
|
695
642
|
// for JNDI the data-source / pool is supposed to
|
696
643
|
// manage connections for us thus no valid check!
|
697
644
|
boolean active = getConnectionFactory() != null;
|
698
645
|
return context.runtime.newBoolean( active );
|
699
646
|
}
|
700
|
-
final Connection connection = getConnection();
|
701
|
-
if ( connection == null ) return context.
|
647
|
+
final Connection connection = getConnection(false);
|
648
|
+
if ( connection == null ) return context.fals; // unlikely
|
702
649
|
return context.runtime.newBoolean( isConnectionValid(context, connection) );
|
703
650
|
}
|
704
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
|
+
|
705
659
|
@JRubyMethod(name = "disconnect!")
|
706
660
|
public synchronized IRubyObject disconnect(final ThreadContext context) {
|
707
661
|
setConnection(null); connected = false;
|
@@ -722,38 +676,43 @@ public class RubyJdbcConnection extends RubyObject {
|
|
722
676
|
|
723
677
|
private void connectImpl(final boolean forceConnection) throws SQLException {
|
724
678
|
setConnection( forceConnection ? newConnection() : null );
|
725
|
-
if (
|
679
|
+
if (forceConnection) {
|
680
|
+
if (getConnectionImpl() == null) throw new SQLException("Didn't get a connection. Wrong URL?");
|
681
|
+
configureConnection();
|
682
|
+
}
|
726
683
|
}
|
727
684
|
|
728
685
|
@JRubyMethod(name = "read_only?")
|
729
686
|
public IRubyObject is_read_only(final ThreadContext context) {
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
return context.runtime.newBoolean(
|
687
|
+
try {
|
688
|
+
final Connection connection = getConnectionInternal(false);
|
689
|
+
if (connection != null) {
|
690
|
+
return context.runtime.newBoolean(connection.isReadOnly());
|
734
691
|
}
|
735
|
-
|
692
|
+
} catch (SQLException e) {
|
693
|
+
return handleException(context, e);
|
736
694
|
}
|
737
695
|
return context.nil;
|
738
696
|
}
|
739
697
|
|
740
698
|
@JRubyMethod(name = "read_only=")
|
741
699
|
public IRubyObject set_read_only(final ThreadContext context, final IRubyObject flag) {
|
742
|
-
final Connection connection = getConnection(true);
|
743
700
|
try {
|
701
|
+
final Connection connection = getConnectionInternal(true);
|
744
702
|
connection.setReadOnly( flag.isTrue() );
|
745
703
|
return context.runtime.newBoolean( connection.isReadOnly() );
|
704
|
+
} catch (SQLException e) {
|
705
|
+
return handleException(context, e);
|
746
706
|
}
|
747
|
-
catch (SQLException e) { return handleException(context, e); }
|
748
707
|
}
|
749
708
|
|
750
709
|
@JRubyMethod(name = { "open?" /* "conn?" */ })
|
751
710
|
public IRubyObject open_p(final ThreadContext context) {
|
752
|
-
|
711
|
+
try {
|
712
|
+
final Connection connection = getConnectionInternal(false);
|
753
713
|
|
754
|
-
|
714
|
+
if (connection == null) return context.fals;
|
755
715
|
|
756
|
-
try {
|
757
716
|
// NOTE: isClosed method generally cannot be called to determine
|
758
717
|
// whether a connection to a database is valid or invalid ...
|
759
718
|
return context.runtime.newBoolean(!connection.isClosed());
|
@@ -766,10 +725,10 @@ public class RubyJdbcConnection extends RubyObject {
|
|
766
725
|
public IRubyObject close(final ThreadContext context) {
|
767
726
|
final Connection connection = getConnection(false);
|
768
727
|
|
769
|
-
if (connection == null) return context.
|
728
|
+
if (connection == null) return context.fals;
|
770
729
|
|
771
730
|
try {
|
772
|
-
if (connection.isClosed()) return context.
|
731
|
+
if (connection.isClosed()) return context.fals;
|
773
732
|
|
774
733
|
setConnection(null); // does connection.close();
|
775
734
|
} catch (Exception e) {
|
@@ -779,69 +738,65 @@ public class RubyJdbcConnection extends RubyObject {
|
|
779
738
|
|
780
739
|
// ActiveRecord expects a closed connection to not try and re-open a connection
|
781
740
|
// whereas JNDI expects that.
|
782
|
-
if (!
|
741
|
+
if (!jndi) disconnect(context);
|
783
742
|
|
784
|
-
return context.
|
743
|
+
return context.tru;
|
785
744
|
}
|
786
745
|
|
787
746
|
@JRubyMethod(name = "database_name")
|
788
747
|
public IRubyObject database_name(final ThreadContext context) {
|
789
|
-
return withConnection(context,
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
if ( name == null ) return context.nil;
|
795
|
-
}
|
796
|
-
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;
|
797
753
|
}
|
754
|
+
return context.runtime.newString(name);
|
798
755
|
});
|
799
756
|
}
|
800
757
|
|
801
758
|
@JRubyMethod(name = "execute", required = 1)
|
802
759
|
public IRubyObject execute(final ThreadContext context, final IRubyObject sql) {
|
803
760
|
final String query = sqlString(sql);
|
804
|
-
return withConnection(context,
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
statement = createStatement(context, connection);
|
809
|
-
|
810
|
-
// For DBs that do support multiple statements, lets return the last result set
|
811
|
-
// to be consistent with AR
|
812
|
-
boolean hasResultSet = doExecute(statement, query);
|
813
|
-
int updateCount = statement.getUpdateCount();
|
761
|
+
return withConnection(context, connection -> {
|
762
|
+
Statement statement = null;
|
763
|
+
try {
|
764
|
+
statement = createStatement(context, connection);
|
814
765
|
|
815
|
-
|
816
|
-
|
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();
|
817
770
|
|
818
|
-
|
771
|
+
IRubyObject result = context.nil; // If no results, return nil
|
772
|
+
ResultSet resultSet;
|
819
773
|
|
820
|
-
|
821
|
-
resultSet = statement.getResultSet();
|
774
|
+
while (hasResultSet || updateCount != -1) {
|
822
775
|
|
823
|
-
|
824
|
-
|
825
|
-
// this shouldn't be an issue in most cases since we're only getting 1 result set anyways
|
826
|
-
result = mapExecuteResult(context, connection, resultSet);
|
827
|
-
resultSet.close();
|
828
|
-
} else {
|
829
|
-
result = context.runtime.newFixnum(updateCount);
|
830
|
-
}
|
776
|
+
if (hasResultSet) {
|
777
|
+
resultSet = statement.getResultSet();
|
831
778
|
|
832
|
-
//
|
833
|
-
|
834
|
-
|
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);
|
835
786
|
}
|
836
787
|
|
837
|
-
|
838
|
-
|
839
|
-
|
840
|
-
debugErrorSQL(context, query);
|
841
|
-
throw e;
|
842
|
-
} finally {
|
843
|
-
close(statement);
|
788
|
+
// Check to see if there is another result set
|
789
|
+
hasResultSet = statement.getMoreResults();
|
790
|
+
updateCount = statement.getUpdateCount();
|
844
791
|
}
|
792
|
+
|
793
|
+
return result;
|
794
|
+
|
795
|
+
} catch (final SQLException e) {
|
796
|
+
debugErrorSQL(context, query);
|
797
|
+
throw e;
|
798
|
+
} finally {
|
799
|
+
close(statement);
|
845
800
|
}
|
846
801
|
});
|
847
802
|
}
|
@@ -880,15 +835,31 @@ public class RubyJdbcConnection extends RubyObject {
|
|
880
835
|
return mapQueryResult(context, connection, resultSet);
|
881
836
|
}
|
882
837
|
|
838
|
+
private static String[] createStatementPk(IRubyObject pk) {
|
839
|
+
String[] statementPk;
|
840
|
+
if (pk instanceof RubyArray) {
|
841
|
+
RubyArray ary = (RubyArray) pk;
|
842
|
+
int size = ary.size();
|
843
|
+
statementPk = new String[size];
|
844
|
+
for (int i = 0; i < size; i++) {
|
845
|
+
statementPk[i] = sqlString(ary.eltInternal(i));
|
846
|
+
}
|
847
|
+
} else {
|
848
|
+
statementPk = new String[] { sqlString(pk) };
|
849
|
+
}
|
850
|
+
return statementPk;
|
851
|
+
}
|
852
|
+
|
883
853
|
/**
|
884
854
|
* Executes an INSERT SQL statement
|
885
855
|
* @param context
|
886
856
|
* @param sql
|
857
|
+
* @param pk Rails PK
|
887
858
|
* @return ActiveRecord::Result
|
888
859
|
* @throws SQLException
|
889
860
|
*/
|
890
|
-
@JRubyMethod(name = "
|
891
|
-
public IRubyObject
|
861
|
+
@JRubyMethod(name = "execute_insert_pk", required = 2)
|
862
|
+
public IRubyObject execute_insert_pk(final ThreadContext context, final IRubyObject sql, final IRubyObject pk) {
|
892
863
|
return withConnection(context, new Callable<IRubyObject>() {
|
893
864
|
public IRubyObject call(final Connection connection) throws SQLException {
|
894
865
|
Statement statement = null;
|
@@ -896,9 +867,14 @@ public class RubyJdbcConnection extends RubyObject {
|
|
896
867
|
try {
|
897
868
|
|
898
869
|
statement = createStatement(context, connection);
|
899
|
-
statement.executeUpdate(query, Statement.RETURN_GENERATED_KEYS);
|
900
|
-
return mapGeneratedKeys(context, connection, statement);
|
901
870
|
|
871
|
+
if (pk == context.nil || pk == context.fals || !supportsGeneratedKeys(connection)) {
|
872
|
+
statement.executeUpdate(query, Statement.RETURN_GENERATED_KEYS);
|
873
|
+
} else {
|
874
|
+
statement.executeUpdate(query, createStatementPk(pk));
|
875
|
+
}
|
876
|
+
|
877
|
+
return mapGeneratedKeys(context, connection, statement);
|
902
878
|
} catch (final SQLException e) {
|
903
879
|
debugErrorSQL(context, query);
|
904
880
|
throw e;
|
@@ -909,27 +885,38 @@ public class RubyJdbcConnection extends RubyObject {
|
|
909
885
|
});
|
910
886
|
}
|
911
887
|
|
888
|
+
@Deprecated
|
889
|
+
@JRubyMethod(name = "execute_insert", required = 1)
|
890
|
+
public IRubyObject execute_insert(final ThreadContext context, final IRubyObject sql) {
|
891
|
+
return execute_insert_pk(context, sql, context.nil);
|
892
|
+
}
|
893
|
+
|
912
894
|
/**
|
913
895
|
* Executes an INSERT SQL statement using a prepared statement
|
914
896
|
* @param context
|
915
897
|
* @param sql
|
916
898
|
* @param binds RubyArray of values to be bound to the query
|
899
|
+
* @param pk Rails PK
|
917
900
|
* @return ActiveRecord::Result
|
918
901
|
* @throws SQLException
|
919
902
|
*/
|
920
|
-
@JRubyMethod(name = "
|
921
|
-
public IRubyObject
|
903
|
+
@JRubyMethod(name = "execute_insert_pk", required = 3)
|
904
|
+
public IRubyObject execute_insert_pk(final ThreadContext context, final IRubyObject sql, final IRubyObject binds,
|
905
|
+
final IRubyObject pk) {
|
922
906
|
return withConnection(context, new Callable<IRubyObject>() {
|
923
907
|
public IRubyObject call(final Connection connection) throws SQLException {
|
924
908
|
PreparedStatement statement = null;
|
925
909
|
final String query = sqlString(sql);
|
926
910
|
try {
|
911
|
+
if (pk == context.nil || pk == context.fals || !supportsGeneratedKeys(connection)) {
|
912
|
+
statement = connection.prepareStatement(query, Statement.RETURN_GENERATED_KEYS);
|
913
|
+
} else {
|
914
|
+
statement = connection.prepareStatement(query, createStatementPk(pk));
|
915
|
+
}
|
927
916
|
|
928
|
-
statement = connection.prepareStatement(query, Statement.RETURN_GENERATED_KEYS);
|
929
917
|
setStatementParameters(context, connection, statement, (RubyArray) binds);
|
930
918
|
statement.executeUpdate();
|
931
919
|
return mapGeneratedKeys(context, connection, statement);
|
932
|
-
|
933
920
|
} catch (final SQLException e) {
|
934
921
|
debugErrorSQL(context, query);
|
935
922
|
throw e;
|
@@ -940,6 +927,12 @@ public class RubyJdbcConnection extends RubyObject {
|
|
940
927
|
});
|
941
928
|
}
|
942
929
|
|
930
|
+
@Deprecated
|
931
|
+
@JRubyMethod(name = "execute_insert", required = 2)
|
932
|
+
public IRubyObject execute_insert(final ThreadContext context, final IRubyObject binds, final IRubyObject sql) {
|
933
|
+
return execute_insert_pk(context, sql, binds, context.nil);
|
934
|
+
}
|
935
|
+
|
943
936
|
/**
|
944
937
|
* Executes an UPDATE (DELETE) SQL statement
|
945
938
|
* @param context
|
@@ -949,22 +942,20 @@ public class RubyJdbcConnection extends RubyObject {
|
|
949
942
|
*/
|
950
943
|
@JRubyMethod(name = {"execute_update", "execute_delete"}, required = 1)
|
951
944
|
public IRubyObject execute_update(final ThreadContext context, final IRubyObject sql) {
|
952
|
-
return withConnection(context,
|
953
|
-
|
954
|
-
|
955
|
-
final String query = sqlString(sql);
|
945
|
+
return withConnection(context, (Callable<IRubyObject>) connection -> {
|
946
|
+
Statement statement = null;
|
947
|
+
final String query = sqlString(sql);
|
956
948
|
|
957
|
-
|
958
|
-
|
949
|
+
try {
|
950
|
+
statement = createStatement(context, connection);
|
959
951
|
|
960
|
-
|
961
|
-
|
962
|
-
|
963
|
-
|
964
|
-
|
965
|
-
|
966
|
-
|
967
|
-
}
|
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);
|
968
959
|
}
|
969
960
|
});
|
970
961
|
}
|
@@ -980,21 +971,19 @@ public class RubyJdbcConnection extends RubyObject {
|
|
980
971
|
*/
|
981
972
|
@JRubyMethod(name = {"execute_prepared_update", "execute_prepared_delete"}, required = 2)
|
982
973
|
public IRubyObject execute_prepared_update(final ThreadContext context, final IRubyObject sql, final IRubyObject binds) {
|
983
|
-
return withConnection(context,
|
984
|
-
|
985
|
-
|
986
|
-
|
987
|
-
|
988
|
-
|
989
|
-
|
990
|
-
|
991
|
-
|
992
|
-
|
993
|
-
|
994
|
-
|
995
|
-
|
996
|
-
close(statement);
|
997
|
-
}
|
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);
|
998
987
|
}
|
999
988
|
});
|
1000
989
|
}
|
@@ -1041,50 +1030,48 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1041
1030
|
|
1042
1031
|
private IRubyObject doExecuteQueryRaw(final ThreadContext context,
|
1043
1032
|
final String query, final int maxRows, final Block block, final RubyArray binds) {
|
1044
|
-
return withConnection(context,
|
1045
|
-
|
1046
|
-
|
1047
|
-
|
1048
|
-
|
1049
|
-
|
1050
|
-
|
1051
|
-
|
1052
|
-
|
1053
|
-
|
1054
|
-
|
1055
|
-
|
1056
|
-
|
1057
|
-
|
1058
|
-
|
1059
|
-
|
1060
|
-
}
|
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
|
+
}
|
1061
1049
|
|
1062
|
-
|
1063
|
-
if (hasResult) {
|
1064
|
-
// yield(id1, name1) ... row 1 result data
|
1065
|
-
// yield(id2, name2) ... row 2 result data
|
1066
|
-
return yieldResultRows(context, connection, statement.getResultSet(), block);
|
1067
|
-
}
|
1068
|
-
return context.nil;
|
1069
|
-
}
|
1050
|
+
if (block.isGiven()) {
|
1070
1051
|
if (hasResult) {
|
1071
|
-
|
1052
|
+
// yield(id1, name1) ... row 1 result data
|
1053
|
+
// yield(id2, name2) ... row 2 result data
|
1054
|
+
return yieldResultRows(context, connection, statement.getResultSet(), block);
|
1072
1055
|
}
|
1073
|
-
return context.
|
1074
|
-
}
|
1075
|
-
catch (final SQLException e) {
|
1076
|
-
debugErrorSQL(context, query);
|
1077
|
-
throw e;
|
1056
|
+
return context.nil;
|
1078
1057
|
}
|
1079
|
-
|
1080
|
-
|
1058
|
+
if (hasResult) {
|
1059
|
+
return mapToRawResult(context, connection, statement.getResultSet(), false);
|
1081
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);
|
1082
1069
|
}
|
1083
1070
|
});
|
1084
1071
|
}
|
1085
1072
|
|
1086
1073
|
protected static String sqlString(final IRubyObject sql) {
|
1087
|
-
return sql
|
1074
|
+
return sql.convertToString().decodeString();
|
1088
1075
|
}
|
1089
1076
|
|
1090
1077
|
/**
|
@@ -1097,26 +1084,24 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1097
1084
|
*/
|
1098
1085
|
@JRubyMethod(required = 1)
|
1099
1086
|
public IRubyObject execute_query(final ThreadContext context, final IRubyObject sql) {
|
1100
|
-
return withConnection(context,
|
1101
|
-
|
1102
|
-
|
1103
|
-
|
1104
|
-
|
1105
|
-
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);
|
1106
1092
|
|
1107
|
-
|
1108
|
-
|
1109
|
-
|
1110
|
-
|
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
|
+
}
|
1111
1097
|
|
1112
|
-
|
1098
|
+
return newEmptyResult(context);
|
1113
1099
|
|
1114
|
-
|
1115
|
-
|
1116
|
-
|
1117
|
-
|
1118
|
-
|
1119
|
-
}
|
1100
|
+
} catch (final SQLException e) {
|
1101
|
+
debugErrorSQL(context, query);
|
1102
|
+
throw e;
|
1103
|
+
} finally {
|
1104
|
+
close(statement);
|
1120
1105
|
}
|
1121
1106
|
});
|
1122
1107
|
}
|
@@ -1129,13 +1114,11 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1129
1114
|
*/
|
1130
1115
|
@JRubyMethod(required = 1)
|
1131
1116
|
public IRubyObject prepare_statement(final ThreadContext context, final IRubyObject sql) {
|
1132
|
-
return withConnection(context,
|
1133
|
-
|
1134
|
-
|
1135
|
-
|
1136
|
-
|
1137
|
-
return JavaUtil.convertJavaToRuby(context.runtime, statement);
|
1138
|
-
}
|
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);
|
1139
1122
|
});
|
1140
1123
|
}
|
1141
1124
|
|
@@ -1158,40 +1141,40 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1158
1141
|
@JRubyMethod(required = 3)
|
1159
1142
|
public IRubyObject execute_prepared_query(final ThreadContext context, final IRubyObject sql,
|
1160
1143
|
final IRubyObject binds, final IRubyObject cachedStatement) {
|
1161
|
-
return withConnection(context,
|
1162
|
-
|
1163
|
-
|
1164
|
-
|
1165
|
-
PreparedStatement statement = null;
|
1144
|
+
return withConnection(context, connection -> {
|
1145
|
+
final boolean cached = !(cachedStatement == null || cachedStatement.isNil());
|
1146
|
+
String query = null;
|
1147
|
+
PreparedStatement statement = null;
|
1166
1148
|
|
1167
|
-
|
1168
|
-
|
1169
|
-
|
1170
|
-
|
1171
|
-
|
1172
|
-
|
1173
|
-
|
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
|
+
}
|
1174
1157
|
|
1175
|
-
|
1158
|
+
setStatementParameters(context, connection, statement, (RubyArray) binds);
|
1176
1159
|
|
1177
|
-
|
1178
|
-
|
1179
|
-
|
1180
|
-
|
1160
|
+
if (statement.execute()) {
|
1161
|
+
ResultSet resultSet = statement.getResultSet();
|
1162
|
+
IRubyObject results = mapQueryResult(context, connection, resultSet);
|
1163
|
+
resultSet.close();
|
1181
1164
|
|
1182
|
-
|
1183
|
-
|
1184
|
-
|
1185
|
-
|
1186
|
-
|
1187
|
-
|
1188
|
-
|
1189
|
-
|
1190
|
-
|
1191
|
-
|
1192
|
-
|
1193
|
-
|
1194
|
-
|
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);
|
1195
1178
|
}
|
1196
1179
|
}
|
1197
1180
|
});
|
@@ -1203,35 +1186,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1203
1186
|
return mapToResult(context, connection, resultSet, columns);
|
1204
1187
|
}
|
1205
1188
|
|
1206
|
-
/**
|
1207
|
-
* @deprecated please do not use this method
|
1208
|
-
*/
|
1209
|
-
@Deprecated // only used by Oracle adapter - also it's really a bad idea
|
1210
|
-
@JRubyMethod(name = "execute_id_insert", required = 2)
|
1211
|
-
public IRubyObject execute_id_insert(final ThreadContext context, final IRubyObject sql, final IRubyObject id) {
|
1212
|
-
final Ruby runtime = context.runtime;
|
1213
|
-
|
1214
|
-
callMethod("warn", RubyString.newUnicodeString(runtime, "DEPRECATED: execute_id_insert(sql, id) will be removed"));
|
1215
|
-
|
1216
|
-
return withConnection(context, new Callable<IRubyObject>() {
|
1217
|
-
public IRubyObject call(final Connection connection) throws SQLException {
|
1218
|
-
PreparedStatement statement = null;
|
1219
|
-
final String insertSQL = sql.convertToString().getUnicodeValue();
|
1220
|
-
try {
|
1221
|
-
statement = connection.prepareStatement(insertSQL);
|
1222
|
-
statement.setLong(1, RubyNumeric.fix2long(id));
|
1223
|
-
statement.executeUpdate();
|
1224
|
-
}
|
1225
|
-
catch (final SQLException e) {
|
1226
|
-
debugErrorSQL(context, insertSQL);
|
1227
|
-
throw e;
|
1228
|
-
}
|
1229
|
-
finally { close(statement); }
|
1230
|
-
return id;
|
1231
|
-
}
|
1232
|
-
});
|
1233
|
-
}
|
1234
|
-
|
1235
1189
|
@JRubyMethod(name = "supported_data_types")
|
1236
1190
|
public IRubyObject supported_data_types(final ThreadContext context) throws SQLException {
|
1237
1191
|
final Connection connection = getConnection(true);
|
@@ -1255,12 +1209,10 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1255
1209
|
protected static final int PRIMARY_KEYS_COLUMN_NAME = 4;
|
1256
1210
|
|
1257
1211
|
private List<RubyString> primaryKeys(final ThreadContext context, final String tableName) {
|
1258
|
-
return withConnection(context,
|
1259
|
-
|
1260
|
-
|
1261
|
-
|
1262
|
-
return primaryKeys(context, connection, table);
|
1263
|
-
}
|
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);
|
1264
1216
|
});
|
1265
1217
|
}
|
1266
1218
|
|
@@ -1268,7 +1220,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1268
1220
|
final Connection connection, final TableName table) throws SQLException {
|
1269
1221
|
final DatabaseMetaData metaData = connection.getMetaData();
|
1270
1222
|
ResultSet resultSet = null;
|
1271
|
-
final List<RubyString> keyNames = new ArrayList
|
1223
|
+
final List<RubyString> keyNames = new ArrayList<>();
|
1272
1224
|
try {
|
1273
1225
|
resultSet = metaData.getPrimaryKeys(table.catalog, table.schema, table.name);
|
1274
1226
|
final Ruby runtime = context.runtime;
|
@@ -1282,26 +1234,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1282
1234
|
return keyNames;
|
1283
1235
|
}
|
1284
1236
|
|
1285
|
-
@Deprecated //@JRubyMethod(name = "tables")
|
1286
|
-
public IRubyObject tables(ThreadContext context) {
|
1287
|
-
return tables(context, null, null, null, TABLE_TYPE);
|
1288
|
-
}
|
1289
|
-
|
1290
|
-
@Deprecated //@JRubyMethod(name = "tables")
|
1291
|
-
public IRubyObject tables(ThreadContext context, IRubyObject catalog) {
|
1292
|
-
return tables(context, toStringOrNull(catalog), null, null, TABLE_TYPE);
|
1293
|
-
}
|
1294
|
-
|
1295
|
-
@Deprecated //@JRubyMethod(name = "tables")
|
1296
|
-
public IRubyObject tables(ThreadContext context, IRubyObject catalog, IRubyObject schemaPattern) {
|
1297
|
-
return tables(context, toStringOrNull(catalog), toStringOrNull(schemaPattern), null, TABLE_TYPE);
|
1298
|
-
}
|
1299
|
-
|
1300
|
-
@Deprecated //@JRubyMethod(name = "tables")
|
1301
|
-
public IRubyObject tables(ThreadContext context, IRubyObject catalog, IRubyObject schemaPattern, IRubyObject tablePattern) {
|
1302
|
-
return tables(context, toStringOrNull(catalog), toStringOrNull(schemaPattern), toStringOrNull(tablePattern), TABLE_TYPE);
|
1303
|
-
}
|
1304
|
-
|
1305
1237
|
@JRubyMethod(name = "tables", required = 0, optional = 4)
|
1306
1238
|
public IRubyObject tables(final ThreadContext context, final IRubyObject[] args) {
|
1307
1239
|
switch ( args.length ) {
|
@@ -1319,11 +1251,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1319
1251
|
|
1320
1252
|
protected IRubyObject tables(final ThreadContext context,
|
1321
1253
|
final String catalog, final String schemaPattern, final String tablePattern, final String[] types) {
|
1322
|
-
return withConnection(context,
|
1323
|
-
public IRubyObject call(final Connection connection) throws SQLException {
|
1324
|
-
return matchTables(context, connection, catalog, schemaPattern, tablePattern, types, false);
|
1325
|
-
}
|
1326
|
-
});
|
1254
|
+
return withConnection(context, connection -> matchTables(context, connection, catalog, schemaPattern, tablePattern, types, false));
|
1327
1255
|
}
|
1328
1256
|
|
1329
1257
|
protected String[] getTableTypes() {
|
@@ -1353,40 +1281,36 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1353
1281
|
|
1354
1282
|
protected IRubyObject tableExists(final ThreadContext context,
|
1355
1283
|
final String defaultSchema, final String tableName) {
|
1356
|
-
return withConnection(context,
|
1357
|
-
|
1358
|
-
|
1359
|
-
return context.runtime.newBoolean( tableExists(context, connection, components) );
|
1360
|
-
}
|
1284
|
+
return withConnection(context, connection -> {
|
1285
|
+
final TableName components = extractTableName(connection, defaultSchema, tableName);
|
1286
|
+
return context.runtime.newBoolean( tableExists(context, connection, components) );
|
1361
1287
|
});
|
1362
1288
|
}
|
1363
1289
|
|
1364
1290
|
@JRubyMethod(name = {"columns", "columns_internal"}, required = 1, optional = 2)
|
1365
1291
|
public RubyArray columns_internal(final ThreadContext context, final IRubyObject[] args)
|
1366
1292
|
throws SQLException {
|
1367
|
-
return withConnection(context,
|
1368
|
-
|
1369
|
-
|
1370
|
-
|
1371
|
-
|
1372
|
-
|
1373
|
-
|
1374
|
-
final String defaultSchema = args.length > 2 ? toStringOrNull(args[2]) : null;
|
1375
|
-
|
1376
|
-
final TableName components;
|
1377
|
-
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;
|
1378
1300
|
|
1379
|
-
|
1380
|
-
|
1381
|
-
}
|
1301
|
+
final TableName components;
|
1302
|
+
components = extractTableName(connection, catalog, defaultSchema, tableName);
|
1382
1303
|
|
1383
|
-
|
1384
|
-
|
1385
|
-
return mapColumnsResult(context, metaData, components, columns);
|
1386
|
-
}
|
1387
|
-
finally {
|
1388
|
-
close(columns);
|
1304
|
+
if ( ! tableExists(context, connection, components) ) {
|
1305
|
+
throw new SQLException("table: " + tableName + " does not exist");
|
1389
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);
|
1390
1314
|
}
|
1391
1315
|
});
|
1392
1316
|
}
|
@@ -1416,70 +1340,68 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1416
1340
|
* should filter the return from this method instead.
|
1417
1341
|
*/
|
1418
1342
|
protected IRubyObject indexes(final ThreadContext context, final String tableName, final String name, final String schemaName) {
|
1419
|
-
return withConnection(context,
|
1420
|
-
|
1421
|
-
|
1422
|
-
final RubyClass IndexDefinition = getIndexDefinition(context);
|
1423
|
-
|
1424
|
-
String _tableName = caseConvertIdentifierForJdbc(connection, tableName);
|
1425
|
-
String _schemaName = caseConvertIdentifierForJdbc(connection, schemaName);
|
1426
|
-
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);
|
1427
1346
|
|
1428
|
-
|
1347
|
+
String _tableName = caseConvertIdentifierForJdbc(connection, tableName);
|
1348
|
+
String _schemaName = caseConvertIdentifierForJdbc(connection, schemaName);
|
1349
|
+
final TableName table = extractTableName(connection, null, _schemaName, _tableName);
|
1429
1350
|
|
1430
|
-
|
1431
|
-
final RubyArray indexes = RubyArray.newArray(runtime, 8);
|
1432
|
-
try {
|
1433
|
-
final DatabaseMetaData metaData = connection.getMetaData();
|
1434
|
-
indexInfoSet = metaData.getIndexInfo(table.catalog, table.schema, table.name, false, true);
|
1435
|
-
String currentIndex = null;
|
1436
|
-
RubyArray currentColumns = null;
|
1351
|
+
final List<RubyString> primaryKeys = primaryKeys(context, connection, table);
|
1437
1352
|
|
1438
|
-
|
1439
|
-
|
1440
|
-
|
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;
|
1441
1359
|
|
1442
|
-
|
1360
|
+
while ( indexInfoSet.next() ) {
|
1361
|
+
String indexName = indexInfoSet.getString(INDEX_INFO_NAME);
|
1362
|
+
if ( indexName == null ) continue;
|
1363
|
+
RubyArray currentColumns = null;
|
1443
1364
|
|
1444
|
-
|
1445
|
-
final RubyString rubyColumnName = cachedString(
|
1446
|
-
context, caseConvertIdentifierForRails(metaData, columnName)
|
1447
|
-
);
|
1448
|
-
if ( primaryKeys.contains(rubyColumnName) ) continue;
|
1365
|
+
indexName = caseConvertIdentifierForRails(metaData, indexName);
|
1449
1366
|
|
1450
|
-
|
1451
|
-
|
1452
|
-
|
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;
|
1453
1372
|
|
1454
|
-
|
1455
|
-
|
1373
|
+
// We are working on a new index
|
1374
|
+
if ( ! indexName.equals(currentIndex) ) {
|
1375
|
+
currentIndex = indexName;
|
1456
1376
|
|
1457
|
-
|
1377
|
+
String indexTableName = indexInfoSet.getString(INDEX_INFO_TABLE_NAME);
|
1378
|
+
indexTableName = caseConvertIdentifierForRails(metaData, indexTableName);
|
1458
1379
|
|
1459
|
-
|
1460
|
-
cachedString(context, indexTableName), // table_name
|
1461
|
-
cachedString(context, indexName), // index_name
|
1462
|
-
nonUnique ? runtime.getFalse() : runtime.getTrue(), // unique
|
1463
|
-
currentColumns = RubyArray.newArray(runtime, 4) // [] column names
|
1464
|
-
// orders, (since AR 3.2) where, type, using (AR 4.0)
|
1465
|
-
};
|
1380
|
+
final boolean nonUnique = indexInfoSet.getBoolean(INDEX_INFO_NON_UNIQUE);
|
1466
1381
|
|
1467
|
-
|
1468
|
-
|
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
|
+
};
|
1469
1389
|
|
1470
|
-
|
1471
|
-
if ( currentColumns != null ) currentColumns.append(rubyColumnName);
|
1390
|
+
indexes.append( IndexDefinition.newInstance(context, args, Block.NULL_BLOCK) ); // IndexDefinition.new
|
1472
1391
|
}
|
1473
1392
|
|
1474
|
-
|
1393
|
+
// one or more columns can be associated with an index
|
1394
|
+
if ( currentColumns != null ) currentColumns.append(rubyColumnName);
|
1395
|
+
}
|
1475
1396
|
|
1476
|
-
|
1477
|
-
|
1397
|
+
return indexes;
|
1398
|
+
|
1399
|
+
} finally { close(indexInfoSet); }
|
1478
1400
|
});
|
1479
1401
|
}
|
1480
1402
|
|
1481
1403
|
protected RubyClass getIndexDefinition(final ThreadContext context) {
|
1482
|
-
final RubyClass adapterClass =
|
1404
|
+
final RubyClass adapterClass = adapter.getMetaClass();
|
1483
1405
|
IRubyObject IDef = adapterClass.getConstantAt("IndexDefinition");
|
1484
1406
|
return IDef != null ? (RubyClass) IDef : getIndexDefinition(context.runtime);
|
1485
1407
|
}
|
@@ -1490,57 +1412,55 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1490
1412
|
}
|
1491
1413
|
|
1492
1414
|
protected IRubyObject foreignKeys(final ThreadContext context, final String tableName, final String schemaName, final String catalog) {
|
1493
|
-
return withConnection(context,
|
1494
|
-
|
1495
|
-
|
1496
|
-
final RubyClass FKDefinition = getForeignKeyDefinition(context);
|
1415
|
+
return withConnection(context, (Callable<IRubyObject>) connection -> {
|
1416
|
+
final Ruby runtime = context.runtime;
|
1417
|
+
final RubyClass FKDefinition = getForeignKeyDefinition(context);
|
1497
1418
|
|
1498
|
-
|
1499
|
-
|
1500
|
-
|
1419
|
+
String _tableName = caseConvertIdentifierForJdbc(connection, tableName);
|
1420
|
+
String _schemaName = caseConvertIdentifierForJdbc(connection, schemaName);
|
1421
|
+
final TableName table = extractTableName(connection, catalog, _schemaName, _tableName);
|
1501
1422
|
|
1502
|
-
|
1503
|
-
|
1504
|
-
|
1505
|
-
|
1506
|
-
|
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);
|
1507
1428
|
|
1508
|
-
|
1509
|
-
|
1429
|
+
while ( fkInfoSet.next() ) {
|
1430
|
+
final RubyHash options = RubyHash.newHash(runtime);
|
1510
1431
|
|
1511
|
-
|
1512
|
-
|
1513
|
-
|
1514
|
-
|
1515
|
-
|
1432
|
+
String fkName = fkInfoSet.getString("FK_NAME");
|
1433
|
+
if (fkName != null) {
|
1434
|
+
fkName = caseConvertIdentifierForRails(metaData, fkName);
|
1435
|
+
options.put(runtime.newSymbol("name"), fkName);
|
1436
|
+
}
|
1516
1437
|
|
1517
|
-
|
1518
|
-
|
1438
|
+
String columnName = fkInfoSet.getString("FKCOLUMN_NAME");
|
1439
|
+
options.put(runtime.newSymbol("column"), caseConvertIdentifierForRails(metaData, columnName));
|
1519
1440
|
|
1520
|
-
|
1521
|
-
|
1441
|
+
columnName = fkInfoSet.getString("PKCOLUMN_NAME");
|
1442
|
+
options.put(runtime.newSymbol("primary_key"), caseConvertIdentifierForRails(metaData, columnName));
|
1522
1443
|
|
1523
|
-
|
1524
|
-
|
1444
|
+
String fkTableName = fkInfoSet.getString("FKTABLE_NAME");
|
1445
|
+
fkTableName = caseConvertIdentifierForRails(metaData, fkTableName);
|
1525
1446
|
|
1526
|
-
|
1527
|
-
|
1447
|
+
String pkTableName = fkInfoSet.getString("PKTABLE_NAME");
|
1448
|
+
pkTableName = caseConvertIdentifierForRails(metaData, pkTableName);
|
1528
1449
|
|
1529
|
-
|
1530
|
-
|
1450
|
+
final String onDelete = extractForeignKeyRule( fkInfoSet.getInt("DELETE_RULE") );
|
1451
|
+
if ( onDelete != null ) options.op_aset(context, runtime.newSymbol("on_delete"), runtime.newSymbol(onDelete));
|
1531
1452
|
|
1532
|
-
|
1533
|
-
|
1453
|
+
final String onUpdate = extractForeignKeyRule( fkInfoSet.getInt("UPDATE_RULE") );
|
1454
|
+
if ( onUpdate != null ) options.op_aset(context, runtime.newSymbol("on_update"), runtime.newSymbol(onUpdate));
|
1534
1455
|
|
1535
|
-
|
1536
|
-
|
1537
|
-
|
1538
|
-
|
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
|
+
}
|
1539
1460
|
|
1540
|
-
|
1461
|
+
return runtime.newArray(fKeys);
|
1541
1462
|
|
1542
|
-
|
1543
|
-
}
|
1463
|
+
} finally { close(fkInfoSet); }
|
1544
1464
|
});
|
1545
1465
|
}
|
1546
1466
|
|
@@ -1555,7 +1475,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1555
1475
|
}
|
1556
1476
|
|
1557
1477
|
protected RubyClass getForeignKeyDefinition(final ThreadContext context) {
|
1558
|
-
final RubyClass adapterClass =
|
1478
|
+
final RubyClass adapterClass = adapter.getMetaClass();
|
1559
1479
|
IRubyObject FKDef = adapterClass.getConstantAt("ForeignKeyDefinition");
|
1560
1480
|
return FKDef != null ? (RubyClass) FKDef : getForeignKeyDefinition(context.runtime);
|
1561
1481
|
}
|
@@ -1563,42 +1483,34 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1563
1483
|
|
1564
1484
|
@JRubyMethod(name = "supports_foreign_keys?")
|
1565
1485
|
public IRubyObject supports_foreign_keys_p(final ThreadContext context) throws SQLException {
|
1566
|
-
return withConnection(context,
|
1567
|
-
|
1568
|
-
|
1569
|
-
return context.runtime.newBoolean( metaData.supportsIntegrityEnhancementFacility() );
|
1570
|
-
}
|
1486
|
+
return withConnection(context, (Callable<IRubyObject>) connection -> {
|
1487
|
+
final DatabaseMetaData metaData = connection.getMetaData();
|
1488
|
+
return context.runtime.newBoolean( metaData.supportsIntegrityEnhancementFacility() );
|
1571
1489
|
});
|
1572
1490
|
}
|
1573
1491
|
|
1574
1492
|
@JRubyMethod(name = "supports_views?")
|
1575
1493
|
public IRubyObject supports_views_p(final ThreadContext context) throws SQLException {
|
1576
|
-
return withConnection(context,
|
1577
|
-
|
1578
|
-
|
1579
|
-
|
1580
|
-
|
1581
|
-
|
1582
|
-
|
1583
|
-
return context.runtime.newBoolean( true );
|
1584
|
-
}
|
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 );
|
1585
1501
|
}
|
1586
1502
|
}
|
1587
|
-
finally {
|
1588
|
-
close(tableTypes);
|
1589
|
-
}
|
1590
|
-
return context.runtime.newBoolean( false );
|
1591
1503
|
}
|
1504
|
+
finally {
|
1505
|
+
close(tableTypes);
|
1506
|
+
}
|
1507
|
+
return context.runtime.newBoolean( false );
|
1592
1508
|
});
|
1593
1509
|
}
|
1594
1510
|
|
1595
1511
|
@JRubyMethod(name = "with_jdbc_connection", alias = "with_connection_retry_guard", frame = true)
|
1596
1512
|
public IRubyObject with_jdbc_connection(final ThreadContext context, final Block block) {
|
1597
|
-
return withConnection(context,
|
1598
|
-
public IRubyObject call(final Connection connection) throws SQLException {
|
1599
|
-
return block.call(context, convertJavaToRuby(connection));
|
1600
|
-
}
|
1601
|
-
});
|
1513
|
+
return withConnection(context, connection -> block.call(context, convertJavaToRuby(connection)));
|
1602
1514
|
}
|
1603
1515
|
|
1604
1516
|
/*
|
@@ -1659,24 +1571,22 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1659
1571
|
// TODO: Fix this, the columns don't have the info needed to handle this anymore
|
1660
1572
|
// currently commented out so that it will compile
|
1661
1573
|
|
1662
|
-
return withConnection(context,
|
1663
|
-
|
1664
|
-
|
1665
|
-
|
1666
|
-
|
1667
|
-
|
1668
|
-
|
1669
|
-
setBlobParameter(context, connection, statement, 1, value, column, Types.BLOB);
|
1670
|
-
}
|
1671
|
-
else { // clob
|
1672
|
-
setClobParameter(context, connection, statement, 1, value, column, Types.CLOB);
|
1673
|
-
}
|
1674
|
-
setStatementParameter(context, context.runtime, connection, statement, 2, idValue, idColumn);
|
1675
|
-
*/
|
1676
|
-
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);
|
1677
1581
|
}
|
1678
|
-
|
1582
|
+
else { // clob
|
1583
|
+
setClobParameter(context, connection, statement, 1, value, column, Types.CLOB);
|
1584
|
+
}
|
1585
|
+
setStatementParameter(context, context.runtime, connection, statement, 2, idValue, idColumn);
|
1586
|
+
*/
|
1587
|
+
return statement.executeUpdate();
|
1679
1588
|
}
|
1589
|
+
finally { close(statement); }
|
1680
1590
|
});
|
1681
1591
|
}
|
1682
1592
|
|
@@ -1732,7 +1642,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1732
1642
|
final IRubyObject self, final IRubyObject config, final Block block) {
|
1733
1643
|
final IRubyObject ds_or_name = rawDataSourceOrName(context, config);
|
1734
1644
|
|
1735
|
-
if ( ds_or_name == null ) return context.
|
1645
|
+
if ( ds_or_name == null ) return context.fals;
|
1736
1646
|
|
1737
1647
|
final javax.sql.DataSource dataSource;
|
1738
1648
|
final Object dsOrName = ds_or_name.toJava(Object.class);
|
@@ -1788,7 +1698,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1788
1698
|
}
|
1789
1699
|
}
|
1790
1700
|
|
1791
|
-
if ( configValue == null || configValue == context.nil || configValue ==
|
1701
|
+
if ( configValue == null || configValue == context.nil || configValue == context.fals ) {
|
1792
1702
|
return null;
|
1793
1703
|
}
|
1794
1704
|
return configValue;
|
@@ -1811,13 +1721,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1811
1721
|
}
|
1812
1722
|
}
|
1813
1723
|
|
1814
|
-
@Deprecated
|
1815
|
-
@JRubyMethod(name = "setup_jdbc_factory", visibility = Visibility.PROTECTED)
|
1816
|
-
public IRubyObject set_driver_factory(final ThreadContext context) {
|
1817
|
-
setDriverFactory(context);
|
1818
|
-
return get_connection_factory(context.runtime);
|
1819
|
-
}
|
1820
|
-
|
1821
1724
|
private ConnectionFactory setDriverFactory(final ThreadContext context) {
|
1822
1725
|
|
1823
1726
|
final IRubyObject url = getConfigValue(context, "url");
|
@@ -1917,12 +1820,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1917
1820
|
return props;
|
1918
1821
|
}
|
1919
1822
|
|
1920
|
-
@JRubyMethod(name = "setup_jndi_factory", visibility = Visibility.PROTECTED)
|
1921
|
-
public IRubyObject set_data_source_factory(final ThreadContext context) {
|
1922
|
-
setDataSourceFactory(context);
|
1923
|
-
return get_connection_factory(context.runtime);
|
1924
|
-
}
|
1925
|
-
|
1926
1823
|
private ConnectionFactory setDataSourceFactory(final ThreadContext context) {
|
1927
1824
|
final javax.sql.DataSource dataSource; final String lookupName;
|
1928
1825
|
IRubyObject value = getConfigValue(context, "data_source");
|
@@ -1944,28 +1841,10 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1944
1841
|
private static volatile boolean defaultConfigJndi;
|
1945
1842
|
private static transient ConnectionFactory defaultConnectionFactory;
|
1946
1843
|
|
1947
|
-
/**
|
1948
|
-
* Sets the connection factory from the available configuration.
|
1949
|
-
* @param context
|
1950
|
-
* @see #initialize
|
1951
|
-
*/
|
1952
|
-
@Deprecated
|
1953
|
-
@JRubyMethod(name = "setup_connection_factory", visibility = Visibility.PROTECTED)
|
1954
|
-
public IRubyObject setup_connection_factory(final ThreadContext context) {
|
1955
|
-
setupConnectionFactory(context);
|
1956
|
-
return get_connection_factory(context.runtime);
|
1957
|
-
}
|
1958
|
-
|
1959
|
-
private IRubyObject get_connection_factory(final Ruby runtime) {
|
1960
|
-
return JavaUtil.convertJavaToRuby(runtime, connectionFactory);
|
1961
|
-
}
|
1962
|
-
|
1963
1844
|
/**
|
1964
1845
|
* @return whether the connection factory is JNDI based
|
1965
1846
|
*/
|
1966
1847
|
private boolean setupConnectionFactory(final ThreadContext context) {
|
1967
|
-
final IRubyObject config = getConfig();
|
1968
|
-
|
1969
1848
|
if ( defaultConfig == null ) {
|
1970
1849
|
synchronized(RubyJdbcConnection.class) {
|
1971
1850
|
if ( defaultConfig == null ) {
|
@@ -1997,18 +1876,17 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1997
1876
|
|
1998
1877
|
@JRubyMethod(name = "jndi?", alias = "jndi_connection?")
|
1999
1878
|
public RubyBoolean jndi_p(final ThreadContext context) {
|
2000
|
-
return context.runtime.newBoolean(
|
1879
|
+
return context.runtime.newBoolean(jndi);
|
2001
1880
|
}
|
2002
1881
|
|
2003
1882
|
protected boolean isJndi() { return this.jndi; }
|
2004
1883
|
|
2005
1884
|
@JRubyMethod(name = "config")
|
2006
|
-
public IRubyObject config() { return
|
1885
|
+
public IRubyObject config() { return config; }
|
2007
1886
|
|
2008
1887
|
public IRubyObject getConfig() { return this.config; }
|
2009
1888
|
|
2010
1889
|
protected final IRubyObject getConfigValue(final ThreadContext context, final String key) {
|
2011
|
-
final IRubyObject config = getConfig();
|
2012
1890
|
final RubySymbol keySym = context.runtime.newSymbol(key);
|
2013
1891
|
if ( config instanceof RubyHash ) {
|
2014
1892
|
final IRubyObject value = ((RubyHash) config).fastARef(keySym);
|
@@ -2019,7 +1897,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2019
1897
|
|
2020
1898
|
protected final IRubyObject setConfigValue(final ThreadContext context,
|
2021
1899
|
final String key, final IRubyObject value) {
|
2022
|
-
final IRubyObject config = getConfig();
|
2023
1900
|
final RubySymbol keySym = context.runtime.newSymbol(key);
|
2024
1901
|
if ( config instanceof RubyHash ) {
|
2025
1902
|
return ((RubyHash) config).op_aset(context, keySym, value);
|
@@ -2029,7 +1906,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2029
1906
|
|
2030
1907
|
protected final IRubyObject setConfigValueIfNotSet(final ThreadContext context,
|
2031
1908
|
final String key, final IRubyObject value) {
|
2032
|
-
final IRubyObject config = getConfig();
|
2033
1909
|
final RubySymbol keySym = context.runtime.newSymbol(key);
|
2034
1910
|
if ( config instanceof RubyHash ) {
|
2035
1911
|
final IRubyObject setValue = ((RubyHash) config).fastARef(keySym);
|
@@ -2049,7 +1925,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2049
1925
|
protected final IRubyObject getAdapter() { return this.adapter; }
|
2050
1926
|
|
2051
1927
|
protected RubyClass getJdbcColumnClass(final ThreadContext context) {
|
2052
|
-
return (RubyClass)
|
1928
|
+
return (RubyClass) adapter.callMethod(context, "jdbc_column_class");
|
2053
1929
|
}
|
2054
1930
|
|
2055
1931
|
protected ConnectionFactory getConnectionFactory() throws RaiseException {
|
@@ -2261,7 +2137,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2261
2137
|
@JRubyMethod(name = "raw_date_time?", meta = true)
|
2262
2138
|
public static IRubyObject useRawDateTime(final ThreadContext context, final IRubyObject self) {
|
2263
2139
|
if ( rawDateTime == null ) return context.nil;
|
2264
|
-
return context.runtime.newBoolean(
|
2140
|
+
return context.runtime.newBoolean(rawDateTime);
|
2265
2141
|
}
|
2266
2142
|
|
2267
2143
|
@JRubyMethod(name = "raw_date_time=", meta = true)
|
@@ -2275,17 +2151,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2275
2151
|
return value;
|
2276
2152
|
}
|
2277
2153
|
|
2278
|
-
/**
|
2279
|
-
* @return AR::Type-casted value
|
2280
|
-
* @since 1.3.18
|
2281
|
-
*/
|
2282
|
-
@Deprecated
|
2283
|
-
protected static IRubyObject typeCastFromDatabase(final ThreadContext context,
|
2284
|
-
final IRubyObject adapter, final RubySymbol typeName, final RubyString value) {
|
2285
|
-
final IRubyObject type = adapter.callMethod(context, "lookup_cast_type", typeName);
|
2286
|
-
return type.callMethod(context, "deserialize", value);
|
2287
|
-
}
|
2288
|
-
|
2289
2154
|
protected IRubyObject dateToRuby(final ThreadContext context,
|
2290
2155
|
final Ruby runtime, final ResultSet resultSet, final int column)
|
2291
2156
|
throws SQLException {
|
@@ -2296,11 +2161,11 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2296
2161
|
return resultSet.wasNull() ? context.nil : RubyString.newEmptyString(runtime);
|
2297
2162
|
}
|
2298
2163
|
|
2299
|
-
if ( rawDateTime != null && rawDateTime
|
2164
|
+
if ( rawDateTime != null && rawDateTime) {
|
2300
2165
|
return RubyString.newString(runtime, DateTimeUtils.dateToString(value));
|
2301
2166
|
}
|
2302
2167
|
|
2303
|
-
return DateTimeUtils.newDateAsTime(context, value,
|
2168
|
+
return DateTimeUtils.newDateAsTime(context, value, DateTimeZone.UTC).callMethod(context, "to_date");
|
2304
2169
|
}
|
2305
2170
|
|
2306
2171
|
protected IRubyObject timeToRuby(final ThreadContext context,
|
@@ -2312,7 +2177,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2312
2177
|
return resultSet.wasNull() ? context.nil : RubyString.newEmptyString(runtime);
|
2313
2178
|
}
|
2314
2179
|
|
2315
|
-
if ( rawDateTime != null && rawDateTime
|
2180
|
+
if ( rawDateTime != null && rawDateTime) {
|
2316
2181
|
return RubyString.newString(runtime, DateTimeUtils.timeToString(value));
|
2317
2182
|
}
|
2318
2183
|
|
@@ -2328,7 +2193,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2328
2193
|
return resultSet.wasNull() ? context.nil : RubyString.newEmptyString(runtime);
|
2329
2194
|
}
|
2330
2195
|
|
2331
|
-
if ( rawDateTime != null && rawDateTime
|
2196
|
+
if ( rawDateTime != null && rawDateTime) {
|
2332
2197
|
return RubyString.newString(runtime, DateTimeUtils.timestampToString(value));
|
2333
2198
|
}
|
2334
2199
|
|
@@ -2340,19 +2205,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2340
2205
|
return DateTimeUtils.newTime(context, value, getDefaultTimeZone(context));
|
2341
2206
|
}
|
2342
2207
|
|
2343
|
-
@Deprecated
|
2344
|
-
protected static RubyString timestampToRubyString(final Ruby runtime, String value) {
|
2345
|
-
// Timestamp's format: yyyy-mm-dd hh:mm:ss.fffffffff
|
2346
|
-
String suffix; // assumes java.sql.Timestamp internals :
|
2347
|
-
if ( value.endsWith( suffix = " 00:00:00.0" ) ) {
|
2348
|
-
value = value.substring( 0, value.length() - suffix.length() );
|
2349
|
-
}
|
2350
|
-
else if ( value.endsWith( suffix = ".0" ) ) {
|
2351
|
-
value = value.substring( 0, value.length() - suffix.length() );
|
2352
|
-
}
|
2353
|
-
return RubyString.newUnicodeString(runtime, value);
|
2354
|
-
}
|
2355
|
-
|
2356
2208
|
protected static Boolean rawBoolean;
|
2357
2209
|
static {
|
2358
2210
|
final String booleanRaw = SafePropertyAccessor.getProperty("arjdbc.boolean.raw");
|
@@ -2364,7 +2216,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2364
2216
|
@JRubyMethod(name = "raw_boolean?", meta = true)
|
2365
2217
|
public static IRubyObject useRawBoolean(final ThreadContext context, final IRubyObject self) {
|
2366
2218
|
if ( rawBoolean == null ) return context.nil;
|
2367
|
-
return context.runtime.newBoolean(
|
2219
|
+
return context.runtime.newBoolean(rawBoolean);
|
2368
2220
|
}
|
2369
2221
|
|
2370
2222
|
@JRubyMethod(name = "raw_boolean=", meta = true)
|
@@ -2396,13 +2248,13 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2396
2248
|
protected IRubyObject booleanToRuby(final ThreadContext context,
|
2397
2249
|
final Ruby runtime, final ResultSet resultSet, final int column)
|
2398
2250
|
throws SQLException {
|
2399
|
-
if ( rawBoolean != null && rawBoolean
|
2251
|
+
if ( rawBoolean != null && rawBoolean) {
|
2400
2252
|
final String value = resultSet.getString(column);
|
2401
2253
|
if ( value == null /* && resultSet.wasNull() */ ) return context.nil;
|
2402
2254
|
return RubyString.newUnicodeString(runtime, value);
|
2403
2255
|
}
|
2404
2256
|
final boolean value = resultSet.getBoolean(column);
|
2405
|
-
if (
|
2257
|
+
if (!value && resultSet.wasNull()) return context.nil;
|
2406
2258
|
return runtime.newBoolean(value);
|
2407
2259
|
}
|
2408
2260
|
|
@@ -2620,7 +2472,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2620
2472
|
}
|
2621
2473
|
}
|
2622
2474
|
|
2623
|
-
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);
|
2624
2476
|
static {
|
2625
2477
|
JDBC_TYPE_FOR.put("string", Types.VARCHAR);
|
2626
2478
|
JDBC_TYPE_FOR.put("text", Types.CLOB);
|
@@ -2662,7 +2514,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2662
2514
|
final String internedType = internedTypeFor(context, attribute);
|
2663
2515
|
final Integer sqlType = jdbcTypeFor(internedType);
|
2664
2516
|
if ( sqlType != null ) {
|
2665
|
-
return sqlType
|
2517
|
+
return sqlType;
|
2666
2518
|
}
|
2667
2519
|
|
2668
2520
|
return Types.OTHER; // -1 as well as 0 are used in Types
|
@@ -2849,11 +2701,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2849
2701
|
statement.setTimestamp(index, timestamp, getCalendar(dateTime.getZone()));
|
2850
2702
|
}
|
2851
2703
|
|
2852
|
-
@Deprecated
|
2853
|
-
protected static Timestamp convertToTimestamp(final RubyFloat value) {
|
2854
|
-
return DateTimeUtils.convertToTimestamp(value);
|
2855
|
-
}
|
2856
|
-
|
2857
2704
|
protected static Calendar getCalendar(final DateTimeZone zone) { // final java.util.Date hint
|
2858
2705
|
if (DateTimeZone.UTC == zone) return getCalendarUTC();
|
2859
2706
|
if (DateTimeZone.getDefault() == zone) return new GregorianCalendar();
|
@@ -2899,9 +2746,14 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2899
2746
|
value = value.callMethod(context, "to_date");
|
2900
2747
|
}
|
2901
2748
|
|
2902
|
-
|
2903
|
-
|
2904
|
-
|
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()));
|
2905
2757
|
}
|
2906
2758
|
|
2907
2759
|
protected void setBooleanParameter(final ThreadContext context,
|
@@ -2938,7 +2790,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2938
2790
|
// For some reason the driver doesn't like "character varying" as a type
|
2939
2791
|
if ( type.eql(context.runtime.newSymbol("string")) ) return "varchar";
|
2940
2792
|
|
2941
|
-
final RubyHash nativeTypes = (RubyHash)
|
2793
|
+
final RubyHash nativeTypes = (RubyHash) adapter.callMethod(context, "native_database_types");
|
2942
2794
|
// e.g. `integer: { name: 'integer' }`
|
2943
2795
|
final RubyHash typeInfo = (RubyHash) nativeTypes.op_aref(context, type);
|
2944
2796
|
|
@@ -2999,16 +2851,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2999
2851
|
}
|
3000
2852
|
|
3001
2853
|
/**
|
3002
|
-
*
|
3003
|
-
* @return connection
|
3004
|
-
* @throws <code>ActiveRecord::ConnectionNotEstablished</code>, <code>ActiveRecord::JDBCError</code>
|
3005
|
-
*/
|
3006
|
-
protected Connection getConnection() throws RaiseException {
|
3007
|
-
return getConnection(false);
|
3008
|
-
}
|
3009
|
-
|
3010
|
-
/**
|
3011
|
-
* @see #getConnection()
|
2854
|
+
* Returns a connection (might cause a reconnect if there's none).
|
3012
2855
|
* @param required set to true if a connection is required to exists (e.g. on commit)
|
3013
2856
|
* @return connection
|
3014
2857
|
* @throws <code>ActiveRecord::ConnectionNotEstablished</code> if disconnected
|
@@ -3023,17 +2866,15 @@ public class RubyJdbcConnection extends RubyObject {
|
|
3023
2866
|
}
|
3024
2867
|
}
|
3025
2868
|
|
3026
|
-
|
2869
|
+
protected Connection getConnectionInternal(final boolean required) throws SQLException {
|
3027
2870
|
Connection connection = getConnectionImpl();
|
3028
|
-
if (
|
3029
|
-
if (
|
3030
|
-
|
3031
|
-
|
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
|
3032
2877
|
connection = getConnectionImpl();
|
3033
|
-
if ( connection == null ) {
|
3034
|
-
connectImpl( true ); // throws SQLException
|
3035
|
-
connection = getConnectionImpl();
|
3036
|
-
}
|
3037
2878
|
}
|
3038
2879
|
}
|
3039
2880
|
}
|
@@ -3164,7 +3005,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
3164
3005
|
try {
|
3165
3006
|
tablesSet = metaData.getTables(catalog, _schemaPattern, _tablePattern, types);
|
3166
3007
|
if ( checkExistsOnly ) { // only check if given table exists
|
3167
|
-
return tablesSet.next() ? context.
|
3008
|
+
return tablesSet.next() ? context.tru : null;
|
3168
3009
|
}
|
3169
3010
|
else {
|
3170
3011
|
return mapTables(context, connection, catalog, _schemaPattern, _tablePattern, tablesSet);
|
@@ -3173,15 +3014,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
3173
3014
|
finally { close(tablesSet); }
|
3174
3015
|
}
|
3175
3016
|
|
3176
|
-
@Deprecated
|
3177
|
-
protected IRubyObject matchTables(final Ruby runtime,
|
3178
|
-
final Connection connection,
|
3179
|
-
final String catalog, final String schemaPattern,
|
3180
|
-
final String tablePattern, final String[] types,
|
3181
|
-
final boolean checkExistsOnly) throws SQLException {
|
3182
|
-
return matchTables(runtime.getCurrentContext(), connection, catalog, schemaPattern, tablePattern, types, checkExistsOnly);
|
3183
|
-
}
|
3184
|
-
|
3185
3017
|
// NOTE java.sql.DatabaseMetaData.getTables :
|
3186
3018
|
protected final static int TABLES_TABLE_CAT = 1;
|
3187
3019
|
protected final static int TABLES_TABLE_SCHEM = 2;
|
@@ -3270,7 +3102,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
3270
3102
|
final String tabName = results.getString(TABLE_NAME);
|
3271
3103
|
final RubyString tableName = cachedString(context, caseConvertIdentifierForRails(metaData, tabName));
|
3272
3104
|
|
3273
|
-
final IRubyObject type_metadata =
|
3105
|
+
final IRubyObject type_metadata = adapter.callMethod(context, "fetch_type_metadata", sqlType);
|
3274
3106
|
|
3275
3107
|
// (name, default, sql_type_metadata = nil, null = true, table_name = nil, default_function = nil, collation = nil, comment: nil)
|
3276
3108
|
final IRubyObject[] args = new IRubyObject[] {
|
@@ -3286,7 +3118,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
3286
3118
|
ResultSet primaryKeys = null;
|
3287
3119
|
try {
|
3288
3120
|
primaryKeys = metaData.getPrimaryKeys(components.catalog, components.schema, components.name);
|
3289
|
-
final List<String> primaryKeyNames = new ArrayList
|
3121
|
+
final List<String> primaryKeyNames = new ArrayList<>(4);
|
3290
3122
|
while ( primaryKeys.next() ) {
|
3291
3123
|
primaryKeyNames.add( primaryKeys.getString(COLUMN_NAME) );
|
3292
3124
|
}
|
@@ -3335,7 +3167,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
3335
3167
|
// not have and auto-generated ID column :
|
3336
3168
|
boolean next = genKeys.next() && genKeys.getMetaData().getColumnCount() > 0;
|
3337
3169
|
// singleResult == null - guess if only single key returned
|
3338
|
-
if ( singleResult == null || singleResult
|
3170
|
+
if ( singleResult == null || singleResult) {
|
3339
3171
|
if ( next ) {
|
3340
3172
|
firstKey = mapGeneratedKey(runtime, genKeys);
|
3341
3173
|
if ( singleResult != null || ! genKeys.next() ) {
|
@@ -3368,7 +3200,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
3368
3200
|
if (supportsGeneratedKeys == null) {
|
3369
3201
|
supportsGeneratedKeys = this.supportsGeneratedKeys = connection.getMetaData().supportsGetGeneratedKeys();
|
3370
3202
|
}
|
3371
|
-
return supportsGeneratedKeys
|
3203
|
+
return supportsGeneratedKeys;
|
3372
3204
|
}
|
3373
3205
|
|
3374
3206
|
/**
|
@@ -3400,8 +3232,8 @@ public class RubyJdbcConnection extends RubyObject {
|
|
3400
3232
|
final ColumnData[] columns = extractColumns(context, connection, resultSet, false);
|
3401
3233
|
|
3402
3234
|
final Ruby runtime = context.runtime;
|
3403
|
-
final IRubyObject[] blockArgs = new IRubyObject[columns.length];
|
3404
3235
|
while ( resultSet.next() ) {
|
3236
|
+
final IRubyObject[] blockArgs = new IRubyObject[columns.length];
|
3405
3237
|
for ( int i = 0; i < columns.length; i++ ) {
|
3406
3238
|
final ColumnData column = columns[i];
|
3407
3239
|
blockArgs[i] = jdbcToRuby(context, runtime, column.index, column.type, resultSet);
|
@@ -3427,16 +3259,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
3427
3259
|
return setupColumns(context, connection, resultSet.getMetaData(), downCase);
|
3428
3260
|
}
|
3429
3261
|
|
3430
|
-
/**
|
3431
|
-
* @deprecated use {@link #extractColumns(ThreadContext, Connection, ResultSet, boolean)}
|
3432
|
-
*/
|
3433
|
-
@Deprecated
|
3434
|
-
protected ColumnData[] extractColumns(final Ruby runtime,
|
3435
|
-
final Connection connection, final ResultSet resultSet,
|
3436
|
-
final boolean downCase) throws SQLException {
|
3437
|
-
return extractColumns(runtime.getCurrentContext(), connection, resultSet, downCase);
|
3438
|
-
}
|
3439
|
-
|
3440
3262
|
protected <T> T withConnection(final ThreadContext context, final Callable<T> block)
|
3441
3263
|
throws RaiseException {
|
3442
3264
|
try {
|
@@ -3542,13 +3364,12 @@ public class RubyJdbcConnection extends RubyObject {
|
|
3542
3364
|
}
|
3543
3365
|
|
3544
3366
|
protected boolean isTransient(final Exception exception) {
|
3545
|
-
|
3546
|
-
return false;
|
3367
|
+
return exception instanceof SQLTransientException;
|
3547
3368
|
}
|
3548
3369
|
|
3549
3370
|
protected boolean isRecoverable(final Exception exception) {
|
3550
|
-
|
3551
|
-
|
3371
|
+
return exception instanceof SQLRecoverableException;
|
3372
|
+
// exception instanceof SQLException; // pre JDBC 4.0 drivers?
|
3552
3373
|
}
|
3553
3374
|
|
3554
3375
|
private static Throwable getCause(Throwable exception) {
|
@@ -3706,6 +3527,11 @@ public class RubyJdbcConnection extends RubyObject {
|
|
3706
3527
|
return Result.newInstance(context, columnsToArray(context, columns), rows, Block.NULL_BLOCK); // Result.new
|
3707
3528
|
}
|
3708
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
|
+
|
3709
3535
|
private static RubyArray columnsToArray(ThreadContext context, ColumnData[] columns) {
|
3710
3536
|
final IRubyObject[] cols = new IRubyObject[columns.length];
|
3711
3537
|
|
@@ -3928,6 +3754,12 @@ public class RubyJdbcConnection extends RubyObject {
|
|
3928
3754
|
}
|
3929
3755
|
}
|
3930
3756
|
|
3757
|
+
public static void debugMessage(final ThreadContext context, final IRubyObject obj) {
|
3758
|
+
if ( isDebug(context.runtime) ) {
|
3759
|
+
debugMessage(context.runtime, obj.callMethod(context, "inspect"));
|
3760
|
+
}
|
3761
|
+
}
|
3762
|
+
|
3931
3763
|
public static void debugMessage(final Ruby runtime, final String msg, final Object e) {
|
3932
3764
|
if ( isDebug(runtime) ) {
|
3933
3765
|
final PrintStream out = runtime != null ? runtime.getOut() : System.out;
|
@@ -3952,7 +3784,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
3952
3784
|
public static void debugStackTrace(final ThreadContext context, final Throwable e) {
|
3953
3785
|
if ( debug || ( context != null && context.runtime.isDebug() ) ) {
|
3954
3786
|
final PrintStream out = context != null ? context.runtime.getOut() : System.out;
|
3955
|
-
if ( debugStackTrace == null || debugStackTrace
|
3787
|
+
if ( debugStackTrace == null || debugStackTrace) {
|
3956
3788
|
e.printStackTrace(out);
|
3957
3789
|
}
|
3958
3790
|
else {
|
@@ -3968,8 +3800,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
3968
3800
|
private static boolean driverUsedLogged;
|
3969
3801
|
|
3970
3802
|
private void logDriverUsed(final Connection connection) {
|
3971
|
-
if (
|
3972
|
-
if ( driverUsedLogged ) return;
|
3803
|
+
if (debug && !driverUsedLogged) {
|
3973
3804
|
driverUsedLogged = true;
|
3974
3805
|
try {
|
3975
3806
|
final DatabaseMetaData meta = connection.getMetaData();
|