activerecord-jdbc-alt-adapter 50.7.0-java → 51.3.0-java
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
//
|