activerecord-jdbc-adapter 1.3.17 → 1.3.18
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.
- checksums.yaml +4 -4
- data/.travis.yml +24 -5
- data/History.md +54 -0
- data/lib/arel/visitors/compat.rb +30 -2
- data/lib/arel/visitors/db2.rb +118 -29
- data/lib/arel/visitors/derby.rb +84 -29
- data/lib/arel/visitors/firebird.rb +66 -9
- data/lib/arel/visitors/h2.rb +16 -0
- data/lib/arel/visitors/hsqldb.rb +6 -3
- data/lib/arel/visitors/postgresql_jdbc.rb +6 -0
- data/lib/arel/visitors/sql_server.rb +121 -40
- data/lib/arel/visitors/sql_server/ng42.rb +293 -0
- data/lib/arjdbc.rb +1 -7
- data/lib/arjdbc/db2.rb +1 -0
- data/lib/arjdbc/db2/adapter.rb +118 -18
- data/lib/arjdbc/derby/adapter.rb +29 -8
- data/lib/arjdbc/firebird.rb +1 -0
- data/lib/arjdbc/firebird/adapter.rb +126 -11
- data/lib/arjdbc/hsqldb/adapter.rb +3 -0
- data/lib/arjdbc/informix.rb +1 -0
- data/lib/arjdbc/jdbc.rb +17 -0
- data/lib/arjdbc/jdbc/adapter.rb +28 -3
- data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
- data/lib/arjdbc/jdbc/column.rb +7 -3
- data/lib/arjdbc/jdbc/type_cast.rb +2 -0
- data/lib/arjdbc/jdbc/type_converter.rb +28 -15
- data/lib/arjdbc/mimer.rb +1 -0
- data/lib/arjdbc/mssql.rb +2 -1
- data/lib/arjdbc/mssql/adapter.rb +105 -30
- data/lib/arjdbc/mssql/column.rb +30 -7
- data/lib/arjdbc/mssql/limit_helpers.rb +22 -9
- data/lib/arjdbc/mssql/types.rb +343 -0
- data/lib/arjdbc/mssql/utils.rb +25 -2
- data/lib/arjdbc/mysql/adapter.rb +22 -21
- data/lib/arjdbc/oracle.rb +1 -0
- data/lib/arjdbc/oracle/adapter.rb +291 -19
- data/lib/arjdbc/oracle/column.rb +9 -5
- data/lib/arjdbc/oracle/connection_methods.rb +4 -1
- data/lib/arjdbc/postgresql/_bc_time_cast_patch.rb +21 -0
- data/lib/arjdbc/postgresql/adapter.rb +7 -1
- data/lib/arjdbc/postgresql/oid/bytea.rb +3 -0
- data/lib/arjdbc/postgresql/oid_types.rb +2 -1
- data/lib/arjdbc/tasks/database_tasks.rb +3 -0
- data/lib/arjdbc/util/quoted_cache.rb +2 -2
- data/lib/arjdbc/util/serialized_attributes.rb +11 -0
- data/lib/arjdbc/version.rb +1 -1
- data/rakelib/02-test.rake +1 -1
- data/rakelib/db.rake +3 -1
- data/src/java/arjdbc/firebird/FirebirdRubyJdbcConnection.java +190 -0
- data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +259 -61
- data/src/java/arjdbc/mssql/MSSQLRubyJdbcConnection.java +13 -2
- data/src/java/arjdbc/oracle/OracleRubyJdbcConnection.java +192 -15
- data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +10 -2
- metadata +9 -4
data/lib/arjdbc/oracle/column.rb
CHANGED
@@ -11,13 +11,13 @@ module ArJdbc
|
|
11
11
|
|
12
12
|
def self.included(base)
|
13
13
|
# NOTE: assumes a standalone OracleColumn class
|
14
|
-
class << base; include Cast; end
|
14
|
+
class << base; include Cast; end # unless AR42
|
15
15
|
end
|
16
16
|
|
17
17
|
def primary=(value)
|
18
18
|
super
|
19
19
|
@type = :integer if value && @sql_type =~ /^NUMBER$/i
|
20
|
-
end
|
20
|
+
end unless AR42
|
21
21
|
|
22
22
|
def type_cast(value)
|
23
23
|
return nil if value.nil?
|
@@ -40,15 +40,19 @@ module ArJdbc
|
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
|
+
def sql_type
|
44
|
+
(@sql_type || '').start_with?('XMLTYPE') ? 'XMLTYPE' : @sql_type
|
45
|
+
end
|
46
|
+
|
43
47
|
private
|
44
48
|
|
45
49
|
def extract_limit(sql_type)
|
46
50
|
case sql_type
|
47
51
|
when /^(clob|date)/i then nil
|
48
|
-
when /^xml/i then
|
52
|
+
when /^xml/i then nil
|
49
53
|
else super
|
50
54
|
end
|
51
|
-
end
|
55
|
+
end unless AR42
|
52
56
|
|
53
57
|
def simplified_type(field_type)
|
54
58
|
case field_type
|
@@ -67,7 +71,7 @@ module ArJdbc
|
|
67
71
|
else
|
68
72
|
super
|
69
73
|
end
|
70
|
-
end
|
74
|
+
end unless AR42
|
71
75
|
|
72
76
|
# Post process default value from JDBC into a Rails-friendly format (columns{-internal})
|
73
77
|
def default_value(value)
|
@@ -9,9 +9,12 @@ ArJdbc::ConnectionMethods.module_eval do
|
|
9
9
|
return jndi_connection(config) if jndi_config?(config)
|
10
10
|
|
11
11
|
config[:port] ||= 1521
|
12
|
-
config[:url] ||= "jdbc:oracle:thin:@#{config[:host]}:#{config[:port]}:#{config[:database]}"
|
12
|
+
config[:url] ||= "jdbc:oracle:thin:@#{config[:host]}:#{config[:port]}:#{config[:database] || 'XE'}"
|
13
13
|
config[:driver] ||= "oracle.jdbc.driver.OracleDriver"
|
14
14
|
config[:connection_alive_sql] ||= 'SELECT 1 FROM DUAL'
|
15
|
+
unless config.key?(:statement_escape_processing)
|
16
|
+
config[:statement_escape_processing] = true
|
17
|
+
end
|
15
18
|
jdbc_connection(config)
|
16
19
|
end
|
17
20
|
alias_method :jdbcoracle_connection, :oracle_connection
|
@@ -0,0 +1,21 @@
|
|
1
|
+
ActiveRecord::ConnectionAdapters::PostgreSQL::OID::DateTime.class_eval do
|
2
|
+
def cast_value(value)
|
3
|
+
if value.is_a?(::String)
|
4
|
+
case value
|
5
|
+
when 'infinity' then ::Float::INFINITY
|
6
|
+
when '-infinity' then -::Float::INFINITY
|
7
|
+
#when / BC$/
|
8
|
+
# astronomical_year = format("%04d", value[/^\d+/].to_i)
|
9
|
+
# super(value.sub(/ BC$/, "").sub(/^\d+/, astronomical_year))
|
10
|
+
else
|
11
|
+
if value.end_with?(' BC')
|
12
|
+
DateTime.parse("-#{value}"[0...-3])
|
13
|
+
else
|
14
|
+
super
|
15
|
+
end
|
16
|
+
end
|
17
|
+
else
|
18
|
+
value
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -44,7 +44,9 @@ module ArJdbc
|
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
|
+
# @see ActiveRecord::ConnectionAdapters::Jdbc::ArelSupport
|
47
48
|
def self.arel_visitor_type(config = nil)
|
49
|
+
require 'arel/visitors/postgresql_jdbc'
|
48
50
|
::Arel::Visitors::PostgreSQL
|
49
51
|
end
|
50
52
|
|
@@ -916,7 +918,7 @@ module ArJdbc
|
|
916
918
|
def _quote(value)
|
917
919
|
case value
|
918
920
|
when Type::Binary::Data
|
919
|
-
"'#{escape_bytea(value.to_s)}'"
|
921
|
+
"E'#{escape_bytea(value.to_s)}'"
|
920
922
|
when OID::Xml::Data
|
921
923
|
"xml '#{quote_string(value.to_s)}'"
|
922
924
|
when OID::Bit::Data
|
@@ -1182,6 +1184,7 @@ module ArJdbc
|
|
1182
1184
|
execute "ALTER INDEX #{quote_column_name(old_name)} RENAME TO #{quote_table_name(new_name)}"
|
1183
1185
|
end
|
1184
1186
|
|
1187
|
+
# @override
|
1185
1188
|
def supports_foreign_keys?; true end
|
1186
1189
|
|
1187
1190
|
def foreign_keys(table_name)
|
@@ -1477,6 +1480,9 @@ module ActiveRecord::ConnectionAdapters
|
|
1477
1480
|
|
1478
1481
|
require 'arjdbc/postgresql/oid_types' if ::ArJdbc::AR40
|
1479
1482
|
include ::ArJdbc::PostgreSQL::OIDTypes if ::ArJdbc::PostgreSQL.const_defined?(:OIDTypes)
|
1483
|
+
|
1484
|
+
load 'arjdbc/postgresql/_bc_time_cast_patch.rb' if ::ArJdbc::AR42
|
1485
|
+
|
1480
1486
|
include ::ArJdbc::PostgreSQL::ColumnHelpers if ::ArJdbc::AR42
|
1481
1487
|
|
1482
1488
|
include ::ArJdbc::Util::QuotedCache
|
@@ -5,6 +5,7 @@ module ArJdbc
|
|
5
5
|
|
6
6
|
if AR42
|
7
7
|
require 'active_record/connection_adapters/postgresql/oid'
|
8
|
+
require 'arjdbc/postgresql/oid/bytea.rb'
|
8
9
|
else
|
9
10
|
require 'arjdbc/postgresql/base/oid'
|
10
11
|
end
|
@@ -264,4 +265,4 @@ module ArJdbc
|
|
264
265
|
|
265
266
|
end
|
266
267
|
end
|
267
|
-
end
|
268
|
+
end
|
@@ -28,7 +28,7 @@ module ArJdbc
|
|
28
28
|
# Caches quoted table names, the cache is stored in the class'
|
29
29
|
# `QUOTED_TABLE_NAMES` constant.
|
30
30
|
# @return [String]
|
31
|
-
def quote_table_name(name)
|
31
|
+
def quote_table_name(name, *args)
|
32
32
|
if cache = self.class::QUOTED_TABLE_NAMES
|
33
33
|
unless quoted = cache[name]
|
34
34
|
quoted = super
|
@@ -43,7 +43,7 @@ module ArJdbc
|
|
43
43
|
# Caches quoted table names, the cache is stored in the class'
|
44
44
|
# `QUOTED_COLUMN_NAMES` constant.
|
45
45
|
# @return [String]
|
46
|
-
def quote_column_name(name)
|
46
|
+
def quote_column_name(name, *args)
|
47
47
|
if cache = self.class::QUOTED_COLUMN_NAMES
|
48
48
|
unless quoted = cache[name]
|
49
49
|
quoted = super
|
@@ -29,6 +29,15 @@ module ArJdbc
|
|
29
29
|
SerializedAttributes.dump_column_value(self, column)
|
30
30
|
end
|
31
31
|
|
32
|
+
if defined? ActiveRecord::Type::Serialized # ArJdbc::AR42
|
33
|
+
|
34
|
+
def self.dump_column_value(record, column)
|
35
|
+
value = record[ column.name.to_s ]
|
36
|
+
column.cast_type.type_cast_for_database(value)
|
37
|
+
end
|
38
|
+
|
39
|
+
else
|
40
|
+
|
32
41
|
def self.dump_column_value(record, column)
|
33
42
|
value = record[ name = column.name.to_s ]
|
34
43
|
if record.class.respond_to?(:serialized_attributes)
|
@@ -45,6 +54,8 @@ module ArJdbc
|
|
45
54
|
value
|
46
55
|
end
|
47
56
|
|
57
|
+
end
|
58
|
+
|
48
59
|
def self.setup(lob_type = nil, after_save_alias = nil)
|
49
60
|
ActiveRecord::Base.send :include, self # include SerializedAttributes
|
50
61
|
ActiveRecord::Base.lob_type = lob_type unless lob_type.nil?
|
data/lib/arjdbc/version.rb
CHANGED
data/rakelib/02-test.rake
CHANGED
@@ -94,7 +94,7 @@ test_task_for :AS400, :desc => "Run tests against AS400 (DB2) (ensure driver is
|
|
94
94
|
:files => FileList["test/db2*_test.rb"] + FileList["test/db/db2/*_test.rb"]
|
95
95
|
|
96
96
|
test_task_for 'JDBC', :desc => 'Run tests against plain JDBC adapter (uses MySQL and Derby)',
|
97
|
-
:files => FileList['test/*jdbc_*test.rb'] do |test_task|
|
97
|
+
:prereqs => 'db:mysql', :files => FileList['test/*jdbc_*test.rb'] do |test_task|
|
98
98
|
test_task.libs << 'jdbc-mysql/lib' << 'jdbc-derby/lib'
|
99
99
|
end
|
100
100
|
|
data/rakelib/db.rake
CHANGED
@@ -32,7 +32,9 @@ SQL
|
|
32
32
|
DROP DATABASE IF EXISTS #{POSTGRES_CONFIG[:database]};
|
33
33
|
DROP USER IF EXISTS #{POSTGRES_CONFIG[:username]};
|
34
34
|
CREATE USER #{POSTGRES_CONFIG[:username]} CREATEDB SUPERUSER LOGIN PASSWORD '#{POSTGRES_CONFIG[:password]}';
|
35
|
-
CREATE DATABASE #{POSTGRES_CONFIG[:database]} OWNER #{POSTGRES_CONFIG[:username]}
|
35
|
+
CREATE DATABASE #{POSTGRES_CONFIG[:database]} OWNER #{POSTGRES_CONFIG[:username]}
|
36
|
+
TEMPLATE template0
|
37
|
+
ENCODING '#{POSTGRES_CONFIG[:encoding]}' LC_COLLATE '#{POSTGRES_CONFIG[:collate]}' LC_CTYPE '#{POSTGRES_CONFIG[:collate]}';
|
36
38
|
SQL
|
37
39
|
params = { '-U' => ENV['PSQL_USER'] || 'postgres' }
|
38
40
|
params['-q'] = nil unless $VERBOSE
|
@@ -0,0 +1,190 @@
|
|
1
|
+
/*
|
2
|
+
* The MIT License
|
3
|
+
*
|
4
|
+
* Copyright 2015 Karol Bucek.
|
5
|
+
*
|
6
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
7
|
+
* of this software and associated documentation files (the "Software"), to deal
|
8
|
+
* in the Software without restriction, including without limitation the rights
|
9
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10
|
+
* copies of the Software, and to permit persons to whom the Software is
|
11
|
+
* furnished to do so, subject to the following conditions:
|
12
|
+
*
|
13
|
+
* The above copyright notice and this permission notice shall be included in
|
14
|
+
* all copies or substantial portions of the Software.
|
15
|
+
*
|
16
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
19
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
22
|
+
* THE SOFTWARE.
|
23
|
+
*/
|
24
|
+
package arjdbc.firebird;
|
25
|
+
|
26
|
+
import arjdbc.jdbc.RubyJdbcConnection;
|
27
|
+
|
28
|
+
import java.sql.Connection;
|
29
|
+
import java.sql.ResultSet;
|
30
|
+
import java.sql.SQLException;
|
31
|
+
import java.sql.PreparedStatement;
|
32
|
+
import java.sql.ResultSetMetaData;
|
33
|
+
import java.sql.Types;
|
34
|
+
|
35
|
+
import org.jruby.Ruby;
|
36
|
+
import org.jruby.RubyClass;
|
37
|
+
import org.jruby.RubyString;
|
38
|
+
import org.jruby.runtime.ObjectAllocator;
|
39
|
+
import org.jruby.runtime.ThreadContext;
|
40
|
+
import org.jruby.runtime.builtin.IRubyObject;
|
41
|
+
|
42
|
+
/**
|
43
|
+
* @author kares
|
44
|
+
*/
|
45
|
+
public class FirebirdRubyJdbcConnection extends RubyJdbcConnection {
|
46
|
+
|
47
|
+
protected FirebirdRubyJdbcConnection(Ruby runtime, RubyClass metaClass) {
|
48
|
+
super(runtime, metaClass);
|
49
|
+
}
|
50
|
+
|
51
|
+
public static RubyClass createFirebirdJdbcConnectionClass(Ruby runtime, RubyClass jdbcConnection) {
|
52
|
+
final RubyClass clazz = RubyJdbcConnection.getConnectionAdapters(runtime).
|
53
|
+
defineClassUnder("FirebirdJdbcConnection", jdbcConnection, ALLOCATOR);
|
54
|
+
clazz.defineAnnotatedMethods(FirebirdRubyJdbcConnection.class);
|
55
|
+
return clazz;
|
56
|
+
}
|
57
|
+
|
58
|
+
private static final ObjectAllocator ALLOCATOR = new ObjectAllocator() {
|
59
|
+
public IRubyObject allocate(Ruby runtime, RubyClass klass) {
|
60
|
+
return new FirebirdRubyJdbcConnection(runtime, klass);
|
61
|
+
}
|
62
|
+
};
|
63
|
+
|
64
|
+
@Override // resultSet.wasNull() might be falsy for '' treated as null
|
65
|
+
protected IRubyObject stringToRuby(final ThreadContext context,
|
66
|
+
final Ruby runtime, final ResultSet resultSet, final int column)
|
67
|
+
throws SQLException {
|
68
|
+
final String value = resultSet.getString(column);
|
69
|
+
if ( value == null ) return runtime.getNil();
|
70
|
+
return RubyString.newUnicodeString(runtime, value);
|
71
|
+
}
|
72
|
+
|
73
|
+
@Override // booleans are emulated can not setNull(index, Types.BOOLEAN)
|
74
|
+
protected void setBooleanParameter(final ThreadContext context,
|
75
|
+
final Connection connection, final PreparedStatement statement,
|
76
|
+
final int index, final Object value,
|
77
|
+
final IRubyObject column, final int type) throws SQLException {
|
78
|
+
if ( value instanceof IRubyObject ) {
|
79
|
+
setBooleanParameter(context, connection, statement, index, (IRubyObject) value, column, type);
|
80
|
+
}
|
81
|
+
else {
|
82
|
+
if ( value == null ) statement.setNull(index, Types.CHAR);
|
83
|
+
else {
|
84
|
+
statement.setBoolean(index, ((Boolean) value).booleanValue());
|
85
|
+
}
|
86
|
+
}
|
87
|
+
}
|
88
|
+
|
89
|
+
@Override // booleans are emulated can not setNull(index, Types.BOOLEAN)
|
90
|
+
protected void setBooleanParameter(final ThreadContext context,
|
91
|
+
final Connection connection, final PreparedStatement statement,
|
92
|
+
final int index, final IRubyObject value,
|
93
|
+
final IRubyObject column, final int type) throws SQLException {
|
94
|
+
if ( value.isNil() ) statement.setNull(index, Types.CHAR);
|
95
|
+
else {
|
96
|
+
statement.setBoolean(index, value.isTrue());
|
97
|
+
}
|
98
|
+
}
|
99
|
+
|
100
|
+
protected IRubyObject jdbcToRuby(
|
101
|
+
final ThreadContext context, final Ruby runtime,
|
102
|
+
final int column, final int type, final ResultSet resultSet)
|
103
|
+
throws SQLException {
|
104
|
+
|
105
|
+
switch (type) {
|
106
|
+
case SMALL_CHAR_1:
|
107
|
+
return smallChar1ToRuby(runtime, resultSet, column);
|
108
|
+
case SMALL_CHAR_2:
|
109
|
+
return smallChar2ToRuby(runtime, resultSet, column);
|
110
|
+
}
|
111
|
+
return super.jdbcToRuby(context, runtime, column, type, resultSet);
|
112
|
+
}
|
113
|
+
|
114
|
+
private static IRubyObject smallChar1ToRuby(
|
115
|
+
final Ruby runtime, final ResultSet resultSet, final int column)
|
116
|
+
throws SQLException {
|
117
|
+
String value = resultSet.getString(column);
|
118
|
+
if ( value == null ) return runtime.getNil();
|
119
|
+
if ( value.length() > 1 && value.charAt(1) == ' ' ) {
|
120
|
+
value = value.substring(0, 1);
|
121
|
+
}
|
122
|
+
return RubyString.newUnicodeString(runtime, value);
|
123
|
+
}
|
124
|
+
|
125
|
+
private static IRubyObject smallChar2ToRuby(
|
126
|
+
final Ruby runtime, final ResultSet resultSet, final int column)
|
127
|
+
throws SQLException {
|
128
|
+
String value = resultSet.getString(column);
|
129
|
+
if ( value == null ) return runtime.getNil();
|
130
|
+
if ( value.length() > 2 && value.charAt(2) == ' ' ) {
|
131
|
+
value = value.substring(0, 2);
|
132
|
+
}
|
133
|
+
return RubyString.newUnicodeString(runtime, value);
|
134
|
+
}
|
135
|
+
|
136
|
+
private final static int SMALL_CHAR_1 = 31431001;
|
137
|
+
private final static int SMALL_CHAR_2 = 31431002;
|
138
|
+
|
139
|
+
@Override
|
140
|
+
protected ColumnData[] extractColumns(final Ruby runtime,
|
141
|
+
final Connection connection, final ResultSet resultSet,
|
142
|
+
final boolean downCase) throws SQLException {
|
143
|
+
|
144
|
+
final ResultSetMetaData resultMetaData = resultSet.getMetaData();
|
145
|
+
|
146
|
+
final int columnCount = resultMetaData.getColumnCount();
|
147
|
+
final ColumnData[] columns = new ColumnData[columnCount];
|
148
|
+
|
149
|
+
for ( int i = 1; i <= columnCount; i++ ) { // metadata is one-based
|
150
|
+
String name = resultMetaData.getColumnLabel(i);
|
151
|
+
if ( downCase ) {
|
152
|
+
name = name.toLowerCase();
|
153
|
+
} else {
|
154
|
+
name = caseConvertIdentifierForRails(connection, name);
|
155
|
+
}
|
156
|
+
final RubyString columnName = RubyString.newUnicodeString(runtime, name);
|
157
|
+
|
158
|
+
int columnType = resultMetaData.getColumnType(i);
|
159
|
+
if (columnType == Types.CHAR) {
|
160
|
+
// CHAR(1) 'aligned' by JayBird to "1 "
|
161
|
+
final int prec = resultMetaData.getPrecision(i);
|
162
|
+
if ( prec == 1 ) {
|
163
|
+
columnType = SMALL_CHAR_1;
|
164
|
+
}
|
165
|
+
else if ( prec == 2 ) {
|
166
|
+
columnType = SMALL_CHAR_2;
|
167
|
+
}
|
168
|
+
}
|
169
|
+
|
170
|
+
columns[i - 1] = new ColumnData(columnName, columnType, i);
|
171
|
+
}
|
172
|
+
|
173
|
+
return columns;
|
174
|
+
}
|
175
|
+
|
176
|
+
// storesMixedCaseIdentifiers() return false;
|
177
|
+
// storesLowerCaseIdentifiers() return false;
|
178
|
+
// storesUpperCaseIdentifiers() return true;
|
179
|
+
|
180
|
+
@Override
|
181
|
+
protected String caseConvertIdentifierForRails(final Connection connection, final String value) {
|
182
|
+
return value == null ? null : value.toLowerCase();
|
183
|
+
}
|
184
|
+
|
185
|
+
@Override
|
186
|
+
protected String caseConvertIdentifierForJdbc(final Connection connection, final String value) {
|
187
|
+
return value == null ? null : value.toUpperCase();
|
188
|
+
}
|
189
|
+
|
190
|
+
}
|
@@ -54,6 +54,7 @@ import java.sql.Types;
|
|
54
54
|
import java.util.ArrayList;
|
55
55
|
import java.util.Calendar;
|
56
56
|
import java.util.Collection;
|
57
|
+
import java.util.HashMap;
|
57
58
|
import java.util.LinkedHashMap;
|
58
59
|
import java.util.List;
|
59
60
|
import java.util.Map;
|
@@ -152,6 +153,15 @@ public class RubyJdbcConnection extends RubyObject {
|
|
152
153
|
return getConnectionAdapters(runtime).getClass("IndexDefinition");
|
153
154
|
}
|
154
155
|
|
156
|
+
/**
|
157
|
+
* @param runtime
|
158
|
+
* @return <code>ActiveRecord::ConnectionAdapters::ForeignKeyDefinition</code>
|
159
|
+
* @note only since AR 4.2
|
160
|
+
*/
|
161
|
+
protected static RubyClass getForeignKeyDefinition(final Ruby runtime) {
|
162
|
+
return getConnectionAdapters(runtime).getClass("ForeignKeyDefinition");
|
163
|
+
}
|
164
|
+
|
155
165
|
/**
|
156
166
|
* @param runtime
|
157
167
|
* @return <code>ActiveRecord::JDBCError</code>
|
@@ -1168,7 +1178,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1168
1178
|
|
1169
1179
|
final DatabaseMetaData metaData = connection.getMetaData();
|
1170
1180
|
columns = metaData.getColumns(components.catalog, components.schema, components.name, null);
|
1171
|
-
return
|
1181
|
+
return mapColumnsResult(context, metaData, components, columns);
|
1172
1182
|
}
|
1173
1183
|
finally {
|
1174
1184
|
close(columns);
|
@@ -1205,7 +1215,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1205
1215
|
return withConnection(context, new Callable<IRubyObject>() {
|
1206
1216
|
public IRubyObject call(final Connection connection) throws SQLException {
|
1207
1217
|
final Ruby runtime = context.getRuntime();
|
1208
|
-
final RubyClass
|
1218
|
+
final RubyClass IndexDefinition = getIndexDefinition(context);
|
1209
1219
|
|
1210
1220
|
String _tableName = caseConvertIdentifierForJdbc(connection, tableName);
|
1211
1221
|
String _schemaName = caseConvertIdentifierForJdbc(connection, schemaName);
|
@@ -1248,7 +1258,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1248
1258
|
// orders, (since AR 3.2) where, type, using (AR 4.0)
|
1249
1259
|
};
|
1250
1260
|
|
1251
|
-
indexes.add(
|
1261
|
+
indexes.add( IndexDefinition.callMethod(context, "new", args) ); // IndexDefinition.new
|
1252
1262
|
}
|
1253
1263
|
|
1254
1264
|
// One or more columns can be associated with an index
|
@@ -1265,6 +1275,103 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1265
1275
|
});
|
1266
1276
|
}
|
1267
1277
|
|
1278
|
+
protected RubyClass getIndexDefinition(final ThreadContext context) {
|
1279
|
+
final RubyClass adapterClass = getAdapter(context).getMetaClass();
|
1280
|
+
IRubyObject IDef = adapterClass.getConstantAt("IndexDefinition");
|
1281
|
+
return IDef != null ? (RubyClass) IDef : getIndexDefinition(context.runtime);
|
1282
|
+
}
|
1283
|
+
|
1284
|
+
@JRubyMethod
|
1285
|
+
public IRubyObject foreign_keys(final ThreadContext context, IRubyObject table_name) {
|
1286
|
+
return foreignKeys(context, table_name.toString(), null, null);
|
1287
|
+
}
|
1288
|
+
|
1289
|
+
protected IRubyObject foreignKeys(final ThreadContext context, final String tableName, final String schemaName, final String catalog) {
|
1290
|
+
return withConnection(context, new Callable<IRubyObject>() {
|
1291
|
+
public IRubyObject call(final Connection connection) throws SQLException {
|
1292
|
+
final Ruby runtime = context.getRuntime();
|
1293
|
+
final RubyClass FKDefinition = getForeignKeyDefinition(context);
|
1294
|
+
|
1295
|
+
String _tableName = caseConvertIdentifierForJdbc(connection, tableName);
|
1296
|
+
String _schemaName = caseConvertIdentifierForJdbc(connection, schemaName);
|
1297
|
+
final TableName table = extractTableName(connection, catalog, _schemaName, _tableName);
|
1298
|
+
|
1299
|
+
ResultSet fkInfoSet = null;
|
1300
|
+
final List<IRubyObject> fKeys = new ArrayList<IRubyObject>(8);
|
1301
|
+
try {
|
1302
|
+
final DatabaseMetaData metaData = connection.getMetaData();
|
1303
|
+
fkInfoSet = metaData.getImportedKeys(table.catalog, table.schema, table.name);
|
1304
|
+
|
1305
|
+
while ( fkInfoSet.next() ) {
|
1306
|
+
final RubyHash options = RubyHash.newHash(runtime);
|
1307
|
+
|
1308
|
+
String fkName = fkInfoSet.getString("FK_NAME");
|
1309
|
+
if (fkName != null) {
|
1310
|
+
fkName = caseConvertIdentifierForRails(metaData, fkName);
|
1311
|
+
options.put(runtime.newSymbol("name"), fkName);
|
1312
|
+
}
|
1313
|
+
|
1314
|
+
String columnName = fkInfoSet.getString("FKCOLUMN_NAME");
|
1315
|
+
options.put(runtime.newSymbol("column"), caseConvertIdentifierForRails(metaData, columnName));
|
1316
|
+
|
1317
|
+
columnName = fkInfoSet.getString("PKCOLUMN_NAME");
|
1318
|
+
options.put(runtime.newSymbol("primary_key"), caseConvertIdentifierForRails(metaData, columnName));
|
1319
|
+
|
1320
|
+
String fkTableName = fkInfoSet.getString("FKTABLE_NAME");
|
1321
|
+
fkTableName = caseConvertIdentifierForRails(metaData, fkTableName);
|
1322
|
+
|
1323
|
+
String pkTableName = fkInfoSet.getString("PKTABLE_NAME");
|
1324
|
+
pkTableName = caseConvertIdentifierForRails(metaData, pkTableName);
|
1325
|
+
|
1326
|
+
final String onDelete = extractForeignKeyRule( fkInfoSet.getInt("DELETE_RULE") );
|
1327
|
+
if ( onDelete != null ) options.op_aset(context, runtime.newSymbol("on_delete"), runtime.newSymbol(onDelete));
|
1328
|
+
|
1329
|
+
final String onUpdate = extractForeignKeyRule( fkInfoSet.getInt("UPDATE_RULE") );
|
1330
|
+
if ( onUpdate != null ) options.op_aset(context, runtime.newSymbol("on_update"), runtime.newSymbol(onUpdate));
|
1331
|
+
|
1332
|
+
IRubyObject[] args = new IRubyObject[] {
|
1333
|
+
RubyString.newUnicodeString(runtime, fkTableName), // from_table
|
1334
|
+
RubyString.newUnicodeString(runtime, pkTableName), // to_table
|
1335
|
+
options
|
1336
|
+
};
|
1337
|
+
|
1338
|
+
fKeys.add( FKDefinition.callMethod(context, "new", args) ); // ForeignKeyDefinition.new
|
1339
|
+
}
|
1340
|
+
|
1341
|
+
return runtime.newArray(fKeys);
|
1342
|
+
|
1343
|
+
} finally { close(fkInfoSet); }
|
1344
|
+
}
|
1345
|
+
});
|
1346
|
+
}
|
1347
|
+
|
1348
|
+
protected String extractForeignKeyRule(final int rule) {
|
1349
|
+
switch (rule) {
|
1350
|
+
case DatabaseMetaData.importedKeyNoAction : return null ;
|
1351
|
+
case DatabaseMetaData.importedKeyCascade : return "cascade" ;
|
1352
|
+
case DatabaseMetaData.importedKeySetNull : return "nullify" ;
|
1353
|
+
case DatabaseMetaData.importedKeySetDefault: return "default" ;
|
1354
|
+
}
|
1355
|
+
return null;
|
1356
|
+
}
|
1357
|
+
|
1358
|
+
protected RubyClass getForeignKeyDefinition(final ThreadContext context) {
|
1359
|
+
final RubyClass adapterClass = getAdapter(context).getMetaClass();
|
1360
|
+
IRubyObject FKDef = adapterClass.getConstantAt("ForeignKeyDefinition");
|
1361
|
+
return FKDef != null ? (RubyClass) FKDef : getForeignKeyDefinition(context.runtime);
|
1362
|
+
}
|
1363
|
+
|
1364
|
+
|
1365
|
+
@JRubyMethod(name = "supports_foreign_keys?")
|
1366
|
+
public IRubyObject supports_foreign_keys_p(final ThreadContext context) throws SQLException {
|
1367
|
+
return withConnection(context, new Callable<IRubyObject>() {
|
1368
|
+
public IRubyObject call(final Connection connection) throws SQLException {
|
1369
|
+
final DatabaseMetaData metaData = connection.getMetaData();
|
1370
|
+
return context.getRuntime().newBoolean( metaData.supportsIntegrityEnhancementFacility() );
|
1371
|
+
}
|
1372
|
+
});
|
1373
|
+
}
|
1374
|
+
|
1268
1375
|
@JRubyMethod(name = "supports_views?")
|
1269
1376
|
public IRubyObject supports_views_p(final ThreadContext context) throws SQLException {
|
1270
1377
|
return withConnection(context, new Callable<IRubyObject>() {
|
@@ -1785,6 +1892,16 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1785
1892
|
return value;
|
1786
1893
|
}
|
1787
1894
|
|
1895
|
+
/**
|
1896
|
+
* @return AR::Type-casted value
|
1897
|
+
* @since 1.3.18
|
1898
|
+
*/
|
1899
|
+
protected static IRubyObject typeCastFromDatabase(final ThreadContext context,
|
1900
|
+
final IRubyObject adapter, final RubySymbol typeName, final RubyString value) {
|
1901
|
+
final IRubyObject type = adapter.callMethod(context, "lookup_cast_type", typeName);
|
1902
|
+
return type.callMethod(context, "type_cast_from_database", value);
|
1903
|
+
}
|
1904
|
+
|
1788
1905
|
protected IRubyObject dateToRuby(final ThreadContext context,
|
1789
1906
|
final Ruby runtime, final ResultSet resultSet, final int column)
|
1790
1907
|
throws SQLException {
|
@@ -1800,6 +1917,11 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1800
1917
|
|
1801
1918
|
final IRubyObject adapter = callMethod(context, "adapter"); // self.adapter
|
1802
1919
|
if ( adapter.isNil() ) return strValue; // NOTE: we warn on init_connection
|
1920
|
+
|
1921
|
+
if ( usesType(runtime) ) {
|
1922
|
+
// NOTE: this CAN NOT be 100% correct - as :date is just a type guess!
|
1923
|
+
return typeCastFromDatabase(context, adapter, runtime.newSymbol("date"), strValue);
|
1924
|
+
}
|
1803
1925
|
return adapter.callMethod(context, "_string_to_date", strValue);
|
1804
1926
|
}
|
1805
1927
|
|
@@ -1818,6 +1940,11 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1818
1940
|
|
1819
1941
|
final IRubyObject adapter = callMethod(context, "adapter"); // self.adapter
|
1820
1942
|
if ( adapter.isNil() ) return strValue; // NOTE: we warn on init_connection
|
1943
|
+
|
1944
|
+
if ( usesType(runtime) ) {
|
1945
|
+
// NOTE: this CAN NOT be 100% correct - as :time is just a type guess!
|
1946
|
+
return typeCastFromDatabase(context, adapter, runtime.newSymbol("time"), strValue);
|
1947
|
+
}
|
1821
1948
|
return adapter.callMethod(context, "_string_to_time", strValue);
|
1822
1949
|
}
|
1823
1950
|
|
@@ -1836,6 +1963,11 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1836
1963
|
|
1837
1964
|
final IRubyObject adapter = callMethod(context, "adapter"); // self.adapter
|
1838
1965
|
if ( adapter.isNil() ) return strValue; // NOTE: we warn on init_connection
|
1966
|
+
|
1967
|
+
if ( usesType(runtime) ) {
|
1968
|
+
// NOTE: this CAN NOT be 100% correct - as :timestamp is just a type guess!
|
1969
|
+
return typeCastFromDatabase(context, adapter, runtime.newSymbol("timestamp"), strValue);
|
1970
|
+
}
|
1839
1971
|
return adapter.callMethod(context, "_string_to_timestamp", strValue);
|
1840
1972
|
}
|
1841
1973
|
|
@@ -2032,9 +2164,17 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2032
2164
|
}
|
2033
2165
|
|
2034
2166
|
protected void setStatementParameter(final ThreadContext context,
|
2035
|
-
|
2036
|
-
|
2037
|
-
|
2167
|
+
final Ruby runtime, final Connection connection,
|
2168
|
+
final PreparedStatement statement, final int index,
|
2169
|
+
final Object rawValue, final IRubyObject column) throws SQLException {
|
2170
|
+
final Object value;
|
2171
|
+
|
2172
|
+
if ( isAr42(column) ) {
|
2173
|
+
final IRubyObject castType = column.callMethod(context, "cast_type");
|
2174
|
+
value = castType.callMethod(context, "type_cast_for_database", (IRubyObject) rawValue);
|
2175
|
+
} else {
|
2176
|
+
value = rawValue;
|
2177
|
+
}
|
2038
2178
|
|
2039
2179
|
final int type = jdbcTypeFor(context, runtime, column, value);
|
2040
2180
|
|
@@ -2078,7 +2218,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2078
2218
|
setXmlParameter(context, connection, statement, index, value, column, type);
|
2079
2219
|
break;
|
2080
2220
|
case Types.ARRAY:
|
2081
|
-
setArrayParameter(context, connection, statement, index,
|
2221
|
+
setArrayParameter(context, connection, statement, index, rawValue, column, type);
|
2082
2222
|
break;
|
2083
2223
|
case Types.JAVA_OBJECT:
|
2084
2224
|
case Types.OTHER:
|
@@ -2135,7 +2275,49 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2135
2275
|
if ( column == null || column.isNil() ) {
|
2136
2276
|
throw runtime.newArgumentError("nil column passed");
|
2137
2277
|
}
|
2138
|
-
|
2278
|
+
|
2279
|
+
final IRubyObject type = column.callMethod(context, "type");
|
2280
|
+
if ( type.isNil() || ! (type instanceof RubySymbol) ) {
|
2281
|
+
throw new IllegalStateException("unexpected type = " + type.inspect() + " for " + column.inspect());
|
2282
|
+
}
|
2283
|
+
return (RubySymbol) type;
|
2284
|
+
}
|
2285
|
+
|
2286
|
+
protected static final Map<String, Integer> JDBC_TYPE_FOR = new HashMap<String, Integer>(32, 1);
|
2287
|
+
static {
|
2288
|
+
JDBC_TYPE_FOR.put("string", Types.VARCHAR);
|
2289
|
+
JDBC_TYPE_FOR.put("text", Types.CLOB);
|
2290
|
+
JDBC_TYPE_FOR.put("integer", Types.INTEGER);
|
2291
|
+
JDBC_TYPE_FOR.put("float", Types.FLOAT);
|
2292
|
+
JDBC_TYPE_FOR.put("real", Types.REAL);
|
2293
|
+
JDBC_TYPE_FOR.put("decimal", Types.DECIMAL);
|
2294
|
+
JDBC_TYPE_FOR.put("date", Types.DATE);
|
2295
|
+
JDBC_TYPE_FOR.put("time", Types.TIME);
|
2296
|
+
JDBC_TYPE_FOR.put("datetime", Types.TIMESTAMP);
|
2297
|
+
JDBC_TYPE_FOR.put("timestamp", Types.TIMESTAMP);
|
2298
|
+
JDBC_TYPE_FOR.put("binary", Types.BLOB);
|
2299
|
+
JDBC_TYPE_FOR.put("boolean", Types.BOOLEAN);
|
2300
|
+
JDBC_TYPE_FOR.put("array", Types.ARRAY);
|
2301
|
+
JDBC_TYPE_FOR.put("xml", Types.SQLXML);
|
2302
|
+
|
2303
|
+
// also mapping standard SQL names :
|
2304
|
+
JDBC_TYPE_FOR.put("bit", Types.BIT);
|
2305
|
+
JDBC_TYPE_FOR.put("tinyint", Types.TINYINT);
|
2306
|
+
JDBC_TYPE_FOR.put("smallint", Types.SMALLINT);
|
2307
|
+
JDBC_TYPE_FOR.put("bigint", Types.BIGINT);
|
2308
|
+
JDBC_TYPE_FOR.put("int", Types.INTEGER);
|
2309
|
+
JDBC_TYPE_FOR.put("double", Types.DOUBLE);
|
2310
|
+
JDBC_TYPE_FOR.put("numeric", Types.NUMERIC);
|
2311
|
+
JDBC_TYPE_FOR.put("char", Types.CHAR);
|
2312
|
+
JDBC_TYPE_FOR.put("varchar", Types.VARCHAR);
|
2313
|
+
JDBC_TYPE_FOR.put("binary", Types.BINARY);
|
2314
|
+
JDBC_TYPE_FOR.put("varbinary", Types.VARBINARY);
|
2315
|
+
//JDBC_TYPE_FOR.put("struct", Types.STRUCT);
|
2316
|
+
JDBC_TYPE_FOR.put("blob", Types.BLOB);
|
2317
|
+
JDBC_TYPE_FOR.put("clob", Types.CLOB);
|
2318
|
+
JDBC_TYPE_FOR.put("nchar", Types.NCHAR);
|
2319
|
+
JDBC_TYPE_FOR.put("nvarchar", Types.NVARCHAR);
|
2320
|
+
JDBC_TYPE_FOR.put("nclob", Types.NCLOB);
|
2139
2321
|
}
|
2140
2322
|
|
2141
2323
|
protected int jdbcTypeFor(final ThreadContext context, final Ruby runtime,
|
@@ -2150,39 +2332,20 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2150
2332
|
internedType = "array";
|
2151
2333
|
}
|
2152
2334
|
else {
|
2153
|
-
|
2154
|
-
internedType = columnType.asJavaString();
|
2335
|
+
internedType = resolveColumnType(context, runtime, column).asJavaString();
|
2155
2336
|
}
|
2156
2337
|
}
|
2157
2338
|
else {
|
2158
|
-
if ( value instanceof RubyInteger )
|
2159
|
-
|
2160
|
-
|
2161
|
-
else
|
2162
|
-
internedType = "float";
|
2163
|
-
}
|
2164
|
-
else if ( value instanceof RubyTime ) {
|
2165
|
-
internedType = "timestamp";
|
2166
|
-
}
|
2167
|
-
else {
|
2168
|
-
internedType = "string";
|
2169
|
-
}
|
2339
|
+
if ( value instanceof RubyInteger ) internedType = "integer";
|
2340
|
+
else if ( value instanceof RubyNumeric ) internedType = "float";
|
2341
|
+
else if ( value instanceof RubyTime ) internedType = "timestamp";
|
2342
|
+
else internedType = "string";
|
2170
2343
|
}
|
2171
2344
|
|
2172
|
-
|
2173
|
-
|
2174
|
-
|
2175
|
-
|
2176
|
-
else if ( internedType == (Object) "float" ) return Types.FLOAT;
|
2177
|
-
else if ( internedType == (Object) "date" ) return Types.DATE;
|
2178
|
-
else if ( internedType == (Object) "time" ) return Types.TIME;
|
2179
|
-
else if ( internedType == (Object) "datetime" ) return Types.TIMESTAMP;
|
2180
|
-
else if ( internedType == (Object) "timestamp" ) return Types.TIMESTAMP;
|
2181
|
-
else if ( internedType == (Object) "binary" ) return Types.BLOB;
|
2182
|
-
else if ( internedType == (Object) "boolean" ) return Types.BOOLEAN;
|
2183
|
-
else if ( internedType == (Object) "xml" ) return Types.SQLXML;
|
2184
|
-
else if ( internedType == (Object) "array" ) return Types.ARRAY;
|
2185
|
-
else return Types.OTHER; // -1 as well as 0 are used in Types
|
2345
|
+
final Integer sqlType = JDBC_TYPE_FOR.get(internedType);
|
2346
|
+
if ( sqlType != null ) return sqlType.intValue();
|
2347
|
+
|
2348
|
+
return Types.OTHER; // -1 as well as 0 are used in Types
|
2186
2349
|
}
|
2187
2350
|
|
2188
2351
|
protected void setIntegerParameter(final ThreadContext context,
|
@@ -2338,6 +2501,9 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2338
2501
|
if ( value.getMetaClass().getName().indexOf("BigDecimal") != -1 ) {
|
2339
2502
|
statement.setBigDecimal(index, getBigDecimalValue(value));
|
2340
2503
|
}
|
2504
|
+
else if ( value instanceof RubyInteger ) {
|
2505
|
+
statement.setBigDecimal(index, new BigDecimal(((RubyInteger) value).getBigIntegerValue()));
|
2506
|
+
}
|
2341
2507
|
else if ( value instanceof RubyNumeric ) {
|
2342
2508
|
statement.setDouble(index, ((RubyNumeric) value).getDoubleValue());
|
2343
2509
|
}
|
@@ -2617,15 +2783,15 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2617
2783
|
}
|
2618
2784
|
|
2619
2785
|
protected void setArrayParameter(final ThreadContext context,
|
2620
|
-
|
2621
|
-
|
2622
|
-
|
2786
|
+
final Connection connection, final PreparedStatement statement,
|
2787
|
+
final int index, final Object value,
|
2788
|
+
final IRubyObject column, final int type) throws SQLException {
|
2623
2789
|
if ( value instanceof IRubyObject ) {
|
2624
2790
|
setArrayParameter(context, connection, statement, index, (IRubyObject) value, column, type);
|
2625
|
-
}
|
2626
|
-
|
2627
|
-
|
2628
|
-
else {
|
2791
|
+
} else {
|
2792
|
+
if ( value == null ) {
|
2793
|
+
statement.setNull(index, Types.ARRAY);
|
2794
|
+
} else {
|
2629
2795
|
String typeName = resolveArrayBaseTypeName(context, value, column, type);
|
2630
2796
|
Array array = connection.createArrayOf(typeName, (Object[]) value);
|
2631
2797
|
statement.setArray(index, array);
|
@@ -2637,8 +2803,9 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2637
2803
|
final Connection connection, final PreparedStatement statement,
|
2638
2804
|
final int index, final IRubyObject value,
|
2639
2805
|
final IRubyObject column, final int type) throws SQLException {
|
2640
|
-
if ( value.isNil() )
|
2641
|
-
|
2806
|
+
if ( value.isNil() ) {
|
2807
|
+
statement.setNull(index, Types.ARRAY);
|
2808
|
+
} else {
|
2642
2809
|
String typeName = resolveArrayBaseTypeName(context, value, column, type);
|
2643
2810
|
Array array = connection.createArrayOf(typeName, ((RubyArray) value).toArray());
|
2644
2811
|
statement.setArray(index, array);
|
@@ -2963,15 +3130,41 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2963
3130
|
return defaultValue == null ? runtime.getNil() : RubyString.newUnicodeString(runtime, defaultValue);
|
2964
3131
|
}
|
2965
3132
|
|
2966
|
-
|
3133
|
+
/**
|
3134
|
+
* Internal API that might be subject to change!
|
3135
|
+
* @since 1.3.18
|
3136
|
+
*/
|
3137
|
+
protected static boolean usesType(final Ruby runtime) { // AR 4.2
|
3138
|
+
return runtime.getModule("ActiveRecord").getConstantAt("Type") != null;
|
3139
|
+
}
|
3140
|
+
|
3141
|
+
/**
|
3142
|
+
* This method is considered internal and is not part of AR-JDBC's Java ext
|
3143
|
+
* API and thus might be subject to change in the future.
|
3144
|
+
* Please copy it to your own class if you rely on it to avoid issues.
|
3145
|
+
*/
|
3146
|
+
protected static boolean isAr42(IRubyObject column) {
|
3147
|
+
return column.respondsTo("cast_type");
|
3148
|
+
}
|
3149
|
+
|
3150
|
+
protected RubyArray mapColumnsResult(final ThreadContext context,
|
2967
3151
|
final DatabaseMetaData metaData, final TableName components, final ResultSet results)
|
2968
3152
|
throws SQLException {
|
2969
3153
|
|
2970
|
-
final
|
2971
|
-
final
|
2972
|
-
|
3154
|
+
final RubyClass Column = getJdbcColumnClass(context);
|
3155
|
+
final boolean lookupCastType = Column.isMethodBound("cast_type", false);
|
2973
3156
|
// NOTE: primary/primary= methods were removed from Column in AR 4.2
|
2974
|
-
|
3157
|
+
// setPrimary = ! lookupCastType by default ... it's better than checking
|
3158
|
+
// whether primary= is bound since it might be a left over in AR-JDBC ext
|
3159
|
+
return mapColumnsResult(context, metaData, components, results, Column, lookupCastType, ! lookupCastType);
|
3160
|
+
}
|
3161
|
+
|
3162
|
+
protected final RubyArray mapColumnsResult(final ThreadContext context,
|
3163
|
+
final DatabaseMetaData metaData, final TableName components, final ResultSet results,
|
3164
|
+
final RubyClass Column, final boolean lookupCastType, final boolean setPrimary)
|
3165
|
+
throws SQLException {
|
3166
|
+
|
3167
|
+
final Ruby runtime = context.getRuntime();
|
2975
3168
|
|
2976
3169
|
final Collection<String> primaryKeyNames =
|
2977
3170
|
setPrimary ? getPrimaryKeyNames(metaData, components) : null;
|
@@ -2980,22 +3173,27 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2980
3173
|
final IRubyObject config = getConfig(context);
|
2981
3174
|
while ( results.next() ) {
|
2982
3175
|
final String colName = results.getString(COLUMN_NAME);
|
2983
|
-
|
2984
|
-
|
2985
|
-
|
2986
|
-
|
2987
|
-
|
2988
|
-
|
2989
|
-
|
2990
|
-
}
|
3176
|
+
final RubyString railsColumnName = RubyString.newUnicodeString(runtime, caseConvertIdentifierForRails(metaData, colName));
|
3177
|
+
final IRubyObject defaultValue = defaultValueFromResultSet( runtime, results );
|
3178
|
+
final RubyString sqlType = RubyString.newUnicodeString( runtime, typeFromResultSet(results) );
|
3179
|
+
final RubyBoolean nullable = runtime.newBoolean( ! results.getString(IS_NULLABLE).trim().equals("NO") );
|
3180
|
+
final IRubyObject[] args;
|
3181
|
+
if ( lookupCastType ) {
|
3182
|
+
final IRubyObject castType = getAdapter(context).callMethod(context, "lookup_cast_type", sqlType);
|
3183
|
+
args = new IRubyObject[] {config, railsColumnName, defaultValue, castType, sqlType, nullable};
|
3184
|
+
} else {
|
3185
|
+
args = new IRubyObject[] {config, railsColumnName, defaultValue, sqlType, nullable};
|
3186
|
+
}
|
3187
|
+
|
3188
|
+
IRubyObject column = Column.callMethod(context, "new", args);
|
2991
3189
|
columns.append(column);
|
2992
3190
|
|
2993
|
-
if ( primaryKeyNames != null
|
2994
|
-
|
3191
|
+
if ( primaryKeyNames != null ) {
|
3192
|
+
final RubyBoolean primary = runtime.newBoolean( primaryKeyNames.contains(colName) );
|
3193
|
+
column.getInstanceVariables().setInstanceVariable("@primary", primary);
|
2995
3194
|
}
|
2996
3195
|
}
|
2997
3196
|
return columns;
|
2998
|
-
|
2999
3197
|
}
|
3000
3198
|
|
3001
3199
|
private static Collection<String> getPrimaryKeyNames(final DatabaseMetaData metaData,
|