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.
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