activerecord-jdbc-adapter 1.3.0.rc1 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CONTRIBUTING.md +3 -5
- data/Gemfile +3 -5
- data/Gemfile.lock +1 -1
- data/History.md +30 -3
- data/README.md +14 -9
- data/gemfiles/rails23.gemfile +3 -0
- data/gemfiles/rails23.gemfile.lock +8 -0
- data/gemfiles/rails30.gemfile +3 -0
- data/gemfiles/rails30.gemfile.lock +11 -0
- data/gemfiles/rails31.gemfile +3 -0
- data/gemfiles/rails31.gemfile.lock +8 -0
- data/gemfiles/rails32.gemfile +3 -0
- data/gemfiles/rails32.gemfile.lock +11 -0
- data/gemfiles/rails40.gemfile +3 -0
- data/gemfiles/rails40.gemfile.lock +6 -0
- data/lib/arjdbc/db2/adapter.rb +39 -23
- data/lib/arjdbc/db2/column.rb +3 -3
- data/lib/arjdbc/derby/adapter.rb +45 -0
- data/lib/arjdbc/firebird/adapter.rb +38 -36
- data/lib/arjdbc/h2/adapter.rb +1 -1
- data/lib/arjdbc/hsqldb/adapter.rb +1 -0
- data/lib/arjdbc/hsqldb/explain_support.rb +6 -6
- data/lib/arjdbc/jdbc/adapter.rb +80 -39
- data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
- data/lib/arjdbc/jdbc/serialized_attributes_helper.rb +3 -21
- data/lib/arjdbc/mssql/adapter.rb +41 -18
- data/lib/arjdbc/mssql/column.rb +3 -8
- data/lib/arjdbc/mssql/explain_support.rb +1 -1
- data/lib/arjdbc/mysql/adapter.rb +19 -9
- data/lib/arjdbc/mysql/column.rb +1 -1
- data/lib/arjdbc/mysql/connection_methods.rb +1 -0
- data/lib/arjdbc/mysql/explain_support.rb +2 -1
- data/lib/arjdbc/oracle/adapter.rb +42 -26
- data/lib/arjdbc/oracle/column.rb +1 -1
- data/lib/arjdbc/postgresql/adapter.rb +13 -4
- data/lib/arjdbc/sqlite3/adapter.rb +2 -0
- data/lib/arjdbc/tasks/oracle/enhanced_structure_dump.rb +5 -5
- data/lib/arjdbc/util/serialized_attributes.rb +87 -0
- data/lib/arjdbc/version.rb +1 -1
- data/rakelib/02-test.rake +1 -1
- data/rakelib/db.rake +1 -1
- data/src/java/arjdbc/db2/DB2RubyJdbcConnection.java +2 -2
- data/src/java/arjdbc/derby/DerbyModule.java +26 -173
- data/src/java/arjdbc/h2/H2Module.java +1 -0
- data/src/java/arjdbc/h2/H2RubyJdbcConnection.java +1 -2
- data/src/java/arjdbc/hsqldb/HSQLDBModule.java +10 -9
- data/src/java/arjdbc/jdbc/AdapterJavaService.java +3 -3
- data/src/java/arjdbc/jdbc/JdbcConnectionFactory.java +4 -3
- data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +189 -70
- data/src/java/arjdbc/jdbc/SQLBlock.java +4 -4
- data/src/java/arjdbc/mssql/MSSQLRubyJdbcConnection.java +6 -7
- data/src/java/arjdbc/mysql/MySQLModule.java +1 -0
- data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +14 -9
- data/src/java/arjdbc/oracle/OracleRubyJdbcConnection.java +19 -3
- data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +305 -11
- data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +3 -3
- metadata +6 -5
@@ -1,5 +1,5 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
/***** BEGIN LICENSE BLOCK *****
|
2
|
+
* Copyright (c) 2012-2013 Karol Bucek <self@kares.org>
|
3
3
|
* Copyright (c) 2006-2010 Nick Sieger <nick@nicksieger.com>
|
4
4
|
* Copyright (c) 2006-2007 Ola Bini <ola.bini@gmail.com>
|
5
5
|
* Copyright (c) 2008-2009 Thomas E Enebo <enebo@acm.org>
|
@@ -41,5 +41,5 @@ public class AdapterJavaService implements BasicLibraryService {
|
|
41
41
|
ArJdbcModule.load(runtime);
|
42
42
|
return true;
|
43
43
|
}
|
44
|
-
|
44
|
+
|
45
45
|
}
|
@@ -1,4 +1,5 @@
|
|
1
1
|
/***** BEGIN LICENSE BLOCK *****
|
2
|
+
* Copyright (c) 2012-2013 Karol Bucek <self@kares.org>
|
2
3
|
* Copyright (c) 2006-2010 Nick Sieger <nick@nicksieger.com>
|
3
4
|
* Copyright (c) 2006-2007 Ola Bini <ola.bini@gmail.com>
|
4
5
|
*
|
@@ -33,12 +34,12 @@ import java.sql.SQLException;
|
|
33
34
|
* @author nicksieger
|
34
35
|
*/
|
35
36
|
public interface JdbcConnectionFactory {
|
36
|
-
|
37
|
+
|
37
38
|
/**
|
38
39
|
* Retrieve a (new) connection from the factory.
|
39
40
|
* @return a connection
|
40
|
-
* @throws SQLException
|
41
|
+
* @throws SQLException
|
41
42
|
*/
|
42
43
|
Connection newConnection() throws SQLException;
|
43
|
-
|
44
|
+
|
44
45
|
}
|
@@ -1,5 +1,5 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
/***** BEGIN LICENSE BLOCK *****
|
2
|
+
* Copyright (c) 2012-2013 Karol Bucek <self@kares.org>
|
3
3
|
* Copyright (c) 2006-2011 Nick Sieger <nick@nicksieger.com>
|
4
4
|
* Copyright (c) 2006-2007 Ola Bini <ola.bini@gmail.com>
|
5
5
|
* Copyright (c) 2008-2009 Thomas E Enebo <enebo@acm.org>
|
@@ -453,9 +453,8 @@ public class RubyJdbcConnection extends RubyObject {
|
|
453
453
|
}
|
454
454
|
}
|
455
455
|
else {
|
456
|
-
|
457
|
-
|
458
|
-
" make sure you pass it on initialize(config, adapter)"));
|
456
|
+
warn(context, "WARN: adapter not set for: " + inspect() +
|
457
|
+
" make sure you pass it on initialize(config, adapter)");
|
459
458
|
}
|
460
459
|
return jdbcConnection;
|
461
460
|
}
|
@@ -542,7 +541,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
542
541
|
try {
|
543
542
|
statement = createStatement(context, connection);
|
544
543
|
if ( doExecute(statement, query) ) {
|
545
|
-
return mapResults(context, connection
|
544
|
+
return mapResults(context, connection, statement, false);
|
546
545
|
} else {
|
547
546
|
return mapGeneratedKeysOrUpdateCount(context, connection, statement);
|
548
547
|
}
|
@@ -791,7 +790,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
791
790
|
return withConnection(context, new Callable<IRubyObject>() {
|
792
791
|
public IRubyObject call(final Connection connection) throws SQLException {
|
793
792
|
final Ruby runtime = context.getRuntime();
|
794
|
-
final DatabaseMetaData metaData = connection.getMetaData();
|
795
793
|
|
796
794
|
Statement statement = null; ResultSet resultSet = null;
|
797
795
|
try {
|
@@ -811,10 +809,10 @@ public class RubyJdbcConnection extends RubyObject {
|
|
811
809
|
if ( block != null && block.isGiven() ) {
|
812
810
|
// yield(id1, name1) ... row 1 result data
|
813
811
|
// yield(id2, name2) ... row 2 result data
|
814
|
-
return yieldResultRows(context, runtime,
|
812
|
+
return yieldResultRows(context, runtime, connection, resultSet, block);
|
815
813
|
}
|
816
814
|
|
817
|
-
return mapToRawResult(context, runtime,
|
815
|
+
return mapToRawResult(context, runtime, connection, resultSet, false);
|
818
816
|
}
|
819
817
|
catch (final SQLException e) {
|
820
818
|
debugErrorSQL(context, query);
|
@@ -938,9 +936,8 @@ public class RubyJdbcConnection extends RubyObject {
|
|
938
936
|
private IRubyObject mapQueryResult(final ThreadContext context,
|
939
937
|
final Connection connection, final ResultSet resultSet) throws SQLException {
|
940
938
|
final Ruby runtime = context.getRuntime();
|
941
|
-
final
|
942
|
-
|
943
|
-
return mapToResult(context, runtime, metaData, resultSet, columns);
|
939
|
+
final ColumnData[] columns = extractColumns(runtime, connection, resultSet, false);
|
940
|
+
return mapToResult(context, runtime, connection, resultSet, columns);
|
944
941
|
}
|
945
942
|
|
946
943
|
/**
|
@@ -976,10 +973,11 @@ public class RubyJdbcConnection extends RubyObject {
|
|
976
973
|
@JRubyMethod(name = "supported_data_types")
|
977
974
|
public IRubyObject supported_data_types(final ThreadContext context) throws SQLException {
|
978
975
|
final Ruby runtime = context.getRuntime();
|
979
|
-
final
|
980
|
-
final
|
976
|
+
final Connection connection = getConnection(true);
|
977
|
+
final ResultSet typeDesc = connection.getMetaData().getTypeInfo();
|
978
|
+
final IRubyObject types;
|
981
979
|
try {
|
982
|
-
types = mapToRawResult(context, runtime,
|
980
|
+
types = mapToRawResult(context, runtime, connection, typeDesc, true);
|
983
981
|
}
|
984
982
|
finally { close(typeDesc); }
|
985
983
|
|
@@ -999,8 +997,8 @@ public class RubyJdbcConnection extends RubyObject {
|
|
999
997
|
return withConnection(context, new Callable<List<RubyString>>() {
|
1000
998
|
public List<RubyString> call(final Connection connection) throws SQLException {
|
1001
999
|
final Ruby runtime = context.getRuntime();
|
1000
|
+
final String _tableName = caseConvertIdentifierForJdbc(connection, tableName);
|
1002
1001
|
final DatabaseMetaData metaData = connection.getMetaData();
|
1003
|
-
final String _tableName = caseConvertIdentifierForJdbc(metaData, tableName);
|
1004
1002
|
ResultSet resultSet = null;
|
1005
1003
|
final List<RubyString> keyNames = new ArrayList<RubyString>();
|
1006
1004
|
try {
|
@@ -1009,7 +1007,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1009
1007
|
|
1010
1008
|
while (resultSet.next()) {
|
1011
1009
|
String columnName = resultSet.getString(PRIMARY_KEYS_COLUMN_NAME);
|
1012
|
-
columnName = caseConvertIdentifierForRails(
|
1010
|
+
columnName = caseConvertIdentifierForRails(connection, columnName);
|
1013
1011
|
keyNames.add( RubyString.newUnicodeString(runtime, columnName) );
|
1014
1012
|
}
|
1015
1013
|
}
|
@@ -1156,9 +1154,9 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1156
1154
|
final Ruby runtime = context.getRuntime();
|
1157
1155
|
final RubyClass indexDefinition = getIndexDefinition(runtime);
|
1158
1156
|
|
1157
|
+
String _tableName = caseConvertIdentifierForJdbc(connection, tableName);
|
1158
|
+
String _schemaName = caseConvertIdentifierForJdbc(connection, schemaName);
|
1159
1159
|
final DatabaseMetaData metaData = connection.getMetaData();
|
1160
|
-
String _tableName = caseConvertIdentifierForJdbc(metaData, tableName);
|
1161
|
-
String _schemaName = caseConvertIdentifierForJdbc(metaData, schemaName);
|
1162
1160
|
|
1163
1161
|
final List<RubyString> primaryKeys = primaryKeys(context, _tableName);
|
1164
1162
|
ResultSet indexInfoSet = null;
|
@@ -1296,12 +1294,12 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1296
1294
|
column.callMethod(context, "type").toString() == (Object) "binary";
|
1297
1295
|
|
1298
1296
|
final RubyClass recordClass = record.getMetaClass(); // record.class
|
1299
|
-
final IRubyObject
|
1297
|
+
final IRubyObject adapter = recordClass.callMethod(context, "connection");
|
1300
1298
|
|
1301
1299
|
IRubyObject columnName = column.callMethod(context, "name");
|
1302
|
-
columnName =
|
1300
|
+
columnName = adapter.callMethod(context, "quote_column_name", columnName);
|
1303
1301
|
IRubyObject tableName = recordClass.callMethod(context, "table_name");
|
1304
|
-
tableName =
|
1302
|
+
tableName = adapter.callMethod(context, "quote_table_name", tableName);
|
1305
1303
|
final IRubyObject idKey = recordClass.callMethod(context, "primary_key"); // 'id'
|
1306
1304
|
// callMethod(context, "quote", primaryKey);
|
1307
1305
|
final IRubyObject idColumn = // record.class.columns_hash['id']
|
@@ -1342,6 +1340,12 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1342
1340
|
});
|
1343
1341
|
}
|
1344
1342
|
|
1343
|
+
protected String caseConvertIdentifierForRails(final Connection connection, final String value)
|
1344
|
+
throws SQLException {
|
1345
|
+
if ( value == null ) return null;
|
1346
|
+
return caseConvertIdentifierForRails(connection.getMetaData(), value);
|
1347
|
+
}
|
1348
|
+
|
1345
1349
|
/**
|
1346
1350
|
* Convert an identifier coming back from the database to a case which Rails is expecting.
|
1347
1351
|
*
|
@@ -1356,16 +1360,21 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1356
1360
|
protected static String caseConvertIdentifierForRails(final DatabaseMetaData metaData, final String value)
|
1357
1361
|
throws SQLException {
|
1358
1362
|
if ( value == null ) return null;
|
1359
|
-
|
1360
1363
|
return metaData.storesUpperCaseIdentifiers() ? value.toLowerCase() : value;
|
1361
1364
|
}
|
1362
1365
|
|
1366
|
+
protected String caseConvertIdentifierForJdbc(final Connection connection, final String value)
|
1367
|
+
throws SQLException {
|
1368
|
+
if ( value == null ) return null;
|
1369
|
+
return caseConvertIdentifierForJdbc(connection.getMetaData(), value);
|
1370
|
+
}
|
1371
|
+
|
1363
1372
|
/**
|
1364
1373
|
* Convert an identifier destined for a method which cares about the databases internal
|
1365
1374
|
* storage case. Methods like DatabaseMetaData.getPrimaryKeys() needs the table name to match
|
1366
|
-
* the internal storage name.
|
1375
|
+
* the internal storage name. Arbitrary queries and the like DO NOT need to do this.
|
1367
1376
|
*/
|
1368
|
-
protected String caseConvertIdentifierForJdbc(final DatabaseMetaData metaData, final String value)
|
1377
|
+
protected static String caseConvertIdentifierForJdbc(final DatabaseMetaData metaData, final String value)
|
1369
1378
|
throws SQLException {
|
1370
1379
|
if ( value == null ) return null;
|
1371
1380
|
|
@@ -1375,7 +1384,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1375
1384
|
else if ( metaData.storesLowerCaseIdentifiers() ) {
|
1376
1385
|
return value.toLowerCase();
|
1377
1386
|
}
|
1378
|
-
|
1379
1387
|
return value;
|
1380
1388
|
}
|
1381
1389
|
|
@@ -1465,7 +1473,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1465
1473
|
* @throws SQLException
|
1466
1474
|
*/
|
1467
1475
|
protected IRubyObject mapToResult(final ThreadContext context, final Ruby runtime,
|
1468
|
-
final
|
1476
|
+
final Connection connection, final ResultSet resultSet,
|
1469
1477
|
final ColumnData[] columns) throws SQLException {
|
1470
1478
|
|
1471
1479
|
final ResultHandler resultHandler = ResultHandler.getInstance(runtime);
|
@@ -1635,20 +1643,29 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1635
1643
|
return runtime.getKernel().callMethod("BigDecimal", runtime.newString(value));
|
1636
1644
|
}
|
1637
1645
|
|
1638
|
-
protected static
|
1646
|
+
protected static Boolean rawDateTime;
|
1647
|
+
static {
|
1648
|
+
final String dateTimeRaw = System.getProperty("arjdbc.datetime.raw");
|
1649
|
+
if ( dateTimeRaw != null ) {
|
1650
|
+
rawDateTime = Boolean.parseBoolean(dateTimeRaw);
|
1651
|
+
}
|
1652
|
+
// NOTE: we do this since it will have a different value depending on
|
1653
|
+
// AR version - since 4.0 false by default otherwise will be true ...
|
1654
|
+
}
|
1639
1655
|
|
1640
|
-
@JRubyMethod(name = "raw_date_time?")
|
1656
|
+
@JRubyMethod(name = "raw_date_time?", meta = true)
|
1641
1657
|
public static IRubyObject useRawDateTime(final ThreadContext context, final IRubyObject self) {
|
1642
|
-
return context.getRuntime().
|
1658
|
+
if ( rawDateTime == null ) return context.getRuntime().getNil();
|
1659
|
+
return context.getRuntime().newBoolean( rawDateTime.booleanValue() );
|
1643
1660
|
}
|
1644
1661
|
|
1645
|
-
@JRubyMethod(name = "raw_date_time=")
|
1662
|
+
@JRubyMethod(name = "raw_date_time=", meta = true)
|
1646
1663
|
public static IRubyObject setRawDateTime(final IRubyObject self, final IRubyObject value) {
|
1647
1664
|
if ( value instanceof RubyBoolean ) {
|
1648
1665
|
rawDateTime = ((RubyBoolean) value).isTrue();
|
1649
1666
|
}
|
1650
1667
|
else {
|
1651
|
-
rawDateTime = value.isNil();
|
1668
|
+
rawDateTime = value.isNil() ? null : Boolean.TRUE;
|
1652
1669
|
}
|
1653
1670
|
return value;
|
1654
1671
|
}
|
@@ -1664,7 +1681,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1664
1681
|
}
|
1665
1682
|
|
1666
1683
|
final RubyString strValue = RubyString.newUnicodeString(runtime, value.toString());
|
1667
|
-
if ( rawDateTime ) return strValue;
|
1684
|
+
if ( rawDateTime != null && rawDateTime.booleanValue() ) return strValue;
|
1668
1685
|
|
1669
1686
|
final IRubyObject adapter = callMethod(context, "adapter"); // self.adapter
|
1670
1687
|
if ( adapter.isNil() ) return strValue; // NOTE: we warn on init_connection
|
@@ -1682,7 +1699,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1682
1699
|
}
|
1683
1700
|
|
1684
1701
|
final RubyString strValue = RubyString.newUnicodeString(runtime, value.toString());
|
1685
|
-
if ( rawDateTime ) return strValue;
|
1702
|
+
if ( rawDateTime != null && rawDateTime.booleanValue() ) return strValue;
|
1686
1703
|
|
1687
1704
|
final IRubyObject adapter = callMethod(context, "adapter"); // self.adapter
|
1688
1705
|
if ( adapter.isNil() ) return strValue; // NOTE: we warn on init_connection
|
@@ -1700,7 +1717,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1700
1717
|
}
|
1701
1718
|
|
1702
1719
|
final RubyString strValue = timestampToRubyString(runtime, value.toString());
|
1703
|
-
if ( rawDateTime ) return strValue;
|
1720
|
+
if ( rawDateTime != null && rawDateTime.booleanValue() ) return strValue;
|
1704
1721
|
|
1705
1722
|
final IRubyObject adapter = callMethod(context, "adapter"); // self.adapter
|
1706
1723
|
if ( adapter.isNil() ) return strValue; // NOTE: we warn on init_connection
|
@@ -1728,9 +1745,39 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1728
1745
|
return timestampToRubyString(runtime, value.toString());
|
1729
1746
|
}
|
1730
1747
|
|
1748
|
+
protected static Boolean rawBoolean;
|
1749
|
+
static {
|
1750
|
+
final String booleanRaw = System.getProperty("arjdbc.boolean.raw");
|
1751
|
+
if ( booleanRaw != null ) {
|
1752
|
+
rawBoolean = Boolean.parseBoolean(booleanRaw);
|
1753
|
+
}
|
1754
|
+
}
|
1755
|
+
|
1756
|
+
@JRubyMethod(name = "raw_boolean?", meta = true)
|
1757
|
+
public static IRubyObject useRawBoolean(final ThreadContext context, final IRubyObject self) {
|
1758
|
+
if ( rawBoolean == null ) return context.getRuntime().getNil();
|
1759
|
+
return context.getRuntime().newBoolean( rawBoolean.booleanValue() );
|
1760
|
+
}
|
1761
|
+
|
1762
|
+
@JRubyMethod(name = "raw_boolean=", meta = true)
|
1763
|
+
public static IRubyObject setRawBoolean(final IRubyObject self, final IRubyObject value) {
|
1764
|
+
if ( value instanceof RubyBoolean ) {
|
1765
|
+
rawBoolean = ((RubyBoolean) value).isTrue();
|
1766
|
+
}
|
1767
|
+
else {
|
1768
|
+
rawBoolean = value.isNil() ? null : Boolean.TRUE;
|
1769
|
+
}
|
1770
|
+
return value;
|
1771
|
+
}
|
1772
|
+
|
1731
1773
|
protected IRubyObject booleanToRuby(final ThreadContext context,
|
1732
1774
|
final Ruby runtime, final ResultSet resultSet, final int column)
|
1733
1775
|
throws SQLException {
|
1776
|
+
if ( rawBoolean != null && rawBoolean.booleanValue() ) {
|
1777
|
+
final String value = resultSet.getString(column);
|
1778
|
+
if ( resultSet.wasNull() ) return runtime.getNil();
|
1779
|
+
return RubyString.newUnicodeString(runtime, value);
|
1780
|
+
}
|
1734
1781
|
final boolean value = resultSet.getBoolean(column);
|
1735
1782
|
if ( resultSet.wasNull() ) return runtime.getNil();
|
1736
1783
|
return booleanToRuby(runtime, resultSet, value);
|
@@ -1863,15 +1910,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1863
1910
|
column = (IRubyObject) _param[0]; param = _param[1];
|
1864
1911
|
}
|
1865
1912
|
|
1866
|
-
|
1867
|
-
if ( column != null && ! column.isNil() ) {
|
1868
|
-
type = column.callMethod(context, "type");
|
1869
|
-
}
|
1870
|
-
else {
|
1871
|
-
type = null;
|
1872
|
-
}
|
1873
|
-
|
1874
|
-
setStatementParameter(context, runtime, connection, statement, i + 1, param, type);
|
1913
|
+
setStatementParameter(context, runtime, connection, statement, i + 1, param, column);
|
1875
1914
|
}
|
1876
1915
|
}
|
1877
1916
|
|
@@ -1987,8 +2026,16 @@ public class RubyJdbcConnection extends RubyObject {
|
|
1987
2026
|
|
1988
2027
|
final String internedType;
|
1989
2028
|
if ( column != null && ! column.isNil() ) {
|
1990
|
-
|
1991
|
-
|
2029
|
+
// NOTE: there's no ActiveRecord "convention" really for this ...
|
2030
|
+
// this is based on Postgre's initial support for arrays :
|
2031
|
+
// `column.type` contains the base type while there's `column.array?`
|
2032
|
+
if ( column.respondsTo("array?") && column.callMethod(context, "array?").isTrue() ) {
|
2033
|
+
internedType = "array";
|
2034
|
+
}
|
2035
|
+
else {
|
2036
|
+
final RubySymbol columnType = resolveColumnType(context, runtime, column);
|
2037
|
+
internedType = columnType.asJavaString();
|
2038
|
+
}
|
1992
2039
|
}
|
1993
2040
|
else {
|
1994
2041
|
if ( value instanceof RubyInteger ) {
|
@@ -2452,7 +2499,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2452
2499
|
}
|
2453
2500
|
}
|
2454
2501
|
|
2455
|
-
|
2502
|
+
protected void setArrayParameter(final ThreadContext context,
|
2456
2503
|
final Connection connection, final PreparedStatement statement,
|
2457
2504
|
final int index, final Object value,
|
2458
2505
|
final IRubyObject column, final int type) throws SQLException {
|
@@ -2462,25 +2509,34 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2462
2509
|
else {
|
2463
2510
|
if ( value == null ) statement.setNull(index, Types.ARRAY);
|
2464
2511
|
else {
|
2465
|
-
|
2466
|
-
Array array = connection.createArrayOf(
|
2512
|
+
String typeName = resolveArrayBaseTypeName(context, value, column, type);
|
2513
|
+
Array array = connection.createArrayOf(typeName, (Object[]) value);
|
2467
2514
|
statement.setArray(index, array);
|
2468
2515
|
}
|
2469
2516
|
}
|
2470
2517
|
}
|
2471
2518
|
|
2472
|
-
|
2519
|
+
protected void setArrayParameter(final ThreadContext context,
|
2473
2520
|
final Connection connection, final PreparedStatement statement,
|
2474
2521
|
final int index, final IRubyObject value,
|
2475
2522
|
final IRubyObject column, final int type) throws SQLException {
|
2476
2523
|
if ( value.isNil() ) statement.setNull(index, Types.ARRAY);
|
2477
2524
|
else {
|
2478
|
-
|
2479
|
-
Array array = connection.createArrayOf(
|
2525
|
+
String typeName = resolveArrayBaseTypeName(context, value, column, type);
|
2526
|
+
Array array = connection.createArrayOf(typeName, ((RubyArray) value).toArray());
|
2480
2527
|
statement.setArray(index, array);
|
2481
2528
|
}
|
2482
2529
|
}
|
2483
2530
|
|
2531
|
+
protected String resolveArrayBaseTypeName(final ThreadContext context,
|
2532
|
+
final Object value, final IRubyObject column, final int type) {
|
2533
|
+
// return column.callMethod(context, "sql_type").toString();
|
2534
|
+
String sqlType = column.callMethod(context, "sql_type").toString();
|
2535
|
+
final int index = sqlType.indexOf('('); // e.g. "character varying(255)"
|
2536
|
+
if ( index > 0 ) sqlType = sqlType.substring(0, index);
|
2537
|
+
return sqlType;
|
2538
|
+
}
|
2539
|
+
|
2484
2540
|
protected void setXmlParameter(final ThreadContext context,
|
2485
2541
|
final Connection connection, final PreparedStatement statement,
|
2486
2542
|
final int index, final Object value,
|
@@ -2637,6 +2693,14 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2637
2693
|
debugMessage(context, "connection considered broken due: " + e.toString());
|
2638
2694
|
return false;
|
2639
2695
|
}
|
2696
|
+
catch (AbstractMethodError e) { // non-JDBC 4.0 driver
|
2697
|
+
warn( context,
|
2698
|
+
"WARN: driver does not support checking if connection isValid()" +
|
2699
|
+
" please make sure you're using a JDBC 4.0 compilant driver or" +
|
2700
|
+
" set `connection_alive_sql: ...` in your database configuration" );
|
2701
|
+
debugStackTrace(context, e);
|
2702
|
+
throw e;
|
2703
|
+
}
|
2640
2704
|
finally { close(statement); }
|
2641
2705
|
}
|
2642
2706
|
|
@@ -2671,11 +2735,10 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2671
2735
|
final String tablePattern, final String[] types,
|
2672
2736
|
final boolean checkExistsOnly) throws SQLException {
|
2673
2737
|
|
2738
|
+
final String _tablePattern = caseConvertIdentifierForJdbc(connection, tablePattern);
|
2739
|
+
final String _schemaPattern = caseConvertIdentifierForJdbc(connection, schemaPattern);
|
2674
2740
|
final DatabaseMetaData metaData = connection.getMetaData();
|
2675
2741
|
|
2676
|
-
final String _tablePattern = caseConvertIdentifierForJdbc(metaData, tablePattern);
|
2677
|
-
final String _schemaPattern = caseConvertIdentifierForJdbc(metaData, schemaPattern);
|
2678
|
-
|
2679
2742
|
ResultSet tablesSet = null;
|
2680
2743
|
try {
|
2681
2744
|
tablesSet = metaData.getTables(catalog, _schemaPattern, _tablePattern, types);
|
@@ -2705,13 +2768,16 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2705
2768
|
* @return List<RubyString>
|
2706
2769
|
* @throws SQLException
|
2707
2770
|
*/
|
2771
|
+
// NOTE: change to accept a connection instead of meta-data
|
2708
2772
|
protected RubyArray mapTables(final Ruby runtime, final DatabaseMetaData metaData,
|
2709
2773
|
final String catalog, final String schemaPattern, final String tablePattern,
|
2710
2774
|
final ResultSet tablesSet) throws SQLException {
|
2711
2775
|
final RubyArray tables = runtime.newArray();
|
2712
2776
|
while ( tablesSet.next() ) {
|
2713
2777
|
String name = tablesSet.getString(TABLES_TABLE_NAME);
|
2778
|
+
|
2714
2779
|
name = caseConvertIdentifierForRails(metaData, name);
|
2780
|
+
|
2715
2781
|
tables.add(RubyString.newUnicodeString(runtime, name));
|
2716
2782
|
}
|
2717
2783
|
return tables;
|
@@ -2920,14 +2986,14 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2920
2986
|
}
|
2921
2987
|
|
2922
2988
|
protected IRubyObject mapResults(final ThreadContext context,
|
2923
|
-
final
|
2989
|
+
final Connection connection, final Statement statement,
|
2924
2990
|
final boolean downCase) throws SQLException {
|
2925
2991
|
|
2926
2992
|
final Ruby runtime = context.getRuntime();
|
2927
2993
|
IRubyObject result;
|
2928
2994
|
ResultSet resultSet = statement.getResultSet();
|
2929
2995
|
try {
|
2930
|
-
result = mapToRawResult(context, runtime,
|
2996
|
+
result = mapToRawResult(context, runtime, connection, resultSet, downCase);
|
2931
2997
|
}
|
2932
2998
|
finally { close(resultSet); }
|
2933
2999
|
|
@@ -2939,7 +3005,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2939
3005
|
do {
|
2940
3006
|
resultSet = statement.getResultSet();
|
2941
3007
|
try {
|
2942
|
-
result = mapToRawResult(context, runtime,
|
3008
|
+
result = mapToRawResult(context, runtime, connection, resultSet, downCase);
|
2943
3009
|
}
|
2944
3010
|
finally { close(resultSet); }
|
2945
3011
|
|
@@ -2966,6 +3032,20 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2966
3032
|
* @param downCase should column names only be in lower case?
|
2967
3033
|
*/
|
2968
3034
|
@SuppressWarnings("unchecked")
|
3035
|
+
private IRubyObject mapToRawResult(final ThreadContext context, final Ruby runtime,
|
3036
|
+
final Connection connection, final ResultSet resultSet,
|
3037
|
+
final boolean downCase) throws SQLException {
|
3038
|
+
|
3039
|
+
final ColumnData[] columns = extractColumns(runtime, connection, resultSet, downCase);
|
3040
|
+
|
3041
|
+
final RubyArray results = runtime.newArray();
|
3042
|
+
// [ { 'col1': 1, 'col2': 2 }, { 'col1': 3, 'col2': 4 } ]
|
3043
|
+
populateFromResultSet(context, runtime, (List<IRubyObject>) results, resultSet, columns);
|
3044
|
+
return results;
|
3045
|
+
}
|
3046
|
+
|
3047
|
+
@Deprecated
|
3048
|
+
@SuppressWarnings("unchecked")
|
2969
3049
|
private IRubyObject mapToRawResult(final ThreadContext context, final Ruby runtime,
|
2970
3050
|
final DatabaseMetaData metaData, final ResultSet resultSet,
|
2971
3051
|
final boolean downCase) throws SQLException {
|
@@ -2979,10 +3059,10 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2979
3059
|
}
|
2980
3060
|
|
2981
3061
|
private IRubyObject yieldResultRows(final ThreadContext context, final Ruby runtime,
|
2982
|
-
final
|
3062
|
+
final Connection connection, final ResultSet resultSet,
|
2983
3063
|
final Block block) throws SQLException {
|
2984
3064
|
|
2985
|
-
final ColumnData[] columns = extractColumns(runtime,
|
3065
|
+
final ColumnData[] columns = extractColumns(runtime, connection, resultSet, false);
|
2986
3066
|
|
2987
3067
|
final IRubyObject[] blockArgs = new IRubyObject[columns.length];
|
2988
3068
|
while ( resultSet.next() ) {
|
@@ -3005,6 +3085,13 @@ public class RubyJdbcConnection extends RubyObject {
|
|
3005
3085
|
* @return columns data
|
3006
3086
|
* @throws SQLException
|
3007
3087
|
*/
|
3088
|
+
protected ColumnData[] extractColumns(final Ruby runtime,
|
3089
|
+
final Connection connection, final ResultSet resultSet,
|
3090
|
+
final boolean downCase) throws SQLException {
|
3091
|
+
return setupColumns(runtime, connection, resultSet.getMetaData(), downCase);
|
3092
|
+
}
|
3093
|
+
|
3094
|
+
@Deprecated
|
3008
3095
|
protected ColumnData[] extractColumns(final Ruby runtime,
|
3009
3096
|
final DatabaseMetaData metaData, final ResultSet resultSet,
|
3010
3097
|
final boolean downCase) throws SQLException {
|
@@ -3358,12 +3445,10 @@ public class RubyJdbcConnection extends RubyObject {
|
|
3358
3445
|
name = nameParts[2];
|
3359
3446
|
}
|
3360
3447
|
|
3361
|
-
final DatabaseMetaData metaData = connection.getMetaData();
|
3362
|
-
|
3363
3448
|
if (schema != null) {
|
3364
|
-
schema = caseConvertIdentifierForJdbc(
|
3449
|
+
schema = caseConvertIdentifierForJdbc(connection, schema);
|
3365
3450
|
}
|
3366
|
-
name = caseConvertIdentifierForJdbc(
|
3451
|
+
name = caseConvertIdentifierForJdbc(connection, name);
|
3367
3452
|
|
3368
3453
|
if (schema != null && ! databaseSupportsSchemas()) {
|
3369
3454
|
catalog = schema;
|
@@ -3395,11 +3480,16 @@ public class RubyJdbcConnection extends RubyObject {
|
|
3395
3480
|
this.index = idx;
|
3396
3481
|
}
|
3397
3482
|
|
3483
|
+
@Override
|
3484
|
+
public String toString() {
|
3485
|
+
return "'" + name + "'i" + index + "t" + type + "";
|
3486
|
+
}
|
3487
|
+
|
3398
3488
|
}
|
3399
3489
|
|
3400
|
-
private
|
3490
|
+
private ColumnData[] setupColumns(
|
3401
3491
|
final Ruby runtime,
|
3402
|
-
final
|
3492
|
+
final Connection connection,
|
3403
3493
|
final ResultSetMetaData resultMetaData,
|
3404
3494
|
final boolean downCase) throws SQLException {
|
3405
3495
|
|
@@ -3407,14 +3497,39 @@ public class RubyJdbcConnection extends RubyObject {
|
|
3407
3497
|
final ColumnData[] columns = new ColumnData[columnCount];
|
3408
3498
|
|
3409
3499
|
for ( int i = 1; i <= columnCount; i++ ) { // metadata is one-based
|
3410
|
-
|
3411
|
-
if (downCase) {
|
3412
|
-
name =
|
3500
|
+
String name = resultMetaData.getColumnLabel(i);
|
3501
|
+
if ( downCase ) {
|
3502
|
+
name = name.toLowerCase();
|
3413
3503
|
} else {
|
3414
|
-
name = caseConvertIdentifierForRails(
|
3504
|
+
name = caseConvertIdentifierForRails(connection, name);
|
3415
3505
|
}
|
3506
|
+
final RubyString columnName = RubyString.newUnicodeString(runtime, name);
|
3416
3507
|
final int columnType = resultMetaData.getColumnType(i);
|
3508
|
+
columns[i - 1] = new ColumnData(columnName, columnType, i);
|
3509
|
+
}
|
3510
|
+
|
3511
|
+
return columns;
|
3512
|
+
}
|
3513
|
+
|
3514
|
+
@Deprecated
|
3515
|
+
private ColumnData[] setupColumns(
|
3516
|
+
final Ruby runtime,
|
3517
|
+
final DatabaseMetaData metaData,
|
3518
|
+
final ResultSetMetaData resultMetaData,
|
3519
|
+
final boolean downCase) throws SQLException {
|
3520
|
+
|
3521
|
+
final int columnCount = resultMetaData.getColumnCount();
|
3522
|
+
final ColumnData[] columns = new ColumnData[columnCount];
|
3523
|
+
|
3524
|
+
for ( int i = 1; i <= columnCount; i++ ) { // metadata is one-based
|
3525
|
+
String name = resultMetaData.getColumnLabel(i);
|
3526
|
+
if ( downCase ) {
|
3527
|
+
name = name.toLowerCase();
|
3528
|
+
} else {
|
3529
|
+
name = caseConvertIdentifierForRails(metaData, name);
|
3530
|
+
}
|
3417
3531
|
final RubyString columnName = RubyString.newUnicodeString(runtime, name);
|
3532
|
+
final int columnType = resultMetaData.getColumnType(i);
|
3418
3533
|
columns[i - 1] = new ColumnData(columnName, columnType, i);
|
3419
3534
|
}
|
3420
3535
|
|
@@ -3491,6 +3606,10 @@ public class RubyJdbcConnection extends RubyObject {
|
|
3491
3606
|
}
|
3492
3607
|
}
|
3493
3608
|
|
3609
|
+
protected void warn(final ThreadContext context, final String message) {
|
3610
|
+
callMethod(context, "warn", context.getRuntime().newString(message));
|
3611
|
+
}
|
3612
|
+
|
3494
3613
|
private static RubyArray createCallerBacktrace(final ThreadContext context) {
|
3495
3614
|
final Ruby runtime = context.getRuntime();
|
3496
3615
|
runtime.incrementCallerCount();
|