activerecord-jdbc-alt-adapter 50.7.0-java → 51.3.0-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +0 -3
- data/.travis.yml +24 -28
- data/Gemfile +5 -2
- data/README.md +26 -20
- data/Rakefile +4 -30
- data/activerecord-jdbc-adapter.gemspec +2 -2
- data/activerecord-jdbc-alt-adapter.gemspec +4 -3
- data/lib/arel/visitors/sqlserver.rb +17 -3
- data/lib/arjdbc/abstract/core.rb +4 -2
- data/lib/arjdbc/abstract/database_statements.rb +2 -8
- data/lib/arjdbc/abstract/transaction_support.rb +2 -9
- data/lib/arjdbc/db2/adapter.rb +2 -52
- data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
- data/lib/arjdbc/jdbc/column.rb +11 -5
- data/lib/arjdbc/jdbc/error.rb +1 -1
- data/lib/arjdbc/jdbc.rb +4 -0
- data/lib/arjdbc/mssql/adapter.rb +33 -39
- data/lib/arjdbc/mssql/connection_methods.rb +0 -5
- data/lib/arjdbc/mssql/database_statements.rb +1 -1
- data/lib/arjdbc/mssql/explain_support.rb +1 -1
- data/lib/arjdbc/mssql/{extensions.rb → extensions/attribute_methods.rb} +0 -0
- data/lib/arjdbc/mssql/extensions/calculations.rb +29 -0
- data/lib/arjdbc/mssql/schema_creation.rb +12 -0
- data/lib/arjdbc/mssql/schema_definitions.rb +17 -0
- data/lib/arjdbc/mssql/schema_dumper.rb +37 -0
- data/lib/arjdbc/mssql/schema_statements.rb +73 -44
- data/lib/arjdbc/mssql/types/date_and_time_types.rb +9 -9
- data/lib/arjdbc/mssql/utils.rb +1 -0
- data/lib/arjdbc/mssql.rb +1 -1
- data/lib/arjdbc/mysql/adapter.rb +12 -1
- data/lib/arjdbc/mysql/connection_methods.rb +7 -13
- data/lib/arjdbc/postgresql/adapter.rb +29 -12
- data/lib/arjdbc/postgresql/column.rb +3 -6
- data/lib/arjdbc/postgresql/connection_methods.rb +1 -3
- data/lib/arjdbc/postgresql/oid_types.rb +7 -12
- data/lib/arjdbc/sqlite3/adapter.rb +169 -139
- data/lib/arjdbc/sqlite3/connection_methods.rb +1 -2
- data/lib/arjdbc/version.rb +1 -1
- data/rakelib/01-tomcat.rake +2 -2
- data/rakelib/02-test.rake +2 -0
- data/rakelib/rails.rake +1 -1
- data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +17 -68
- data/src/java/arjdbc/mssql/MSSQLRubyJdbcConnection.java +38 -282
- data/src/java/arjdbc/postgresql/ByteaUtils.java +1 -0
- data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +3 -3
- data/src/java/arjdbc/util/DateTimeUtils.java +5 -22
- metadata +20 -12
- data/lib/activerecord-jdbc-alt-adapter.rb +0 -1
@@ -487,7 +487,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
487
487
|
savepoint = ((IRubyObject) savepoint).toJava(Savepoint.class);
|
488
488
|
}
|
489
489
|
|
490
|
-
releaseSavepoint(
|
490
|
+
connection.releaseSavepoint((Savepoint) savepoint);
|
491
491
|
return context.nil;
|
492
492
|
}
|
493
493
|
catch (SQLException e) {
|
@@ -495,11 +495,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
495
495
|
}
|
496
496
|
}
|
497
497
|
|
498
|
-
// MSSQL doesn't support releasing savepoints so we make it possible to override the actual release action
|
499
|
-
protected void releaseSavepoint(final Connection connection, final Savepoint savepoint) throws SQLException {
|
500
|
-
connection.releaseSavepoint(savepoint);
|
501
|
-
}
|
502
|
-
|
503
498
|
protected static RuntimeException newSavepointNotSetError(final ThreadContext context, final IRubyObject name, final String op) {
|
504
499
|
RubyClass StatementInvalid = ActiveRecord(context).getClass("StatementInvalid");
|
505
500
|
return context.runtime.newRaiseException(StatementInvalid, "could not " + op + " savepoint: '" + name + "' (not set)");
|
@@ -727,10 +722,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
727
722
|
|
728
723
|
private void connectImpl(final boolean forceConnection) throws SQLException {
|
729
724
|
setConnection( forceConnection ? newConnection() : null );
|
730
|
-
if (forceConnection)
|
731
|
-
if (getConnectionImpl() == null) throw new SQLException("Didn't get a connection. Wrong URL?");
|
732
|
-
configureConnection();
|
733
|
-
}
|
725
|
+
if ( forceConnection ) configureConnection();
|
734
726
|
}
|
735
727
|
|
736
728
|
@JRubyMethod(name = "read_only?")
|
@@ -888,31 +880,15 @@ public class RubyJdbcConnection extends RubyObject {
|
|
888
880
|
return mapQueryResult(context, connection, resultSet);
|
889
881
|
}
|
890
882
|
|
891
|
-
private static String[] createStatementPk(IRubyObject pk) {
|
892
|
-
String[] statementPk;
|
893
|
-
if (pk instanceof RubyArray) {
|
894
|
-
RubyArray ary = (RubyArray) pk;
|
895
|
-
int size = ary.size();
|
896
|
-
statementPk = new String[size];
|
897
|
-
for (int i = 0; i < size; i++) {
|
898
|
-
statementPk[i] = sqlString(ary.eltInternal(i));
|
899
|
-
}
|
900
|
-
} else {
|
901
|
-
statementPk = new String[] { sqlString(pk) };
|
902
|
-
}
|
903
|
-
return statementPk;
|
904
|
-
}
|
905
|
-
|
906
883
|
/**
|
907
884
|
* Executes an INSERT SQL statement
|
908
885
|
* @param context
|
909
886
|
* @param sql
|
910
|
-
* @param pk Rails PK
|
911
887
|
* @return ActiveRecord::Result
|
912
888
|
* @throws SQLException
|
913
889
|
*/
|
914
|
-
@JRubyMethod(name = "
|
915
|
-
public IRubyObject
|
890
|
+
@JRubyMethod(name = "execute_insert", required = 1)
|
891
|
+
public IRubyObject execute_insert(final ThreadContext context, final IRubyObject sql) {
|
916
892
|
return withConnection(context, new Callable<IRubyObject>() {
|
917
893
|
public IRubyObject call(final Connection connection) throws SQLException {
|
918
894
|
Statement statement = null;
|
@@ -920,13 +896,7 @@ public class RubyJdbcConnection extends RubyObject {
|
|
920
896
|
try {
|
921
897
|
|
922
898
|
statement = createStatement(context, connection);
|
923
|
-
|
924
|
-
if (pk == context.nil || pk == context.fals || !supportsGeneratedKeys(connection)) {
|
925
|
-
statement.executeUpdate(query, Statement.RETURN_GENERATED_KEYS);
|
926
|
-
} else {
|
927
|
-
statement.executeUpdate(query, createStatementPk(pk));
|
928
|
-
}
|
929
|
-
|
899
|
+
statement.executeUpdate(query, Statement.RETURN_GENERATED_KEYS);
|
930
900
|
return mapGeneratedKeys(context, connection, statement);
|
931
901
|
|
932
902
|
} catch (final SQLException e) {
|
@@ -939,35 +909,23 @@ public class RubyJdbcConnection extends RubyObject {
|
|
939
909
|
});
|
940
910
|
}
|
941
911
|
|
942
|
-
@Deprecated
|
943
|
-
@JRubyMethod(name = "execute_insert", required = 1)
|
944
|
-
public IRubyObject execute_insert(final ThreadContext context, final IRubyObject sql) {
|
945
|
-
return execute_insert_pk(context, sql, context.nil);
|
946
|
-
}
|
947
|
-
|
948
912
|
/**
|
949
913
|
* Executes an INSERT SQL statement using a prepared statement
|
950
914
|
* @param context
|
951
915
|
* @param sql
|
952
916
|
* @param binds RubyArray of values to be bound to the query
|
953
|
-
* @param pk Rails PK
|
954
917
|
* @return ActiveRecord::Result
|
955
918
|
* @throws SQLException
|
956
919
|
*/
|
957
|
-
@JRubyMethod(name = "
|
958
|
-
public IRubyObject
|
959
|
-
final IRubyObject pk) {
|
920
|
+
@JRubyMethod(name = "execute_insert", required = 2)
|
921
|
+
public IRubyObject execute_insert(final ThreadContext context, final IRubyObject sql, final IRubyObject binds) {
|
960
922
|
return withConnection(context, new Callable<IRubyObject>() {
|
961
923
|
public IRubyObject call(final Connection connection) throws SQLException {
|
962
924
|
PreparedStatement statement = null;
|
963
925
|
final String query = sqlString(sql);
|
964
926
|
try {
|
965
|
-
if (pk == context.nil || pk == context.fals || !supportsGeneratedKeys(connection)) {
|
966
|
-
statement = connection.prepareStatement(query, Statement.RETURN_GENERATED_KEYS);
|
967
|
-
} else {
|
968
|
-
statement = connection.prepareStatement(query, createStatementPk(pk));
|
969
|
-
}
|
970
927
|
|
928
|
+
statement = connection.prepareStatement(query, Statement.RETURN_GENERATED_KEYS);
|
971
929
|
setStatementParameters(context, connection, statement, (RubyArray) binds);
|
972
930
|
statement.executeUpdate();
|
973
931
|
return mapGeneratedKeys(context, connection, statement);
|
@@ -982,12 +940,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
982
940
|
});
|
983
941
|
}
|
984
942
|
|
985
|
-
@Deprecated
|
986
|
-
@JRubyMethod(name = "execute_insert", required = 2)
|
987
|
-
public IRubyObject execute_insert(final ThreadContext context, final IRubyObject binds, final IRubyObject sql) {
|
988
|
-
return execute_insert_pk(context, sql, binds, context.nil);
|
989
|
-
}
|
990
|
-
|
991
943
|
/**
|
992
944
|
* Executes an UPDATE (DELETE) SQL statement
|
993
945
|
* @param context
|
@@ -2742,18 +2694,22 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2742
2694
|
|
2743
2695
|
final IRubyObject value = value_site.call(context, attribute, attribute);
|
2744
2696
|
|
2745
|
-
if (
|
2697
|
+
if (value instanceof RubyInteger) {
|
2746
2698
|
return "integer";
|
2747
2699
|
}
|
2748
2700
|
|
2749
|
-
if (
|
2701
|
+
if (value instanceof RubyNumeric) {
|
2750
2702
|
return "float";
|
2751
2703
|
}
|
2752
2704
|
|
2753
|
-
if (
|
2705
|
+
if (value instanceof RubyTime) {
|
2754
2706
|
return "timestamp";
|
2755
2707
|
}
|
2756
2708
|
|
2709
|
+
if (value instanceof RubyBoolean) {
|
2710
|
+
return "boolean";
|
2711
|
+
}
|
2712
|
+
|
2757
2713
|
return "string";
|
2758
2714
|
}
|
2759
2715
|
|
@@ -2943,9 +2899,8 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2943
2899
|
value = value.callMethod(context, "to_date");
|
2944
2900
|
}
|
2945
2901
|
|
2946
|
-
// NOTE:
|
2947
|
-
|
2948
|
-
statement.setDate(index, Date.valueOf(value.callMethod(context, "to_s", context.runtime.newSymbol("db")).toString()));
|
2902
|
+
// NOTE: assuming Date#to_s does right ...
|
2903
|
+
statement.setDate(index, Date.valueOf(value.toString()));
|
2949
2904
|
}
|
2950
2905
|
|
2951
2906
|
protected void setBooleanParameter(final ThreadContext context,
|
@@ -3972,12 +3927,6 @@ public class RubyJdbcConnection extends RubyObject {
|
|
3972
3927
|
}
|
3973
3928
|
}
|
3974
3929
|
|
3975
|
-
public static void debugMessage(final ThreadContext context, final IRubyObject obj) {
|
3976
|
-
if ( isDebug(context.runtime) ) {
|
3977
|
-
debugMessage(context.runtime, obj.callMethod(context, "inspect"));
|
3978
|
-
}
|
3979
|
-
}
|
3980
|
-
|
3981
3930
|
public static void debugMessage(final Ruby runtime, final String msg, final Object e) {
|
3982
3931
|
if ( isDebug(runtime) ) {
|
3983
3932
|
final PrintStream out = runtime != null ? runtime.getOut() : System.out;
|
@@ -29,33 +29,22 @@ import arjdbc.jdbc.Callable;
|
|
29
29
|
import arjdbc.jdbc.RubyJdbcConnection;
|
30
30
|
import arjdbc.util.DateTimeUtils;
|
31
31
|
|
32
|
-
import java.lang.reflect.InvocationTargetException;
|
33
|
-
import java.lang.reflect.Method;
|
34
32
|
import java.sql.Connection;
|
35
33
|
import java.sql.DatabaseMetaData;
|
36
|
-
import java.sql.Date;
|
37
34
|
import java.sql.PreparedStatement;
|
38
35
|
import java.sql.ResultSet;
|
39
36
|
import java.sql.Savepoint;
|
40
|
-
import java.sql.Statement;
|
41
37
|
import java.sql.SQLException;
|
42
|
-
import java.sql.Timestamp;
|
43
38
|
import java.sql.Types;
|
39
|
+
import java.sql.Timestamp;
|
44
40
|
import java.util.Locale;
|
45
|
-
import java.util.ArrayList;
|
46
|
-
import java.util.HashMap;
|
47
|
-
import java.util.List;
|
48
|
-
import java.util.Map;
|
49
41
|
|
50
|
-
import org.joda.time.DateTime;
|
51
|
-
import org.joda.time.DateTimeZone;
|
52
42
|
import org.jruby.Ruby;
|
53
43
|
import org.jruby.RubyArray;
|
54
44
|
import org.jruby.RubyBoolean;
|
55
45
|
import org.jruby.RubyClass;
|
56
46
|
import org.jruby.RubyString;
|
57
47
|
import org.jruby.RubySymbol;
|
58
|
-
import org.jruby.RubyTime;
|
59
48
|
import org.jruby.anno.JRubyMethod;
|
60
49
|
import org.jruby.runtime.ObjectAllocator;
|
61
50
|
import org.jruby.runtime.ThreadContext;
|
@@ -69,54 +58,6 @@ import org.jruby.util.ByteList;
|
|
69
58
|
public class MSSQLRubyJdbcConnection extends RubyJdbcConnection {
|
70
59
|
private static final long serialVersionUID = -745716565005219263L;
|
71
60
|
|
72
|
-
private static final int DATETIMEOFFSET_TYPE;
|
73
|
-
private static final Method DateTimeOffsetGetMinutesOffsetMethod;
|
74
|
-
private static final Method DateTimeOffsetGetTimestampMethod;
|
75
|
-
private static final Method DateTimeOffsetValueOfMethod;
|
76
|
-
private static final Method PreparedStatementSetDateTimeOffsetMethod;
|
77
|
-
|
78
|
-
private static final Map<String, Integer> MSSQL_JDBC_TYPE_FOR = new HashMap<String, Integer>(32, 1);
|
79
|
-
static {
|
80
|
-
|
81
|
-
Class<?> DateTimeOffset;
|
82
|
-
Class<?> MssqlPreparedStatement;
|
83
|
-
Class<?> MssqlTypes;
|
84
|
-
try {
|
85
|
-
DateTimeOffset = Class.forName("microsoft.sql.DateTimeOffset");
|
86
|
-
MssqlPreparedStatement = Class.forName("com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement");
|
87
|
-
MssqlTypes = Class.forName("microsoft.sql.Types");
|
88
|
-
} catch (ClassNotFoundException e) {
|
89
|
-
System.err.println("You must require the Microsoft JDBC driver to use this gem"); // The exception doesn't bubble when ruby is initializing
|
90
|
-
throw new RuntimeException("You must require the Microsoft JDBC driver to use this gem");
|
91
|
-
}
|
92
|
-
|
93
|
-
try {
|
94
|
-
DATETIMEOFFSET_TYPE = MssqlTypes.getField("DATETIMEOFFSET").getInt(null);
|
95
|
-
DateTimeOffsetGetMinutesOffsetMethod = DateTimeOffset.getDeclaredMethod("getMinutesOffset");
|
96
|
-
DateTimeOffsetGetTimestampMethod = DateTimeOffset.getDeclaredMethod("getTimestamp");
|
97
|
-
|
98
|
-
Class<?>[] valueOfArgTypes = { Timestamp.class, int.class };
|
99
|
-
DateTimeOffsetValueOfMethod = DateTimeOffset.getDeclaredMethod("valueOf", valueOfArgTypes);
|
100
|
-
|
101
|
-
Class<?>[] setOffsetArgTypes = { int.class, DateTimeOffset };
|
102
|
-
PreparedStatementSetDateTimeOffsetMethod = MssqlPreparedStatement.getDeclaredMethod("setDateTimeOffset", setOffsetArgTypes);
|
103
|
-
} catch (Exception e) {
|
104
|
-
System.err.println("You must require the Microsoft JDBC driver to use this gem"); // The exception doesn't bubble when ruby is initializing
|
105
|
-
throw new RuntimeException("Please make sure you are using the latest version of the Microsoft JDBC driver");
|
106
|
-
}
|
107
|
-
|
108
|
-
MSSQL_JDBC_TYPE_FOR.put("binary_basic", Types.BINARY);
|
109
|
-
MSSQL_JDBC_TYPE_FOR.put("image", Types.BINARY);
|
110
|
-
MSSQL_JDBC_TYPE_FOR.put("datetimeoffset", DATETIMEOFFSET_TYPE);
|
111
|
-
MSSQL_JDBC_TYPE_FOR.put("money", Types.DECIMAL);
|
112
|
-
MSSQL_JDBC_TYPE_FOR.put("smalldatetime", Types.TIMESTAMP);
|
113
|
-
MSSQL_JDBC_TYPE_FOR.put("smallmoney", Types.DECIMAL);
|
114
|
-
MSSQL_JDBC_TYPE_FOR.put("ss_timestamp", Types.BINARY);
|
115
|
-
MSSQL_JDBC_TYPE_FOR.put("text_basic", Types.LONGVARCHAR);
|
116
|
-
MSSQL_JDBC_TYPE_FOR.put("uuid", Types.CHAR);
|
117
|
-
MSSQL_JDBC_TYPE_FOR.put("varchar_max", Types.VARCHAR);
|
118
|
-
}
|
119
|
-
|
120
61
|
public MSSQLRubyJdbcConnection(Ruby runtime, RubyClass metaClass) {
|
121
62
|
super(runtime, metaClass);
|
122
63
|
}
|
@@ -148,176 +89,6 @@ public class MSSQLRubyJdbcConnection extends RubyJdbcConnection {
|
|
148
89
|
return context.runtime.newBoolean( startsWithIgnoreCase(sqlBytes, EXEC) );
|
149
90
|
}
|
150
91
|
|
151
|
-
// Support multiple result sets for mssql
|
152
|
-
@Override
|
153
|
-
@JRubyMethod(name = "execute", required = 1)
|
154
|
-
public IRubyObject execute(final ThreadContext context, final IRubyObject sql) {
|
155
|
-
final String query = sqlString(sql);
|
156
|
-
return withConnection(context, new Callable<IRubyObject>() {
|
157
|
-
public IRubyObject call(final Connection connection) throws SQLException {
|
158
|
-
Statement statement = null;
|
159
|
-
try {
|
160
|
-
statement = createStatement(context, connection);
|
161
|
-
|
162
|
-
// For DBs that do support multiple statements, lets return the last result set
|
163
|
-
// to be consistent with AR
|
164
|
-
boolean hasResultSet = doExecute(statement, query);
|
165
|
-
int updateCount = statement.getUpdateCount();
|
166
|
-
|
167
|
-
final List<IRubyObject> results = new ArrayList<IRubyObject>();
|
168
|
-
ResultSet resultSet;
|
169
|
-
|
170
|
-
while (hasResultSet || updateCount != -1) {
|
171
|
-
|
172
|
-
if (hasResultSet) {
|
173
|
-
resultSet = statement.getResultSet();
|
174
|
-
|
175
|
-
// Unfortunately the result set gets closed when getMoreResults()
|
176
|
-
// is called, so we have to process the result sets as we get them
|
177
|
-
// this shouldn't be an issue in most cases since we're only getting 1 result set anyways
|
178
|
-
results.add(mapExecuteResult(context, connection, resultSet));
|
179
|
-
} else {
|
180
|
-
results.add(context.runtime.newFixnum(updateCount));
|
181
|
-
}
|
182
|
-
|
183
|
-
// Check to see if there is another result set
|
184
|
-
hasResultSet = statement.getMoreResults();
|
185
|
-
updateCount = statement.getUpdateCount();
|
186
|
-
}
|
187
|
-
|
188
|
-
if (results.size() == 0) {
|
189
|
-
return context.nil; // If no results, return nil
|
190
|
-
} else if (results.size() == 1) {
|
191
|
-
return results.get(0);
|
192
|
-
} else {
|
193
|
-
return context.runtime.newArray(results);
|
194
|
-
}
|
195
|
-
|
196
|
-
} catch (final SQLException e) {
|
197
|
-
debugErrorSQL(context, query);
|
198
|
-
throw e;
|
199
|
-
} finally {
|
200
|
-
close(statement);
|
201
|
-
}
|
202
|
-
}
|
203
|
-
});
|
204
|
-
}
|
205
|
-
|
206
|
-
/**
|
207
|
-
* Executes an INSERT SQL statement
|
208
|
-
* @param context
|
209
|
-
* @param sql
|
210
|
-
* @param pk Rails PK
|
211
|
-
* @return ActiveRecord::Result
|
212
|
-
* @throws SQLException
|
213
|
-
*/
|
214
|
-
@Override
|
215
|
-
@JRubyMethod(name = "execute_insert_pk", required = 2)
|
216
|
-
public IRubyObject execute_insert_pk(final ThreadContext context, final IRubyObject sql, final IRubyObject pk) {
|
217
|
-
|
218
|
-
// MSSQL does not like composite primary keys here so chop it if there is more than one column
|
219
|
-
IRubyObject modifiedPk = pk;
|
220
|
-
|
221
|
-
if (pk instanceof RubyArray) {
|
222
|
-
RubyArray ary = (RubyArray) pk;
|
223
|
-
if (ary.size() > 0) {
|
224
|
-
modifiedPk = ary.eltInternal(0);
|
225
|
-
}
|
226
|
-
}
|
227
|
-
|
228
|
-
return super.execute_insert_pk(context, sql, modifiedPk);
|
229
|
-
}
|
230
|
-
|
231
|
-
/**
|
232
|
-
* Executes an INSERT SQL statement using a prepared statement
|
233
|
-
* @param context
|
234
|
-
* @param sql
|
235
|
-
* @param binds RubyArray of values to be bound to the query
|
236
|
-
* @param pk Rails PK
|
237
|
-
* @return ActiveRecord::Result
|
238
|
-
* @throws SQLException
|
239
|
-
*/
|
240
|
-
@Override
|
241
|
-
@JRubyMethod(name = "execute_insert_pk", required = 3)
|
242
|
-
public IRubyObject execute_insert_pk(final ThreadContext context, final IRubyObject sql, final IRubyObject binds,
|
243
|
-
final IRubyObject pk) {
|
244
|
-
// MSSQL does not like composite primary keys here so chop it if there is more than one column
|
245
|
-
IRubyObject modifiedPk = pk;
|
246
|
-
|
247
|
-
if (pk instanceof RubyArray) {
|
248
|
-
RubyArray ary = (RubyArray) pk;
|
249
|
-
if (ary.size() > 0) {
|
250
|
-
modifiedPk = ary.eltInternal(0);
|
251
|
-
}
|
252
|
-
}
|
253
|
-
|
254
|
-
return super.execute_insert_pk(context, sql, binds, modifiedPk);
|
255
|
-
}
|
256
|
-
|
257
|
-
@Override
|
258
|
-
protected Integer jdbcTypeFor(final String type) {
|
259
|
-
|
260
|
-
Integer typeValue = MSSQL_JDBC_TYPE_FOR.get(type);
|
261
|
-
|
262
|
-
if ( typeValue != null ) {
|
263
|
-
return typeValue;
|
264
|
-
}
|
265
|
-
|
266
|
-
return super.jdbcTypeFor(type);
|
267
|
-
}
|
268
|
-
|
269
|
-
// Datetimeoffset values also make it into here
|
270
|
-
@Override
|
271
|
-
protected void setStringParameter(final ThreadContext context, final Connection connection,
|
272
|
-
final PreparedStatement statement, final int index, final IRubyObject value,
|
273
|
-
final IRubyObject attribute, final int type) throws SQLException {
|
274
|
-
|
275
|
-
// datetimeoffset values also make it in here
|
276
|
-
if (type == DATETIMEOFFSET_TYPE) {
|
277
|
-
|
278
|
-
Object dto = convertToDateTimeOffset(context, value);
|
279
|
-
|
280
|
-
try {
|
281
|
-
|
282
|
-
Object[] setStatementArgs = { index, dto };
|
283
|
-
PreparedStatementSetDateTimeOffsetMethod.invoke(statement, setStatementArgs);
|
284
|
-
|
285
|
-
} catch (IllegalAccessException e) {
|
286
|
-
debugMessage(context.runtime, e.getMessage());
|
287
|
-
throw new RuntimeException("Please make sure you are using the latest version of the Microsoft JDBC driver");
|
288
|
-
} catch (InvocationTargetException e) {
|
289
|
-
debugMessage(context.runtime, e.getMessage());
|
290
|
-
throw new RuntimeException("Please make sure you are using the latest version of the Microsoft JDBC driver");
|
291
|
-
}
|
292
|
-
|
293
|
-
return;
|
294
|
-
}
|
295
|
-
super.setStringParameter(context, connection, statement, index, value, attribute, type);
|
296
|
-
}
|
297
|
-
|
298
|
-
private Object convertToDateTimeOffset(final ThreadContext context, final IRubyObject value) {
|
299
|
-
|
300
|
-
RubyTime time = (RubyTime) value;
|
301
|
-
DateTime dt = time.getDateTime();
|
302
|
-
Timestamp timestamp = new Timestamp(dt.getMillis());
|
303
|
-
timestamp.setNanos(timestamp.getNanos() + (int) time.getNSec());
|
304
|
-
int offsetMinutes = dt.getZone().getOffset(dt.getMillis()) / 60000;
|
305
|
-
|
306
|
-
try {
|
307
|
-
|
308
|
-
Object[] dtoArgs = { timestamp, offsetMinutes };
|
309
|
-
return DateTimeOffsetValueOfMethod.invoke(null, dtoArgs);
|
310
|
-
|
311
|
-
} catch (IllegalAccessException e) {
|
312
|
-
debugMessage(context.runtime, e.getMessage());
|
313
|
-
throw new RuntimeException("Please make sure you are using the latest version of the Microsoft JDBC driver");
|
314
|
-
} catch (InvocationTargetException e) {
|
315
|
-
debugMessage(context.runtime, e.getMessage());
|
316
|
-
throw new RuntimeException("Please make sure you are using the latest version of the Microsoft JDBC driver");
|
317
|
-
}
|
318
|
-
}
|
319
|
-
|
320
|
-
|
321
92
|
@Override
|
322
93
|
protected RubyArray mapTables(final ThreadContext context, final Connection connection,
|
323
94
|
final String catalog, final String schemaPattern, final String tablePattern,
|
@@ -534,6 +305,29 @@ public class MSSQLRubyJdbcConnection extends RubyJdbcConnection {
|
|
534
305
|
statement.setObject(index, timeStr, Types.NVARCHAR);
|
535
306
|
}
|
536
307
|
|
308
|
+
// Overrides the method in parent, we only remove the savepoint
|
309
|
+
// from the getSavepoints Map
|
310
|
+
@JRubyMethod(name = "release_savepoint", required = 1)
|
311
|
+
public IRubyObject release_savepoint(final ThreadContext context, final IRubyObject name) {
|
312
|
+
if (name == context.nil) throw context.runtime.newArgumentError("nil savepoint name given");
|
313
|
+
|
314
|
+
final Connection connection = getConnection(true);
|
315
|
+
|
316
|
+
Object savepoint = getSavepoints(context).remove(name);
|
317
|
+
|
318
|
+
if (savepoint == null) throw newSavepointNotSetError(context, name, "release");
|
319
|
+
|
320
|
+
// NOTE: RubyHash.remove does not convert to Java as get does :
|
321
|
+
if (!(savepoint instanceof Savepoint)) {
|
322
|
+
savepoint = ((IRubyObject) savepoint).toJava(Savepoint.class);
|
323
|
+
}
|
324
|
+
|
325
|
+
// The 'releaseSavepoint' method is not currently supported
|
326
|
+
// by the Microsoft SQL Server JDBC Driver
|
327
|
+
// connection.releaseSavepoint((Savepoint) savepoint);
|
328
|
+
return context.nil;
|
329
|
+
}
|
330
|
+
|
537
331
|
//----------------------------------------------------------------
|
538
332
|
// read_uncommitted: "READ UNCOMMITTED",
|
539
333
|
// read_committed: "READ COMMITTED",
|
@@ -659,64 +453,16 @@ public class MSSQLRubyJdbcConnection extends RubyJdbcConnection {
|
|
659
453
|
|
660
454
|
/**
|
661
455
|
* Treat LONGVARCHAR as CLOB on MSSQL for purposes of converting a JDBC value to Ruby.
|
662
|
-
* Also handle datetimeoffset values here
|
663
456
|
*/
|
664
457
|
@Override
|
665
458
|
protected IRubyObject jdbcToRuby(
|
666
459
|
final ThreadContext context, final Ruby runtime,
|
667
460
|
final int column, int type, final ResultSet resultSet)
|
668
461
|
throws SQLException {
|
669
|
-
|
670
|
-
if (type == DATETIMEOFFSET_TYPE) {
|
671
|
-
|
672
|
-
Object dto = resultSet.getObject(column); // Returns a microsoft.sql.DateTimeOffset
|
673
|
-
|
674
|
-
if (dto == null) return context.nil;
|
675
|
-
|
676
|
-
try {
|
677
|
-
|
678
|
-
int minutes = (int) DateTimeOffsetGetMinutesOffsetMethod.invoke(dto);
|
679
|
-
DateTimeZone zone = DateTimeZone.forOffsetHoursMinutes(minutes / 60, minutes % 60);
|
680
|
-
Timestamp ts = (Timestamp) DateTimeOffsetGetTimestampMethod.invoke(dto);
|
681
|
-
|
682
|
-
int nanos = ts.getNanos(); // max 999-999-999
|
683
|
-
nanos = nanos % 1000000;
|
684
|
-
|
685
|
-
// We have to do this differently than the newTime helper because the Timestamp loses its zone information when passed around
|
686
|
-
DateTime dateTime = new DateTime(ts.getTime(), zone);
|
687
|
-
return RubyTime.newTime(context.runtime, dateTime, nanos);
|
688
|
-
|
689
|
-
} catch (IllegalAccessException e) {
|
690
|
-
debugMessage(runtime, e.getMessage());
|
691
|
-
return context.nil;
|
692
|
-
} catch (InvocationTargetException e) {
|
693
|
-
debugMessage(runtime, e.getMessage());
|
694
|
-
return context.nil;
|
695
|
-
}
|
696
|
-
}
|
697
|
-
|
698
|
-
if (type == Types.LONGVARCHAR || type == Types.LONGNVARCHAR) type = Types.CLOB;
|
462
|
+
if ( type == Types.LONGVARCHAR || type == Types.LONGNVARCHAR ) type = Types.CLOB;
|
699
463
|
return super.jdbcToRuby(context, runtime, column, type, resultSet);
|
700
464
|
}
|
701
465
|
|
702
|
-
/**
|
703
|
-
* Converts a JDBC date object to a Ruby date by referencing Date#civil
|
704
|
-
* @param context current thread context
|
705
|
-
* @param resultSet the jdbc result set to pull the value from
|
706
|
-
* @param index the index of the column to convert
|
707
|
-
* @return RubyNil if NULL or RubyDate if there is a value
|
708
|
-
* @throws SQLException if it fails to retrieve the value from the result set
|
709
|
-
*/
|
710
|
-
@Override
|
711
|
-
protected IRubyObject dateToRuby(ThreadContext context, Ruby runtime, ResultSet resultSet, int index) throws SQLException {
|
712
|
-
|
713
|
-
final Date value = resultSet.getDate(index);
|
714
|
-
|
715
|
-
if (value == null) return context.nil;
|
716
|
-
|
717
|
-
return DateTimeUtils.newDate(context, value);
|
718
|
-
}
|
719
|
-
|
720
466
|
@Override
|
721
467
|
protected ColumnData[] extractColumns(final ThreadContext context,
|
722
468
|
final Connection connection, final ResultSet resultSet,
|
@@ -746,9 +492,19 @@ public class MSSQLRubyJdbcConnection extends RubyJdbcConnection {
|
|
746
492
|
return columns;
|
747
493
|
}
|
748
494
|
|
749
|
-
|
750
|
-
|
751
|
-
|
495
|
+
// internal helper not meant as a "public" API - used in one place thus every
|
496
|
+
@JRubyMethod(name = "jtds_driver?")
|
497
|
+
public RubyBoolean jtds_driver_p(final ThreadContext context) throws SQLException {
|
498
|
+
// "jTDS Type 4 JDBC Driver for MS SQL Server and Sybase"
|
499
|
+
// SQLJDBC: "Microsoft JDBC Driver 4.0 for SQL Server"
|
500
|
+
return withConnection(context, new Callable<RubyBoolean>() {
|
501
|
+
// NOTE: only used in one place for now (on release_savepoint) ...
|
502
|
+
// might get optimized to only happen once since driver won't change
|
503
|
+
public RubyBoolean call(final Connection connection) throws SQLException {
|
504
|
+
final String driver = connection.getMetaData().getDriverName();
|
505
|
+
return context.getRuntime().newBoolean( driver.indexOf("jTDS") >= 0 );
|
506
|
+
}
|
507
|
+
});
|
752
508
|
}
|
753
509
|
|
754
510
|
}
|
@@ -27,6 +27,7 @@ package arjdbc.postgresql;
|
|
27
27
|
|
28
28
|
import arjdbc.jdbc.Callable;
|
29
29
|
import arjdbc.jdbc.DriverWrapper;
|
30
|
+
import arjdbc.postgresql.PostgreSQLResult;
|
30
31
|
import arjdbc.util.DateTimeUtils;
|
31
32
|
import arjdbc.util.StringHelper;
|
32
33
|
|
@@ -366,9 +367,8 @@ public class PostgreSQLRubyJdbcConnection extends arjdbc.jdbc.RubyJdbcConnection
|
|
366
367
|
value = value.callMethod(context, "to_date");
|
367
368
|
}
|
368
369
|
|
369
|
-
// NOTE:
|
370
|
-
|
371
|
-
statement.setDate(index, Date.valueOf(value.callMethod(context, "to_s", context.runtime.newSymbol("db")).toString()));
|
370
|
+
// NOTE: assuming Date#to_s does right ...
|
371
|
+
statement.setDate(index, Date.valueOf(value.toString()));
|
372
372
|
}
|
373
373
|
|
374
374
|
@Override
|
@@ -31,7 +31,6 @@ import java.util.TimeZone;
|
|
31
31
|
import org.joda.time.Chronology;
|
32
32
|
import org.joda.time.DateTime;
|
33
33
|
import org.joda.time.DateTimeZone;
|
34
|
-
import org.joda.time.chrono.GJChronology;
|
35
34
|
import org.joda.time.chrono.ISOChronology;
|
36
35
|
import org.jruby.Ruby;
|
37
36
|
import org.jruby.RubyFloat;
|
@@ -51,9 +50,6 @@ import static arjdbc.util.StringHelper.decByte;
|
|
51
50
|
* @author kares
|
52
51
|
*/
|
53
52
|
public abstract class DateTimeUtils {
|
54
|
-
|
55
|
-
private static final GJChronology CHRONO_ITALY_UTC = GJChronology.getInstance(DateTimeZone.UTC);
|
56
|
-
|
57
53
|
public static RubyTime toTime(final ThreadContext context, final IRubyObject value) {
|
58
54
|
if (!(value instanceof RubyTime)) { // unlikely
|
59
55
|
return (RubyTime) TypeConverter.convertToTypeWithCheck(value, context.runtime.getTime(), "to_time");
|
@@ -221,11 +217,9 @@ public abstract class DateTimeUtils {
|
|
221
217
|
final int hours = time.getHours();
|
222
218
|
final int minutes = time.getMinutes();
|
223
219
|
final int seconds = time.getSeconds();
|
224
|
-
int nanos = time.getNanos(); // max 999-999-999
|
225
|
-
final int millis = nanos / 1000000;
|
226
|
-
nanos = nanos % 1000000;
|
220
|
+
final int nanos = time.getNanos(); // max 999-999-999
|
227
221
|
|
228
|
-
DateTime dateTime = new DateTime(2000, 1, 1, hours, minutes, seconds,
|
222
|
+
DateTime dateTime = new DateTime(2000, 1, 1, hours, minutes, seconds, defaultZone);
|
229
223
|
return RubyTime.newTime(context.runtime, dateTime, nanos);
|
230
224
|
}
|
231
225
|
|
@@ -238,11 +232,9 @@ public abstract class DateTimeUtils {
|
|
238
232
|
final int hours = timestamp.getHours();
|
239
233
|
final int minutes = timestamp.getMinutes();
|
240
234
|
final int seconds = timestamp.getSeconds();
|
241
|
-
int nanos = timestamp.getNanos(); // max 999-999-999
|
242
|
-
final int millis = nanos / 1000000;
|
243
|
-
nanos = nanos % 1000000;
|
235
|
+
final int nanos = timestamp.getNanos(); // max 999-999-999
|
244
236
|
|
245
|
-
DateTime dateTime = new DateTime(year, month, day, hours, minutes, seconds,
|
237
|
+
DateTime dateTime = new DateTime(year, month, day, hours, minutes, seconds, 0, defaultZone);
|
246
238
|
return RubyTime.newTime(context.runtime, dateTime, nanos);
|
247
239
|
}
|
248
240
|
|
@@ -267,15 +259,6 @@ public abstract class DateTimeUtils {
|
|
267
259
|
return newDate(context, year, month, day, ISOChronology.getInstance(zone));
|
268
260
|
}
|
269
261
|
|
270
|
-
@SuppressWarnings("deprecation")
|
271
|
-
public static IRubyObject newDate(final ThreadContext context, final Date date) {
|
272
|
-
final int year = date.getYear() + 1900;
|
273
|
-
final int month = date.getMonth() + 1;
|
274
|
-
final int day = date.getDate();
|
275
|
-
|
276
|
-
return newDate(context, year, month, day, CHRONO_ITALY_UTC);
|
277
|
-
}
|
278
|
-
|
279
262
|
// @Deprecated
|
280
263
|
public static Timestamp convertToTimestamp(final RubyFloat value) {
|
281
264
|
final Timestamp timestamp = new Timestamp(value.getLongValue() * 1000); // millis
|
@@ -570,7 +553,7 @@ public abstract class DateTimeUtils {
|
|
570
553
|
}
|
571
554
|
|
572
555
|
private static IRubyObject newDate(final ThreadContext context, final int year, final int month, final int day,
|
573
|
-
final
|
556
|
+
final ISOChronology chronology) {
|
574
557
|
// NOTE: JRuby really needs a native date.rb until than its a bit costly going from ...
|
575
558
|
// java.sql.Date -> allocating a DateTime proxy, help a bit by shooting at the internals
|
576
559
|
//
|