activerecord-jdbc-adapter 1.0.0.beta1-java → 1.0.0.beta2-java
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.
- 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
|
}
|