activerecord-jdbc-adapter 0.8 → 0.8.1
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.
- data/History.txt +21 -0
- data/Manifest.txt +12 -0
- data/README.txt +1 -0
- data/Rakefile +19 -13
- data/lib/active_record/connection_adapters/cachedb_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/jdbc_adapter.rb +22 -5
- data/lib/active_record/connection_adapters/jdbc_adapter_spec.rb +3 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +13 -0
- data/lib/jdbc_adapter/jdbc.rake +32 -29
- data/lib/jdbc_adapter/jdbc_adapter_internal.jar +0 -0
- data/lib/jdbc_adapter/jdbc_cachedb.rb +33 -0
- data/lib/jdbc_adapter/jdbc_db2.rb +96 -7
- data/lib/jdbc_adapter/jdbc_derby.rb +35 -28
- data/lib/jdbc_adapter/jdbc_mssql.rb +62 -103
- data/lib/jdbc_adapter/jdbc_mysql.rb +34 -25
- data/lib/jdbc_adapter/jdbc_oracle.rb +7 -7
- data/lib/jdbc_adapter/jdbc_postgre.rb +1 -1
- data/lib/jdbc_adapter/jdbc_sqlite3.rb +188 -0
- data/lib/jdbc_adapter/jdbc_sybase.rb +39 -0
- data/lib/jdbc_adapter/tsql_helper.rb +59 -0
- data/lib/jdbc_adapter/version.rb +1 -1
- data/src/java/jdbc_adapter/JdbcAdapterInternalService.java +66 -40
- data/src/java/jdbc_adapter/JdbcMySQLSpec.java +2 -2
- data/test/cachedb_simple_test.rb +6 -0
- data/test/db/cachedb.rb +9 -0
- data/test/db/mssql.rb +9 -0
- data/test/db/oracle.rb +22 -2
- data/test/db/sqlite3.rb +11 -0
- data/test/db2_simple_test.rb +4 -0
- data/test/jdbc_common.rb +3 -1
- data/test/manualTestDatabase.rb +1 -5
- data/test/models/entry.rb +1 -1
- data/test/mssql_simple_test.rb +6 -0
- data/test/mysql_simple_test.rb +9 -0
- data/test/oracle_simple_test.rb +23 -0
- data/test/simple.rb +3 -2
- data/test/sqlite3_simple_test.rb +6 -0
- metadata +14 -2
data/lib/jdbc_adapter/version.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
/***** BEGIN LICENSE BLOCK *****
|
2
|
-
* Copyright (c) 2006-
|
2
|
+
* Copyright (c) 2006-2008 Nick Sieger <nick@nicksieger.com>
|
3
3
|
* Copyright (c) 2006-2007 Ola Bini <ola.bini@gmail.com>
|
4
|
-
*
|
4
|
+
*
|
5
5
|
* Permission is hereby granted, free of charge, to any person obtaining
|
6
6
|
* a copy of this software and associated documentation files (the
|
7
7
|
* "Software"), to deal in the Software without restriction, including
|
@@ -9,10 +9,10 @@
|
|
9
9
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
10
10
|
* permit persons to whom the Software is furnished to do so, subject to
|
11
11
|
* the following conditions:
|
12
|
-
*
|
12
|
+
*
|
13
13
|
* The above copyright notice and this permission notice shall be
|
14
14
|
* included in all copies or substantial portions of the Software.
|
15
|
-
*
|
15
|
+
*
|
16
16
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
17
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
18
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
@@ -233,34 +233,38 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
|
|
233
233
|
int tries = 1;
|
234
234
|
int i = 0;
|
235
235
|
Throwable toWrap = null;
|
236
|
+
boolean autoCommit = false;
|
236
237
|
while (i < tries) {
|
237
238
|
Connection c = getConnection(recv);
|
238
239
|
try {
|
240
|
+
autoCommit = c.getAutoCommit();
|
239
241
|
return block.call(c);
|
240
242
|
} catch (Exception e) {
|
241
243
|
toWrap = e;
|
242
244
|
while (toWrap.getCause() != null && toWrap.getCause() != toWrap) {
|
243
245
|
toWrap = toWrap.getCause();
|
244
246
|
}
|
245
|
-
if (i == 0) {
|
246
|
-
tries = (int) rubyApi.convertToRubyInteger(config_value(recv, "retry_count")).getLongValue();
|
247
|
-
if (tries <= 0) {
|
248
|
-
tries = 1;
|
249
|
-
}
|
250
|
-
}
|
251
247
|
i++;
|
252
|
-
if (
|
253
|
-
|
254
|
-
|
255
|
-
|
248
|
+
if (autoCommit) {
|
249
|
+
if (i == 1) {
|
250
|
+
tries = (int) rubyApi.convertToRubyInteger(config_value(recv, "retry_count")).getLongValue();
|
251
|
+
if (tries <= 0) {
|
252
|
+
tries = 1;
|
253
|
+
}
|
254
|
+
}
|
255
|
+
if (isConnectionBroken(recv, c)) {
|
256
|
+
reconnect(recv);
|
257
|
+
} else {
|
258
|
+
throw wrap(recv, toWrap);
|
259
|
+
}
|
256
260
|
}
|
257
261
|
}
|
258
262
|
}
|
259
263
|
throw wrap(recv, toWrap);
|
260
264
|
}
|
261
265
|
|
262
|
-
private static SQLBlock tableLookupBlock(final Ruby runtime,
|
263
|
-
final String catalog, final String schemapat,
|
266
|
+
private static SQLBlock tableLookupBlock(final Ruby runtime,
|
267
|
+
final String catalog, final String schemapat,
|
264
268
|
final String tablepat, final String[] types) {
|
265
269
|
return new SQLBlock() {
|
266
270
|
public IRubyObject call(Connection c) throws SQLException {
|
@@ -271,6 +275,16 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
|
|
271
275
|
boolean isOracle = clzName.indexOf("oracle") != -1 || clzName.indexOf("oci") != -1;
|
272
276
|
|
273
277
|
String realschema = schemapat;
|
278
|
+
String realtablepat = tablepat;
|
279
|
+
|
280
|
+
if(metadata.storesUpperCaseIdentifiers()) {
|
281
|
+
if (realschema != null) realschema = realschema.toUpperCase();
|
282
|
+
if (realtablepat != null) realtablepat = realtablepat.toUpperCase();
|
283
|
+
} else if(metadata.storesLowerCaseIdentifiers()) {
|
284
|
+
if (null != realschema) realschema = realschema.toLowerCase();
|
285
|
+
if (realtablepat != null) realtablepat = realtablepat.toLowerCase();
|
286
|
+
}
|
287
|
+
|
274
288
|
if (realschema == null && isOracle) {
|
275
289
|
ResultSet schemas = metadata.getSchemas();
|
276
290
|
String username = metadata.getUserName();
|
@@ -282,7 +296,7 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
|
|
282
296
|
}
|
283
297
|
schemas.close();
|
284
298
|
}
|
285
|
-
rs = metadata.getTables(catalog, realschema,
|
299
|
+
rs = metadata.getTables(catalog, realschema, realtablepat, types);
|
286
300
|
List arr = new ArrayList();
|
287
301
|
while (rs.next()) {
|
288
302
|
String name = rs.getString(3).toLowerCase();
|
@@ -351,7 +365,7 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
|
|
351
365
|
@JRubyMethod(name = "native_database_types")
|
352
366
|
public static IRubyObject native_database_types(IRubyObject recv) {
|
353
367
|
return rubyApi.getInstanceVariable(recv, "@tps");
|
354
|
-
}
|
368
|
+
}
|
355
369
|
|
356
370
|
@JRubyMethod(name = "set_native_database_types")
|
357
371
|
public static IRubyObject set_native_database_types(IRubyObject recv) throws SQLException, IOException {
|
@@ -383,22 +397,28 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
|
|
383
397
|
|
384
398
|
@JRubyMethod(name = "commit")
|
385
399
|
public static IRubyObject commit(IRubyObject recv) throws SQLException {
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
400
|
+
Connection c = getConnection(recv);
|
401
|
+
if (!c.getAutoCommit()) {
|
402
|
+
try {
|
403
|
+
c.commit();
|
404
|
+
} finally {
|
405
|
+
c.setAutoCommit(true);
|
406
|
+
}
|
391
407
|
}
|
408
|
+
return recv.getRuntime().getNil();
|
392
409
|
}
|
393
410
|
|
394
411
|
@JRubyMethod(name = "rollback")
|
395
412
|
public static IRubyObject rollback(IRubyObject recv) throws SQLException {
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
413
|
+
Connection c = getConnection(recv);
|
414
|
+
if (!c.getAutoCommit()) {
|
415
|
+
try {
|
416
|
+
c.rollback();
|
417
|
+
} finally {
|
418
|
+
c.setAutoCommit(true);
|
419
|
+
}
|
401
420
|
}
|
421
|
+
return recv.getRuntime().getNil();
|
402
422
|
}
|
403
423
|
|
404
424
|
@JRubyMethod(name = {"columns", "columns_internal"}, required = 1, optional = 2)
|
@@ -410,9 +430,10 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
|
|
410
430
|
String table_name = rubyApi.convertToRubyString(args[0]).getUnicodeValue();
|
411
431
|
String schemaName = null;
|
412
432
|
|
413
|
-
|
414
|
-
|
415
|
-
|
433
|
+
int index = table_name.indexOf(".");
|
434
|
+
if(index != -1) {
|
435
|
+
schemaName = table_name.substring(0, index);
|
436
|
+
table_name = table_name.substring(index + 1);
|
416
437
|
}
|
417
438
|
|
418
439
|
DatabaseMetaData metadata = c.getMetaData();
|
@@ -425,8 +446,10 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
|
|
425
446
|
}
|
426
447
|
|
427
448
|
if(metadata.storesUpperCaseIdentifiers()) {
|
449
|
+
if (null != schemaName) schemaName = schemaName.toUpperCase();
|
428
450
|
table_name = table_name.toUpperCase();
|
429
451
|
} else if(metadata.storesLowerCaseIdentifiers()) {
|
452
|
+
if (null != schemaName) schemaName = schemaName.toLowerCase();
|
430
453
|
table_name = table_name.toLowerCase();
|
431
454
|
}
|
432
455
|
|
@@ -442,7 +465,7 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
|
|
442
465
|
schemas.close();
|
443
466
|
}
|
444
467
|
|
445
|
-
RubyArray matchingTables = (RubyArray) tableLookupBlock(recv.getRuntime(),
|
468
|
+
RubyArray matchingTables = (RubyArray) tableLookupBlock(recv.getRuntime(),
|
446
469
|
c.getCatalog(), schemaName, table_name, new String[]{"TABLE","VIEW"}).call(c);
|
447
470
|
if (matchingTables.isEmpty()) {
|
448
471
|
throw new SQLException("Table " + table_name + " does not exist");
|
@@ -486,6 +509,9 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
|
|
486
509
|
if(scal != null) {
|
487
510
|
scale = Integer.parseInt(scal);
|
488
511
|
}
|
512
|
+
else if(isOracle && rs.getInt(5) == java.sql.Types.DECIMAL) { // NUMBER type in Oracle
|
513
|
+
prec = null;
|
514
|
+
}
|
489
515
|
}
|
490
516
|
String type = rs.getString(6);
|
491
517
|
if(prec != null && precision > 0) {
|
@@ -611,7 +637,7 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
|
|
611
637
|
} else {
|
612
638
|
maxrows = 0;
|
613
639
|
}
|
614
|
-
|
640
|
+
|
615
641
|
return withConnectionAndRetry(recv, new SQLBlock() {
|
616
642
|
public IRubyObject call(Connection c) throws SQLException {
|
617
643
|
Statement stmt = null;
|
@@ -682,7 +708,7 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
|
|
682
708
|
rs.close();
|
683
709
|
} catch(Exception e) {}
|
684
710
|
}
|
685
|
-
|
711
|
+
|
686
712
|
return runtime.newArray(results);
|
687
713
|
}
|
688
714
|
|
@@ -771,7 +797,7 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
|
|
771
797
|
rs.close();
|
772
798
|
} catch(Exception e) {}
|
773
799
|
}
|
774
|
-
|
800
|
+
|
775
801
|
return runtime.newArray(results);
|
776
802
|
}
|
777
803
|
|
@@ -856,7 +882,7 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
|
|
856
882
|
|
857
883
|
private static int getTypeValueFor(Ruby runtime, IRubyObject type) throws SQLException {
|
858
884
|
if(!(type instanceof RubySymbol)) {
|
859
|
-
type = rubyApi.callMethod(type, "
|
885
|
+
type = rubyApi.callMethod(type, "class");
|
860
886
|
}
|
861
887
|
if(type == runtime.newSymbol("string")) {
|
862
888
|
return Types.VARCHAR;
|
@@ -884,7 +910,7 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
|
|
884
910
|
return -1;
|
885
911
|
}
|
886
912
|
}
|
887
|
-
|
913
|
+
|
888
914
|
private final static DateFormat FORMAT = new SimpleDateFormat("%y-%M-%d %H:%m:%s");
|
889
915
|
|
890
916
|
private static void setValue(PreparedStatement ps, int index, Ruby runtime, ThreadContext context,
|
@@ -1012,7 +1038,7 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
|
|
1012
1038
|
ps = c.prepareStatement(sql);
|
1013
1039
|
if (args[0].isTrue()) { // binary
|
1014
1040
|
ByteList outp = rubyApi.convertToRubyString(args[5]).getByteList();
|
1015
|
-
ps.setBinaryStream(1, new ByteArrayInputStream(outp.bytes,
|
1041
|
+
ps.setBinaryStream(1, new ByteArrayInputStream(outp.bytes,
|
1016
1042
|
outp.begin, outp.realSize), outp.realSize);
|
1017
1043
|
} else { // clob
|
1018
1044
|
String ss = rubyApi.convertToRubyString(args[5]).getUnicodeValue();
|
@@ -1048,7 +1074,7 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
|
|
1048
1074
|
jo = (JavaObject) rubyApi.getInstanceVariable(inp, "@java_object");
|
1049
1075
|
}
|
1050
1076
|
return (ResultSet) jo.getValue();
|
1051
|
-
}
|
1077
|
+
}
|
1052
1078
|
|
1053
1079
|
private static boolean isConnectionBroken(IRubyObject recv, Connection c) {
|
1054
1080
|
try {
|
@@ -1061,7 +1087,7 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
|
|
1061
1087
|
} finally {
|
1062
1088
|
try { s.close(); } catch (SQLException ignored) {}
|
1063
1089
|
}
|
1064
|
-
return
|
1090
|
+
return false;
|
1065
1091
|
} else {
|
1066
1092
|
return !c.isClosed();
|
1067
1093
|
}
|
@@ -66,7 +66,7 @@ public class JdbcMySQLSpec {
|
|
66
66
|
default: continue;
|
67
67
|
}
|
68
68
|
if(i > startOfExtend)
|
69
|
-
blNew.append(bl, startOfExtend, i-startOfExtend);
|
69
|
+
blNew.append(bl, startOfExtend-bl.begin, i-startOfExtend);
|
70
70
|
blNew.append(rep, 0, 2);
|
71
71
|
startOfExtend = i+1;
|
72
72
|
}
|
@@ -75,7 +75,7 @@ public class JdbcMySQLSpec {
|
|
75
75
|
return string;
|
76
76
|
}
|
77
77
|
if (bl.begin + bl.realSize > startOfExtend)
|
78
|
-
blNew.append(bl, startOfExtend, bl.begin + bl.realSize - startOfExtend);
|
78
|
+
blNew.append(bl, startOfExtend-bl.begin, bl.begin + bl.realSize - startOfExtend);
|
79
79
|
|
80
80
|
return recv.getRuntime().newStringShared(blNew);
|
81
81
|
}
|
data/test/db/cachedb.rb
ADDED
data/test/db/mssql.rb
ADDED
data/test/db/oracle.rb
CHANGED
@@ -1,9 +1,29 @@
|
|
1
1
|
config = {
|
2
2
|
:username => 'blog',
|
3
|
-
:password => '',
|
3
|
+
:password => 'blog',
|
4
4
|
:adapter => 'oracle',
|
5
5
|
:host => ENV["ORACLE_HOST"] || 'localhost',
|
6
|
-
:database => ENV["ORACLE_SID"] || '
|
6
|
+
:database => ENV["ORACLE_SID"] || 'XE' # XE is the default SID for oracle xe
|
7
7
|
}
|
8
8
|
|
9
9
|
ActiveRecord::Base.establish_connection(config)
|
10
|
+
|
11
|
+
# Here are some notes of things I had to do to get running on Oracle
|
12
|
+
# XE.
|
13
|
+
#
|
14
|
+
# create tablespace weblog_development
|
15
|
+
# datafile '/usr/lib/oracle/xe/oradata/XE/weblog_development.dbf';
|
16
|
+
# create user blog identified by blog
|
17
|
+
# default tablespace weblog_development;
|
18
|
+
# grant all privileges to blog;
|
19
|
+
#
|
20
|
+
# You might need to up the number of processes and restart the
|
21
|
+
# listener. (In my case, I had to reboot.) See
|
22
|
+
# http://it.newinstance.it/2007/06/01/ora-12519-tnsno-appropriate-service-handler-found/
|
23
|
+
#
|
24
|
+
# alter system set PROCESSES=150 scope=SPFILE;
|
25
|
+
#
|
26
|
+
# These might be helpful too (numbers are rather arbitrary...)
|
27
|
+
#
|
28
|
+
# alter system set TRANSACTIONS=126 scope=SPFILE;
|
29
|
+
# alter system set SESSIONS=115 scope=SPFILE;
|
data/test/db/sqlite3.rb
ADDED
data/test/db2_simple_test.rb
CHANGED
data/test/jdbc_common.rb
CHANGED
data/test/manualTestDatabase.rb
CHANGED
@@ -172,11 +172,7 @@ end
|
|
172
172
|
pelle.female = false
|
173
173
|
pelle.save
|
174
174
|
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
prods = Product.find_all
|
175
|
+
prods = Product.find :all
|
180
176
|
order = Order.new(:name => "Dalai Lama", :address => "Great Road 32", :email => "abc@dot.com", :pay_type => "cash")
|
181
177
|
order.line_items << LineItem.new(:product => prods[0], :quantity => 3, :total_price => (prods[0].price * 3))
|
182
178
|
order.line_items << LineItem.new(:product => prods[2], :quantity => 1, :total_price => (prods[2].price))
|
data/test/models/entry.rb
CHANGED
@@ -7,7 +7,7 @@ class CreateEntries < ActiveRecord::Migration
|
|
7
7
|
t.column :title, :string, :limit => 100
|
8
8
|
t.column :updated_on, :datetime
|
9
9
|
t.column :content, :text
|
10
|
-
t.column :rating, :decimal, :precision => 10
|
10
|
+
t.column :rating, :decimal, :precision => 10, :scale => 2
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
data/test/mysql_simple_test.rb
CHANGED
@@ -10,6 +10,15 @@ require 'db/mysql'
|
|
10
10
|
|
11
11
|
class MysqlSimpleTest < Test::Unit::TestCase
|
12
12
|
include SimpleTestMethods
|
13
|
+
|
14
|
+
def test_string_quoting_oddity
|
15
|
+
s = "0123456789a'a"
|
16
|
+
assert_equal "'0123456789a\\'a'", ActiveRecord::Base.connection.quote(s)
|
17
|
+
|
18
|
+
s2 = s[10,3]
|
19
|
+
assert_equal "a'a", s2
|
20
|
+
assert_equal "'a\\'a'", ActiveRecord::Base.connection.quote(s2)
|
21
|
+
end
|
13
22
|
end
|
14
23
|
|
15
24
|
class MysqlHasManyThroughTest < Test::Unit::TestCase
|
data/test/oracle_simple_test.rb
CHANGED
@@ -4,3 +4,26 @@ require 'db/oracle'
|
|
4
4
|
class OracleSimpleTest < Test::Unit::TestCase
|
5
5
|
include SimpleTestMethods
|
6
6
|
end
|
7
|
+
|
8
|
+
class OracleSpecificTest < Test::Unit::TestCase
|
9
|
+
include MultibyteTestMethods
|
10
|
+
|
11
|
+
def setup
|
12
|
+
super
|
13
|
+
@java_con.createStatement.execute "CREATE TABLE DEFAULT_NUMBER (VALUE NUMBER)"
|
14
|
+
@java_con.createStatement.execute "INSERT INTO DEFAULT_NUMBER (VALUE) VALUES (0.076)"
|
15
|
+
end
|
16
|
+
|
17
|
+
def teardown
|
18
|
+
@java_con.createStatement.execute "DROP TABLE DEFAULT_NUMBER"
|
19
|
+
super
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
def test_default_number_precision
|
24
|
+
klass = Class.new(ActiveRecord::Base)
|
25
|
+
klass.set_table_name "DEFAULT_NUMBER"
|
26
|
+
obj = klass.find(:first)
|
27
|
+
assert_equal 0.076, obj.value
|
28
|
+
end
|
29
|
+
end
|