activerecord-jdbc-adapter 51.8-java → 52.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 +1 -2
- data/.travis.yml +26 -51
- data/README.md +9 -11
- data/Rakefile +19 -74
- data/activerecord-jdbc-adapter.gemspec +2 -2
- data/lib/active_record/connection_adapters/mssql_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +1 -0
- data/lib/arjdbc/abstract/core.rb +2 -12
- data/lib/arjdbc/abstract/database_statements.rb +24 -10
- data/lib/arjdbc/abstract/statement_cache.rb +4 -4
- data/lib/arjdbc/db2/adapter.rb +52 -2
- data/lib/arjdbc/jdbc.rb +4 -0
- data/lib/arjdbc/jdbc/column.rb +11 -5
- data/lib/arjdbc/jdbc/connection_methods.rb +9 -2
- data/lib/arjdbc/jdbc/jdbc.rake +4 -0
- data/lib/arjdbc/mssql.rb +7 -0
- data/lib/arjdbc/mssql/adapter.rb +804 -0
- data/lib/arjdbc/mssql/column.rb +200 -0
- data/lib/arjdbc/mssql/connection_methods.rb +79 -0
- data/lib/arjdbc/mssql/explain_support.rb +99 -0
- data/lib/arjdbc/mssql/limit_helpers.rb +231 -0
- data/lib/arjdbc/mssql/lock_methods.rb +77 -0
- data/lib/arjdbc/mssql/types.rb +343 -0
- data/lib/arjdbc/mssql/utils.rb +82 -0
- data/lib/arjdbc/mysql/adapter.rb +22 -14
- data/lib/arjdbc/mysql/connection_methods.rb +9 -18
- data/lib/arjdbc/postgresql/adapter.rb +102 -75
- data/lib/arjdbc/postgresql/column.rb +3 -6
- data/lib/arjdbc/postgresql/connection_methods.rb +3 -12
- data/lib/arjdbc/postgresql/oid_types.rb +12 -86
- data/lib/arjdbc/sqlite3/adapter.rb +88 -92
- data/lib/arjdbc/sqlite3/connection_methods.rb +0 -1
- data/lib/arjdbc/tasks/database_tasks.rb +36 -16
- data/lib/arjdbc/tasks/databases.rake +75 -32
- data/lib/arjdbc/tasks/databases3.rake +215 -0
- data/lib/arjdbc/tasks/databases4.rake +39 -0
- data/lib/arjdbc/version.rb +1 -1
- data/rakelib/01-tomcat.rake +2 -2
- data/rakelib/02-test.rake +3 -0
- data/rakelib/compile.rake +70 -0
- data/rakelib/db.rake +7 -21
- data/rakelib/rails.rake +4 -5
- data/src/java/arjdbc/ArJdbcModule.java +15 -5
- data/src/java/arjdbc/derby/DerbyRubyJdbcConnection.java +2 -2
- data/src/java/arjdbc/jdbc/ConnectionFactory.java +87 -0
- data/src/java/arjdbc/jdbc/DataSourceConnectionFactory.java +1 -0
- data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +29 -113
- data/src/java/arjdbc/mssql/MSSQLRubyJdbcConnection.java +14 -310
- data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +2 -2
- data/src/java/arjdbc/postgresql/PgResultSetMetaDataWrapper.java +23 -0
- data/src/java/arjdbc/postgresql/PostgreSQLResult.java +13 -21
- data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +50 -44
- data/src/java/arjdbc/util/DateTimeUtils.java +5 -141
- data/src/java/arjdbc/util/QuotingUtils.java +7 -6
- metadata +26 -11
- data/src/java/arjdbc/jdbc/RubyConnectionFactory.java +0 -61
- data/src/java/arjdbc/postgresql/PgDateTimeUtils.java +0 -52
data/lib/arjdbc/version.rb
CHANGED
data/rakelib/01-tomcat.rake
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
namespace :'tomcat-jndi' do # contains a FS JNDI impl (for tests)
|
2
2
|
|
3
|
-
TOMCAT_MAVEN_REPO = '
|
3
|
+
TOMCAT_MAVEN_REPO = 'http://repo2.maven.org/maven2/org/apache/tomcat'
|
4
4
|
TOMCAT_VERSION = '7.0.54'
|
5
5
|
|
6
6
|
DOWNLOAD_DIR = File.expand_path('../test/jars', File.dirname(__FILE__))
|
@@ -48,4 +48,4 @@ namespace :'tomcat-jndi' do # contains a FS JNDI impl (for tests)
|
|
48
48
|
rm jar_path if File.exist?(jar_path)
|
49
49
|
end
|
50
50
|
|
51
|
-
end
|
51
|
+
end
|
data/rakelib/02-test.rake
CHANGED
@@ -58,6 +58,7 @@ end
|
|
58
58
|
test_task_for :Derby, :desc => 'Run tests against (embedded) DerbyDB'
|
59
59
|
test_task_for :H2, :desc => 'Run tests against H2 database engine'
|
60
60
|
test_task_for :HSQLDB, :desc => 'Run tests against HyperSQL (Java) database'
|
61
|
+
test_task_for :MSSQL, :driver => :jtds, :database_name => 'MS-SQL (SQLServer)'
|
61
62
|
test_task_for :MySQL #, :prereqs => 'db:mysql'
|
62
63
|
task :test_mysql2 => :test_mysql
|
63
64
|
test_task_for :PostgreSQL, :driver => ENV['JDBC_POSTGRES_VERSION'] || 'postgres' #, :prereqs => 'db:postgresql'
|
@@ -75,6 +76,8 @@ end
|
|
75
76
|
test_task_for adapter, :desc => "Run tests against #{adapter} (ensure driver is on class-path)"
|
76
77
|
end
|
77
78
|
|
79
|
+
#test_task_for :MSSQL, :name => 'test_sqlserver', :driver => nil, :database_name => 'MS-SQL using SQLJDBC'
|
80
|
+
|
78
81
|
test_task_for :AS400, :desc => "Run tests against AS400 (DB2) (ensure driver is on class-path)",
|
79
82
|
:files => FileList["test/db2*_test.rb"] + FileList["test/db/db2/*_test.rb"]
|
80
83
|
|
@@ -0,0 +1,70 @@
|
|
1
|
+
jar_file = File.join(*%w(lib arjdbc jdbc adapter_java.jar))
|
2
|
+
begin
|
3
|
+
require 'ant'
|
4
|
+
directory classes = "pkg/classes"
|
5
|
+
CLEAN << classes
|
6
|
+
|
7
|
+
driver_jars = []
|
8
|
+
# PostgreSQL driver :
|
9
|
+
driver_jars << Dir.glob("jdbc-postgres/lib/*.jar").sort.last
|
10
|
+
|
11
|
+
file jar_file => FileList['src/java/**/*.java', 'pkg/classes'] do
|
12
|
+
rm_rf FileList["#{classes}/**/*"]
|
13
|
+
ant.javac :srcdir => "src/java", :destdir => "pkg/classes",
|
14
|
+
:source => "7", :target => "7", :debug => true, :deprecation => true,
|
15
|
+
:classpath => "${java.class.path}:${sun.boot.class.path}:#{driver_jars.join(':')}",
|
16
|
+
:includeantRuntime => false
|
17
|
+
|
18
|
+
ant.tstamp do |ts|
|
19
|
+
ts.format(:property => 'TODAY', :pattern => 'yyyy-MM-dd HH:mm:ss')
|
20
|
+
end
|
21
|
+
|
22
|
+
begin
|
23
|
+
require 'arjdbc/version'
|
24
|
+
rescue LoadError
|
25
|
+
path = File.expand_path('../lib', File.dirname(__FILE__))
|
26
|
+
unless $LOAD_PATH.include?(path)
|
27
|
+
$LOAD_PATH << path; retry
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
gem_version = Gem::Version.create(ArJdbc::VERSION)
|
32
|
+
if gem_version.segments.last == 'DEV'
|
33
|
+
version = gem_version.segments[0...-1] # 1.3.0.DEV -> 1.3.0
|
34
|
+
else
|
35
|
+
version = gem_version.segments.dup
|
36
|
+
end
|
37
|
+
version = version.join('.')
|
38
|
+
|
39
|
+
ant.manifest :file => 'MANIFEST.MF' do |mf|
|
40
|
+
mf.attribute :name => 'Built-By', :value => '${user.name}'
|
41
|
+
mf.attribute :name => 'Built-Time', :value => '${TODAY}'
|
42
|
+
mf.attribute :name => 'Built-Jdk', :value => '${java.version}'
|
43
|
+
mf.attribute :name => 'Built-JRuby', :value => JRUBY_VERSION
|
44
|
+
|
45
|
+
mf.attribute :name => 'Specification-Title', :value => 'ActiveRecord-JDBC'
|
46
|
+
mf.attribute :name => 'Specification-Version', :value => '1.3'
|
47
|
+
mf.attribute :name => 'Specification-Vendor', :value => 'JRuby'
|
48
|
+
mf.attribute :name => 'Implementation-Version', :value => version
|
49
|
+
mf.attribute :name => 'Implementation-Vendor', :value => 'The JRuby Team'
|
50
|
+
end
|
51
|
+
|
52
|
+
ant.jar :basedir => "pkg/classes", :includes => "**/*.class",
|
53
|
+
:destfile => jar_file, :manifest => 'MANIFEST.MF'
|
54
|
+
end
|
55
|
+
|
56
|
+
desc "Compile the native Java code."
|
57
|
+
task :jar => jar_file
|
58
|
+
|
59
|
+
namespace :jar do
|
60
|
+
task :force do
|
61
|
+
rm jar_file if File.exist?(jar_file)
|
62
|
+
Rake::Task['jar'].invoke
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
rescue LoadError
|
67
|
+
task :jar do
|
68
|
+
puts "Run 'jar' with JRuby to re-compile the agent extension class"
|
69
|
+
end
|
70
|
+
end
|
data/rakelib/db.rake
CHANGED
@@ -4,35 +4,25 @@ namespace :db do
|
|
4
4
|
task :mysql do
|
5
5
|
require File.expand_path('../../test/shared_helper', __FILE__)
|
6
6
|
fail "could not create test database: mysql executable not found" unless mysql = which('mysql')
|
7
|
-
|
8
7
|
load 'test/db/mysql_config.rb' # rescue nil
|
9
8
|
enc = MYSQL_CONFIG[:encoding] || 'utf8' # 'utf8mb4'
|
10
9
|
puts MYSQL_CONFIG.inspect if $VERBOSE
|
11
|
-
|
12
|
-
clean_script = sql_script <<-SQL, 'mysqlclean'
|
13
|
-
DROP USER #{MYSQL_CONFIG[:username]}@localhost;
|
14
|
-
SQL
|
15
|
-
|
10
|
+
# DROP USER arjdbc@localhost; __ERROR 1396 (HY000): Operation CREATE USER failed__
|
16
11
|
script = sql_script <<-SQL, 'mysql'
|
17
12
|
DROP DATABASE IF EXISTS `#{MYSQL_CONFIG[:database]}`;
|
18
13
|
CREATE DATABASE `#{MYSQL_CONFIG[:database]}` DEFAULT CHARACTER SET `#{enc}` COLLATE `#{enc}_general_ci`;
|
19
|
-
CREATE USER #{MYSQL_CONFIG[:username]}@localhost IDENTIFIED BY '#{MYSQL_CONFIG[:password]}';
|
20
14
|
GRANT ALL PRIVILEGES ON `#{MYSQL_CONFIG[:database]}`.* TO #{MYSQL_CONFIG[:username]}@localhost;
|
21
15
|
GRANT ALL PRIVILEGES ON `test\_%`.* TO #{MYSQL_CONFIG[:username]}@localhost;
|
16
|
+
SET PASSWORD FOR #{MYSQL_CONFIG[:username]}@localhost = PASSWORD('#{MYSQL_CONFIG[:password]}');
|
22
17
|
SQL
|
23
|
-
|
24
18
|
params = { '-u' => 'root' }
|
25
|
-
if ENV['DATABASE_YML']
|
26
|
-
|
27
|
-
params['-p'] = YAML.load(File.new(ENV['DATABASE_YML']))["production"]["password"]
|
19
|
+
if ENV['DATABASE_YML']; require 'yaml'
|
20
|
+
params['-p'] = YAML.load(File.new(ENV['DATABASE_YML']))["production"]["password"]
|
28
21
|
end
|
29
22
|
params['-u'] = ENV['MY_USER'] if ENV['MY_USER']
|
30
23
|
params['-p'] = ENV['MY_PASSWORD'] if ENV['MY_PASSWORD']
|
31
|
-
|
32
24
|
puts "Creating MySQL (test) database: #{MYSQL_CONFIG[:database]}"
|
33
|
-
|
34
|
-
sh "cat #{clean_script.path} | #{mysql_cmd}", verbose: false
|
35
|
-
sh "cat #{script.path} | #{mysql_cmd}", verbose: $VERBOSE # so password is not echoed
|
25
|
+
sh "cat #{script.path} | #{mysql} -f #{params.map {|k, v| "#{k}#{v}"}.join(' ')}", :verbose => $VERBOSE # so password is not echoed
|
36
26
|
end
|
37
27
|
|
38
28
|
desc "Creates the test database for PostgreSQL"
|
@@ -40,10 +30,8 @@ GRANT ALL PRIVILEGES ON `test\_%`.* TO #{MYSQL_CONFIG[:username]}@localhost;
|
|
40
30
|
require File.expand_path('../../test/shared_helper', __FILE__)
|
41
31
|
fail 'could not create test database: psql executable not found' unless psql = which('psql')
|
42
32
|
fail 'could not create test database: missing "postgres" role' unless PostgresHelper.postgres_role?
|
43
|
-
|
44
33
|
load 'test/db/postgres_config.rb' # rescue nil
|
45
34
|
puts POSTGRES_CONFIG.inspect if $VERBOSE
|
46
|
-
|
47
35
|
script = sql_script <<-SQL, 'psql'
|
48
36
|
DROP DATABASE IF EXISTS #{POSTGRES_CONFIG[:database]};
|
49
37
|
DROP USER IF EXISTS #{POSTGRES_CONFIG[:username]};
|
@@ -52,14 +40,12 @@ CREATE DATABASE #{POSTGRES_CONFIG[:database]} OWNER #{POSTGRES_CONFIG[:username]
|
|
52
40
|
TEMPLATE template0
|
53
41
|
ENCODING '#{POSTGRES_CONFIG[:encoding]}' LC_COLLATE '#{POSTGRES_CONFIG[:collate]}' LC_CTYPE '#{POSTGRES_CONFIG[:collate]}';
|
54
42
|
SQL
|
55
|
-
|
56
43
|
params = { '-U' => ENV['PSQL_USER'] || 'postgres' }
|
57
44
|
params['-q'] = nil unless $VERBOSE
|
58
|
-
|
59
45
|
puts "Creating PostgreSQL (test) database: #{POSTGRES_CONFIG[:database]}"
|
60
|
-
sh "cat #{script.path} | #{psql} #{params.to_a.join(' ')}", verbose
|
46
|
+
sh "cat #{script.path} | #{psql} #{params.to_a.join(' ')}", :verbose => $VERBOSE
|
61
47
|
end
|
62
|
-
task postgres
|
48
|
+
task :postgres => :postgresql
|
63
49
|
|
64
50
|
private
|
65
51
|
|
data/rakelib/rails.rake
CHANGED
@@ -9,15 +9,14 @@ namespace :rails do
|
|
9
9
|
if ENV['RAILS']
|
10
10
|
ar_path = File.join(ENV['RAILS'], 'activerecord')
|
11
11
|
end
|
12
|
-
|
12
|
+
|
13
13
|
unless ar_path && File.exist?(ar_path)
|
14
|
-
ar_path = `bundle info --path activerecord`.
|
14
|
+
ar_path = `bundle info --path activerecord`.chomp
|
15
15
|
end
|
16
16
|
|
17
17
|
unless File.exist? ar_test_dir = File.join(ar_path, 'test')
|
18
18
|
raise "can not directly load Rails tests;" +
|
19
|
-
" try setting a local repository path e.g. export RAILS=`pwd`/../rails
|
20
|
-
" failed guess: #{ar_path}"
|
19
|
+
" try setting a local repository path e.g. export RAILS=`pwd`/../rails"
|
21
20
|
end
|
22
21
|
|
23
22
|
driver = "jdbc-#{ENV['DRIVER'] ? ENV['DRIVER'].downcase : (adapter =~ /postgres/i ? 'postgres' : adapter)}"
|
@@ -51,7 +50,7 @@ namespace :rails do
|
|
51
50
|
ruby_opts_string += " -C \"#{ar_path}\""
|
52
51
|
ruby_opts_string += " -rbundler/setup"
|
53
52
|
ruby_opts_string += " -rminitest -rminitest/excludes" unless ENV['NO_EXCLUDES'].eql?('true')
|
54
|
-
file_list = ENV["TEST"] ? FileList[ ENV["TEST"]
|
53
|
+
file_list = ENV["TEST"] ? FileList[ ENV["TEST"] ] : test_files_finder.call
|
55
54
|
file_list_string = file_list.map { |fn| "\"#{fn}\"" }.join(' ')
|
56
55
|
# test_loader_code = "-e \"ARGV.each{|f| require f}\"" # :direct
|
57
56
|
option_list = ( ENV["TESTOPTS"] || ENV["TESTOPT"] || ENV["TEST_OPTS"] || '' )
|
@@ -29,6 +29,7 @@ import java.util.HashMap;
|
|
29
29
|
import java.util.Map;
|
30
30
|
import java.util.WeakHashMap;
|
31
31
|
|
32
|
+
import org.jruby.NativeException;
|
32
33
|
import org.jruby.Ruby;
|
33
34
|
import org.jruby.RubyArray;
|
34
35
|
import org.jruby.RubyClass;
|
@@ -147,7 +148,13 @@ public class ArJdbcModule {
|
|
147
148
|
}
|
148
149
|
}
|
149
150
|
catch (ClassNotFoundException e) { /* ignored */ }
|
150
|
-
catch (NoSuchMethodException
|
151
|
+
catch (NoSuchMethodException e) {
|
152
|
+
throw newNativeException(runtime, e);
|
153
|
+
}
|
154
|
+
catch (IllegalAccessException e) {
|
155
|
+
throw newNativeException(runtime, e);
|
156
|
+
}
|
157
|
+
catch (InvocationTargetException e) {
|
151
158
|
throw newNativeException(runtime, e);
|
152
159
|
}
|
153
160
|
|
@@ -256,15 +263,18 @@ public class ArJdbcModule {
|
|
256
263
|
try {
|
257
264
|
return klass.getMethod(name, argType).invoke(null, arg);
|
258
265
|
}
|
259
|
-
catch (IllegalAccessException
|
266
|
+
catch (IllegalAccessException e) {
|
267
|
+
throw newNativeException(runtime, e);
|
268
|
+
}
|
269
|
+
catch (InvocationTargetException e) {
|
260
270
|
throw newNativeException(runtime, e);
|
261
271
|
}
|
262
272
|
}
|
263
273
|
|
264
274
|
private static RaiseException newNativeException(final Ruby runtime, final Throwable cause) {
|
265
|
-
|
266
|
-
|
267
|
-
return
|
275
|
+
RubyClass nativeClass = runtime.getClass(NativeException.CLASS_NAME);
|
276
|
+
NativeException nativeException = new NativeException(runtime, nativeClass, cause);
|
277
|
+
return new RaiseException(cause, nativeException);
|
268
278
|
}
|
269
279
|
|
270
280
|
@JRubyMethod(meta = true)
|
@@ -83,8 +83,8 @@ public class DerbyRubyJdbcConnection extends RubyJdbcConnection {
|
|
83
83
|
final int minor = jdbcDriver.getMinorVersion();
|
84
84
|
if ( major < 10 || ( major == 10 && minor < 5 ) ) {
|
85
85
|
final RubyClass errorClass = getConnectionNotEstablished(context.runtime);
|
86
|
-
throw context.runtime
|
87
|
-
"adapter requires Derby >= 10.5 got: " + major + "." + minor + "");
|
86
|
+
throw new RaiseException(context.runtime, errorClass,
|
87
|
+
"adapter requires Derby >= 10.5 got: " + major + "." + minor + "", false);
|
88
88
|
}
|
89
89
|
if ( major == 10 && minor < 8 ) { // 10.8 ~ supports JDBC 4.1
|
90
90
|
// config[:connection_alive_sql] ||= 'SELECT 1 FROM SYS.SYSSCHEMAS FETCH FIRST 1 ROWS ONLY'
|
@@ -27,6 +27,12 @@ package arjdbc.jdbc;
|
|
27
27
|
|
28
28
|
import java.sql.Connection;
|
29
29
|
import java.sql.SQLException;
|
30
|
+
import javax.sql.DataSource;
|
31
|
+
|
32
|
+
import org.jruby.RubyObject;
|
33
|
+
import org.jruby.RubyString;
|
34
|
+
import org.jruby.runtime.ThreadContext;
|
35
|
+
import org.jruby.runtime.builtin.IRubyObject;
|
30
36
|
|
31
37
|
/**
|
32
38
|
* Interface to be implemented in Ruby for retrieving a new connection.
|
@@ -43,3 +49,84 @@ public interface ConnectionFactory {
|
|
43
49
|
Connection newConnection() throws SQLException;
|
44
50
|
|
45
51
|
}
|
52
|
+
|
53
|
+
class DataSourceConnectionFactoryImpl implements ConnectionFactory {
|
54
|
+
|
55
|
+
private final DataSource dataSource;
|
56
|
+
final String username, password; // optional
|
57
|
+
|
58
|
+
public DataSourceConnectionFactoryImpl(final DataSource dataSource) {
|
59
|
+
this.dataSource = dataSource;
|
60
|
+
this.username = null; this.password = null;
|
61
|
+
}
|
62
|
+
|
63
|
+
public DataSourceConnectionFactoryImpl(final DataSource dataSource,
|
64
|
+
final String username, final String password) {
|
65
|
+
this.dataSource = dataSource;
|
66
|
+
this.username = username; this.password = password;
|
67
|
+
}
|
68
|
+
|
69
|
+
@Override
|
70
|
+
public Connection newConnection() throws SQLException {
|
71
|
+
if ( username != null ) {
|
72
|
+
dataSource.getConnection(username, password);
|
73
|
+
}
|
74
|
+
return dataSource.getConnection();
|
75
|
+
}
|
76
|
+
|
77
|
+
DataSource getDataSource() { return dataSource; } /* for tests */
|
78
|
+
|
79
|
+
}
|
80
|
+
|
81
|
+
class DriverConnectionFactoryImpl implements ConnectionFactory {
|
82
|
+
|
83
|
+
private final DriverWrapper driverWrapper;
|
84
|
+
final String url;
|
85
|
+
final String username, password; // null allowed
|
86
|
+
|
87
|
+
public DriverConnectionFactoryImpl(final DriverWrapper driver, final String url) {
|
88
|
+
this.driverWrapper = driver; this.url = url;
|
89
|
+
this.username = null; this.password = null;
|
90
|
+
}
|
91
|
+
|
92
|
+
public DriverConnectionFactoryImpl(final DriverWrapper driver, final String url,
|
93
|
+
final String username, final String password) {
|
94
|
+
this.driverWrapper = driver; this.url = url;
|
95
|
+
this.username = username; this.password = password;
|
96
|
+
}
|
97
|
+
|
98
|
+
@Override
|
99
|
+
public Connection newConnection() throws SQLException {
|
100
|
+
return driverWrapper.connect(url, username, password);
|
101
|
+
}
|
102
|
+
|
103
|
+
DriverWrapper getDriverWrapper() { return driverWrapper; } /* for tests */
|
104
|
+
|
105
|
+
}
|
106
|
+
|
107
|
+
// @legacy ActiveRecord::ConnectionAdapters::JdbcDriver
|
108
|
+
class RubyConnectionFactoryImpl implements ConnectionFactory {
|
109
|
+
|
110
|
+
private final IRubyObject driver;
|
111
|
+
final RubyString url;
|
112
|
+
final IRubyObject username, password; // null allowed
|
113
|
+
|
114
|
+
private final RubyObject contextProvider;
|
115
|
+
|
116
|
+
public RubyConnectionFactoryImpl(final IRubyObject driver, final RubyString url,
|
117
|
+
final IRubyObject username, final IRubyObject password) {
|
118
|
+
this.driver = driver; this.url = url;
|
119
|
+
this.username = username; this.password = password;
|
120
|
+
contextProvider = (RubyObject) driver;
|
121
|
+
}
|
122
|
+
|
123
|
+
@Override
|
124
|
+
public Connection newConnection() throws SQLException {
|
125
|
+
final ThreadContext context = contextProvider.getRuntime().getCurrentContext();
|
126
|
+
final IRubyObject connection = driver.callMethod(context, "connection", new IRubyObject[] { url, username, password });
|
127
|
+
return (Connection) connection.toJava(Connection.class);
|
128
|
+
}
|
129
|
+
|
130
|
+
IRubyObject getDriver() { return driver; } /* for tests */
|
131
|
+
|
132
|
+
}
|
@@ -68,6 +68,7 @@ final class DataSourceConnectionFactory implements ConnectionFactory {
|
|
68
68
|
|
69
69
|
@Override
|
70
70
|
public Connection newConnection() throws SQLException {
|
71
|
+
DataSource dataSource = this.dataSource;
|
71
72
|
// in case DS failed previously look it up again from JNDI :
|
72
73
|
if (dataSource == null) {
|
73
74
|
lookupDataSource();
|
@@ -128,7 +128,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
128
128
|
private boolean lazy = false; // final once set on initialize
|
129
129
|
private boolean jndi; // final once set on initialize
|
130
130
|
private boolean configureConnection = true; // final once initialized
|
131
|
-
private int fetchSize = 0; // 0 = JDBC default
|
132
131
|
|
133
132
|
protected RubyJdbcConnection(Ruby runtime, RubyClass metaClass) {
|
134
133
|
super(runtime, metaClass);
|
@@ -487,7 +486,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
487
486
|
savepoint = ((IRubyObject) savepoint).toJava(Savepoint.class);
|
488
487
|
}
|
489
488
|
|
490
|
-
releaseSavepoint(
|
489
|
+
connection.releaseSavepoint((Savepoint) savepoint);
|
491
490
|
return context.nil;
|
492
491
|
}
|
493
492
|
catch (SQLException e) {
|
@@ -495,11 +494,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
495
494
|
}
|
496
495
|
}
|
497
496
|
|
498
|
-
// MSSQL doesn't support releasing savepoints so we make it possible to override the actual release action
|
499
|
-
protected void releaseSavepoint(final Connection connection, final Savepoint savepoint) throws SQLException {
|
500
|
-
connection.releaseSavepoint(savepoint);
|
501
|
-
}
|
502
|
-
|
503
497
|
protected static RuntimeException newSavepointNotSetError(final ThreadContext context, final IRubyObject name, final String op) {
|
504
498
|
RubyClass StatementInvalid = ActiveRecord(context).getClass("StatementInvalid");
|
505
499
|
return context.runtime.newRaiseException(StatementInvalid, "could not " + op + " savepoint: '" + name + "' (not set)");
|
@@ -577,11 +571,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
577
571
|
else {
|
578
572
|
this.configureConnection = value != context.runtime.getFalse();
|
579
573
|
}
|
580
|
-
|
581
|
-
IRubyObject jdbcFetchSize = getConfigValue(context, "jdbc_fetch_size");
|
582
|
-
if (jdbcFetchSize != context.nil) {
|
583
|
-
this.fetchSize = RubyNumeric.fix2int(jdbcFetchSize);
|
584
|
-
}
|
585
574
|
}
|
586
575
|
|
587
576
|
@JRubyMethod(name = "adapter")
|
@@ -727,10 +716,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
727
716
|
|
728
717
|
private void connectImpl(final boolean forceConnection) throws SQLException {
|
729
718
|
setConnection( forceConnection ? newConnection() : null );
|
730
|
-
if (forceConnection)
|
731
|
-
if (getConnectionImpl() == null) throw new SQLException("Didn't get a connection. Wrong URL?");
|
732
|
-
configureConnection();
|
733
|
-
}
|
719
|
+
if ( forceConnection ) configureConnection();
|
734
720
|
}
|
735
721
|
|
736
722
|
@JRubyMethod(name = "read_only?")
|
@@ -832,7 +818,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
832
818
|
// is called, so we have to process the result sets as we get them
|
833
819
|
// this shouldn't be an issue in most cases since we're only getting 1 result set anyways
|
834
820
|
result = mapExecuteResult(context, connection, resultSet);
|
835
|
-
resultSet.close();
|
836
821
|
} else {
|
837
822
|
result = context.runtime.newFixnum(updateCount);
|
838
823
|
}
|
@@ -866,7 +851,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
866
851
|
else {
|
867
852
|
statement.setEscapeProcessing(escapeProcessing.isTrue());
|
868
853
|
}
|
869
|
-
if (fetchSize != 0) statement.setFetchSize(fetchSize);
|
870
854
|
return statement;
|
871
855
|
}
|
872
856
|
|
@@ -888,31 +872,15 @@ public class RubyJdbcConnection extends RubyObject {
|
|
888
872
|
return mapQueryResult(context, connection, resultSet);
|
889
873
|
}
|
890
874
|
|
891
|
-
private static String[] createStatementPk(IRubyObject pk) {
|
892
|
-
String[] statementPk;
|
893
|
-
if (pk instanceof RubyArray) {
|
894
|
-
RubyArray ary = (RubyArray) pk;
|
895
|
-
int size = ary.size();
|
896
|
-
statementPk = new String[size];
|
897
|
-
for (int i = 0; i < size; i++) {
|
898
|
-
statementPk[i] = sqlString(ary.eltInternal(i));
|
899
|
-
}
|
900
|
-
} else {
|
901
|
-
statementPk = new String[] { sqlString(pk) };
|
902
|
-
}
|
903
|
-
return statementPk;
|
904
|
-
}
|
905
|
-
|
906
875
|
/**
|
907
876
|
* Executes an INSERT SQL statement
|
908
877
|
* @param context
|
909
878
|
* @param sql
|
910
|
-
* @param pk Rails PK
|
911
879
|
* @return ActiveRecord::Result
|
912
880
|
* @throws SQLException
|
913
881
|
*/
|
914
|
-
@JRubyMethod(name = "
|
915
|
-
public IRubyObject
|
882
|
+
@JRubyMethod(name = "execute_insert", required = 1)
|
883
|
+
public IRubyObject execute_insert(final ThreadContext context, final IRubyObject sql) {
|
916
884
|
return withConnection(context, new Callable<IRubyObject>() {
|
917
885
|
public IRubyObject call(final Connection connection) throws SQLException {
|
918
886
|
Statement statement = null;
|
@@ -920,13 +888,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
920
888
|
try {
|
921
889
|
|
922
890
|
statement = createStatement(context, connection);
|
923
|
-
|
924
|
-
if (pk == context.nil || pk == context.fals || !supportsGeneratedKeys(connection)) {
|
925
|
-
statement.executeUpdate(query, Statement.RETURN_GENERATED_KEYS);
|
926
|
-
} else {
|
927
|
-
statement.executeUpdate(query, createStatementPk(pk));
|
928
|
-
}
|
929
|
-
|
891
|
+
statement.executeUpdate(query, Statement.RETURN_GENERATED_KEYS);
|
930
892
|
return mapGeneratedKeys(context, connection, statement);
|
931
893
|
|
932
894
|
} catch (final SQLException e) {
|
@@ -939,35 +901,23 @@ public class RubyJdbcConnection extends RubyObject {
|
|
939
901
|
});
|
940
902
|
}
|
941
903
|
|
942
|
-
@Deprecated
|
943
|
-
@JRubyMethod(name = "execute_insert", required = 1)
|
944
|
-
public IRubyObject execute_insert(final ThreadContext context, final IRubyObject sql) {
|
945
|
-
return execute_insert_pk(context, sql, context.nil);
|
946
|
-
}
|
947
|
-
|
948
904
|
/**
|
949
905
|
* Executes an INSERT SQL statement using a prepared statement
|
950
906
|
* @param context
|
951
907
|
* @param sql
|
952
908
|
* @param binds RubyArray of values to be bound to the query
|
953
|
-
* @param pk Rails PK
|
954
909
|
* @return ActiveRecord::Result
|
955
910
|
* @throws SQLException
|
956
911
|
*/
|
957
|
-
@JRubyMethod(name = "
|
958
|
-
public IRubyObject
|
959
|
-
final IRubyObject pk) {
|
912
|
+
@JRubyMethod(name = "execute_insert", required = 2)
|
913
|
+
public IRubyObject execute_insert(final ThreadContext context, final IRubyObject sql, final IRubyObject binds) {
|
960
914
|
return withConnection(context, new Callable<IRubyObject>() {
|
961
915
|
public IRubyObject call(final Connection connection) throws SQLException {
|
962
916
|
PreparedStatement statement = null;
|
963
917
|
final String query = sqlString(sql);
|
964
918
|
try {
|
965
|
-
if (pk == context.nil || pk == context.fals || !supportsGeneratedKeys(connection)) {
|
966
|
-
statement = connection.prepareStatement(query, Statement.RETURN_GENERATED_KEYS);
|
967
|
-
} else {
|
968
|
-
statement = connection.prepareStatement(query, createStatementPk(pk));
|
969
|
-
}
|
970
919
|
|
920
|
+
statement = connection.prepareStatement(query, Statement.RETURN_GENERATED_KEYS);
|
971
921
|
setStatementParameters(context, connection, statement, (RubyArray) binds);
|
972
922
|
statement.executeUpdate();
|
973
923
|
return mapGeneratedKeys(context, connection, statement);
|
@@ -982,12 +932,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
982
932
|
});
|
983
933
|
}
|
984
934
|
|
985
|
-
@Deprecated
|
986
|
-
@JRubyMethod(name = "execute_insert", required = 2)
|
987
|
-
public IRubyObject execute_insert(final ThreadContext context, final IRubyObject binds, final IRubyObject sql) {
|
988
|
-
return execute_insert_pk(context, sql, binds, context.nil);
|
989
|
-
}
|
990
|
-
|
991
935
|
/**
|
992
936
|
* Executes an UPDATE (DELETE) SQL statement
|
993
937
|
* @param context
|
@@ -1101,7 +1045,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1101
1045
|
else {
|
1102
1046
|
final PreparedStatement prepStatement;
|
1103
1047
|
statement = prepStatement = connection.prepareStatement(query);
|
1104
|
-
if (fetchSize != 0) statement.setFetchSize(fetchSize);
|
1105
1048
|
statement.setMaxRows(maxRows); // zero means there is no limit
|
1106
1049
|
setStatementParameters(context, connection, prepStatement, binds);
|
1107
1050
|
hasResult = prepStatement.execute();
|
@@ -1169,24 +1112,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1169
1112
|
});
|
1170
1113
|
}
|
1171
1114
|
|
1172
|
-
/**
|
1173
|
-
* Prepares a query, returns a wrapped PreparedStatement. This takes care of exception wrapping
|
1174
|
-
* @param context which context this method is executing on.
|
1175
|
-
* @param sql the query to prepare-
|
1176
|
-
* @return a Ruby <code>PreparedStatement</code>
|
1177
|
-
*/
|
1178
|
-
@JRubyMethod(required = 1)
|
1179
|
-
public IRubyObject prepare_statement(final ThreadContext context, final IRubyObject sql) {
|
1180
|
-
return withConnection(context, new Callable<IRubyObject>() {
|
1181
|
-
public IRubyObject call(Connection connection) throws SQLException {
|
1182
|
-
final String query = sql.convertToString().getUnicodeValue();
|
1183
|
-
PreparedStatement statement = connection.prepareStatement(query);
|
1184
|
-
if (fetchSize != 0) statement.setFetchSize(fetchSize);
|
1185
|
-
return JavaUtil.convertJavaToRuby(context.runtime, statement);
|
1186
|
-
}
|
1187
|
-
});
|
1188
|
-
}
|
1189
|
-
|
1190
1115
|
// Called from exec_query in abstract/database_statements
|
1191
1116
|
/**
|
1192
1117
|
* Executes a query and returns the (AR) result. There are three parameters:
|
@@ -1217,7 +1142,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1217
1142
|
statement = (PreparedStatement) JavaEmbedUtils.rubyToJava(cachedStatement);
|
1218
1143
|
} else {
|
1219
1144
|
statement = connection.prepareStatement(query);
|
1220
|
-
if (fetchSize != 0) statement.setFetchSize(fetchSize);
|
1221
1145
|
}
|
1222
1146
|
|
1223
1147
|
setStatementParameters(context, connection, statement, (RubyArray) binds);
|
@@ -1225,7 +1149,12 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1225
1149
|
if (statement.execute()) {
|
1226
1150
|
ResultSet resultSet = statement.getResultSet();
|
1227
1151
|
IRubyObject results = mapQueryResult(context, connection, resultSet);
|
1228
|
-
|
1152
|
+
|
1153
|
+
if (cached) {
|
1154
|
+
// Make sure we free the result set if we are caching the statement
|
1155
|
+
// It gets closed automatically when the statement is closed if we aren't caching
|
1156
|
+
resultSet.close();
|
1157
|
+
}
|
1229
1158
|
|
1230
1159
|
return results;
|
1231
1160
|
} else {
|
@@ -1878,7 +1807,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1878
1807
|
if ( url.isNil() || ( driver.isNil() && driver_instance.isNil() ) ) {
|
1879
1808
|
final Ruby runtime = context.runtime;
|
1880
1809
|
final RubyClass errorClass = getConnectionNotEstablished( runtime );
|
1881
|
-
throw runtime
|
1810
|
+
throw new RaiseException(runtime, errorClass, "adapter requires :driver class and jdbc :url", false);
|
1882
1811
|
}
|
1883
1812
|
|
1884
1813
|
final String jdbcURL = buildURL(context, url);
|
@@ -1895,7 +1824,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1895
1824
|
return factory;
|
1896
1825
|
}
|
1897
1826
|
else {
|
1898
|
-
setConnectionFactory(factory = new
|
1827
|
+
setConnectionFactory(factory = new RubyConnectionFactoryImpl(
|
1899
1828
|
driver_instance, context.runtime.newString(jdbcURL),
|
1900
1829
|
( username.isNil() ? username : username.asString() ),
|
1901
1830
|
( password.isNil() ? password : password.asString() )
|
@@ -2556,8 +2485,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2556
2485
|
while ( arrayResult.next() ) {
|
2557
2486
|
array.append( jdbcToRuby(context, runtime, 2, baseType, arrayResult) );
|
2558
2487
|
}
|
2559
|
-
arrayResult.close();
|
2560
|
-
|
2561
2488
|
return array;
|
2562
2489
|
}
|
2563
2490
|
finally { if ( value != null ) value.free(); }
|
@@ -2760,7 +2687,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2760
2687
|
}
|
2761
2688
|
|
2762
2689
|
protected final RubyTime timeInDefaultTimeZone(final ThreadContext context, final IRubyObject value) {
|
2763
|
-
return timeInDefaultTimeZone(context,
|
2690
|
+
return timeInDefaultTimeZone(context, toTime(context, value));
|
2764
2691
|
}
|
2765
2692
|
|
2766
2693
|
protected final RubyTime timeInDefaultTimeZone(final ThreadContext context, final RubyTime time) {
|
@@ -2772,14 +2699,11 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2772
2699
|
return timeInDefaultTZ;
|
2773
2700
|
}
|
2774
2701
|
|
2775
|
-
protected final DateTime dateTimeInDefaultTimeZone(final ThreadContext context, final DateTime dateTime) {
|
2776
|
-
final DateTimeZone defaultZone = getDefaultTimeZone(context);
|
2777
|
-
if (defaultZone == dateTime.getZone()) return dateTime;
|
2778
|
-
return dateTime.withZone(defaultZone);
|
2779
|
-
}
|
2780
|
-
|
2781
2702
|
public static RubyTime toTime(final ThreadContext context, final IRubyObject value) {
|
2782
|
-
|
2703
|
+
if ( ! ( value instanceof RubyTime ) ) { // unlikely
|
2704
|
+
return (RubyTime) TypeConverter.convertToTypeWithCheck(value, context.runtime.getTime(), "to_time");
|
2705
|
+
}
|
2706
|
+
return (RubyTime) value;
|
2783
2707
|
}
|
2784
2708
|
|
2785
2709
|
protected boolean isDefaultTimeZoneUTC(final ThreadContext context) {
|
@@ -2879,8 +2803,8 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2879
2803
|
final int index, IRubyObject value,
|
2880
2804
|
final IRubyObject attribute, final int type) throws SQLException {
|
2881
2805
|
|
2882
|
-
final RubyTime timeValue =
|
2883
|
-
final DateTime dateTime =
|
2806
|
+
final RubyTime timeValue = timeInDefaultTimeZone(context, value);
|
2807
|
+
final DateTime dateTime = timeValue.getDateTime();
|
2884
2808
|
final Timestamp timestamp = new Timestamp(dateTime.getMillis());
|
2885
2809
|
// 1942-11-30T01:02:03.123_456
|
2886
2810
|
if (timeValue.getNSec() > 0) timestamp.setNanos((int) (timestamp.getNanos() + timeValue.getNSec()));
|
@@ -2974,7 +2898,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2974
2898
|
final RubySymbol type = (RubySymbol) attributeSQLType(context, attribute);
|
2975
2899
|
|
2976
2900
|
// For some reason the driver doesn't like "character varying" as a type
|
2977
|
-
if ( type.eql(context.runtime.newSymbol("string")) ) return "
|
2901
|
+
if ( type.eql(context.runtime.newSymbol("string")) ) return "text";
|
2978
2902
|
|
2979
2903
|
final RubyHash nativeTypes = (RubyHash) getAdapter().callMethod(context, "native_database_types");
|
2980
2904
|
// e.g. `integer: { name: 'integer' }`
|
@@ -3081,7 +3005,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
3081
3005
|
private void handleNotConnected() {
|
3082
3006
|
final Ruby runtime = getRuntime();
|
3083
3007
|
final RubyClass errorClass = getConnectionNotEstablished( runtime );
|
3084
|
-
throw runtime
|
3008
|
+
throw new RaiseException(runtime, errorClass, "no connection available", false);
|
3085
3009
|
}
|
3086
3010
|
|
3087
3011
|
/**
|
@@ -3521,14 +3445,12 @@ public class RubyJdbcConnection extends RubyObject {
|
|
3521
3445
|
if ( ! gotConnection ) { // SQLException from driver/data-source
|
3522
3446
|
reconnectOnRetry = connected;
|
3523
3447
|
}
|
3524
|
-
else if (!autoCommit) {
|
3525
|
-
// never retry inside a transaction
|
3526
|
-
break;
|
3527
|
-
}
|
3528
3448
|
else if ( isTransient(exception) ) {
|
3529
3449
|
reconnectOnRetry = false; // continue;
|
3530
3450
|
}
|
3531
3451
|
else {
|
3452
|
+
if ( ! autoCommit ) break; // do not retry if (inside) transactions
|
3453
|
+
|
3532
3454
|
if ( isConnectionValid(context, getConnectionImpl()) ) {
|
3533
3455
|
break; // connection not broken yet failed (do not retry)
|
3534
3456
|
}
|
@@ -3618,7 +3540,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
3618
3540
|
return (RaiseException) exception;
|
3619
3541
|
}
|
3620
3542
|
if ( exception instanceof RuntimeException ) {
|
3621
|
-
return
|
3543
|
+
return RaiseException.createNativeRaiseException(runtime, exception);
|
3622
3544
|
}
|
3623
3545
|
// NOTE: compat - maybe makes sense or maybe not (e.g. IOException) :
|
3624
3546
|
return wrapException(context, getJDBCError(runtime), exception);
|
@@ -3631,7 +3553,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
3631
3553
|
|
3632
3554
|
public static RaiseException wrapException(final ThreadContext context,
|
3633
3555
|
final RubyClass errorClass, final Throwable exception, final String message) {
|
3634
|
-
final RaiseException error = context.runtime
|
3556
|
+
final RaiseException error = new RaiseException(context.runtime, errorClass, message, true);
|
3635
3557
|
error.initCause(exception);
|
3636
3558
|
return error;
|
3637
3559
|
}
|
@@ -3965,12 +3887,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
3965
3887
|
}
|
3966
3888
|
}
|
3967
3889
|
|
3968
|
-
public static void debugMessage(final ThreadContext context, final IRubyObject obj) {
|
3969
|
-
if ( isDebug(context.runtime) ) {
|
3970
|
-
debugMessage(context.runtime, obj.callMethod(context, "inspect"));
|
3971
|
-
}
|
3972
|
-
}
|
3973
|
-
|
3974
3890
|
public static void debugMessage(final Ruby runtime, final String msg, final Object e) {
|
3975
3891
|
if ( isDebug(runtime) ) {
|
3976
3892
|
final PrintStream out = runtime != null ? runtime.getOut() : System.out;
|