activerecord-jdbc-adapter 1.0.0.beta1-java → 1.0.0.beta2-java
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +37 -0
- data/Manifest.txt +8 -0
- data/README.txt +41 -88
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +1 -0
- data/lib/arel/engines/sql/compilers/hsqldb_compiler.rb +9 -0
- data/lib/arel/engines/sql/compilers/mssql_compiler.rb +34 -0
- data/lib/arjdbc/db2/adapter.rb +232 -52
- data/lib/arjdbc/derby/adapter.rb +28 -1
- data/lib/arjdbc/derby/connection_methods.rb +1 -1
- data/lib/arjdbc/discover.rb +1 -1
- data/lib/arjdbc/firebird/adapter.rb +26 -0
- data/lib/arjdbc/h2/adapter.rb +13 -0
- data/lib/arjdbc/hsqldb/adapter.rb +8 -6
- data/lib/arjdbc/informix/adapter.rb +4 -0
- data/lib/arjdbc/jdbc/adapter.rb +27 -5
- data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
- data/lib/arjdbc/jdbc/connection.rb +76 -45
- data/lib/arjdbc/jdbc/jdbc.rake +22 -20
- data/lib/arjdbc/jdbc/type_converter.rb +9 -2
- data/lib/arjdbc/mssql/adapter.rb +102 -24
- data/lib/arjdbc/mssql/connection_methods.rb +19 -2
- data/lib/arjdbc/mssql/tsql_helper.rb +1 -0
- data/lib/arjdbc/mysql/adapter.rb +6 -0
- data/lib/arjdbc/mysql/connection_methods.rb +8 -7
- data/lib/arjdbc/oracle/adapter.rb +8 -6
- data/lib/arjdbc/postgresql/adapter.rb +51 -19
- data/lib/arjdbc/version.rb +1 -1
- data/lib/jdbc_adapter/rake_tasks.rb +3 -0
- data/rails_generators/templates/lib/tasks/jdbc.rake +2 -2
- data/rakelib/package.rake +2 -0
- data/rakelib/test.rake +6 -3
- data/src/java/arjdbc/derby/DerbyModule.java +30 -1
- data/src/java/arjdbc/informix/InformixRubyJdbcConnection.java +74 -0
- data/src/java/arjdbc/jdbc/AdapterJavaService.java +7 -3
- data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +45 -30
- data/src/java/arjdbc/mssql/MssqlRubyJdbcConnection.java +54 -1
- data/src/java/arjdbc/oracle/OracleRubyJdbcConnection.java +85 -0
- data/test/abstract_db_create.rb +6 -1
- data/test/db/jndi_config.rb +20 -10
- data/test/db2_simple_test.rb +34 -1
- data/test/derby_simple_test.rb +78 -0
- data/test/generic_jdbc_connection_test.rb +21 -1
- data/test/jndi_callbacks_test.rb +2 -1
- data/test/jndi_test.rb +1 -11
- data/test/models/entry.rb +20 -0
- data/test/mssql_limit_offset_test.rb +28 -0
- data/test/mssql_simple_test.rb +7 -1
- data/test/mysql_info_test.rb +49 -6
- data/test/mysql_simple_test.rb +4 -0
- data/test/oracle_simple_test.rb +3 -47
- data/test/oracle_specific_test.rb +83 -0
- data/test/postgres_db_create_test.rb +6 -0
- data/test/postgres_drop_db_test.rb +16 -0
- data/test/postgres_simple_test.rb +17 -0
- data/test/postgres_table_alias_length_test.rb +15 -0
- data/test/simple.rb +17 -4
- metadata +33 -7
data/lib/arjdbc/version.rb
CHANGED
data/rakelib/package.rake
CHANGED
@@ -24,6 +24,8 @@ begin
|
|
24
24
|
p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
|
25
25
|
p.description = p.paragraphs_of('README.txt', 0...1).join("\n\n")
|
26
26
|
end
|
27
|
+
hoe.spec.rdoc_options += ["-SHN", "-f", "darkfish"]
|
28
|
+
|
27
29
|
task :gemspec do
|
28
30
|
File.open("#{hoe.name}.gemspec", "w") {|f| f << hoe.spec.to_ruby }
|
29
31
|
end
|
data/rakelib/test.rake
CHANGED
@@ -4,6 +4,9 @@ if defined?(JRUBY_VERSION)
|
|
4
4
|
if find_executable?("psql") && `psql -c '\\l'` && $?.exitstatus == 0
|
5
5
|
databases << :test_postgres
|
6
6
|
end
|
7
|
+
if File.exist?('test/fscontext.jar')
|
8
|
+
databases << :test_jndi
|
9
|
+
end
|
7
10
|
task :test => databases
|
8
11
|
else
|
9
12
|
task :test => [:test_mysql]
|
@@ -37,12 +40,12 @@ declare_test_task_for :postgres
|
|
37
40
|
declare_test_task_for :sqlite3
|
38
41
|
|
39
42
|
Rake::TestTask.new(:test_jdbc) do |t|
|
40
|
-
t.test_files = FileList['test/generic_jdbc_connection_test.rb'
|
43
|
+
t.test_files = FileList['test/generic_jdbc_connection_test.rb']
|
41
44
|
t.libs << 'test' << 'drivers/mysql/lib'
|
42
45
|
end
|
43
46
|
|
44
47
|
Rake::TestTask.new(:test_jndi) do |t|
|
45
|
-
t.test_files = FileList['test/
|
48
|
+
t.test_files = FileList['test/jndi*_test.rb']
|
46
49
|
t.libs << 'test' << 'drivers/derby/lib'
|
47
50
|
end
|
48
51
|
|
@@ -52,7 +55,7 @@ task :test_pgsql => [:test_postgres]
|
|
52
55
|
# Ensure driver for these DBs is on your classpath
|
53
56
|
%w(oracle db2 cachedb informix).each do |d|
|
54
57
|
Rake::TestTask.new("test_#{d}") do |t|
|
55
|
-
t.test_files = FileList["test/#{d}
|
58
|
+
t.test_files = FileList["test/#{d}*_test.rb"]
|
56
59
|
t.libs = []
|
57
60
|
t.libs << 'lib' if defined?(JRUBY_VERSION)
|
58
61
|
t.libs << 'test'
|
@@ -111,6 +111,10 @@ public class DerbyModule {
|
|
111
111
|
if (args.length > 1) {
|
112
112
|
IRubyObject col = args[1];
|
113
113
|
String type = rubyApi.callMethod(col, "type").toString();
|
114
|
+
// intercept and change value, maybe, if the column type is :text or :string
|
115
|
+
if (type.equals("text") || type.equals("string")) {
|
116
|
+
value = make_ruby_string_for_text_column(context, recv, runtime, value);
|
117
|
+
}
|
114
118
|
if (value instanceof RubyString) {
|
115
119
|
if (type.equals("string")) {
|
116
120
|
return quote_string_with_surround(runtime, "'", (RubyString)value, "'");
|
@@ -135,7 +139,32 @@ public class DerbyModule {
|
|
135
139
|
return super_quote(context, recv, runtime, value, runtime.getNil());
|
136
140
|
}
|
137
141
|
|
138
|
-
|
142
|
+
/*
|
143
|
+
* Derby is not permissive like MySql. Try and send an Integer to a CLOB or VARCHAR column and Derby will vomit.
|
144
|
+
* This method turns non stringy things into strings.
|
145
|
+
*/
|
146
|
+
private static IRubyObject make_ruby_string_for_text_column(ThreadContext context, IRubyObject recv, Ruby runtime, IRubyObject value) {
|
147
|
+
RubyModule multibyteChars = (RubyModule)
|
148
|
+
((RubyModule) ((RubyModule) runtime.getModule("ActiveSupport")).getConstant("Multibyte")).getConstantAt("Chars");
|
149
|
+
if (value instanceof RubyString || rubyApi.isKindOf(value, multibyteChars) || value.isNil()) {
|
150
|
+
return value;
|
151
|
+
}
|
152
|
+
if (value instanceof RubyBoolean) {
|
153
|
+
return value.isTrue() ? runtime.newString("1") : runtime.newString("0");
|
154
|
+
} else if (value instanceof RubyFloat || value instanceof RubyFixnum || value instanceof RubyBignum) {
|
155
|
+
return RubyString.objAsString(context, value);
|
156
|
+
} else if ( value instanceof RubyBigDecimal) {
|
157
|
+
return rubyApi.callMethod(value, "to_s", runtime.newString("F"));
|
158
|
+
} else {
|
159
|
+
if (rubyApi.callMethod(value, "acts_like?", runtime.newString("date")).isTrue() || rubyApi.callMethod(value, "acts_like?", runtime.newString("time")).isTrue()) {
|
160
|
+
return (RubyString)rubyApi.callMethod(recv, "quoted_date", value);
|
161
|
+
} else {
|
162
|
+
return (RubyString)rubyApi.callMethod(value, "to_yaml");
|
163
|
+
}
|
164
|
+
}
|
165
|
+
}
|
166
|
+
|
167
|
+
private final static ByteList NULL = new ByteList("NULL".getBytes());
|
139
168
|
|
140
169
|
private static IRubyObject super_quote(ThreadContext context, IRubyObject recv, Ruby runtime, IRubyObject value, IRubyObject col) {
|
141
170
|
if (value.respondsTo("quoted_id")) {
|
@@ -0,0 +1,74 @@
|
|
1
|
+
/*
|
2
|
+
**** BEGIN LICENSE BLOCK *****
|
3
|
+
* Copyright (c) 2006-2010 Nick Sieger <nick@nicksieger.com>
|
4
|
+
* Copyright (c) 2006-2007 Ola Bini <ola.bini@gmail.com>
|
5
|
+
* Copyright (c) 2008-2009 Thomas E Enebo <enebo@acm.org>
|
6
|
+
*
|
7
|
+
* Permission is hereby granted, free of charge, to any person obtaining
|
8
|
+
* a copy of this software and associated documentation files (the
|
9
|
+
* "Software"), to deal in the Software without restriction, including
|
10
|
+
* without limitation the rights to use, copy, modify, merge, publish,
|
11
|
+
* distribute, sublicense, and/or sell copies of the Software, and to
|
12
|
+
* permit persons to whom the Software is furnished to do so, subject to
|
13
|
+
* the following conditions:
|
14
|
+
*
|
15
|
+
* The above copyright notice and this permission notice shall be
|
16
|
+
* included in all copies or substantial portions of the Software.
|
17
|
+
*
|
18
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
19
|
+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
20
|
+
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
21
|
+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
22
|
+
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
23
|
+
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
24
|
+
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
25
|
+
***** END LICENSE BLOCK *****/
|
26
|
+
|
27
|
+
package arjdbc.informix;
|
28
|
+
|
29
|
+
import java.sql.ResultSet;
|
30
|
+
import java.sql.SQLException;
|
31
|
+
import java.sql.Types;
|
32
|
+
|
33
|
+
import arjdbc.jdbc.RubyJdbcConnection;
|
34
|
+
|
35
|
+
import org.jruby.Ruby;
|
36
|
+
import org.jruby.RubyClass;
|
37
|
+
import org.jruby.runtime.ObjectAllocator;
|
38
|
+
import org.jruby.runtime.builtin.IRubyObject;
|
39
|
+
|
40
|
+
/**
|
41
|
+
*
|
42
|
+
* @author nicksieger
|
43
|
+
*/
|
44
|
+
public class InformixRubyJdbcConnection extends RubyJdbcConnection {
|
45
|
+
protected InformixRubyJdbcConnection(Ruby runtime, RubyClass metaClass) {
|
46
|
+
super(runtime, metaClass);
|
47
|
+
}
|
48
|
+
|
49
|
+
public static RubyClass createInformixJdbcConnectionClass(Ruby runtime, RubyClass jdbcConnection) {
|
50
|
+
RubyClass clazz = RubyJdbcConnection.getConnectionAdapters(runtime).defineClassUnder("InformixJdbcConnection",
|
51
|
+
jdbcConnection, INFORMIX_JDBCCONNECTION_ALLOCATOR);
|
52
|
+
clazz.defineAnnotatedMethods(InformixRubyJdbcConnection.class);
|
53
|
+
|
54
|
+
return clazz;
|
55
|
+
}
|
56
|
+
|
57
|
+
private static ObjectAllocator INFORMIX_JDBCCONNECTION_ALLOCATOR = new ObjectAllocator() {
|
58
|
+
public IRubyObject allocate(Ruby runtime, RubyClass klass) {
|
59
|
+
return new InformixRubyJdbcConnection(runtime, klass);
|
60
|
+
}
|
61
|
+
};
|
62
|
+
|
63
|
+
/**
|
64
|
+
* Treat LONGVARCHAR as CLOB on Informix for purposes of converting a JDBC value to Ruby.
|
65
|
+
*/
|
66
|
+
@Override
|
67
|
+
protected IRubyObject jdbcToRuby(Ruby runtime, int column, int type, ResultSet resultSet)
|
68
|
+
throws SQLException {
|
69
|
+
if (type == Types.LONGVARCHAR) {
|
70
|
+
type = Types.CLOB;
|
71
|
+
}
|
72
|
+
return super.jdbcToRuby(runtime, column, type, resultSet);
|
73
|
+
}
|
74
|
+
}
|
@@ -28,11 +28,13 @@ package arjdbc.jdbc;
|
|
28
28
|
|
29
29
|
import java.io.IOException;
|
30
30
|
|
31
|
-
import arjdbc.
|
31
|
+
import arjdbc.derby.DerbyModule;
|
32
|
+
import arjdbc.informix.InformixRubyJdbcConnection;
|
32
33
|
import arjdbc.mssql.MssqlRubyJdbcConnection;
|
33
|
-
import arjdbc.sqlite3.Sqlite3RubyJdbcConnection;
|
34
34
|
import arjdbc.mysql.MySQLModule;
|
35
|
-
import arjdbc.
|
35
|
+
import arjdbc.oracle.OracleRubyJdbcConnection;
|
36
|
+
import arjdbc.postgresql.PostgresqlRubyJdbcConnection;
|
37
|
+
import arjdbc.sqlite3.Sqlite3RubyJdbcConnection;
|
36
38
|
|
37
39
|
import org.jruby.Ruby;
|
38
40
|
import org.jruby.RubyClass;
|
@@ -48,6 +50,8 @@ public class AdapterJavaService implements BasicLibraryService {
|
|
48
50
|
RubyClass jdbcConnection = RubyJdbcConnection.createJdbcConnectionClass(runtime);
|
49
51
|
PostgresqlRubyJdbcConnection.createPostgresqlJdbcConnectionClass(runtime, jdbcConnection);
|
50
52
|
MssqlRubyJdbcConnection.createMssqlJdbcConnectionClass(runtime, jdbcConnection);
|
53
|
+
InformixRubyJdbcConnection.createInformixJdbcConnectionClass(runtime, jdbcConnection);
|
54
|
+
OracleRubyJdbcConnection.createOracleJdbcConnectionClass(runtime, jdbcConnection);
|
51
55
|
Sqlite3RubyJdbcConnection.createSqlite3JdbcConnectionClass(runtime, jdbcConnection);
|
52
56
|
RubyModule arJdbc = runtime.getOrCreateModule("ArJdbc");
|
53
57
|
|
@@ -123,21 +123,32 @@ public class RubyJdbcConnection extends RubyObject {
|
|
123
123
|
String table_name = rubyApi.convertToRubyString(args[0]).getUnicodeValue();
|
124
124
|
String schemaName = null;
|
125
125
|
|
126
|
-
|
127
|
-
if(
|
128
|
-
|
129
|
-
table_name = table_name.substring(index + 1);
|
126
|
+
final String[] name_parts = table_name.split( "\\." );
|
127
|
+
if ( name_parts.length > 3 ) {
|
128
|
+
throw new SQLException("Table name '" + table_name + "' should not contain more than 2 '.'");
|
130
129
|
}
|
131
130
|
|
132
131
|
DatabaseMetaData metadata = c.getMetaData();
|
132
|
+
String clzName = metadata.getClass().getName().toLowerCase();
|
133
|
+
boolean isDB2 = clzName.indexOf("db2") != -1 || clzName.indexOf("as400") != -1;
|
134
|
+
|
135
|
+
String catalog = c.getCatalog();
|
136
|
+
if( name_parts.length == 2 ) {
|
137
|
+
schemaName = name_parts[0];
|
138
|
+
table_name = name_parts[1];
|
139
|
+
}
|
140
|
+
else if ( name_parts.length == 3 ) {
|
141
|
+
catalog = name_parts[0];
|
142
|
+
schemaName = name_parts[1];
|
143
|
+
table_name = name_parts[2];
|
144
|
+
}
|
133
145
|
|
134
146
|
if(args.length > 2 && schemaName == null) schemaName = toStringOrNull(args[2]);
|
135
147
|
|
136
148
|
if (schemaName != null) schemaName = caseConvertIdentifierForJdbc(metadata, schemaName);
|
137
149
|
table_name = caseConvertIdentifierForJdbc(metadata, table_name);
|
138
150
|
|
139
|
-
|
140
|
-
if (schemaName != null) { catalog = schemaName; }
|
151
|
+
if (schemaName != null && !isDB2 && !databaseSupportsSchemas()) { catalog = schemaName; }
|
141
152
|
|
142
153
|
String[] tableTypes = new String[]{"TABLE","VIEW","SYNONYM"};
|
143
154
|
RubyArray matchingTables = (RubyArray) tableLookupBlock(context.getRuntime(),
|
@@ -645,10 +656,11 @@ public class RubyJdbcConnection extends RubyObject {
|
|
645
656
|
public static String caseConvertIdentifierForJdbc(DatabaseMetaData metadata, String value)
|
646
657
|
throws SQLException {
|
647
658
|
if (value == null) return null;
|
659
|
+
boolean isPostgres = metadata.getDatabaseProductName().equals("PostgreSQL");
|
648
660
|
|
649
661
|
if (metadata.storesUpperCaseIdentifiers()) {
|
650
662
|
return value.toUpperCase();
|
651
|
-
} else if (metadata.storesLowerCaseIdentifiers()) {
|
663
|
+
} else if (metadata.storesLowerCaseIdentifiers() && ! isPostgres) {
|
652
664
|
return value.toLowerCase();
|
653
665
|
}
|
654
666
|
|
@@ -839,8 +851,9 @@ public class RubyJdbcConnection extends RubyObject {
|
|
839
851
|
RubyHash row = RubyHash.newHash(runtime);
|
840
852
|
|
841
853
|
for (int i = 0; i < columnCount; i++) {
|
842
|
-
row.op_aset(context, columns[i].name, jdbcToRuby(runtime, i
|
854
|
+
row.op_aset(context, columns[i].name, jdbcToRuby(runtime, columns[i].index, columns[i].type, resultSet));
|
843
855
|
}
|
856
|
+
|
844
857
|
results.add(row);
|
845
858
|
}
|
846
859
|
}
|
@@ -970,10 +983,12 @@ public class RubyJdbcConnection extends RubyObject {
|
|
970
983
|
DatabaseMetaData metadata = c.getMetaData();
|
971
984
|
String clzName = metadata.getClass().getName().toLowerCase();
|
972
985
|
boolean isOracle = clzName.indexOf("oracle") != -1 || clzName.indexOf("oci") != -1;
|
986
|
+
boolean isDerby = clzName.indexOf("derby") != 1;
|
973
987
|
|
974
988
|
String realschema = schemapat;
|
975
989
|
String realtablepat = tablepat;
|
976
990
|
|
991
|
+
if (isDerby && realschema != null && realschema.equals("")) realschema = null; // Derby doesn't like empty-string schema name
|
977
992
|
if (realtablepat != null) realtablepat = caseConvertIdentifierForJdbc(metadata, realtablepat);
|
978
993
|
if (realschema != null) realschema = caseConvertIdentifierForJdbc(metadata, realschema);
|
979
994
|
|
@@ -1015,15 +1030,15 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1015
1030
|
return RubyString.newUnicodeString(runtime, str);
|
1016
1031
|
}
|
1017
1032
|
|
1018
|
-
|
1019
|
-
|
1020
|
-
|
1021
|
-
|
1022
|
-
|
1023
|
-
|
1024
|
-
|
1033
|
+
protected static final int COLUMN_NAME = 4;
|
1034
|
+
protected static final int DATA_TYPE = 5;
|
1035
|
+
protected static final int TYPE_NAME = 6;
|
1036
|
+
protected static final int COLUMN_SIZE = 7;
|
1037
|
+
protected static final int DECIMAL_DIGITS = 9;
|
1038
|
+
protected static final int COLUMN_DEF = 13;
|
1039
|
+
protected static final int IS_NULLABLE = 18;
|
1025
1040
|
|
1026
|
-
|
1041
|
+
protected int intFromResultSet(ResultSet resultSet, int column) throws SQLException {
|
1027
1042
|
int precision = resultSet.getInt(column);
|
1028
1043
|
|
1029
1044
|
return precision == 0 && resultSet.wasNull() ? -1 : precision;
|
@@ -1032,20 +1047,11 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1032
1047
|
/**
|
1033
1048
|
* Create a string which represents a sql type usable by Rails from the resultSet column
|
1034
1049
|
* metadata object.
|
1035
|
-
*
|
1036
|
-
* @param numberAsBoolean the database uses decimal as a boolean data type
|
1037
|
-
* because it does not support optional SQL92 type or mandatory SQL99
|
1038
|
-
* booleans.
|
1039
1050
|
*/
|
1040
|
-
|
1051
|
+
protected String typeFromResultSet(ResultSet resultSet) throws SQLException {
|
1041
1052
|
int precision = intFromResultSet(resultSet, COLUMN_SIZE);
|
1042
1053
|
int scale = intFromResultSet(resultSet, DECIMAL_DIGITS);
|
1043
1054
|
|
1044
|
-
// Assume db's which use decimal for boolean will not also specify a
|
1045
|
-
// valid precision 1 decimal also. Seems sketchy to me...
|
1046
|
-
if (numberAsBoolean && precision != 1 &&
|
1047
|
-
resultSet.getInt(DATA_TYPE) == java.sql.Types.DECIMAL) precision = -1;
|
1048
|
-
|
1049
1055
|
String type = resultSet.getString(TYPE_NAME);
|
1050
1056
|
if (precision > 0) {
|
1051
1057
|
type += "(" + precision;
|
@@ -1070,7 +1076,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1070
1076
|
List columns = new ArrayList();
|
1071
1077
|
List pkeyNames = new ArrayList();
|
1072
1078
|
String clzName = metadata.getClass().getName().toLowerCase();
|
1073
|
-
boolean isOracle = clzName.indexOf("oracle") != -1 || clzName.indexOf("oci") != -1;
|
1074
1079
|
|
1075
1080
|
RubyHash types = (RubyHash) native_database_types();
|
1076
1081
|
IRubyObject jdbcCol = getJdbcColumnClass(context);
|
@@ -1087,7 +1092,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1087
1092
|
RubyString.newUnicodeString(runtime,
|
1088
1093
|
caseConvertIdentifierForRails(metadata, colName)),
|
1089
1094
|
defaultValueFromResultSet(runtime, rs),
|
1090
|
-
RubyString.newUnicodeString(runtime, typeFromResultSet(rs
|
1095
|
+
RubyString.newUnicodeString(runtime, typeFromResultSet(rs)),
|
1091
1096
|
runtime.newBoolean(!rs.getString(IS_NULLABLE).trim().equals("NO"))
|
1092
1097
|
});
|
1093
1098
|
columns.add(column);
|
@@ -1192,6 +1197,14 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1192
1197
|
return Java.java_to_ruby(this, JavaObject.wrap(getRuntime(), c), Block.NULL_BLOCK);
|
1193
1198
|
}
|
1194
1199
|
|
1200
|
+
/**
|
1201
|
+
* Some databases support schemas and others do not.
|
1202
|
+
* For ones which do this method should return true, aiding in decisions regarding schema vs database determination.
|
1203
|
+
*/
|
1204
|
+
protected boolean databaseSupportsSchemas() {
|
1205
|
+
return false;
|
1206
|
+
}
|
1207
|
+
|
1195
1208
|
private static int whitespace(int start, ByteList bl) {
|
1196
1209
|
int end = bl.begin + bl.realSize;
|
1197
1210
|
|
@@ -1222,11 +1235,13 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1222
1235
|
|
1223
1236
|
public static class ColumnData {
|
1224
1237
|
public IRubyObject name;
|
1238
|
+
public int index;
|
1225
1239
|
public int type;
|
1226
1240
|
|
1227
|
-
public ColumnData(IRubyObject name, int type) {
|
1241
|
+
public ColumnData(IRubyObject name, int type, int idx) {
|
1228
1242
|
this.name = name;
|
1229
1243
|
this.type = type;
|
1244
|
+
this.index = idx;
|
1230
1245
|
}
|
1231
1246
|
|
1232
1247
|
public static ColumnData[] setup(Ruby runtime, DatabaseMetaData databaseMetadata,
|
@@ -1242,7 +1257,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1242
1257
|
name = RubyJdbcConnection.caseConvertIdentifierForRails(databaseMetadata, metadata.getColumnLabel(i));
|
1243
1258
|
}
|
1244
1259
|
|
1245
|
-
columns[i - 1] = new ColumnData(RubyString.newUnicodeString(runtime, name), metadata.getColumnType(i));
|
1260
|
+
columns[i - 1] = new ColumnData(RubyString.newUnicodeString(runtime, name), metadata.getColumnType(i), i);
|
1246
1261
|
}
|
1247
1262
|
|
1248
1263
|
return columns;
|
@@ -28,12 +28,16 @@ package arjdbc.mssql;
|
|
28
28
|
import java.sql.ResultSet;
|
29
29
|
import java.sql.SQLException;
|
30
30
|
import java.sql.Types;
|
31
|
+
import java.util.List;
|
31
32
|
|
32
33
|
import arjdbc.jdbc.RubyJdbcConnection;
|
34
|
+
import static arjdbc.jdbc.RubyJdbcConnection.ColumnData;
|
33
35
|
|
34
36
|
import org.jruby.Ruby;
|
35
37
|
import org.jruby.RubyClass;
|
38
|
+
import org.jruby.RubyString;
|
36
39
|
import org.jruby.runtime.ObjectAllocator;
|
40
|
+
import org.jruby.runtime.ThreadContext;
|
37
41
|
import org.jruby.runtime.builtin.IRubyObject;
|
38
42
|
|
39
43
|
/**
|
@@ -42,8 +46,11 @@ import org.jruby.runtime.builtin.IRubyObject;
|
|
42
46
|
*/
|
43
47
|
public class MssqlRubyJdbcConnection extends RubyJdbcConnection {
|
44
48
|
|
49
|
+
private RubyString _row_num;
|
50
|
+
|
45
51
|
protected MssqlRubyJdbcConnection(Ruby runtime, RubyClass metaClass) {
|
46
52
|
super(runtime, metaClass);
|
53
|
+
_row_num = runtime.newString("_row_num");
|
47
54
|
}
|
48
55
|
|
49
56
|
public static RubyClass createMssqlJdbcConnectionClass(Ruby runtime, RubyClass jdbcConnection) {
|
@@ -53,22 +60,68 @@ public class MssqlRubyJdbcConnection extends RubyJdbcConnection {
|
|
53
60
|
|
54
61
|
return clazz;
|
55
62
|
}
|
56
|
-
private static ObjectAllocator MSSQL_JDBCCONNECTION_ALLOCATOR = new ObjectAllocator() {
|
57
63
|
|
64
|
+
private static ObjectAllocator MSSQL_JDBCCONNECTION_ALLOCATOR = new ObjectAllocator() {
|
58
65
|
public IRubyObject allocate(Ruby runtime, RubyClass klass) {
|
59
66
|
return new MssqlRubyJdbcConnection(runtime, klass);
|
60
67
|
}
|
61
68
|
};
|
62
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);
|
74
|
+
}
|
75
|
+
|
63
76
|
/**
|
64
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
|
65
79
|
*/
|
66
80
|
@Override
|
67
81
|
protected IRubyObject jdbcToRuby(Ruby runtime, int column, int type, ResultSet resultSet)
|
68
82
|
throws SQLException {
|
83
|
+
if ( Types.BOOLEAN == type || Types.BIT == type ) {
|
84
|
+
return booleanToRuby(runtime, resultSet, resultSet.getBoolean(column));
|
85
|
+
}
|
69
86
|
if (type == Types.LONGVARCHAR) {
|
70
87
|
type = Types.CLOB;
|
71
88
|
}
|
72
89
|
return super.jdbcToRuby(runtime, column, type, resultSet);
|
73
90
|
}
|
91
|
+
|
92
|
+
/**
|
93
|
+
* Microsoft SQL 2000+ support schemas
|
94
|
+
*/
|
95
|
+
@Override
|
96
|
+
protected boolean databaseSupportsSchemas() {
|
97
|
+
return true;
|
98
|
+
}
|
99
|
+
|
100
|
+
@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));
|
104
|
+
}
|
105
|
+
|
106
|
+
/**
|
107
|
+
* Filter out the <tt>_row_num</tt> column from results.
|
108
|
+
*/
|
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) {
|
114
|
+
System.arraycopy(columns, 0, filtered, 0, i);
|
115
|
+
}
|
116
|
+
|
117
|
+
if (i + 1 < columns.length) {
|
118
|
+
System.arraycopy(columns, i + 1, filtered, i, columns.length - (i + 1));
|
119
|
+
}
|
120
|
+
|
121
|
+
return filtered;
|
122
|
+
}
|
123
|
+
}
|
124
|
+
|
125
|
+
return columns;
|
126
|
+
}
|
74
127
|
}
|