activerecord-jdbc-adapter 1.2.5 → 1.2.8
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/.travis.yml +5 -1
- data/Appraisals +5 -5
- data/Gemfile +9 -1
- data/Gemfile.lock +44 -10
- data/History.txt +126 -2
- data/README.md +246 -0
- data/Rakefile +34 -25
- data/activerecord-jdbc-adapter.gemspec +1 -1
- data/gemfiles/rails23.gemfile +5 -3
- data/gemfiles/rails23.gemfile.lock +26 -18
- data/gemfiles/rails30.gemfile +4 -2
- data/gemfiles/rails30.gemfile.lock +16 -8
- data/gemfiles/rails31.gemfile +4 -2
- data/gemfiles/rails31.gemfile.lock +16 -9
- data/gemfiles/rails32.gemfile +4 -2
- data/gemfiles/rails32.gemfile.lock +15 -8
- data/lib/active_record/connection_adapters/db2_adapter.rb +1 -0
- data/lib/arel/visitors/sql_server.rb +3 -0
- data/lib/arjdbc.rb +3 -5
- data/lib/arjdbc/db2.rb +1 -0
- data/lib/arjdbc/db2/adapter.rb +302 -196
- data/lib/arjdbc/db2/connection_methods.rb +18 -0
- data/lib/arjdbc/derby/active_record_patch.rb +12 -0
- data/lib/arjdbc/derby/adapter.rb +180 -158
- data/lib/arjdbc/derby/connection_methods.rb +5 -1
- data/lib/arjdbc/firebird/adapter.rb +27 -19
- data/lib/arjdbc/h2/adapter.rb +162 -7
- data/lib/arjdbc/h2/connection_methods.rb +5 -1
- data/lib/arjdbc/hsqldb.rb +1 -1
- data/lib/arjdbc/hsqldb/adapter.rb +96 -61
- data/lib/arjdbc/hsqldb/connection_methods.rb +5 -1
- data/lib/arjdbc/hsqldb/explain_support.rb +35 -0
- data/lib/arjdbc/informix/adapter.rb +56 -55
- data/lib/arjdbc/jdbc/adapter.rb +173 -86
- data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
- data/lib/arjdbc/jdbc/column.rb +28 -23
- data/lib/arjdbc/jdbc/connection.rb +10 -6
- data/lib/arjdbc/jdbc/driver.rb +13 -5
- data/lib/arjdbc/jdbc/serialized_attributes_helper.rb +21 -0
- data/lib/arjdbc/mssql.rb +1 -1
- data/lib/arjdbc/mssql/adapter.rb +51 -53
- data/lib/arjdbc/mssql/connection_methods.rb +8 -1
- data/lib/arjdbc/mysql.rb +1 -1
- data/lib/arjdbc/mysql/adapter.rb +186 -150
- data/lib/arjdbc/mysql/connection_methods.rb +9 -9
- data/lib/arjdbc/mysql/explain_support.rb +85 -0
- data/lib/arjdbc/oracle.rb +1 -1
- data/lib/arjdbc/oracle/adapter.rb +232 -125
- data/lib/arjdbc/oracle/connection_methods.rb +2 -2
- data/lib/arjdbc/postgresql.rb +1 -1
- data/lib/arjdbc/postgresql/adapter.rb +134 -86
- data/lib/arjdbc/postgresql/connection_methods.rb +6 -4
- data/lib/arjdbc/postgresql/explain_support.rb +55 -0
- data/lib/arjdbc/sqlite3.rb +1 -1
- data/lib/arjdbc/sqlite3/adapter.rb +176 -108
- data/lib/arjdbc/sqlite3/connection_methods.rb +5 -5
- data/lib/arjdbc/sqlite3/explain_support.rb +32 -0
- data/lib/arjdbc/sybase/adapter.rb +7 -6
- data/lib/arjdbc/version.rb +1 -1
- data/pom.xml +1 -1
- data/rakelib/02-test.rake +9 -11
- data/rakelib/rails.rake +18 -10
- data/src/java/arjdbc/db2/DB2Module.java +70 -0
- data/src/java/arjdbc/derby/DerbyModule.java +24 -5
- data/src/java/arjdbc/hsqldb/HSQLDBModule.java +66 -0
- data/src/java/arjdbc/jdbc/AdapterJavaService.java +14 -7
- data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +111 -89
- data/src/java/arjdbc/mysql/MySQLModule.java +79 -70
- data/src/java/arjdbc/oracle/OracleModule.java +74 -0
- data/src/java/arjdbc/oracle/OracleRubyJdbcConnection.java +5 -10
- data/src/java/arjdbc/sqlite3/SQLite3Module.java +77 -0
- data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +127 -0
- data/src/java/arjdbc/sqlite3/Sqlite3RubyJdbcConnection.java +25 -111
- data/src/java/arjdbc/util/QuotingUtils.java +104 -0
- data/test/abstract_db_create.rb +6 -6
- data/test/activerecord/connection_adapters/type_conversion_test.rb +2 -2
- data/test/assets/flowers.jpg +0 -0
- data/test/binary.rb +67 -0
- data/test/db/db2.rb +30 -7
- data/test/db/jdbc.rb +4 -2
- data/test/db/oracle.rb +18 -27
- data/test/db2_binary_test.rb +6 -0
- data/test/db2_serialize_test.rb +6 -0
- data/test/db2_simple_test.rb +20 -25
- data/test/db2_test.rb +71 -0
- data/test/derby_binary_test.rb +6 -0
- data/test/derby_migration_test.rb +42 -35
- data/test/derby_reset_column_information_test.rb +1 -0
- data/test/derby_row_locking_test.rb +17 -0
- data/test/derby_schema_dump_test.rb +9 -0
- data/test/derby_serialize_test.rb +6 -0
- data/test/derby_simple_test.rb +59 -17
- data/test/generic_jdbc_connection_test.rb +112 -5
- data/test/h2_binary_test.rb +6 -0
- data/test/h2_change_column_test.rb +1 -1
- data/test/h2_schema_dump_test.rb +25 -0
- data/test/h2_serialize_test.rb +6 -0
- data/test/h2_simple_test.rb +23 -9
- data/test/has_many_through.rb +18 -4
- data/test/hsqldb_binary_test.rb +6 -0
- data/test/hsqldb_schema_dump_test.rb +15 -0
- data/test/hsqldb_serialize_test.rb +6 -0
- data/test/hsqldb_simple_test.rb +1 -0
- data/test/informix_simple_test.rb +1 -1
- data/test/jdbc/db2.rb +23 -0
- data/test/jdbc/oracle.rb +23 -0
- data/test/jdbc_common.rb +3 -110
- data/test/jndi_callbacks_test.rb +0 -2
- data/test/jndi_test.rb +2 -0
- data/test/models/binary.rb +18 -0
- data/test/models/custom_pk_name.rb +1 -0
- data/test/models/data_types.rb +11 -2
- data/test/models/entry.rb +1 -1
- data/test/models/string_id.rb +2 -2
- data/test/models/thing.rb +1 -1
- data/test/models/topic.rb +32 -0
- data/test/mssql_legacy_types_test.rb +1 -1
- data/test/mssql_limit_offset_test.rb +13 -3
- data/test/mssql_serialize_test.rb +6 -0
- data/test/mysql_binary_test.rb +6 -0
- data/test/mysql_schema_dump_test.rb +220 -0
- data/test/mysql_serialize_test.rb +6 -0
- data/test/mysql_simple_test.rb +22 -2
- data/test/mysql_test.rb +93 -0
- data/test/oracle_binary_test.rb +6 -0
- data/test/oracle_limit_test.rb +2 -1
- data/test/oracle_serialize_test.rb +6 -0
- data/test/oracle_simple_test.rb +61 -0
- data/test/oracle_specific_test.rb +77 -26
- data/test/postgres_binary_test.rb +6 -0
- data/test/postgres_native_type_mapping_test.rb +12 -11
- data/test/postgres_nonseq_pkey_test.rb +1 -0
- data/test/postgres_reserved_test.rb +1 -0
- data/test/postgres_reset_column_information_test.rb +1 -0
- data/test/postgres_row_locking_test.rb +21 -0
- data/test/postgres_schema_dump_test.rb +88 -0
- data/test/postgres_schema_search_path_test.rb +1 -0
- data/test/postgres_simple_test.rb +62 -89
- data/test/postgres_table_alias_length_test.rb +1 -0
- data/test/postgres_test.rb +31 -0
- data/test/postgres_type_conversion_test.rb +16 -16
- data/test/row_locking.rb +69 -64
- data/test/schema_dump.rb +168 -0
- data/test/serialize.rb +277 -0
- data/test/simple.rb +326 -122
- data/test/sqlite3_serialize_test.rb +6 -0
- data/test/sqlite3_simple_test.rb +51 -84
- data/test/sqlite3_type_conversion_test.rb +101 -0
- data/test/test_helper.rb +224 -0
- metadata +325 -366
- data/README.rdoc +0 -214
- data/test/db/logger.rb +0 -3
- data/test/derby_multibyte_test.rb +0 -11
- data/test/mysql_info_test.rb +0 -123
@@ -31,12 +31,13 @@ module ArJdbc
|
|
31
31
|
!@limit.nil? && @limit == 0
|
32
32
|
end
|
33
33
|
|
34
|
-
def modify_types(
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
34
|
+
def modify_types(types) # :nodoc:
|
35
|
+
super(types)
|
36
|
+
types[:primary_key] = "NUMERIC(22,0) IDENTITY PRIMARY KEY"
|
37
|
+
types[:integer][:limit] = nil
|
38
|
+
types[:boolean] = {:name => "bit"}
|
39
|
+
types[:binary] = {:name => "image"}
|
40
|
+
types
|
40
41
|
end
|
41
42
|
|
42
43
|
def remove_index(table_name, options = {})
|
data/lib/arjdbc/version.rb
CHANGED
data/pom.xml
CHANGED
data/rakelib/02-test.rake
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require File.expand_path
|
1
|
+
require File.expand_path('../../test/helper', __FILE__)
|
2
2
|
if defined?(JRUBY_VERSION)
|
3
3
|
databases = [ :test_mysql, :test_sqlite3, :test_derby, :test_hsqldb, :test_h2 ]
|
4
4
|
databases << :test_postgres if PostgresHelper.have_postgres?(false)
|
@@ -20,16 +20,16 @@ def set_compat_version(task)
|
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
|
-
def all_appraisal_names
|
24
|
-
@appraisal_names ||= begin names = []; Appraisal::File.each { |file| names << file.name }; names end
|
25
|
-
end
|
26
|
-
|
27
23
|
def declare_test_task_for(adapter, options = {})
|
28
24
|
driver = options[:driver] || adapter
|
29
25
|
prereqs = options[:prereqs] || []
|
30
26
|
prereqs = [ prereqs ].flatten
|
31
27
|
task "test_#{adapter}_pre" do
|
32
|
-
|
28
|
+
unless (ENV['BUNDLE_GEMFILE'] rescue '') =~ /gemfiles\/.*?\.gemfile/
|
29
|
+
appraisals = []; Appraisal::File.each { |file| appraisals << file.name }
|
30
|
+
puts "Specify AR version with `rake appraisal:{version} test_#{adapter}'" +
|
31
|
+
" where version=(#{appraisals.join('|')})"
|
32
|
+
end
|
33
33
|
end
|
34
34
|
prereqs << "test_#{adapter}_pre"
|
35
35
|
test_task = lambda do |t|
|
@@ -43,12 +43,11 @@ def declare_test_task_for(adapter, options = {})
|
|
43
43
|
t.libs = []
|
44
44
|
set_compat_version(t)
|
45
45
|
if defined?(JRUBY_VERSION)
|
46
|
-
t.ruby_opts << "-rjdbc/#{driver}"
|
47
46
|
t.libs << "lib" << "jdbc-#{driver}/lib"
|
48
47
|
t.libs.push *FileList["activerecord-jdbc#{adapter}*/lib"]
|
49
48
|
end
|
50
49
|
t.libs << "test"
|
51
|
-
t.verbose = true
|
50
|
+
t.verbose = true if $VERBOSE
|
52
51
|
end
|
53
52
|
Rake::TestTask.new("test_#{adapter}" => prereqs) { |t| test_task.call t }
|
54
53
|
Rake::TestTask.new("test_jdbc_#{adapter}" => prereqs) { |t| test_task.call t }
|
@@ -64,12 +63,11 @@ declare_test_task_for :sqlite3
|
|
64
63
|
|
65
64
|
Rake::TestTask.new(:test_jdbc) do |t|
|
66
65
|
t.test_files = FileList['test/generic_jdbc_connection_test.rb']
|
67
|
-
t.libs << 'test' << 'jdbc-mysql/lib'
|
66
|
+
t.libs << 'test' << 'jdbc-mysql/lib' << 'jdbc-derby/lib'
|
68
67
|
set_compat_version(t)
|
69
68
|
end
|
70
69
|
|
71
|
-
Rake::TestTask.new(:test_jndi) do |t|
|
72
|
-
Rake::Task['tomcat-jndi:check'].invoke
|
70
|
+
Rake::TestTask.new(:test_jndi => 'tomcat-jndi:check') do |t|
|
73
71
|
t.test_files = FileList['test/jndi_test.rb']
|
74
72
|
t.libs << 'test' << 'jdbc-derby/lib'
|
75
73
|
set_compat_version(t)
|
data/rakelib/rails.rake
CHANGED
@@ -27,15 +27,23 @@ namespace :rails do
|
|
27
27
|
end
|
28
28
|
|
29
29
|
task :test => :jar do
|
30
|
-
driver = ENV['DRIVER']
|
31
|
-
raise "need
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
30
|
+
raise "need a DRIVER" unless driver = ENV['DRIVER']
|
31
|
+
raise "need location of RAILS source code" unless rails_dir = ENV['RAILS']
|
32
|
+
rails_dir = File.join(rails_dir, '..') if rails_dir =~ /activerecord$/
|
33
|
+
activerecord_dir = File.join(rails_dir, 'activerecord') # rails/activerecord
|
34
|
+
|
35
|
+
ar_jdbc_dir = File.expand_path('..', File.dirname(__FILE__))
|
36
|
+
|
37
|
+
rubylib = [
|
38
|
+
"#{ar_jdbc_dir}/lib",
|
39
|
+
"#{ar_jdbc_dir}/jdbc-#{_driver(driver)}/lib",
|
40
|
+
"#{ar_jdbc_dir}/activerecord-jdbc#{_adapter(driver)}-adapter/lib"
|
41
|
+
]
|
42
|
+
rubylib << File.expand_path('activesupport/lib', rails_dir)
|
43
|
+
rubylib << File.expand_path('activemodel/lib', rails_dir)
|
44
|
+
rubylib << File.expand_path(File.join(activerecord_dir, 'lib'))
|
45
|
+
#rubylib << File.expand_path('actionpack/lib', rails_dir)
|
46
|
+
|
47
|
+
Dir.chdir(activerecord_dir) { rake "RUBYLIB=#{rubylib.join(':')}", "#{_target(driver)}" }
|
40
48
|
end
|
41
49
|
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
/*
|
2
|
+
* The MIT License
|
3
|
+
*
|
4
|
+
* Copyright 2013 Karol Bucek.
|
5
|
+
*
|
6
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
7
|
+
* of this software and associated documentation files (the "Software"), to deal
|
8
|
+
* in the Software without restriction, including without limitation the rights
|
9
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10
|
+
* copies of the Software, and to permit persons to whom the Software is
|
11
|
+
* furnished to do so, subject to the following conditions:
|
12
|
+
*
|
13
|
+
* The above copyright notice and this permission notice shall be included in
|
14
|
+
* all copies or substantial portions of the Software.
|
15
|
+
*
|
16
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
19
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
22
|
+
* THE SOFTWARE.
|
23
|
+
*/
|
24
|
+
package arjdbc.db2;
|
25
|
+
|
26
|
+
import static arjdbc.util.QuotingUtils.BYTES_0;
|
27
|
+
import static arjdbc.util.QuotingUtils.BYTES_1;
|
28
|
+
import static arjdbc.util.QuotingUtils.quoteSingleQuotesWithFallback;
|
29
|
+
|
30
|
+
import org.jruby.RubyModule;
|
31
|
+
import org.jruby.RubyString;
|
32
|
+
import org.jruby.anno.JRubyMethod;
|
33
|
+
import org.jruby.runtime.ThreadContext;
|
34
|
+
import org.jruby.runtime.builtin.IRubyObject;
|
35
|
+
|
36
|
+
/**
|
37
|
+
* ArJdbc::DB2
|
38
|
+
*
|
39
|
+
* @author kares
|
40
|
+
*/
|
41
|
+
public class DB2Module {
|
42
|
+
|
43
|
+
public static void load(final RubyModule arJdbc) {
|
44
|
+
RubyModule db2 = arJdbc.defineModuleUnder("DB2");
|
45
|
+
db2.defineAnnotatedMethods( DB2Module.class );
|
46
|
+
}
|
47
|
+
|
48
|
+
@JRubyMethod(name = "quote_string", required = 1, frame = false)
|
49
|
+
public static IRubyObject quote_string(
|
50
|
+
final ThreadContext context,
|
51
|
+
final IRubyObject self,
|
52
|
+
final IRubyObject string) {
|
53
|
+
return quoteSingleQuotesWithFallback(context, string);
|
54
|
+
}
|
55
|
+
|
56
|
+
@JRubyMethod(name = "quoted_true", required = 0, frame = false)
|
57
|
+
public static IRubyObject quoted_true(
|
58
|
+
final ThreadContext context,
|
59
|
+
final IRubyObject self) {
|
60
|
+
return RubyString.newString(context.getRuntime(), BYTES_1);
|
61
|
+
}
|
62
|
+
|
63
|
+
@JRubyMethod(name = "quoted_false", required = 0, frame = false)
|
64
|
+
public static IRubyObject quoted_false(
|
65
|
+
final ThreadContext context,
|
66
|
+
final IRubyObject self) {
|
67
|
+
return RubyString.newString(context.getRuntime(), BYTES_0);
|
68
|
+
}
|
69
|
+
|
70
|
+
}
|
@@ -26,27 +26,32 @@ package arjdbc.derby;
|
|
26
26
|
|
27
27
|
import java.sql.SQLException;
|
28
28
|
|
29
|
+
import static arjdbc.util.QuotingUtils.BYTES_0;
|
30
|
+
import static arjdbc.util.QuotingUtils.BYTES_1;
|
31
|
+
|
29
32
|
import arjdbc.jdbc.RubyJdbcConnection;
|
30
33
|
|
31
34
|
import org.jruby.Ruby;
|
32
35
|
import org.jruby.RubyBoolean;
|
33
36
|
import org.jruby.RubyModule;
|
34
37
|
import org.jruby.RubyObjectAdapter;
|
35
|
-
import org.jruby.RubyRange;
|
36
38
|
import org.jruby.RubyString;
|
37
39
|
import org.jruby.anno.JRubyMethod;
|
40
|
+
import org.jruby.javasupport.JavaEmbedUtils;
|
38
41
|
import org.jruby.runtime.ThreadContext;
|
39
42
|
import org.jruby.runtime.builtin.IRubyObject;
|
40
43
|
import org.jruby.util.ByteList;
|
41
44
|
|
42
45
|
public class DerbyModule {
|
46
|
+
|
43
47
|
private static RubyObjectAdapter rubyApi;
|
44
|
-
|
48
|
+
|
49
|
+
public static void load(final RubyModule arJdbc) {
|
45
50
|
RubyModule derby = arJdbc.defineModuleUnder("Derby");
|
46
51
|
derby.defineAnnotatedMethods(DerbyModule.class);
|
47
52
|
RubyModule column = derby.defineModuleUnder("Column");
|
48
53
|
column.defineAnnotatedMethods(Column.class);
|
49
|
-
rubyApi =
|
54
|
+
rubyApi = JavaEmbedUtils.newObjectAdapter();
|
50
55
|
}
|
51
56
|
|
52
57
|
public static class Column {
|
@@ -105,7 +110,7 @@ public class DerbyModule {
|
|
105
110
|
IRubyObject value = args[0];
|
106
111
|
if (args.length > 1) {
|
107
112
|
IRubyObject col = args[1];
|
108
|
-
String type = rubyApi.callMethod(col, "type").toString();
|
113
|
+
String type = col.isNil() ? "" : rubyApi.callMethod(col, "type").toString();
|
109
114
|
// intercept and change value, maybe, if the column type is :text or :string
|
110
115
|
if (type.equals("text") || type.equals("string")) {
|
111
116
|
value = make_ruby_string_for_text_column(context, recv, runtime, value);
|
@@ -208,7 +213,7 @@ public class DerbyModule {
|
|
208
213
|
|
209
214
|
private static IRubyObject quote_string_with_surround(Ruby runtime, String before, RubyString string, String after) {
|
210
215
|
ByteList input = string.getByteList();
|
211
|
-
ByteList output = new ByteList(before.getBytes());
|
216
|
+
ByteList output = new ByteList(before.getBytes(), input.encoding);
|
212
217
|
for(int i = input.begin; i< input.begin + input.realSize; i++) {
|
213
218
|
switch(input.bytes[i]) {
|
214
219
|
case '\'':
|
@@ -286,6 +291,20 @@ public class DerbyModule {
|
|
286
291
|
}
|
287
292
|
}
|
288
293
|
|
294
|
+
@JRubyMethod(name = "quoted_true", required = 0, frame = false)
|
295
|
+
public static IRubyObject quoted_true(
|
296
|
+
final ThreadContext context,
|
297
|
+
final IRubyObject self) {
|
298
|
+
return RubyString.newString(context.getRuntime(), BYTES_1);
|
299
|
+
}
|
300
|
+
|
301
|
+
@JRubyMethod(name = "quoted_false", required = 0, frame = false)
|
302
|
+
public static IRubyObject quoted_false(
|
303
|
+
final ThreadContext context,
|
304
|
+
final IRubyObject self) {
|
305
|
+
return RubyString.newString(context.getRuntime(), BYTES_0);
|
306
|
+
}
|
307
|
+
|
289
308
|
@JRubyMethod(name = "select_all", rest = true)
|
290
309
|
public static IRubyObject select_all(IRubyObject recv, IRubyObject[] args) {
|
291
310
|
return rubyApi.callMethod(recv, "execute", args);
|
@@ -0,0 +1,66 @@
|
|
1
|
+
/***** BEGIN LICENSE BLOCK *****
|
2
|
+
* Copyright (c) 2006-2010 Nick Sieger <nick@nicksieger.com>
|
3
|
+
* Copyright (c) 2006-2007 Ola Bini <ola.bini@gmail.com>
|
4
|
+
*
|
5
|
+
* Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
* a copy of this software and associated documentation files (the
|
7
|
+
* "Software"), to deal in the Software without restriction, including
|
8
|
+
* without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
* distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
* permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
* the following conditions:
|
12
|
+
*
|
13
|
+
* The above copyright notice and this permission notice shall be
|
14
|
+
* included in all copies or substantial portions of the Software.
|
15
|
+
*
|
16
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
23
|
+
***** END LICENSE BLOCK *****/
|
24
|
+
|
25
|
+
package arjdbc.hsqldb;
|
26
|
+
|
27
|
+
import static arjdbc.util.QuotingUtils.BYTES_0;
|
28
|
+
import static arjdbc.util.QuotingUtils.BYTES_1;
|
29
|
+
import static arjdbc.util.QuotingUtils.quoteSingleQuotesWithFallback;
|
30
|
+
|
31
|
+
import org.jruby.RubyModule;
|
32
|
+
import org.jruby.RubyString;
|
33
|
+
import org.jruby.anno.JRubyMethod;
|
34
|
+
import org.jruby.runtime.ThreadContext;
|
35
|
+
import org.jruby.runtime.builtin.IRubyObject;
|
36
|
+
|
37
|
+
public class HSQLDBModule {
|
38
|
+
|
39
|
+
public static void load(final RubyModule arJdbc) {
|
40
|
+
RubyModule hsqldb = arJdbc.defineModuleUnder("HSQLDB");
|
41
|
+
hsqldb.defineAnnotatedMethods(HSQLDBModule.class);
|
42
|
+
}
|
43
|
+
|
44
|
+
@JRubyMethod(name = "quote_string", required = 1, frame = false)
|
45
|
+
public static IRubyObject quote_string(
|
46
|
+
final ThreadContext context,
|
47
|
+
final IRubyObject self,
|
48
|
+
final IRubyObject string) {
|
49
|
+
return quoteSingleQuotesWithFallback(context, string);
|
50
|
+
}
|
51
|
+
|
52
|
+
@JRubyMethod(name = "quoted_true", required = 0, frame = false)
|
53
|
+
public static IRubyObject quoted_true(
|
54
|
+
final ThreadContext context,
|
55
|
+
final IRubyObject self) {
|
56
|
+
return RubyString.newString(context.getRuntime(), BYTES_1);
|
57
|
+
}
|
58
|
+
|
59
|
+
@JRubyMethod(name = "quoted_false", required = 0, frame = false)
|
60
|
+
public static IRubyObject quoted_false(
|
61
|
+
final ThreadContext context,
|
62
|
+
final IRubyObject self) {
|
63
|
+
return RubyString.newString(context.getRuntime(), BYTES_0);
|
64
|
+
}
|
65
|
+
|
66
|
+
}
|
@@ -28,41 +28,48 @@ package arjdbc.jdbc;
|
|
28
28
|
|
29
29
|
import java.io.IOException;
|
30
30
|
|
31
|
+
import arjdbc.db2.DB2Module;
|
31
32
|
import arjdbc.db2.DB2RubyJdbcConnection;
|
32
33
|
import arjdbc.derby.DerbyModule;
|
33
34
|
import arjdbc.h2.H2RubyJdbcConnection;
|
35
|
+
import arjdbc.hsqldb.HSQLDBModule;
|
34
36
|
import arjdbc.informix.InformixRubyJdbcConnection;
|
35
37
|
import arjdbc.mssql.MssqlRubyJdbcConnection;
|
36
38
|
import arjdbc.mysql.MySQLModule;
|
37
39
|
import arjdbc.mysql.MySQLRubyJdbcConnection;
|
40
|
+
import arjdbc.oracle.OracleModule;
|
38
41
|
import arjdbc.oracle.OracleRubyJdbcConnection;
|
39
42
|
import arjdbc.postgresql.PostgresqlRubyJdbcConnection;
|
40
|
-
import arjdbc.sqlite3.
|
43
|
+
import arjdbc.sqlite3.SQLite3Module;
|
44
|
+
import arjdbc.sqlite3.SQLite3RubyJdbcConnection;
|
41
45
|
|
42
46
|
import org.jruby.Ruby;
|
43
47
|
import org.jruby.RubyClass;
|
44
48
|
import org.jruby.RubyModule;
|
45
|
-
import org.jruby.RubyObjectAdapter;
|
46
|
-
import org.jruby.javasupport.JavaEmbedUtils;
|
47
49
|
import org.jruby.runtime.load.BasicLibraryService;
|
48
50
|
|
49
51
|
public class AdapterJavaService implements BasicLibraryService {
|
50
|
-
private static RubyObjectAdapter rubyApi;
|
51
52
|
|
52
53
|
public boolean basicLoad(final Ruby runtime) throws IOException {
|
54
|
+
// ActiveRecord::ConnectionAdapter-s :
|
53
55
|
RubyClass jdbcConnection = RubyJdbcConnection.createJdbcConnectionClass(runtime);
|
54
56
|
PostgresqlRubyJdbcConnection.createPostgresqlJdbcConnectionClass(runtime, jdbcConnection);
|
55
57
|
MssqlRubyJdbcConnection.createMssqlJdbcConnectionClass(runtime, jdbcConnection);
|
56
58
|
InformixRubyJdbcConnection.createInformixJdbcConnectionClass(runtime, jdbcConnection);
|
57
59
|
OracleRubyJdbcConnection.createOracleJdbcConnectionClass(runtime, jdbcConnection);
|
58
|
-
|
60
|
+
SQLite3RubyJdbcConnection.createSQLite3JdbcConnectionClass(runtime, jdbcConnection);
|
59
61
|
H2RubyJdbcConnection.createH2JdbcConnectionClass(runtime, jdbcConnection);
|
60
62
|
MySQLRubyJdbcConnection.createMySQLJdbcConnectionClass(runtime, jdbcConnection);
|
61
63
|
DB2RubyJdbcConnection.createDB2JdbcConnectionClass(runtime, jdbcConnection);
|
64
|
+
// ArJdbc :
|
62
65
|
RubyModule arJdbc = runtime.getOrCreateModule("ArJdbc");
|
63
|
-
rubyApi = JavaEmbedUtils.newObjectAdapter();
|
64
66
|
MySQLModule.load(arJdbc);
|
65
|
-
DerbyModule.load(arJdbc
|
67
|
+
DerbyModule.load(arJdbc);
|
68
|
+
HSQLDBModule.load(arJdbc);
|
69
|
+
SQLite3Module.load(arJdbc);
|
70
|
+
OracleModule.load(arJdbc);
|
71
|
+
DB2Module.load(arJdbc);
|
66
72
|
return true;
|
67
73
|
}
|
74
|
+
|
68
75
|
}
|
@@ -61,14 +61,14 @@ import org.jruby.RubySymbol;
|
|
61
61
|
import org.jruby.RubyTime;
|
62
62
|
import org.jruby.anno.JRubyMethod;
|
63
63
|
import org.jruby.exceptions.RaiseException;
|
64
|
-
import org.jruby.javasupport.Java;
|
65
64
|
import org.jruby.javasupport.JavaEmbedUtils;
|
66
|
-
import org.jruby.javasupport.
|
65
|
+
import org.jruby.javasupport.JavaUtil;
|
67
66
|
import org.jruby.javasupport.util.RuntimeHelpers;
|
68
67
|
import org.jruby.runtime.Arity;
|
69
68
|
import org.jruby.runtime.Block;
|
70
69
|
import org.jruby.runtime.ObjectAllocator;
|
71
70
|
import org.jruby.runtime.ThreadContext;
|
71
|
+
import org.jruby.runtime.backtrace.RubyStackTraceElement;
|
72
72
|
import org.jruby.runtime.builtin.IRubyObject;
|
73
73
|
import org.jruby.util.ByteList;
|
74
74
|
|
@@ -85,9 +85,15 @@ public class RubyJdbcConnection extends RubyObject {
|
|
85
85
|
super(runtime, metaClass);
|
86
86
|
}
|
87
87
|
|
88
|
-
|
89
|
-
|
90
|
-
|
88
|
+
private static ObjectAllocator JDBCCONNECTION_ALLOCATOR = new ObjectAllocator() {
|
89
|
+
public IRubyObject allocate(Ruby runtime, RubyClass klass) {
|
90
|
+
return new RubyJdbcConnection(runtime, klass);
|
91
|
+
}
|
92
|
+
};
|
93
|
+
|
94
|
+
public static RubyClass createJdbcConnectionClass(final Ruby runtime) {
|
95
|
+
RubyClass jdbcConnection = getConnectionAdapters(runtime).
|
96
|
+
defineClassUnder("JdbcConnection", runtime.getObject(), JDBCCONNECTION_ALLOCATOR);
|
91
97
|
jdbcConnection.defineAnnotatedMethods(RubyJdbcConnection.class);
|
92
98
|
|
93
99
|
rubyApi = JavaEmbedUtils.newObjectAdapter();
|
@@ -95,31 +101,14 @@ public class RubyJdbcConnection extends RubyObject {
|
|
95
101
|
return jdbcConnection;
|
96
102
|
}
|
97
103
|
|
98
|
-
private static ObjectAllocator JDBCCONNECTION_ALLOCATOR = new ObjectAllocator() {
|
99
|
-
public IRubyObject allocate(Ruby runtime, RubyClass klass) {
|
100
|
-
return new RubyJdbcConnection(runtime, klass);
|
101
|
-
}
|
102
|
-
};
|
103
|
-
|
104
104
|
protected static RubyModule getConnectionAdapters(Ruby runtime) {
|
105
105
|
return (RubyModule) runtime.getModule("ActiveRecord").getConstant("ConnectionAdapters");
|
106
106
|
}
|
107
|
-
|
107
|
+
|
108
108
|
protected String[] getTableTypes() {
|
109
109
|
return TABLE_TYPES;
|
110
110
|
}
|
111
111
|
|
112
|
-
@JRubyMethod(name = "begin")
|
113
|
-
public IRubyObject begin(ThreadContext context) throws SQLException {
|
114
|
-
final Ruby runtime = context.getRuntime();
|
115
|
-
return (IRubyObject) withConnectionAndRetry(context, new SQLBlock() {
|
116
|
-
public Object call(Connection c) throws SQLException {
|
117
|
-
getConnection(true).setAutoCommit(false);
|
118
|
-
return runtime.getNil();
|
119
|
-
}
|
120
|
-
});
|
121
|
-
}
|
122
|
-
|
123
112
|
@JRubyMethod(name = {"columns", "columns_internal"}, required = 1, optional = 2)
|
124
113
|
public IRubyObject columns_internal(final ThreadContext context, final IRubyObject[] args)
|
125
114
|
throws SQLException, IOException {
|
@@ -149,6 +138,17 @@ public class RubyJdbcConnection extends RubyObject {
|
|
149
138
|
});
|
150
139
|
}
|
151
140
|
|
141
|
+
@JRubyMethod(name = "begin")
|
142
|
+
public IRubyObject begin(ThreadContext context) throws SQLException {
|
143
|
+
final Ruby runtime = context.getRuntime();
|
144
|
+
return (IRubyObject) withConnectionAndRetry(context, new SQLBlock() {
|
145
|
+
public Object call(Connection c) throws SQLException {
|
146
|
+
getConnection(true).setAutoCommit(false);
|
147
|
+
return runtime.getNil();
|
148
|
+
}
|
149
|
+
});
|
150
|
+
}
|
151
|
+
|
152
152
|
@JRubyMethod(name = "commit")
|
153
153
|
public IRubyObject commit(ThreadContext context) throws SQLException {
|
154
154
|
Connection connection = getConnection(true);
|
@@ -164,14 +164,39 @@ public class RubyJdbcConnection extends RubyObject {
|
|
164
164
|
return context.getRuntime().getNil();
|
165
165
|
}
|
166
166
|
|
167
|
-
@JRubyMethod(name = "connection"
|
167
|
+
@JRubyMethod(name = "connection")
|
168
168
|
public IRubyObject connection() {
|
169
|
-
if (getConnection() == null)
|
170
|
-
|
169
|
+
if ( getConnection(false) == null ) {
|
170
|
+
synchronized (this) {
|
171
|
+
if ( getConnection(false) == null ) {
|
172
|
+
reconnect();
|
173
|
+
}
|
174
|
+
}
|
175
|
+
}
|
171
176
|
return getInstanceVariable("@connection");
|
172
177
|
}
|
173
178
|
|
174
|
-
@JRubyMethod(name = "
|
179
|
+
@JRubyMethod(name = "disconnect!")
|
180
|
+
public IRubyObject disconnect(final ThreadContext context) {
|
181
|
+
// TODO: only here to try resolving multi-thread issues :
|
182
|
+
// https://github.com/jruby/activerecord-jdbc-adapter/issues/197
|
183
|
+
// https://github.com/jruby/activerecord-jdbc-adapter/issues/198
|
184
|
+
if ( Boolean.getBoolean("arjdbc.disconnect.debug") ) {
|
185
|
+
final Ruby runtime = context.getRuntime();
|
186
|
+
List backtrace = (List) context.createCallerBacktrace(runtime, 0);
|
187
|
+
runtime.getOut().println(this + " connection.disconnect! occured: ");
|
188
|
+
for ( Object element : backtrace ) runtime.getOut().println(element);
|
189
|
+
runtime.getOut().flush();
|
190
|
+
}
|
191
|
+
return setConnection(null);
|
192
|
+
}
|
193
|
+
|
194
|
+
@JRubyMethod(name = "reconnect!")
|
195
|
+
public IRubyObject reconnect() {
|
196
|
+
return setConnection( getConnectionFactory().newConnection() );
|
197
|
+
}
|
198
|
+
|
199
|
+
@JRubyMethod(name = "database_name")
|
175
200
|
public IRubyObject database_name(ThreadContext context) throws SQLException {
|
176
201
|
Connection connection = getConnection(true);
|
177
202
|
String name = connection.getCatalog();
|
@@ -185,12 +210,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
185
210
|
return context.getRuntime().newString(name);
|
186
211
|
}
|
187
212
|
|
188
|
-
@JRubyMethod(name = "
|
189
|
-
public IRubyObject disconnect() {
|
190
|
-
return setConnection(null);
|
191
|
-
}
|
192
|
-
|
193
|
-
@JRubyMethod
|
213
|
+
@JRubyMethod(name = "execute", required = 1)
|
194
214
|
public IRubyObject execute(final ThreadContext context, final IRubyObject sql) {
|
195
215
|
return (IRubyObject) withConnectionAndRetry(context, new SQLBlock() {
|
196
216
|
public Object call(Connection c) throws SQLException {
|
@@ -481,11 +501,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
481
501
|
});
|
482
502
|
}
|
483
503
|
|
484
|
-
@JRubyMethod(name = "reconnect!")
|
485
|
-
public IRubyObject reconnect() {
|
486
|
-
return setConnection(getConnectionFactory().newConnection());
|
487
|
-
}
|
488
|
-
|
489
504
|
|
490
505
|
@JRubyMethod(name = "rollback")
|
491
506
|
public IRubyObject rollback(ThreadContext context) throws SQLException {
|
@@ -698,19 +713,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
698
713
|
return runtime.newFloat(doubleValue);
|
699
714
|
}
|
700
715
|
|
701
|
-
protected Connection getConnection() {
|
702
|
-
return getConnection(false);
|
703
|
-
}
|
704
|
-
|
705
|
-
protected Connection getConnection(boolean error) {
|
706
|
-
Connection conn = (Connection) dataGetStruct();
|
707
|
-
if(error && conn == null) {
|
708
|
-
RubyClass err = getRuntime().getModule("ActiveRecord").getClass("ConnectionNotEstablished");
|
709
|
-
throw new RaiseException(getRuntime(), err, "no connection available", false);
|
710
|
-
}
|
711
|
-
return conn;
|
712
|
-
}
|
713
|
-
|
714
716
|
protected IRubyObject getAdapter(ThreadContext context) {
|
715
717
|
return callMethod(context, "adapter");
|
716
718
|
}
|
@@ -721,17 +723,21 @@ public class RubyJdbcConnection extends RubyObject {
|
|
721
723
|
|
722
724
|
protected JdbcConnectionFactory getConnectionFactory() throws RaiseException {
|
723
725
|
IRubyObject connection_factory = getInstanceVariable("@connection_factory");
|
724
|
-
|
726
|
+
if (connection_factory == null) {
|
727
|
+
throw getRuntime().newRuntimeError("@connection_factory not set");
|
728
|
+
}
|
729
|
+
JdbcConnectionFactory connectionFactory;
|
725
730
|
try {
|
726
|
-
|
727
|
-
|
728
|
-
} catch (Exception e) {
|
729
|
-
factory = null;
|
731
|
+
connectionFactory = (JdbcConnectionFactory)
|
732
|
+
connection_factory.toJava(JdbcConnectionFactory.class);
|
730
733
|
}
|
731
|
-
|
734
|
+
catch (Exception e) { // TODO debug this !
|
735
|
+
connectionFactory = null;
|
736
|
+
}
|
737
|
+
if (connectionFactory == null) {
|
732
738
|
throw getRuntime().newRuntimeError("@connection_factory not set properly");
|
733
739
|
}
|
734
|
-
return
|
740
|
+
return connectionFactory;
|
735
741
|
}
|
736
742
|
|
737
743
|
private static String[] getTypes(IRubyObject typeArg) {
|
@@ -880,12 +886,26 @@ public class RubyJdbcConnection extends RubyObject {
|
|
880
886
|
return RubyString.newUnicodeString(runtime, str.toString());
|
881
887
|
}
|
882
888
|
|
883
|
-
|
884
|
-
|
889
|
+
protected final Connection getConnection() {
|
890
|
+
return getConnection(false);
|
891
|
+
}
|
885
892
|
|
886
|
-
|
887
|
-
|
888
|
-
|
893
|
+
protected Connection getConnection(boolean error) {
|
894
|
+
final Connection connection = (Connection) dataGetStruct();
|
895
|
+
if ( connection == null && error ) {
|
896
|
+
RubyClass err = getRuntime().getModule("ActiveRecord").getClass("ConnectionNotEstablished");
|
897
|
+
throw new RaiseException(getRuntime(), err, "no connection available", false);
|
898
|
+
}
|
899
|
+
return connection;
|
900
|
+
}
|
901
|
+
|
902
|
+
private synchronized RubyJdbcConnection setConnection(final Connection connection) {
|
903
|
+
close( getConnection(false) ); // close previously open connection if there is one
|
904
|
+
|
905
|
+
final IRubyObject rubyConnectionObject =
|
906
|
+
connection != null ? wrappedConnection(connection) : getRuntime().getNil();
|
907
|
+
setInstanceVariable( "@connection", rubyConnectionObject );
|
908
|
+
dataWrapStruct(connection);
|
889
909
|
return this;
|
890
910
|
}
|
891
911
|
|
@@ -1061,18 +1081,21 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1061
1081
|
* Create a string which represents a sql type usable by Rails from the resultSet column
|
1062
1082
|
* metadata object.
|
1063
1083
|
*/
|
1064
|
-
protected String typeFromResultSet(ResultSet resultSet) throws SQLException {
|
1065
|
-
int precision = intFromResultSet(resultSet, COLUMN_SIZE);
|
1066
|
-
int scale = intFromResultSet(resultSet, DECIMAL_DIGITS);
|
1067
|
-
|
1068
|
-
String type = resultSet.getString(TYPE_NAME);
|
1069
|
-
if (precision > 0) {
|
1070
|
-
type += "(" + precision;
|
1071
|
-
if(scale > 0) type += "," + scale;
|
1072
|
-
type += ")";
|
1073
|
-
}
|
1084
|
+
protected String typeFromResultSet(final ResultSet resultSet) throws SQLException {
|
1085
|
+
final int precision = intFromResultSet(resultSet, COLUMN_SIZE);
|
1086
|
+
final int scale = intFromResultSet(resultSet, DECIMAL_DIGITS);
|
1074
1087
|
|
1075
|
-
|
1088
|
+
final String type = resultSet.getString(TYPE_NAME);
|
1089
|
+
return formatTypeWithPrecisionAndScale(type, precision, scale);
|
1090
|
+
}
|
1091
|
+
|
1092
|
+
protected static String formatTypeWithPrecisionAndScale(final String type, final int precision, final int scale) {
|
1093
|
+
if ( precision <= 0 ) return type;
|
1094
|
+
|
1095
|
+
final StringBuilder typeStr = new StringBuilder().append(type);
|
1096
|
+
typeStr.append('(').append(precision); // type += "(" + precision;
|
1097
|
+
if ( scale > 0 ) typeStr.append(',').append(scale); // type += "," + scale;
|
1098
|
+
return typeStr.append(')').toString(); // type += ")";
|
1076
1099
|
}
|
1077
1100
|
|
1078
1101
|
private IRubyObject defaultValueFromResultSet(Ruby runtime, ResultSet resultSet)
|
@@ -1134,21 +1157,20 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1134
1157
|
|
1135
1158
|
protected IRubyObject unmarshalResults(ThreadContext context, DatabaseMetaData metadata,
|
1136
1159
|
Statement stmt, boolean downCase) throws SQLException {
|
1137
|
-
|
1138
|
-
|
1139
|
-
|
1140
|
-
|
1141
|
-
|
1142
|
-
|
1143
|
-
|
1144
|
-
|
1160
|
+
|
1161
|
+
IRubyObject result = unmarshalResult(context, metadata, stmt.getResultSet(), downCase);
|
1162
|
+
|
1163
|
+
if ( ! stmt.getMoreResults() ) return result;
|
1164
|
+
|
1165
|
+
final List<IRubyObject> results = new ArrayList<IRubyObject>();
|
1166
|
+
results.add(result);
|
1167
|
+
do {
|
1168
|
+
result = unmarshalResult(context, metadata, stmt.getResultSet(), downCase);
|
1169
|
+
results.add(result);
|
1145
1170
|
}
|
1171
|
+
while ( stmt.getMoreResults() );
|
1146
1172
|
|
1147
|
-
|
1148
|
-
return runtime.newArray(sets);
|
1149
|
-
} else {
|
1150
|
-
return sets.get(0);
|
1151
|
-
}
|
1173
|
+
return context.getRuntime().newArray(results);
|
1152
1174
|
}
|
1153
1175
|
|
1154
1176
|
/**
|
@@ -1225,8 +1247,8 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1225
1247
|
return (RuntimeException) arError;
|
1226
1248
|
}
|
1227
1249
|
|
1228
|
-
private IRubyObject wrappedConnection(Connection
|
1229
|
-
return
|
1250
|
+
private IRubyObject wrappedConnection(final Connection connection) {
|
1251
|
+
return JavaUtil.convertJavaToRuby( getRuntime(), connection );
|
1230
1252
|
}
|
1231
1253
|
|
1232
1254
|
/**
|