activerecord-jdbc-adapter 0.8 → 0.8.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|