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.
Files changed (38) hide show
  1. data/History.txt +21 -0
  2. data/Manifest.txt +12 -0
  3. data/README.txt +1 -0
  4. data/Rakefile +19 -13
  5. data/lib/active_record/connection_adapters/cachedb_adapter.rb +1 -0
  6. data/lib/active_record/connection_adapters/jdbc_adapter.rb +22 -5
  7. data/lib/active_record/connection_adapters/jdbc_adapter_spec.rb +3 -0
  8. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +13 -0
  9. data/lib/jdbc_adapter/jdbc.rake +32 -29
  10. data/lib/jdbc_adapter/jdbc_adapter_internal.jar +0 -0
  11. data/lib/jdbc_adapter/jdbc_cachedb.rb +33 -0
  12. data/lib/jdbc_adapter/jdbc_db2.rb +96 -7
  13. data/lib/jdbc_adapter/jdbc_derby.rb +35 -28
  14. data/lib/jdbc_adapter/jdbc_mssql.rb +62 -103
  15. data/lib/jdbc_adapter/jdbc_mysql.rb +34 -25
  16. data/lib/jdbc_adapter/jdbc_oracle.rb +7 -7
  17. data/lib/jdbc_adapter/jdbc_postgre.rb +1 -1
  18. data/lib/jdbc_adapter/jdbc_sqlite3.rb +188 -0
  19. data/lib/jdbc_adapter/jdbc_sybase.rb +39 -0
  20. data/lib/jdbc_adapter/tsql_helper.rb +59 -0
  21. data/lib/jdbc_adapter/version.rb +1 -1
  22. data/src/java/jdbc_adapter/JdbcAdapterInternalService.java +66 -40
  23. data/src/java/jdbc_adapter/JdbcMySQLSpec.java +2 -2
  24. data/test/cachedb_simple_test.rb +6 -0
  25. data/test/db/cachedb.rb +9 -0
  26. data/test/db/mssql.rb +9 -0
  27. data/test/db/oracle.rb +22 -2
  28. data/test/db/sqlite3.rb +11 -0
  29. data/test/db2_simple_test.rb +4 -0
  30. data/test/jdbc_common.rb +3 -1
  31. data/test/manualTestDatabase.rb +1 -5
  32. data/test/models/entry.rb +1 -1
  33. data/test/mssql_simple_test.rb +6 -0
  34. data/test/mysql_simple_test.rb +9 -0
  35. data/test/oracle_simple_test.rb +23 -0
  36. data/test/simple.rb +3 -2
  37. data/test/sqlite3_simple_test.rb +6 -0
  38. metadata +14 -2
@@ -1,5 +1,5 @@
1
1
  module JdbcAdapter
2
2
  module Version
3
- VERSION = "0.8"
3
+ VERSION = "0.8.1"
4
4
  end
5
5
  end
@@ -1,7 +1,7 @@
1
1
  /***** BEGIN LICENSE BLOCK *****
2
- * Copyright (c) 2006-2007 Nick Sieger <nick@nicksieger.com>
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 (isConnectionBroken(recv, c)) {
253
- reconnect(recv);
254
- } else {
255
- throw wrap(recv, toWrap);
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, tablepat, types);
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
- try {
387
- getConnection(recv).commit();
388
- return recv.getRuntime().getNil();
389
- } finally {
390
- getConnection(recv).setAutoCommit(true);
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
- try {
397
- getConnection(recv).rollback();
398
- return recv.getRuntime().getNil();
399
- } finally {
400
- getConnection(recv).setAutoCommit(true);
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
- if(table_name.indexOf(".") != -1) {
414
- schemaName = table_name.substring(table_name.indexOf(".")+1);
415
- table_name = table_name.substring(0, table_name.indexOf(".")+1);
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, "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 true;
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
  }
@@ -0,0 +1,6 @@
1
+ require 'jdbc_common'
2
+ require 'db/cachedb'
3
+
4
+ class CacheDBSimpleTest < Test::Unit::TestCase
5
+ include SimpleTestMethods
6
+ end
@@ -0,0 +1,9 @@
1
+ config = {
2
+ :username => '_SYSTEM',
3
+ :password => 'SYS',
4
+ :adapter => 'cachedb',
5
+ :host => ENV[ "CACHE_HOST" ] || 'localhost',
6
+ :database => ENV[ "CACHE_NAMESPACE" ] || 'weblog_development'
7
+ }
8
+
9
+ ActiveRecord::Base.establish_connection( config )
data/test/db/mssql.rb ADDED
@@ -0,0 +1,9 @@
1
+ config = {
2
+ :username => 'blog',
3
+ :password => '',
4
+ :adapter => 'jdbc',
5
+ :url => "jdbc:jtds:sqlserver://localhost:1433/weblog_development",
6
+ :driver => 'net.sourceforge.jtds.jdbc.Driver'
7
+ }
8
+
9
+ ActiveRecord::Base.establish_connection( config )
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"] || 'weblog_development'
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;
@@ -0,0 +1,11 @@
1
+ config = {
2
+ :adapter => 'sqlite3',
3
+ :database => 'test.sqlite3'
4
+ }
5
+
6
+ ActiveRecord::Base.establish_connection(config)
7
+
8
+ at_exit {
9
+ # Clean up hsqldb when done
10
+ Dir['test.sqlite3*'].each {|f| File.delete(f)}
11
+ }
@@ -4,3 +4,7 @@ require 'db/db2'
4
4
  class DB2SimpleTest < Test::Unit::TestCase
5
5
  include SimpleTestMethods
6
6
  end
7
+
8
+ class DB2HasManyThroughTest < Test::Unit::TestCase
9
+ include HasManyThroughMethods
10
+ end
data/test/jdbc_common.rb CHANGED
@@ -1,5 +1,7 @@
1
- require 'jdbc_adapter'
2
1
  require 'rubygems'
2
+ # Specify version of activerecord here if desired
3
+ # gem 'activerecord', '=2.1'
4
+ require 'jdbc_adapter'
3
5
  require 'models/auto_id'
4
6
  require 'models/entry'
5
7
  require 'models/add_not_null_column_to_table'
@@ -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
 
@@ -0,0 +1,6 @@
1
+ require 'jdbc_common'
2
+ require 'db/mssql'
3
+
4
+ class MsSQLSimpleTest < Test::Unit::TestCase
5
+ include SimpleTestMethods
6
+ end
@@ -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
@@ -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