activerecord-jdbc-adapter 1.2.9.1 → 1.3.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (231) hide show
  1. data/.travis.yml +3 -0
  2. data/Appraisals +12 -4
  3. data/Gemfile +3 -3
  4. data/Gemfile.lock +19 -19
  5. data/History.txt +90 -16
  6. data/LICENSE.txt +2 -1
  7. data/README.md +14 -1
  8. data/activerecord-jdbc-adapter.gemspec +2 -2
  9. data/gemfiles/rails23.gemfile +5 -5
  10. data/gemfiles/rails23.gemfile.lock +27 -27
  11. data/gemfiles/rails30.gemfile +3 -3
  12. data/gemfiles/rails30.gemfile.lock +8 -8
  13. data/gemfiles/rails31.gemfile +4 -4
  14. data/gemfiles/rails31.gemfile.lock +18 -18
  15. data/gemfiles/rails32.gemfile +4 -4
  16. data/gemfiles/rails32.gemfile.lock +17 -17
  17. data/gemfiles/rails40.gemfile +17 -0
  18. data/gemfiles/rails40.gemfile.lock +126 -0
  19. data/lib/activerecord-jdbc-adapter.rb +0 -7
  20. data/lib/arjdbc.rb +6 -5
  21. data/lib/arjdbc/db2.rb +1 -1
  22. data/lib/arjdbc/db2/adapter.rb +52 -29
  23. data/lib/arjdbc/db2/connection_methods.rb +13 -14
  24. data/lib/arjdbc/derby.rb +1 -1
  25. data/lib/arjdbc/derby/adapter.rb +29 -9
  26. data/lib/arjdbc/derby/connection_methods.rb +17 -20
  27. data/lib/arjdbc/firebird.rb +1 -1
  28. data/lib/arjdbc/h2.rb +2 -2
  29. data/lib/arjdbc/h2/adapter.rb +1 -1
  30. data/lib/arjdbc/h2/connection_methods.rb +12 -16
  31. data/lib/arjdbc/hsqldb.rb +1 -1
  32. data/lib/arjdbc/hsqldb/connection_methods.rb +13 -16
  33. data/lib/arjdbc/informix.rb +1 -1
  34. data/lib/arjdbc/informix/connection_methods.rb +8 -10
  35. data/lib/arjdbc/jdbc.rb +1 -1
  36. data/lib/arjdbc/jdbc/adapter.rb +125 -53
  37. data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
  38. data/lib/arjdbc/jdbc/base_ext.rb +34 -9
  39. data/lib/arjdbc/jdbc/column.rb +15 -2
  40. data/lib/arjdbc/jdbc/connection.rb +0 -2
  41. data/lib/arjdbc/jdbc/connection_methods.rb +10 -3
  42. data/lib/arjdbc/jdbc/driver.rb +2 -2
  43. data/lib/arjdbc/jdbc/extension.rb +35 -21
  44. data/lib/arjdbc/jdbc/java.rb +0 -2
  45. data/lib/arjdbc/jdbc/missing_functionality_helper.rb +35 -25
  46. data/lib/arjdbc/jdbc/railtie.rb +2 -9
  47. data/lib/arjdbc/mimer.rb +1 -1
  48. data/lib/arjdbc/mssql.rb +2 -2
  49. data/lib/arjdbc/mssql/adapter.rb +271 -92
  50. data/lib/arjdbc/mssql/connection_methods.rb +30 -32
  51. data/lib/arjdbc/mssql/explain_support.rb +107 -0
  52. data/lib/arjdbc/mssql/limit_helpers.rb +48 -18
  53. data/lib/arjdbc/mysql.rb +1 -1
  54. data/lib/arjdbc/mysql/adapter.rb +63 -14
  55. data/lib/arjdbc/mysql/connection_methods.rb +22 -24
  56. data/lib/arjdbc/mysql/explain_support.rb +2 -5
  57. data/lib/arjdbc/oracle.rb +1 -1
  58. data/lib/arjdbc/oracle/adapter.rb +78 -38
  59. data/lib/arjdbc/oracle/connection_methods.rb +9 -10
  60. data/lib/arjdbc/postgresql.rb +1 -1
  61. data/lib/arjdbc/postgresql/adapter.rb +964 -380
  62. data/lib/arjdbc/postgresql/column_cast.rb +136 -0
  63. data/lib/arjdbc/postgresql/connection_methods.rb +19 -21
  64. data/lib/arjdbc/postgresql/explain_support.rb +3 -6
  65. data/lib/arjdbc/railtie.rb +9 -0
  66. data/lib/arjdbc/sqlite3.rb +1 -1
  67. data/lib/arjdbc/sqlite3/adapter.rb +73 -26
  68. data/lib/arjdbc/sqlite3/connection_methods.rb +27 -28
  69. data/lib/arjdbc/sqlite3/explain_support.rb +2 -5
  70. data/lib/arjdbc/sybase.rb +1 -1
  71. data/lib/arjdbc/version.rb +5 -4
  72. data/pom.xml +8 -0
  73. data/rakelib/02-test.rake +57 -51
  74. data/rakelib/compile.rake +17 -5
  75. data/rakelib/rails.rake +42 -31
  76. data/src/java/arjdbc/db2/DB2RubyJdbcConnection.java +4 -3
  77. data/src/java/arjdbc/derby/DerbyModule.java +98 -85
  78. data/src/java/arjdbc/derby/DerbyRubyJdbcConnection.java +70 -0
  79. data/src/java/arjdbc/h2/H2RubyJdbcConnection.java +0 -4
  80. data/src/java/arjdbc/jdbc/AdapterJavaService.java +26 -15
  81. data/src/java/arjdbc/jdbc/Callable.java +44 -0
  82. data/src/java/arjdbc/jdbc/JdbcConnectionFactory.java +10 -2
  83. data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +1675 -834
  84. data/src/java/arjdbc/jdbc/SQLBlock.java +9 -3
  85. data/src/java/arjdbc/mssql/MSSQLRubyJdbcConnection.java +73 -36
  86. data/src/java/arjdbc/mysql/MySQLModule.java +11 -10
  87. data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +86 -80
  88. data/src/java/arjdbc/oracle/OracleRubyJdbcConnection.java +27 -7
  89. data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +214 -0
  90. data/src/java/arjdbc/postgresql/PostgresqlRubyJdbcConnection.java +25 -67
  91. data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +52 -49
  92. data/src/java/arjdbc/util/QuotingUtils.java +6 -6
  93. data/test/abstract_db_create.rb +11 -11
  94. data/test/activerecord/connection_adapters/type_conversion_test.rb +18 -12
  95. data/test/db/db2.rb +1 -1
  96. data/test/{db2_binary_test.rb → db/db2/binary_test.rb} +0 -0
  97. data/test/db/db2/has_many_through_test.rb +6 -0
  98. data/test/{db2_reset_column_information_test.rb → db/db2/reset_column_information_test.rb} +1 -2
  99. data/test/{db2_serialize_test.rb → db/db2/serialize_test.rb} +0 -0
  100. data/test/{db2_simple_test.rb → db/db2/simple_test.rb} +1 -8
  101. data/test/db/db2/test_helper.rb +6 -0
  102. data/test/{db2_test.rb → db/db2/unit_test.rb} +1 -1
  103. data/test/db/derby.rb +1 -1
  104. data/test/{derby_binary_test.rb → db/derby/binary_test.rb} +0 -0
  105. data/test/{derby_migration_test.rb → db/derby/migration_test.rb} +0 -0
  106. data/test/{derby_reset_column_information_test.rb → db/derby/reset_column_information_test.rb} +0 -0
  107. data/test/{derby_row_locking_test.rb → db/derby/row_locking_test.rb} +1 -4
  108. data/test/db/derby/schema_dump_test.rb +5 -0
  109. data/test/{derby_serialize_test.rb → db/derby/serialize_test.rb} +0 -0
  110. data/test/{derby_simple_test.rb → db/derby/simple_test.rb} +23 -38
  111. data/test/db/derby/test_helper.rb +6 -0
  112. data/test/db/derby/unit_test.rb +32 -0
  113. data/test/db/derby/xml_column_test.rb +17 -0
  114. data/test/db/h2.rb +1 -1
  115. data/test/{h2_binary_test.rb → db/h2/binary_test.rb} +0 -0
  116. data/test/{h2_change_column_test.rb → db/h2/change_column_test.rb} +1 -0
  117. data/test/{h2_schema_dump_test.rb → db/h2/schema_dump_test.rb} +0 -0
  118. data/test/{h2_serialize_test.rb → db/h2/serialize_test.rb} +0 -0
  119. data/test/{h2_simple_test.rb → db/h2/simple_test.rb} +3 -1
  120. data/test/db/hsqldb.rb +1 -1
  121. data/test/{hsqldb_binary_test.rb → db/hsqldb/binary_test.rb} +0 -0
  122. data/test/{hsqldb_schema_dump_test.rb → db/hsqldb/schema_dump_test.rb} +0 -0
  123. data/test/{hsqldb_serialize_test.rb → db/hsqldb/serialize_test.rb} +0 -0
  124. data/test/{hsqldb_simple_test.rb → db/hsqldb/simple_test.rb} +3 -1
  125. data/test/db/informix.rb +1 -1
  126. data/test/db/jdbc.rb +3 -2
  127. data/test/db/jdbc_derby.rb +1 -1
  128. data/test/db/jdbc_h2.rb +1 -1
  129. data/test/db/jdbc_mysql.rb +1 -1
  130. data/test/db/jdbc_postgres.rb +1 -1
  131. data/test/db/jndi_config.rb +1 -2
  132. data/test/db/jndi_pooled_config.rb +2 -3
  133. data/test/db/mssql.rb +2 -2
  134. data/test/{mssql_binary_test.rb → db/mssql/binary_test.rb} +0 -0
  135. data/test/{mssql_db_create_test.rb → db/mssql/db_create_test.rb} +1 -1
  136. data/test/db/mssql/exec_proc_test.rb +46 -0
  137. data/test/{mssql_identity_insert_test.rb → db/mssql/identity_insert_test.rb} +0 -0
  138. data/test/db/mssql/ignore_system_views_test.rb +40 -0
  139. data/test/{mssql_limit_offset_test.rb → db/mssql/limit_offset_test.rb} +10 -1
  140. data/test/{mssql_multibyte_test.rb → db/mssql/multibyte_test.rb} +0 -0
  141. data/test/db/mssql/multiple_connections_test.rb +71 -0
  142. data/test/{mssql_reset_column_information_test.rb → db/mssql/reset_column_information_test.rb} +0 -0
  143. data/test/{mssql_row_locking_test.rb → db/mssql/row_locking_test.rb} +0 -0
  144. data/test/{mssql_serialize_test.rb → db/mssql/serialize_test.rb} +1 -1
  145. data/test/db/mssql/simple_test.rb +140 -0
  146. data/test/db/mssql/transaction_test.rb +6 -0
  147. data/test/db/mssql/types_test.rb +205 -0
  148. data/test/{mssql_test.rb → db/mssql/unit_test.rb} +2 -2
  149. data/test/db/mysql.rb +1 -2
  150. data/test/db/mysql/_rails_test_mysql.32.out +6768 -0
  151. data/test/{mysql_binary_test.rb → db/mysql/binary_test.rb} +0 -0
  152. data/test/db/mysql/connection_test.rb +51 -0
  153. data/test/{mysql_db_create_test.rb → db/mysql/db_create_test.rb} +0 -0
  154. data/test/{mysql_index_length_test.rb → db/mysql/index_length_test.rb} +0 -0
  155. data/test/{mysql_multibyte_test.rb → db/mysql/multibyte_test.rb} +0 -0
  156. data/test/{mysql_nonstandard_primary_key_test.rb → db/mysql/nonstandard_primary_key_test.rb} +0 -0
  157. data/test/{mysql_reset_column_information_test.rb → db/mysql/reset_column_information_test.rb} +0 -0
  158. data/test/{mysql_schema_dump_test.rb → db/mysql/schema_dump_test.rb} +9 -1
  159. data/test/{mysql_serialize_test.rb → db/mysql/serialize_test.rb} +0 -0
  160. data/test/{mysql_simple_test.rb → db/mysql/simple_test.rb} +16 -8
  161. data/test/db/mysql/transaction_test.rb +6 -0
  162. data/test/db/mysql/types_test.rb +30 -0
  163. data/test/{mysql_test.rb → db/mysql/unit_test.rb} +1 -1
  164. data/test/db/mysql_config.rb +1 -1
  165. data/test/db/oracle.rb +1 -1
  166. data/test/{oracle_binary_test.rb → db/oracle/binary_test.rb} +0 -0
  167. data/test/{oracle_limit_test.rb → db/oracle/limit_test.rb} +0 -0
  168. data/test/db/oracle/multibyte_test.rb +22 -0
  169. data/test/{oracle_reset_column_information_test.rb → db/oracle/reset_column_information_test.rb} +0 -0
  170. data/test/{oracle_serialize_test.rb → db/oracle/serialize_test.rb} +0 -0
  171. data/test/{oracle_simple_test.rb → db/oracle/simple_test.rb} +14 -19
  172. data/test/{oracle_specific_test.rb → db/oracle/specific_test.rb} +62 -16
  173. data/test/db/oracle/transaction_test.rb +31 -0
  174. data/test/db/oracle/unit_test.rb +31 -0
  175. data/test/db/postgres.rb +1 -1
  176. data/test/db/postgres/_rails_test_postgres.32.out +6777 -0
  177. data/test/db/postgres/a_custom_primary_key_test.rb +50 -0
  178. data/test/db/postgres/array_type_test.rb +101 -0
  179. data/test/{postgres_binary_test.rb → db/postgres/binary_test.rb} +0 -0
  180. data/test/db/postgres/connection_test.rb +55 -0
  181. data/test/db/postgres/data_types_test.rb +703 -0
  182. data/test/{postgres_db_create_test.rb → db/postgres/db_create_test.rb} +1 -1
  183. data/test/{postgres_drop_db_test.rb → db/postgres/db_drop_test.rb} +2 -0
  184. data/test/db/postgres/hstore_test.rb +200 -0
  185. data/test/db/postgres/information_schema_leak_test.rb +30 -0
  186. data/test/db/postgres/json_test.rb +86 -0
  187. data/test/db/postgres/ltree_test.rb +50 -0
  188. data/test/{postgres_mixed_case_test.rb → db/postgres/mixed_case_test.rb} +0 -0
  189. data/test/db/postgres/native_types_test.rb +128 -0
  190. data/test/{postgres_reserved_test.rb → db/postgres/reserved_test.rb} +0 -0
  191. data/test/{postgres_reset_column_information_test.rb → db/postgres/reset_column_information_test.rb} +0 -0
  192. data/test/{postgres_row_locking_test.rb → db/postgres/row_locking_test.rb} +0 -0
  193. data/test/{postgres_schema_dump_test.rb → db/postgres/schema_dump_test.rb} +4 -4
  194. data/test/db/postgres/schema_test.rb +113 -0
  195. data/test/{postgres_simple_test.rb → db/postgres/simple_test.rb} +48 -8
  196. data/test/{postgres_table_alias_length_test.rb → db/postgres/table_alias_length_test.rb} +2 -1
  197. data/test/db/postgres/transaction_test.rb +6 -0
  198. data/test/{postgres_test.rb → db/postgres/unit_test.rb} +3 -3
  199. data/test/db/sqlite3.rb +1 -1
  200. data/test/db/sqlite3/_rails_test_sqlite3.32.out +6502 -0
  201. data/test/db/sqlite3/has_many_though_test.rb +6 -0
  202. data/test/{sqlite3_reset_column_information_test.rb → db/sqlite3/reset_column_information_test.rb} +0 -0
  203. data/test/{sqlite3_schema_dump_test.rb → db/sqlite3/schema_dump_test.rb} +0 -0
  204. data/test/{sqlite3_serialize_test.rb → db/sqlite3/serialize_test.rb} +0 -0
  205. data/test/{sqlite3_simple_test.rb → db/sqlite3/simple_test.rb} +63 -63
  206. data/test/db/sqlite3/transaction_test.rb +32 -0
  207. data/test/{sqlite3_type_conversion_test.rb → db/sqlite3/type_conversion_test.rb} +0 -0
  208. data/test/has_many_through.rb +29 -64
  209. data/test/jdbc/oracle.rb +11 -0
  210. data/test/jndi_test.rb +16 -4
  211. data/test/models/auto_id.rb +1 -1
  212. data/test/models/rights_and_roles.rb +57 -0
  213. data/test/row_locking.rb +3 -0
  214. data/test/schema_dump.rb +24 -10
  215. data/test/simple.rb +359 -104
  216. data/test/test_helper.rb +4 -2
  217. data/test/transaction.rb +109 -0
  218. metadata +119 -86
  219. data/lib/arjdbc/jdbc/compatibility.rb +0 -51
  220. data/lib/arjdbc/jdbc/core_ext.rb +0 -24
  221. data/lib/arjdbc/jdbc/discover.rb +0 -18
  222. data/test/derby_schema_dump_test.rb +0 -9
  223. data/test/mssql_ignore_system_views_test.rb +0 -30
  224. data/test/mssql_legacy_types_test.rb +0 -58
  225. data/test/mssql_null_test.rb +0 -14
  226. data/test/mssql_simple_test.rb +0 -51
  227. data/test/postgres_information_schema_leak_test.rb +0 -28
  228. data/test/postgres_native_type_mapping_test.rb +0 -93
  229. data/test/postgres_nonseq_pkey_test.rb +0 -38
  230. data/test/postgres_schema_search_path_test.rb +0 -48
  231. data/test/postgres_type_conversion_test.rb +0 -33
