activerecord-jdbc-adapter 1.3.11 → 1.3.12
Sign up to get free protection for your applications and to get access to all the features.
- 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
|