activerecord-jdbc-adapter 1.3.11 → 1.3.12
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/Appraisals +2 -2
- data/Gemfile +4 -0
- data/History.md +11 -0
- data/lib/arjdbc/db2/adapter.rb +3 -0
- data/lib/arjdbc/h2/adapter.rb +4 -1
- data/lib/arjdbc/hsqldb/adapter.rb +4 -1
- data/lib/arjdbc/jdbc.rb +9 -8
- data/lib/arjdbc/jdbc/adapter.rb +46 -15
- data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
- data/lib/arjdbc/mssql/adapter.rb +12 -6
- data/lib/arjdbc/mysql/adapter.rb +78 -13
- data/lib/arjdbc/mysql/column.rb +20 -0
- data/lib/arjdbc/mysql/connection_methods.rb +56 -2
- data/lib/arjdbc/oracle/adapter.rb +16 -17
- data/lib/arjdbc/postgresql/adapter.rb +136 -98
- data/lib/arjdbc/postgresql/base/oid.rb +78 -146
- data/lib/arjdbc/postgresql/oid_types.rb +132 -10
- data/lib/arjdbc/sqlite3/adapter.rb +58 -9
- data/lib/arjdbc/version.rb +1 -1
- data/rakelib/02-test.rake +2 -2
- data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +48 -10
- data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +81 -11
- metadata +2 -2
@@ -202,6 +202,11 @@ module ArJdbc
|
|
202
202
|
true
|
203
203
|
end
|
204
204
|
|
205
|
+
# @override
|
206
|
+
def supports_views?
|
207
|
+
true
|
208
|
+
end
|
209
|
+
|
205
210
|
def sqlite_version
|
206
211
|
@sqlite_version ||= Version.new(select_value('SELECT sqlite_version(*)'))
|
207
212
|
end
|
@@ -213,8 +218,8 @@ module ArJdbc
|
|
213
218
|
|
214
219
|
if value.kind_of?(String)
|
215
220
|
column_type = column && column.type
|
216
|
-
if column_type == :binary
|
217
|
-
"x'#{
|
221
|
+
if column_type == :binary
|
222
|
+
"x'#{value.unpack("H*")[0]}'"
|
218
223
|
else
|
219
224
|
super
|
220
225
|
end
|
@@ -344,8 +349,15 @@ module ArJdbc
|
|
344
349
|
# @override
|
345
350
|
def columns(table_name, name = nil)
|
346
351
|
klass = ::ActiveRecord::ConnectionAdapters::SQLite3Column
|
352
|
+
pass_cast_type = respond_to?(:lookup_cast_type)
|
347
353
|
table_structure(table_name).map do |field|
|
348
|
-
|
354
|
+
sql_type = field['type']
|
355
|
+
if pass_cast_type
|
356
|
+
cast_type = lookup_cast_type(sql_type)
|
357
|
+
klass.new(field['name'], field['dflt_value'], cast_type, sql_type, field['notnull'] == 0)
|
358
|
+
else
|
359
|
+
klass.new(field['name'], field['dflt_value'], sql_type, field['notnull'] == 0)
|
360
|
+
end
|
349
361
|
end
|
350
362
|
end
|
351
363
|
|
@@ -355,6 +367,38 @@ module ArJdbc
|
|
355
367
|
column && column['name']
|
356
368
|
end
|
357
369
|
|
370
|
+
# NOTE: do not override indexes without testing support for 3.7.2 & 3.8.7 !
|
371
|
+
# @override
|
372
|
+
def indexes(table_name, name = nil)
|
373
|
+
# on JDBC 3.7 we'll simply do super since it can not handle "PRAGMA index_info"
|
374
|
+
return @connection.indexes(table_name, name) if sqlite_version < '3.8' # super
|
375
|
+
|
376
|
+
name ||= 'SCHEMA'
|
377
|
+
exec_query_raw("PRAGMA index_list(#{quote_table_name(table_name)})", name).map do |row|
|
378
|
+
index_name = row['name']
|
379
|
+
sql = "SELECT sql FROM sqlite_master"
|
380
|
+
sql << " WHERE name=#{quote(index_name)} AND type='index'"
|
381
|
+
sql << " UNION ALL "
|
382
|
+
sql << "SELECT sql FROM sqlite_temp_master"
|
383
|
+
sql << " WHERE name=#{quote(index_name)} AND type='index'"
|
384
|
+
where = nil
|
385
|
+
exec_query_raw(sql, name) do |index_sql|
|
386
|
+
match = /\sWHERE\s+(.+)$/i.match(index_sql)
|
387
|
+
where = match[1] if match
|
388
|
+
end
|
389
|
+
begin
|
390
|
+
columns = exec_query_raw("PRAGMA index_info('#{index_name}')", name).map { |col| col['name'] }
|
391
|
+
rescue => e
|
392
|
+
# NOTE: JDBC <= 3.8.7 bug work-around :
|
393
|
+
if e.message && e.message.index('[SQLITE_ERROR] SQL error or missing database')
|
394
|
+
columns = []
|
395
|
+
end
|
396
|
+
raise e
|
397
|
+
end
|
398
|
+
new_index_definition(table_name, index_name, row['unique'] != 0, columns, nil, nil, where)
|
399
|
+
end
|
400
|
+
end
|
401
|
+
|
358
402
|
# @override
|
359
403
|
def remove_index!(table_name, index_name)
|
360
404
|
execute "DROP INDEX #{quote_column_name(index_name)}"
|
@@ -476,12 +520,17 @@ module ArJdbc
|
|
476
520
|
end
|
477
521
|
|
478
522
|
def translate_exception(exception, message)
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
523
|
+
if msg = exception.message
|
524
|
+
# SQLite 3.8.2 returns a newly formatted error message:
|
525
|
+
# UNIQUE constraint failed: *table_name*.*column_name*
|
526
|
+
# Older versions of SQLite return:
|
527
|
+
# column *column_name* is not unique
|
528
|
+
if msg.index('UNIQUE constraint failed: ') ||
|
529
|
+
msg =~ /column(s)? .* (is|are) not unique/
|
530
|
+
return RecordNotUnique.new(message, exception)
|
531
|
+
end
|
484
532
|
end
|
533
|
+
super
|
485
534
|
end
|
486
535
|
|
487
536
|
# @private available in native adapter way back to AR-2.3
|
@@ -560,4 +609,4 @@ module ActiveRecord::ConnectionAdapters
|
|
560
609
|
|
561
610
|
SQLiteAdapter = SQLite3Adapter
|
562
611
|
end
|
563
|
-
end
|
612
|
+
end
|
data/lib/arjdbc/version.rb
CHANGED
data/rakelib/02-test.rake
CHANGED
@@ -53,7 +53,7 @@ def test_task_for(adapter, options = {})
|
|
53
53
|
desc = options[:desc] || options[:comment] ||
|
54
54
|
"Run tests against #{options[:database_name] || adapter}"
|
55
55
|
adapter = adapter.to_s.downcase
|
56
|
-
driver =
|
56
|
+
driver = adapter if ( driver = options[:driver] ).nil?
|
57
57
|
prereqs = options[:prereqs] || []
|
58
58
|
unless prereqs.frozen?
|
59
59
|
prereqs = [ prereqs ].flatten; prereqs << 'test_appraisal_hint'
|
@@ -87,7 +87,7 @@ test_task_for :MSSQL, :driver => :jtds, :database_name => 'MS-SQL (SQLServer)'
|
|
87
87
|
test_task_for :MySQL, :prereqs => 'db:mysql'
|
88
88
|
test_task_for :PostgreSQL, :driver => 'postgres', :prereqs => 'db:postgresql'
|
89
89
|
task :test_postgres => :test_postgresql # alias
|
90
|
-
test_task_for :SQLite3
|
90
|
+
test_task_for :SQLite3, :driver => ENV['JDBC_SQLITE_VERSION']
|
91
91
|
task :test_sqlite => :test_sqlite3 # alias
|
92
92
|
test_task_for :Firebird
|
93
93
|
|
@@ -89,7 +89,7 @@ import org.jruby.runtime.builtin.IRubyObject;
|
|
89
89
|
import org.jruby.util.ByteList;
|
90
90
|
|
91
91
|
/**
|
92
|
-
*
|
92
|
+
* Most of our ActiveRecord::ConnectionAdapters::JdbcConnection implementation.
|
93
93
|
*/
|
94
94
|
public class RubyJdbcConnection extends RubyObject {
|
95
95
|
|
@@ -444,7 +444,16 @@ public class RubyJdbcConnection extends RubyObject {
|
|
444
444
|
* @return connection
|
445
445
|
*/
|
446
446
|
@JRubyMethod(name = "init_connection")
|
447
|
-
public synchronized IRubyObject init_connection(final ThreadContext context)
|
447
|
+
public synchronized IRubyObject init_connection(final ThreadContext context) {
|
448
|
+
try {
|
449
|
+
return initConnection(context);
|
450
|
+
}
|
451
|
+
catch (SQLException e) {
|
452
|
+
return handleException(context, e); // throws
|
453
|
+
}
|
454
|
+
}
|
455
|
+
|
456
|
+
private IRubyObject initConnection(final ThreadContext context) throws SQLException {
|
448
457
|
final IRubyObject jdbcConnection = setConnection( newConnection() );
|
449
458
|
final IRubyObject adapter = callMethod("adapter"); // self.adapter
|
450
459
|
if ( ! adapter.isNil() ) {
|
@@ -1140,10 +1149,10 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1140
1149
|
}
|
1141
1150
|
|
1142
1151
|
// NOTE: metaData.getIndexInfo row mappings :
|
1143
|
-
|
1144
|
-
|
1145
|
-
|
1146
|
-
|
1152
|
+
protected static final int INDEX_INFO_TABLE_NAME = 3;
|
1153
|
+
protected static final int INDEX_INFO_NON_UNIQUE = 4;
|
1154
|
+
protected static final int INDEX_INFO_NAME = 6;
|
1155
|
+
protected static final int INDEX_INFO_COLUMN_NAME = 9;
|
1147
1156
|
|
1148
1157
|
/**
|
1149
1158
|
* Default JDBC introspection for index metadata on the JdbcConnection.
|
@@ -1217,6 +1226,27 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1217
1226
|
});
|
1218
1227
|
}
|
1219
1228
|
|
1229
|
+
@JRubyMethod(name = "supports_views?")
|
1230
|
+
public IRubyObject supports_views_p(final ThreadContext context) throws SQLException {
|
1231
|
+
return withConnection(context, new Callable<IRubyObject>() {
|
1232
|
+
public IRubyObject call(final Connection connection) throws SQLException {
|
1233
|
+
final DatabaseMetaData metaData = connection.getMetaData();
|
1234
|
+
final ResultSet tableTypes = metaData.getTableTypes();
|
1235
|
+
try {
|
1236
|
+
while ( tableTypes.next() ) {
|
1237
|
+
if ( "VIEW".equalsIgnoreCase( tableTypes.getString(1) ) ) {
|
1238
|
+
return context.getRuntime().newBoolean( true );
|
1239
|
+
}
|
1240
|
+
}
|
1241
|
+
}
|
1242
|
+
finally {
|
1243
|
+
close(tableTypes);
|
1244
|
+
}
|
1245
|
+
return context.getRuntime().newBoolean( false );
|
1246
|
+
}
|
1247
|
+
});
|
1248
|
+
}
|
1249
|
+
|
1220
1250
|
// NOTE: this seems to be not used ... at all ?!
|
1221
1251
|
/*
|
1222
1252
|
* sql, values (array), types (column.type array), name = nil, pk = nil, id_value = nil, sequence_name = nil
|
@@ -1425,9 +1455,17 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1425
1455
|
return context.getRuntime().newBoolean( true );
|
1426
1456
|
}
|
1427
1457
|
|
1458
|
+
private IRubyObject getConfig(final ThreadContext context) {
|
1459
|
+
return getInstanceVariable("@config"); // this.callMethod(context, "config");
|
1460
|
+
}
|
1461
|
+
|
1428
1462
|
protected final IRubyObject getConfigValue(final ThreadContext context, final String key) {
|
1429
|
-
final IRubyObject config =
|
1430
|
-
|
1463
|
+
final IRubyObject config = getConfig(context);
|
1464
|
+
final RubySymbol keySym = context.runtime.newSymbol(key);
|
1465
|
+
if ( config instanceof RubyHash ) {
|
1466
|
+
return ((RubyHash) config).op_aref(context, keySym);
|
1467
|
+
}
|
1468
|
+
return config.callMethod(context, "[]", keySym);
|
1431
1469
|
}
|
1432
1470
|
|
1433
1471
|
/**
|
@@ -1518,7 +1556,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1518
1556
|
final RubyArray resultRows = runtime.newArray();
|
1519
1557
|
|
1520
1558
|
while ( resultSet.next() ) {
|
1521
|
-
resultRows.
|
1559
|
+
resultRows.append( resultHandler.mapRow(context, runtime, columns, resultSet, this) );
|
1522
1560
|
}
|
1523
1561
|
|
1524
1562
|
return resultHandler.newResult(context, runtime, columns, resultRows);
|
@@ -2897,7 +2935,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2897
2935
|
}
|
2898
2936
|
|
2899
2937
|
final RubyArray columns = runtime.newArray();
|
2900
|
-
final IRubyObject config =
|
2938
|
+
final IRubyObject config = getConfig(context);
|
2901
2939
|
while ( results.next() ) {
|
2902
2940
|
final String colName = results.getString(COLUMN_NAME);
|
2903
2941
|
IRubyObject column = jdbcColumn.callMethod(context, "new",
|
@@ -37,6 +37,7 @@ import java.sql.SQLException;
|
|
37
37
|
import java.sql.Statement;
|
38
38
|
import java.sql.DatabaseMetaData;
|
39
39
|
import java.sql.Savepoint;
|
40
|
+
import java.sql.Types;
|
40
41
|
import java.util.ArrayList;
|
41
42
|
import java.util.List;
|
42
43
|
|
@@ -118,15 +119,81 @@ public class SQLite3RubyJdbcConnection extends RubyJdbcConnection {
|
|
118
119
|
}
|
119
120
|
|
120
121
|
@Override
|
121
|
-
protected IRubyObject indexes(final ThreadContext context, String
|
122
|
-
if (
|
123
|
-
final int i =
|
124
|
-
if ( i > 0 &&
|
125
|
-
|
126
|
-
|
122
|
+
protected IRubyObject indexes(final ThreadContext context, String table, final String name, String schema) {
|
123
|
+
if ( table != null ) {
|
124
|
+
final int i = table.indexOf('.');
|
125
|
+
if ( i > 0 && schema == null ) {
|
126
|
+
schema = table.substring(0, i);
|
127
|
+
table = table.substring(i + 1);
|
127
128
|
}
|
128
129
|
}
|
129
|
-
|
130
|
+
final String tableName = table;
|
131
|
+
final String schemaName = schema;
|
132
|
+
// return super.indexes(context, tableName, name, schemaName);
|
133
|
+
return withConnection(context, new Callable<IRubyObject>() {
|
134
|
+
public RubyArray call(final Connection connection) throws SQLException {
|
135
|
+
final Ruby runtime = context.runtime;
|
136
|
+
final RubyClass indexDefinition = getIndexDefinition(runtime);
|
137
|
+
|
138
|
+
final TableName table = extractTableName(connection, schemaName, tableName);
|
139
|
+
|
140
|
+
final List<RubyString> primaryKeys = primaryKeys(context, connection, table);
|
141
|
+
|
142
|
+
final DatabaseMetaData metaData = connection.getMetaData();
|
143
|
+
ResultSet indexInfoSet = null;
|
144
|
+
try {
|
145
|
+
indexInfoSet = metaData.getIndexInfo(table.catalog, table.schema, table.name, false, true);
|
146
|
+
}
|
147
|
+
catch (SQLException e) {
|
148
|
+
final String msg = e.getMessage();
|
149
|
+
if ( msg != null && msg.startsWith("[SQLITE_ERROR] SQL error or missing database") ) {
|
150
|
+
return RubyArray.newEmptyArray(runtime); // on 3.8.7 getIndexInfo fails if table has no indexes
|
151
|
+
}
|
152
|
+
throw e;
|
153
|
+
}
|
154
|
+
final RubyArray indexes = RubyArray.newArray(runtime, 8);
|
155
|
+
try {
|
156
|
+
String currentIndex = null;
|
157
|
+
|
158
|
+
while ( indexInfoSet.next() ) {
|
159
|
+
String indexName = indexInfoSet.getString(INDEX_INFO_NAME);
|
160
|
+
if ( indexName == null ) continue;
|
161
|
+
|
162
|
+
final String columnName = indexInfoSet.getString(INDEX_INFO_COLUMN_NAME);
|
163
|
+
final RubyString rubyColumnName = RubyString.newUnicodeString(runtime, columnName);
|
164
|
+
if ( primaryKeys.contains(rubyColumnName) ) continue;
|
165
|
+
|
166
|
+
// We are working on a new index
|
167
|
+
if ( ! indexName.equals(currentIndex) ) {
|
168
|
+
currentIndex = indexName;
|
169
|
+
|
170
|
+
String indexTableName = indexInfoSet.getString(INDEX_INFO_TABLE_NAME);
|
171
|
+
|
172
|
+
final boolean nonUnique = indexInfoSet.getBoolean(INDEX_INFO_NON_UNIQUE);
|
173
|
+
|
174
|
+
IRubyObject[] args = new IRubyObject[] {
|
175
|
+
RubyString.newUnicodeString(runtime, indexTableName), // table_name
|
176
|
+
RubyString.newUnicodeString(runtime, indexName), // index_name
|
177
|
+
runtime.newBoolean( ! nonUnique ), // unique
|
178
|
+
runtime.newArray() // [] for column names, we'll add to that in just a bit
|
179
|
+
// orders, (since AR 3.2) where, type, using (AR 4.0)
|
180
|
+
};
|
181
|
+
|
182
|
+
indexes.append( indexDefinition.callMethod(context, "new", args) ); // IndexDefinition.new
|
183
|
+
}
|
184
|
+
|
185
|
+
// One or more columns can be associated with an index
|
186
|
+
IRubyObject lastIndexDef = indexes.isEmpty() ? null : indexes.entry(-1);
|
187
|
+
if ( lastIndexDef != null ) {
|
188
|
+
( (RubyArray) lastIndexDef.callMethod(context, "columns") ).append(rubyColumnName);
|
189
|
+
}
|
190
|
+
}
|
191
|
+
|
192
|
+
return indexes;
|
193
|
+
|
194
|
+
} finally { close(indexInfoSet); }
|
195
|
+
}
|
196
|
+
});
|
130
197
|
}
|
131
198
|
|
132
199
|
@Override
|
@@ -151,14 +218,10 @@ public class SQLite3RubyJdbcConnection extends RubyJdbcConnection {
|
|
151
218
|
name = nameParts[2];
|
152
219
|
}
|
153
220
|
|
154
|
-
name = caseConvertIdentifierForJdbc(connection, name);
|
155
|
-
|
156
221
|
if ( schema != null ) {
|
157
|
-
schema = caseConvertIdentifierForJdbc(connection, schema);
|
158
222
|
// NOTE: hack to work-around SQLite JDBC ignoring schema :
|
159
223
|
return new TableName(catalog, null, schema + '.' + name);
|
160
224
|
}
|
161
|
-
|
162
225
|
return new TableName(catalog, schema, name);
|
163
226
|
}
|
164
227
|
|
@@ -173,6 +236,13 @@ public class SQLite3RubyJdbcConnection extends RubyJdbcConnection {
|
|
173
236
|
if ( resultSet instanceof ResultSetMetaData ) {
|
174
237
|
type = ((ResultSetMetaData) resultSet).getColumnType(column);
|
175
238
|
}
|
239
|
+
// since JDBC 3.8 there seems to be more cleverness built-in that
|
240
|
+
// seems (<= 3.8.7) to get things wrong ... reports DATE SQL type
|
241
|
+
// for "datetime" columns :
|
242
|
+
if ( type == Types.DATE ) {
|
243
|
+
// return timestampToRuby(context, runtime, resultSet, column);
|
244
|
+
return stringToRuby(context, runtime, resultSet, column);
|
245
|
+
}
|
176
246
|
return super.jdbcToRuby(context, runtime, column, type, resultSet);
|
177
247
|
}
|
178
248
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activerecord-jdbc-adapter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.3.
|
4
|
+
version: 1.3.12
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nick Sieger, Ola Bini, Karol Bucek and JRuby contributors
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-11-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|