@@ -32,11 +32,17 @@ import java.sql.SQLException;
32
32
  import java.sql.Statement;
33
33
 
34
34
  /**
35
- *
35
+ * @deprecated implement a {@link Callable} directly instead.
36
+ *
36
37
  * @author nicksieger
37
38
  */
38
- public abstract class SQLBlock {
39
- protected abstract Object call(Connection c) throws SQLException;
39
+ @Deprecated
40
+ public abstract class SQLBlock implements Callable {
41
+
42
+ /**
43
+ * @see Callable#call(Connection)
44
+ */
45
+ public abstract Object call(final Connection connection) throws SQLException;
40
46
 
41
47
  public void close(Statement statement) {
42
48
  RubyJdbcConnection.close(statement);
@@ -25,32 +25,34 @@
25
25
  ***** END LICENSE BLOCK *****/
26
26
  package arjdbc.mssql;
27
27
 
28
+ import arjdbc.jdbc.RubyJdbcConnection;
29
+
30
+ import java.sql.DatabaseMetaData;
28
31
  import java.sql.ResultSet;
29
32
  import java.sql.SQLException;
30
33
  import java.sql.Types;
31
34
  import java.util.List;
32
35
 
33
- import arjdbc.jdbc.RubyJdbcConnection;
34
- import static arjdbc.jdbc.RubyJdbcConnection.ColumnData;
36
+ import org.jcodings.specific.UTF8Encoding;
35
37
 
36
38
  import org.jruby.Ruby;
39
+ import org.jruby.RubyArray;
37
40
  import org.jruby.RubyClass;
38
41
  import org.jruby.RubyString;
42
+ import org.jruby.anno.JRubyMethod;
39
43
  import org.jruby.runtime.ObjectAllocator;
40
44
  import org.jruby.runtime.ThreadContext;
41
45
  import org.jruby.runtime.builtin.IRubyObject;
46
+ import org.jruby.util.ByteList;
42
47
 
43
48
  /**
44
49
  *
45
50
  * @author nicksieger
46
51
  */
47
52
  public class MSSQLRubyJdbcConnection extends RubyJdbcConnection {
48
-
49
- private RubyString _row_num;
50
-
53
+
51
54
  protected MSSQLRubyJdbcConnection(Ruby runtime, RubyClass metaClass) {
52
55
  super(runtime, metaClass);
53
- _row_num = runtime.newString("_row_num");
54
56
  }
55
57
 
56
58
  public static RubyClass createMSSQLJdbcConnectionClass(Ruby runtime, RubyClass jdbcConnection) {
@@ -66,29 +68,47 @@ public class MSSQLRubyJdbcConnection extends RubyJdbcConnection {
66
68
  return new MSSQLRubyJdbcConnection(runtime, klass);
67
69
  }
68
70
  };
69
-
70
- protected static IRubyObject booleanToRuby(Ruby runtime, ResultSet resultSet, boolean booleanValue)
71
- throws SQLException {
72
- if (booleanValue == false && resultSet.wasNull()) return runtime.getNil();
73
- return runtime.newBoolean(booleanValue);
71
+
72
+ private static final byte[] EXEC = new byte[] { 'e', 'x', 'e', 'c' };
73
+
74
+ @JRubyMethod(name = "exec?", required = 1, meta = true, frame = false)
75
+ public static IRubyObject exec_p(ThreadContext context, IRubyObject self, IRubyObject sql) {
76
+ final ByteList sqlBytes = sql.convertToString().getByteList();
77
+ return context.getRuntime().newBoolean( startsWithIgnoreCase(sqlBytes, EXEC) );
74
78
  }
75
-
76
- /**
77
- * Treat LONGVARCHAR as CLOB on Mssql for purposes of converting a JDBC value to Ruby.
78
- * Treat BOOLEAN/BIT as Boolean, rather than the default behaviour of conversion to string
79
- */
79
+
80
80
  @Override
81
- protected IRubyObject jdbcToRuby(Ruby runtime, int column, int type, ResultSet resultSet)
82
- throws SQLException {
83
- if ( Types.BOOLEAN == type || Types.BIT == type ) {
84
- return booleanToRuby(runtime, resultSet, resultSet.getBoolean(column));
85
- }
86
- if (type == Types.LONGVARCHAR) {
87
- type = Types.CLOB;
81
+ protected RubyArray mapTables(final Ruby runtime, final DatabaseMetaData metaData,
82
+ final String catalog, final String schemaPattern, final String tablePattern,
83
+ final ResultSet tablesSet) throws SQLException, IllegalStateException {
84
+
85
+ final RubyArray tables = runtime.newArray();
86
+
87
+ while ( tablesSet.next() ) {
88
+ String schema = tablesSet.getString(TABLES_TABLE_SCHEM);
89
+ if ( schema != null ) schema = schema.toLowerCase();
90
+ // Under MS-SQL, don't return system tables/views unless explicitly asked for :
91
+ if ( schemaPattern == null &&
92
+ ( "sys".equals(schema) || "information_schema".equals(schema) ) ) {
93
+ continue;
94
+ }
95
+ String name = tablesSet.getString(TABLES_TABLE_NAME);
96
+ if ( name == null ) {
97
+ // NOTE: seems there's a jTDS but when doing getColumns while
98
+ // EXPLAIN is on (e.g. `SET SHOWPLAN_TEXT ON`) not returning
99
+ // correct result set with table info (null NAME, invalid CAT)
100
+ throw new IllegalStateException("got null name while matching table(s): [" +
101
+ catalog + "." + schemaPattern + "." + tablePattern + "] check " +
102
+ "if this happened during EXPLAIN (SET SHOWPLAN_TEXT ON) if so please try " +
103
+ "turning it off using the system property 'arjdbc.mssql.explain_support.disabled=true' " +
104
+ "or programatically by changing: `ArJdbc::MSSQL::ExplainSupport::DISABLED`");
105
+ }
106
+ name = caseConvertIdentifierForRails(metaData, name);
107
+ tables.add(RubyString.newUnicodeString(runtime, name));
88
108
  }
89
- return super.jdbcToRuby(runtime, column, type, resultSet);
109
+ return tables;
90
110
  }
91
-
111
+
92
112
  /**
93
113
  * Microsoft SQL 2000+ support schemas
94
114
  */
@@ -96,32 +116,49 @@ public class MSSQLRubyJdbcConnection extends RubyJdbcConnection {
96
116
  protected boolean databaseSupportsSchemas() {
97
117
  return true;
98
118
  }
99
-
119
+
120
+ /**
121
+ * Treat LONGVARCHAR as CLOB on MSSQL for purposes of converting a JDBC value to Ruby.
122
+ */
100
123
  @Override
101
- protected void populateFromResultSet(ThreadContext context, Ruby runtime, List results,
102
- ResultSet resultSet, ColumnData[] columns) throws SQLException {
103
- super.populateFromResultSet(context, runtime, results, resultSet, filterRowNumFromColumns(columns));
124
+ protected IRubyObject jdbcToRuby(Ruby runtime, int column, int type, ResultSet resultSet)
125
+ throws SQLException {
126
+ if ( type == Types.LONGVARCHAR || type == Types.LONGNVARCHAR ) type = Types.CLOB;
127
+ return super.jdbcToRuby(runtime, column, type, resultSet);
104
128
  }
105
129
 
130
+ @Override
131
+ protected ColumnData[] extractColumns(final Ruby runtime,
132
+ final DatabaseMetaData metaData, final ResultSet resultSet,
133
+ final boolean downCase) throws SQLException {
134
+ return filterRowNumFromColumns( super.extractColumns(runtime, metaData, resultSet, downCase) );
135
+ }
136
+
137
+ private static final ByteList _row_num; // "_row_num"
138
+ static {
139
+ _row_num = new ByteList(new byte[] { '_','r','o','w','_','n','u','m' }, false);
140
+ _row_num.setEncoding(UTF8Encoding.INSTANCE);
141
+ }
142
+
106
143
  /**
107
144
  * Filter out the <tt>_row_num</tt> column from results.
108
145
  */
109
- private ColumnData[] filterRowNumFromColumns(ColumnData[] columns) {
110
- for (int i = 0; i < columns.length; i++) {
111
- if (columns[i].name.equals(_row_num)) {
112
- ColumnData[] filtered = new ColumnData[columns.length - 1];
113
- if (i > 0) {
146
+ private static ColumnData[] filterRowNumFromColumns(final ColumnData[] columns) {
147
+ for ( int i = 0; i < columns.length; i++ ) {
148
+ if ( _row_num.equal( columns[i].name.getByteList() ) ) {
149
+ final ColumnData[] filtered = new ColumnData[columns.length - 1];
150
+
151
+ if ( i > 0 ) {
114
152
  System.arraycopy(columns, 0, filtered, 0, i);
115
153
  }
116
154
 
117
- if (i + 1 < columns.length) {
155
+ if ( i + 1 < columns.length ) {
118
156
  System.arraycopy(columns, i + 1, filtered, i, columns.length - (i + 1));
119
157
  }
120
158
 
121
159
  return filtered;
122
160
  }
123
161
  }
124
-
125
162
  return columns;
126
163
  }
127
164
 
@@ -24,6 +24,7 @@
24
24
 
25
25
  package arjdbc.mysql;
26
26
 
27
+ import static arjdbc.jdbc.RubyJdbcConnection.debugStackTrace;
27
28
  import static arjdbc.util.QuotingUtils.BYTES_0;
28
29
  import static arjdbc.util.QuotingUtils.BYTES_1;
29
30
 
@@ -61,9 +62,9 @@ public class MySQLModule {
61
62
  final IRubyObject recv, final IRubyObject string) {
62
63
 
63
64
  final ByteList stringBytes = ((RubyString) string).getByteList();
64
- final byte[] bytes = stringBytes.bytes; // unsafeBytes();
65
- final int begin = stringBytes.begin; // getBegin();
66
- final int realSize = stringBytes.realSize; // getRealSize();
65
+ final byte[] bytes = stringBytes.unsafeBytes();
66
+ final int begin = stringBytes.getBegin();
67
+ final int realSize = stringBytes.getRealSize();
67
68
 
68
69
  ByteList quotedBytes = null; int appendFrom = begin;
69
70
  for ( int i = begin; i < begin + realSize; i++ ) {
@@ -82,10 +83,10 @@ public class MySQLModule {
82
83
  if ( quotedBytes == null ) {
83
84
  quotedBytes = new ByteList(
84
85
  new byte[realSize + STRING_QUOTES_OPTIMISTIC_QUESS],
85
- stringBytes.encoding // getEncoding()
86
+ stringBytes.getEncoding()
86
87
  );
87
- quotedBytes.begin = 0; // setBegin(0);
88
- quotedBytes.realSize = 0; // setRealSize(0);
88
+ quotedBytes.setBegin(0);
89
+ quotedBytes.setRealSize(0);
89
90
  } // copy string on-first quote we "optimize" for non-quoted
90
91
  quotedBytes.append(bytes, appendFrom, i - appendFrom);
91
92
  quotedBytes.append('\\').append(byte2);
@@ -126,18 +127,18 @@ public class MySQLModule {
126
127
  */
127
128
  @JRubyMethod(module = true, frame = false)
128
129
  public static IRubyObject kill_cancel_timer(final ThreadContext context,
129
- final IRubyObject recv, final IRubyObject raw_connection) {
130
+ final IRubyObject self, final IRubyObject raw_connection) {
130
131
 
131
132
  final Connection conn = (Connection) raw_connection.dataGetStruct();
132
- if (conn != null && conn.getClass().getClassLoader() == recv.getRuntime().getJRubyClassLoader()) {
133
+ if (conn != null && conn.getClass().getClassLoader() == self.getRuntime().getJRubyClassLoader()) {
133
134
  try {
134
135
  java.lang.reflect.Field f = conn.getClass().getDeclaredField("cancelTimer");
135
136
  f.setAccessible(true);
136
137
  java.util.Timer timer = (java.util.Timer) f.get(null);
137
138
  timer.cancel();
138
139
  }
139
- catch (Exception e) { /* ignored */ }
140
+ catch (Exception e) { debugStackTrace(context, e); }
140
141
  }
141
- return recv.getRuntime().getNil();
142
+ return self.getRuntime().getNil();
142
143
  }
143
144
  }
@@ -25,6 +25,9 @@
25
25
  ***** END LICENSE BLOCK *****/
26
26
  package arjdbc.mysql;
27
27
 
28
+ import arjdbc.jdbc.RubyJdbcConnection;
29
+ import arjdbc.jdbc.Callable;
30
+
28
31
  import java.sql.Connection;
29
32
  import java.sql.DatabaseMetaData;
30
33
  import java.sql.PreparedStatement;
@@ -35,46 +38,44 @@ import java.sql.Types;
35
38
  import java.util.ArrayList;
36
39
  import java.util.List;
37
40
 
38
- import arjdbc.jdbc.SQLBlock;
39
41
  import org.jruby.Ruby;
40
42
  import org.jruby.RubyClass;
41
43
  import org.jruby.RubyModule;
42
- import org.jruby.RubyNil;
43
44
  import org.jruby.RubyString;
44
45
  import org.jruby.runtime.ObjectAllocator;
45
46
  import org.jruby.runtime.ThreadContext;
46
47
  import org.jruby.runtime.builtin.IRubyObject;
47
48
 
48
- import arjdbc.jdbc.RubyJdbcConnection;
49
-
50
49
  /**
51
50
  *
52
51
  * @author nicksieger
53
52
  */
54
53
  public class MySQLRubyJdbcConnection extends RubyJdbcConnection {
54
+
55
55
  protected MySQLRubyJdbcConnection(Ruby runtime, RubyClass metaClass) {
56
56
  super(runtime, metaClass);
57
57
  }
58
58
 
59
59
  @Override
60
- protected boolean genericExecute(Statement stmt, String query) throws SQLException {
61
- return stmt.execute(query, Statement.RETURN_GENERATED_KEYS);
60
+ protected boolean doExecute(final Statement statement,
61
+ final String query) throws SQLException {
62
+ return statement.execute(query, Statement.RETURN_GENERATED_KEYS);
62
63
  }
63
64
 
64
65
  @Override
65
- protected IRubyObject unmarshalKeysOrUpdateCount(ThreadContext context, Connection c, Statement stmt) throws SQLException {
66
- IRubyObject key = unmarshal_id_result(context.getRuntime(), stmt.getGeneratedKeys());
67
- if (key.isNil()) {
68
- return context.getRuntime().newFixnum(stmt.getUpdateCount());
69
- }
70
- return key;
66
+ protected IRubyObject unmarshalKeysOrUpdateCount(final ThreadContext context,
67
+ final Connection connection, final Statement statement) throws SQLException {
68
+ final Ruby runtime = context.getRuntime();
69
+ final IRubyObject key = unmarshalIdResult(runtime, statement);
70
+ return key.isNil() ? runtime.newFixnum(statement.getUpdateCount()) : key;
71
71
  }
72
72
 
73
73
  @Override
74
74
  protected IRubyObject jdbcToRuby(Ruby runtime, int column, int type, ResultSet resultSet)
75
- throws SQLException {
76
- if (Types.BOOLEAN == type || Types.BIT == type) {
77
- return integerToRuby(runtime, resultSet, resultSet.getBoolean(column) ? 1 : 0);
75
+ throws SQLException {
76
+ if ( Types.BOOLEAN == type || Types.BIT == type ) {
77
+ final boolean value = resultSet.getBoolean(column);
78
+ return resultSet.wasNull() ? runtime.getNil() : runtime.newFixnum(value ? 1 : 0);
78
79
  }
79
80
  return super.jdbcToRuby(runtime, column, type, resultSet);
80
81
  }
@@ -86,76 +87,81 @@ public class MySQLRubyJdbcConnection extends RubyJdbcConnection {
86
87
 
87
88
  return clazz;
88
89
  }
89
-
90
90
  private static ObjectAllocator MYSQL_JDBCCONNECTION_ALLOCATOR = new ObjectAllocator() {
91
91
  public IRubyObject allocate(Ruby runtime, RubyClass klass) {
92
92
  return new MySQLRubyJdbcConnection(runtime, klass);
93
93
  }
94
94
  };
95
95
 
96
- @Override
97
- protected IRubyObject indexes(final ThreadContext context, final String tableNameArg, String name, final String schemaNameArg) {
98
- return (IRubyObject) withConnectionAndRetry(context, new SQLBlock() {
99
- @Override
100
- public Object call(Connection connection) throws SQLException {
101
- Ruby runtime = context.getRuntime();
102
- DatabaseMetaData metadata = connection.getMetaData();
103
- String jdbcTableName = caseConvertIdentifierForJdbc(metadata, tableNameArg);
104
- String jdbcSchemaName = caseConvertIdentifierForJdbc(metadata, schemaNameArg);
105
-
106
- StringBuilder buffer = new StringBuilder("SHOW KEYS FROM ");
107
- if (jdbcSchemaName != null) buffer.append(jdbcSchemaName).append(".");
108
- buffer.append(jdbcTableName);
109
- buffer.append(" WHERE key_name != 'PRIMARY'");
110
- String query = buffer.toString();
111
-
112
- List<IRubyObject> indexes = new ArrayList<IRubyObject>();
113
- PreparedStatement stmt = null;
114
- ResultSet rs = null;
115
-
116
- try {
117
- stmt = connection.prepareStatement(query);
118
- rs = stmt.executeQuery();
119
-
120
- IRubyObject rubyTableName = RubyString.newUnicodeString(runtime, caseConvertIdentifierForJdbc(metadata, tableNameArg));
121
- RubyModule indexDefinitionClass = getConnectionAdapters(runtime).getClass("IndexDefinition");
122
- String currentKeyName = null;
123
-
124
- while (rs.next()) {
125
- String keyName = caseConvertIdentifierForRails(metadata, rs.getString("key_name"));
126
-
127
- if (!keyName.equals(currentKeyName)) {
128
- currentKeyName = keyName;
129
-
130
- boolean nonUnique = rs.getBoolean("non_unique");
131
- IRubyObject indexDefinition = indexDefinitionClass.callMethod(context, "new", new IRubyObject[]{
132
- rubyTableName,
133
- RubyString.newUnicodeString(runtime, keyName),
134
- runtime.newBoolean(!nonUnique),
135
- runtime.newArray(),
136
- runtime.newArray()
137
- });
138
-
139
- indexes.add(indexDefinition);
140
- }
141
-
142
- IRubyObject lastIndex = indexes.get(indexes.size() - 1);
143
- if (lastIndex != null) {
144
- String columnName = caseConvertIdentifierForRails(metadata, rs.getString("column_name"));
145
- int length = rs.getInt("sub_part");
146
- boolean lengthIsNull = rs.wasNull();
147
-
148
- lastIndex.callMethod(context, "columns").callMethod(context, "<<", RubyString.newUnicodeString(runtime, columnName));
149
- lastIndex.callMethod(context, "lengths").callMethod(context, "<<", lengthIsNull ? runtime.getNil() : runtime.newFixnum(length));
96
+ @Override
97
+ protected IRubyObject indexes(final ThreadContext context, final String tableName, final String name, final String schemaName) {
98
+ return withConnection(context, new Callable<IRubyObject>() {
99
+ public IRubyObject call(final Connection connection) throws SQLException {
100
+ final Ruby runtime = context.getRuntime();
101
+ final RubyModule indexDefinition = getIndexDefinition(runtime);
102
+ final DatabaseMetaData metaData = connection.getMetaData();
103
+ final String jdbcTableName = caseConvertIdentifierForJdbc(metaData, tableName);
104
+ final String jdbcSchemaName = caseConvertIdentifierForJdbc(metaData, schemaName);
105
+ final IRubyObject rubyTableName = RubyString.newUnicodeString(
106
+ runtime, caseConvertIdentifierForJdbc(metaData, tableName)
107
+ );
108
+
109
+ StringBuilder query = new StringBuilder("SHOW KEYS FROM ");
110
+ if (jdbcSchemaName != null) {
111
+ query.append(jdbcSchemaName).append(".");
112
+ }
113
+ query.append(jdbcTableName);
114
+ query.append(" WHERE key_name != 'PRIMARY'");
115
+
116
+ final List<IRubyObject> indexes = new ArrayList<IRubyObject>();
117
+ PreparedStatement statement = null;
118
+ ResultSet keySet = null;
119
+
120
+ try {
121
+ statement = connection.prepareStatement(query.toString());
122
+ keySet = statement.executeQuery();
123
+
124
+ String currentKeyName = null;
125
+
126
+ while ( keySet.next() ) {
127
+ final String keyName = caseConvertIdentifierForRails(metaData, keySet.getString("key_name"));
128
+
129
+ if ( ! keyName.equals(currentKeyName) ) {
130
+ currentKeyName = keyName;
131
+
132
+ final boolean nonUnique = keySet.getBoolean("non_unique");
133
+
134
+ IRubyObject[] args = new IRubyObject[] {
135
+ rubyTableName, // table_name
136
+ RubyString.newUnicodeString(runtime, keyName), // index_name
137
+ runtime.newBoolean( ! nonUnique ), // unique
138
+ runtime.newArray(), // [] for column names, we'll add to that in just a bit
139
+ runtime.newArray() // lengths
140
+ };
141
+
142
+ indexes.add( indexDefinition.callMethod(context, "new", args) ); // IndexDefinition.new
143
+ }
144
+
145
+ IRubyObject lastIndexDef = indexes.isEmpty() ? null : indexes.get(indexes.size() - 1);
146
+ if (lastIndexDef != null) {
147
+ final String columnName = caseConvertIdentifierForRails(metaData, keySet.getString("column_name"));
148
+ final int length = keySet.getInt("sub_part");
149
+ final boolean nullLength = keySet.wasNull();
150
+
151
+ lastIndexDef.callMethod(context, "columns").callMethod(context,
152
+ "<<", RubyString.newUnicodeString(runtime, columnName));
153
+ lastIndexDef.callMethod(context, "lengths").callMethod(context,
154
+ "<<", nullLength ? runtime.getNil() : runtime.newFixnum(length));
155
+ }
156
+ }
157
+
158
+ return runtime.newArray(indexes);
159
+ }
160
+ finally {
161
+ close(keySet);
162
+ close(statement);
163
+ }
150
164
  }
151
- }
152
-
153
- return runtime.newArray(indexes);
154
- } finally {
155
- close(rs);
156
- close(stmt);
157
- }
158
- }
159
- });
160
- }
165
+ });
166
+ }
161
167
  }