activerecord-jdbc-adapter 50.2-java → 50.3-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.
@@ -68,7 +68,6 @@ final class DataSourceConnectionFactory implements ConnectionFactory {
68
68
 
69
69
  @Override
70
70
  public Connection newConnection() throws SQLException {
71
- DataSource dataSource = this.dataSource;
72
71
  // in case DS failed previously look it up again from JNDI :
73
72
  if (dataSource == null) {
74
73
  lookupDataSource();
@@ -0,0 +1,61 @@
1
+ /***** BEGIN LICENSE BLOCK *****
2
+ * Copyright (c) 2012-2014 Karol Bucek <self@kares.org>
3
+ * Copyright (c) 2006-2010 Nick Sieger <nick@nicksieger.com>
4
+ * Copyright (c) 2006-2007 Ola Bini <ola.bini@gmail.com>
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining
7
+ * a copy of this software and associated documentation files (the
8
+ * "Software"), to deal in the Software without restriction, including
9
+ * without limitation the rights to use, copy, modify, merge, publish,
10
+ * distribute, sublicense, and/or sell copies of the Software, and to
11
+ * permit persons to whom the Software is furnished to do so, subject to
12
+ * the following conditions:
13
+ *
14
+ * The above copyright notice and this permission notice shall be
15
+ * included in all copies or substantial portions of the Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
+ ***** END LICENSE BLOCK *****/
25
+
26
+ package arjdbc.jdbc;
27
+
28
+ import java.sql.Connection;
29
+ import java.sql.SQLException;
30
+
31
+ import org.jruby.RubyObject;
32
+ import org.jruby.RubyString;
33
+ import org.jruby.runtime.ThreadContext;
34
+ import org.jruby.runtime.builtin.IRubyObject;
35
+
36
+ // @legacy ActiveRecord::ConnectionAdapters::JdbcDriver
37
+ class RubyConnectionFactory implements ConnectionFactory {
38
+
39
+ private final IRubyObject driver;
40
+ final RubyString url;
41
+ final IRubyObject username, password; // null allowed
42
+
43
+ private final RubyObject contextProvider;
44
+
45
+ public RubyConnectionFactory(final IRubyObject driver, final RubyString url,
46
+ final IRubyObject username, final IRubyObject password) {
47
+ this.driver = driver; this.url = url;
48
+ this.username = username; this.password = password;
49
+ contextProvider = (RubyObject) driver;
50
+ }
51
+
52
+ @Override
53
+ public Connection newConnection() throws SQLException {
54
+ final ThreadContext context = contextProvider.getRuntime().getCurrentContext();
55
+ final IRubyObject connection = driver.callMethod(context, "connection", new IRubyObject[] { url, username, password });
56
+ return (Connection) connection.toJava(Connection.class);
57
+ }
58
+
59
+ IRubyObject getDriver() { return driver; } /* for tests */
60
+
61
+ }
@@ -128,6 +128,7 @@ public class RubyJdbcConnection extends RubyObject {
128
128
  private boolean lazy = false; // final once set on initialize
129
129
  private boolean jndi; // final once set on initialize
130
130
  private boolean configureConnection = true; // final once initialized
131
+ private int fetchSize = 0; // 0 = JDBC default
131
132
 
132
133
  protected RubyJdbcConnection(Ruby runtime, RubyClass metaClass) {
133
134
  super(runtime, metaClass);
@@ -571,6 +572,11 @@ public class RubyJdbcConnection extends RubyObject {
571
572
  else {
572
573
  this.configureConnection = value != context.runtime.getFalse();
573
574
  }
575
+
576
+ IRubyObject jdbcFetchSize = getConfigValue(context, "jdbc_fetch_size");
577
+ if (jdbcFetchSize != context.nil) {
578
+ this.fetchSize = RubyNumeric.fix2int(jdbcFetchSize);
579
+ }
574
580
  }
575
581
 
576
582
  @JRubyMethod(name = "adapter")
@@ -818,6 +824,7 @@ public class RubyJdbcConnection extends RubyObject {
818
824
  // is called, so we have to process the result sets as we get them
819
825
  // this shouldn't be an issue in most cases since we're only getting 1 result set anyways
820
826
  result = mapExecuteResult(context, connection, resultSet);
827
+ resultSet.close();
821
828
  } else {
822
829
  result = context.runtime.newFixnum(updateCount);
823
830
  }
@@ -851,6 +858,7 @@ public class RubyJdbcConnection extends RubyObject {
851
858
  else {
852
859
  statement.setEscapeProcessing(escapeProcessing.isTrue());
853
860
  }
861
+ if (fetchSize != 0) statement.setFetchSize(fetchSize);
854
862
  return statement;
855
863
  }
856
864
 
@@ -1045,6 +1053,7 @@ public class RubyJdbcConnection extends RubyObject {
1045
1053
  else {
1046
1054
  final PreparedStatement prepStatement;
1047
1055
  statement = prepStatement = connection.prepareStatement(query);
1056
+ if (fetchSize != 0) statement.setFetchSize(fetchSize);
1048
1057
  statement.setMaxRows(maxRows); // zero means there is no limit
1049
1058
  setStatementParameters(context, connection, prepStatement, binds);
1050
1059
  hasResult = prepStatement.execute();
@@ -1112,6 +1121,24 @@ public class RubyJdbcConnection extends RubyObject {
1112
1121
  });
1113
1122
  }
1114
1123
 
1124
+ /**
1125
+ * Prepares a query, returns a wrapped PreparedStatement. This takes care of exception wrapping
1126
+ * @param context which context this method is executing on.
1127
+ * @param sql the query to prepare-
1128
+ * @return a Ruby <code>PreparedStatement</code>
1129
+ */
1130
+ @JRubyMethod(required = 1)
1131
+ public IRubyObject prepare_statement(final ThreadContext context, final IRubyObject sql) {
1132
+ return withConnection(context, new Callable<IRubyObject>() {
1133
+ public IRubyObject call(Connection connection) throws SQLException {
1134
+ final String query = sql.convertToString().getUnicodeValue();
1135
+ PreparedStatement statement = connection.prepareStatement(query);
1136
+ if (fetchSize != 0) statement.setFetchSize(fetchSize);
1137
+ return JavaUtil.convertJavaToRuby(context.runtime, statement);
1138
+ }
1139
+ });
1140
+ }
1141
+
1115
1142
  // Called from exec_query in abstract/database_statements
1116
1143
  /**
1117
1144
  * Executes a query and returns the (AR) result. There are three parameters:
@@ -1142,6 +1169,7 @@ public class RubyJdbcConnection extends RubyObject {
1142
1169
  statement = (PreparedStatement) JavaEmbedUtils.rubyToJava(cachedStatement);
1143
1170
  } else {
1144
1171
  statement = connection.prepareStatement(query);
1172
+ if (fetchSize != 0) statement.setFetchSize(fetchSize);
1145
1173
  }
1146
1174
 
1147
1175
  setStatementParameters(context, connection, statement, (RubyArray) binds);
@@ -1149,12 +1177,7 @@ public class RubyJdbcConnection extends RubyObject {
1149
1177
  if (statement.execute()) {
1150
1178
  ResultSet resultSet = statement.getResultSet();
1151
1179
  IRubyObject results = mapQueryResult(context, connection, resultSet);
1152
-
1153
- if (cached) {
1154
- // Make sure we free the result set if we are caching the statement
1155
- // It gets closed automatically when the statement is closed if we aren't caching
1156
- resultSet.close();
1157
- }
1180
+ resultSet.close();
1158
1181
 
1159
1182
  return results;
1160
1183
  } else {
@@ -1807,7 +1830,7 @@ public class RubyJdbcConnection extends RubyObject {
1807
1830
  if ( url.isNil() || ( driver.isNil() && driver_instance.isNil() ) ) {
1808
1831
  final Ruby runtime = context.runtime;
1809
1832
  final RubyClass errorClass = getConnectionNotEstablished( runtime );
1810
- throw new RaiseException(runtime, errorClass, "adapter requires :driver class and jdbc :url", false);
1833
+ throw runtime.newRaiseException(errorClass, "adapter requires :driver class and jdbc :url");
1811
1834
  }
1812
1835
 
1813
1836
  final String jdbcURL = buildURL(context, url);
@@ -1824,7 +1847,7 @@ public class RubyJdbcConnection extends RubyObject {
1824
1847
  return factory;
1825
1848
  }
1826
1849
  else {
1827
- setConnectionFactory(factory = new RubyConnectionFactoryImpl(
1850
+ setConnectionFactory(factory = new RubyConnectionFactory(
1828
1851
  driver_instance, context.runtime.newString(jdbcURL),
1829
1852
  ( username.isNil() ? username : username.asString() ),
1830
1853
  ( password.isNil() ? password : password.asString() )
@@ -2485,6 +2508,8 @@ public class RubyJdbcConnection extends RubyObject {
2485
2508
  while ( arrayResult.next() ) {
2486
2509
  array.append( jdbcToRuby(context, runtime, 2, baseType, arrayResult) );
2487
2510
  }
2511
+ arrayResult.close();
2512
+
2488
2513
  return array;
2489
2514
  }
2490
2515
  finally { if ( value != null ) value.free(); }
@@ -2683,7 +2708,7 @@ public class RubyJdbcConnection extends RubyObject {
2683
2708
  }
2684
2709
 
2685
2710
  protected final RubyTime timeInDefaultTimeZone(final ThreadContext context, final IRubyObject value) {
2686
- return timeInDefaultTimeZone(context, toTime(context, value));
2711
+ return timeInDefaultTimeZone(context, DateTimeUtils.toTime(context, value));
2687
2712
  }
2688
2713
 
2689
2714
  protected final RubyTime timeInDefaultTimeZone(final ThreadContext context, final RubyTime time) {
@@ -2695,11 +2720,14 @@ public class RubyJdbcConnection extends RubyObject {
2695
2720
  return timeInDefaultTZ;
2696
2721
  }
2697
2722
 
2723
+ protected final DateTime dateTimeInDefaultTimeZone(final ThreadContext context, final DateTime dateTime) {
2724
+ final DateTimeZone defaultZone = getDefaultTimeZone(context);
2725
+ if (defaultZone == dateTime.getZone()) return dateTime;
2726
+ return dateTime.withZone(defaultZone);
2727
+ }
2728
+
2698
2729
  public static RubyTime toTime(final ThreadContext context, final IRubyObject value) {
2699
- if ( ! ( value instanceof RubyTime ) ) { // unlikely
2700
- return (RubyTime) TypeConverter.convertToTypeWithCheck(value, context.runtime.getTime(), "to_time");
2701
- }
2702
- return (RubyTime) value;
2730
+ return DateTimeUtils.toTime(context, value);
2703
2731
  }
2704
2732
 
2705
2733
  protected boolean isDefaultTimeZoneUTC(final ThreadContext context) {
@@ -2799,8 +2827,8 @@ public class RubyJdbcConnection extends RubyObject {
2799
2827
  final int index, IRubyObject value,
2800
2828
  final IRubyObject attribute, final int type) throws SQLException {
2801
2829
 
2802
- final RubyTime timeValue = timeInDefaultTimeZone(context, value);
2803
- final DateTime dateTime = timeValue.getDateTime();
2830
+ final RubyTime timeValue = DateTimeUtils.toTime(context, value);
2831
+ final DateTime dateTime = dateTimeInDefaultTimeZone(context, timeValue.getDateTime());
2804
2832
  final Timestamp timestamp = new Timestamp(dateTime.getMillis());
2805
2833
  // 1942-11-30T01:02:03.123_456
2806
2834
  if (timeValue.getNSec() > 0) timestamp.setNanos((int) (timestamp.getNanos() + timeValue.getNSec()));
@@ -2894,7 +2922,7 @@ public class RubyJdbcConnection extends RubyObject {
2894
2922
  final RubySymbol type = (RubySymbol) attributeSQLType(context, attribute);
2895
2923
 
2896
2924
  // For some reason the driver doesn't like "character varying" as a type
2897
- if ( type.eql(context.runtime.newSymbol("string")) ) return "text";
2925
+ if ( type.eql(context.runtime.newSymbol("string")) ) return "varchar";
2898
2926
 
2899
2927
  final RubyHash nativeTypes = (RubyHash) getAdapter().callMethod(context, "native_database_types");
2900
2928
  // e.g. `integer: { name: 'integer' }`
@@ -3001,7 +3029,7 @@ public class RubyJdbcConnection extends RubyObject {
3001
3029
  private void handleNotConnected() {
3002
3030
  final Ruby runtime = getRuntime();
3003
3031
  final RubyClass errorClass = getConnectionNotEstablished( runtime );
3004
- throw new RaiseException(runtime, errorClass, "no connection available", false);
3032
+ throw runtime.newRaiseException(errorClass, "no connection available");
3005
3033
  }
3006
3034
 
3007
3035
  /**
@@ -3538,7 +3566,7 @@ public class RubyJdbcConnection extends RubyObject {
3538
3566
  return (RaiseException) exception;
3539
3567
  }
3540
3568
  if ( exception instanceof RuntimeException ) {
3541
- return RaiseException.createNativeRaiseException(runtime, exception);
3569
+ return wrapException(context, context.runtime.getRuntimeError(), exception);
3542
3570
  }
3543
3571
  // NOTE: compat - maybe makes sense or maybe not (e.g. IOException) :
3544
3572
  return wrapException(context, getJDBCError(runtime), exception);
@@ -3551,7 +3579,7 @@ public class RubyJdbcConnection extends RubyObject {
3551
3579
 
3552
3580
  public static RaiseException wrapException(final ThreadContext context,
3553
3581
  final RubyClass errorClass, final Throwable exception, final String message) {
3554
- final RaiseException error = new RaiseException(context.runtime, errorClass, message, true);
3582
+ final RaiseException error = context.runtime.newRaiseException(errorClass, message);
3555
3583
  error.initCause(exception);
3556
3584
  return error;
3557
3585
  }
@@ -107,8 +107,8 @@ public class MySQLRubyJdbcConnection extends RubyJdbcConnection {
107
107
  final int minor = jdbcDriver.getMinorVersion();
108
108
  if ( major < 5 ) {
109
109
  final RubyClass errorClass = getConnectionNotEstablished(context.runtime);
110
- throw new RaiseException(context.runtime, errorClass,
111
- "MySQL adapter requires driver >= 5.0 got: " + major + "." + minor + "", false);
110
+ throw context.runtime.newRaiseException(errorClass,
111
+ "MySQL adapter requires driver >= 5.0 got: " + major + "." + minor + "");
112
112
  }
113
113
  if ( major == 5 && minor < 1 ) { // need 5.1 for JDBC 4.0
114
114
  // lightweight validation query: "/* ping */ SELECT 1"
@@ -0,0 +1,52 @@
1
+ package arjdbc.postgresql;
2
+
3
+ import arjdbc.util.DateTimeUtils;
4
+ import org.joda.time.DateTimeZone;
5
+ import org.jruby.RubyArray;
6
+ import org.jruby.RubyFloat;
7
+ import org.jruby.runtime.ThreadContext;
8
+ import org.jruby.runtime.builtin.IRubyObject;
9
+
10
+ /**
11
+ * PostgreSQL specific DateTime/Timestamp helpers
12
+ * @author dritz
13
+ */
14
+ public abstract class PgDateTimeUtils extends DateTimeUtils {
15
+ /**
16
+ * Convert a ruby value to a PostgreSQL timestamp string
17
+ * @param context
18
+ * @param value Ruby value, typically a Time instance
19
+ * @param zone DateTimeZone to adjust to, optional
20
+ * @param withZone include timezone in string?
21
+ * @return A string fit for PostgreSQL
22
+ */
23
+ public static String timestampValueToString(final ThreadContext context, IRubyObject value, DateTimeZone zone,
24
+ boolean withZone) {
25
+ if (value instanceof RubyFloat) {
26
+ final double dv = ((RubyFloat) value).getValue();
27
+ if (dv == Double.POSITIVE_INFINITY) {
28
+ return "infinity";
29
+ } else if (dv == Double.NEGATIVE_INFINITY) {
30
+ return "-infinity";
31
+ }
32
+ }
33
+ return timestampTimeToString(context, value, zone, withZone);
34
+ }
35
+
36
+ /**
37
+ * Converts a RubyArray with timestamp values to a java array of PostgreSQL timestamp strings
38
+ * @param context
39
+ * @param rubyArray
40
+ * @return Array of timestamp strings
41
+ */
42
+ public static String[] timestampStringArray(final ThreadContext context, final RubyArray rubyArray) {
43
+ int size = rubyArray.size();
44
+ String[] values = new String[size];
45
+
46
+ for (int i = 0; i < size; i++) {
47
+ IRubyObject elem = rubyArray.eltInternal(i);
48
+ values[i] = timestampValueToString(context, elem, DateTimeZone.UTC, false);
49
+ }
50
+ return values;
51
+ }
52
+ }
@@ -4,6 +4,7 @@ import arjdbc.jdbc.JdbcResult;
4
4
  import arjdbc.jdbc.RubyJdbcConnection;
5
5
 
6
6
  import java.sql.ResultSet;
7
+ import java.sql.ResultSetMetaData;
7
8
  import java.sql.SQLException;
8
9
  import java.sql.Types;
9
10
 
@@ -11,7 +12,6 @@ import org.jruby.Ruby;
11
12
  import org.jruby.RubyArray;
12
13
  import org.jruby.RubyClass;
13
14
  import org.jruby.RubyHash;
14
- import org.jruby.RubyMethod;
15
15
  import org.jruby.RubyModule;
16
16
  import org.jruby.RubyString;
17
17
  import org.jruby.anno.JRubyMethod;
@@ -21,17 +21,13 @@ import org.jruby.runtime.ObjectAllocator;
21
21
  import org.jruby.runtime.ThreadContext;
22
22
  import org.jruby.runtime.builtin.IRubyObject;
23
23
 
24
- import org.postgresql.core.Field;
25
- import org.postgresql.jdbc.PgResultSetMetaData;
26
- import org.postgresql.jdbc.PgResultSetMetaDataWrapper; // This is a hack unfortunately to get around method scoping
27
-
28
24
  /*
29
25
  * This class mimics the PG:Result class enough to get by
30
26
  */
31
27
  public class PostgreSQLResult extends JdbcResult {
32
28
 
33
29
  // These are needed when generating an AR::Result
34
- private final PgResultSetMetaData resultSetMetaData;
30
+ private final ResultSetMetaData resultSetMetaData;
35
31
 
36
32
  /********* JRuby compat methods ***********/
37
33
 
@@ -61,7 +57,7 @@ public class PostgreSQLResult extends JdbcResult {
61
57
  ResultSet resultSet) throws SQLException {
62
58
  super(context, clazz, connection, resultSet);
63
59
 
64
- resultSetMetaData = (PgResultSetMetaData) resultSet.getMetaData();
60
+ resultSetMetaData = resultSet.getMetaData();
65
61
  }
66
62
 
67
63
  /**
@@ -74,16 +70,28 @@ public class PostgreSQLResult extends JdbcResult {
74
70
  protected IRubyObject columnTypeMap(final ThreadContext context) throws SQLException {
75
71
  Ruby runtime = context.runtime;
76
72
  RubyHash types = RubyHash.newHash(runtime);
77
- PgResultSetMetaDataWrapper mdWrapper = new PgResultSetMetaDataWrapper(resultSetMetaData);
78
73
  int columnCount = columnNames.length;
79
74
 
80
75
  IRubyObject adapter = connection.adapter(context);
81
76
  for (int i = 0; i < columnCount; i++) {
82
- final Field field = mdWrapper.getField(i + 1);
77
+ int col = i + 1;
78
+ String typeName = resultSetMetaData.getColumnTypeName(col);
79
+
80
+ int mod = 0;
81
+ if ("numeric".equals(typeName)) {
82
+ // this field is only relevant for "numeric" type in AR
83
+ // AR checks (fmod - 4 & 0xffff).zero?
84
+ // pgjdbc:
85
+ // - for typmod == -1, getScale() and getPrecision() return 0
86
+ // - for typmod != -1, getScale() returns "(typmod - 4) & 0xFFFF;"
87
+ mod = resultSetMetaData.getScale(col);
88
+ mod = mod == 0 && resultSetMetaData.getPrecision(col) == 0 ? -1 : mod + 4;
89
+ }
90
+
83
91
  final RubyString name = columnNames[i];
84
92
  final IRubyObject type = Helpers.invoke(context, adapter, "get_oid_type",
85
- runtime.newFixnum(field.getOID()),
86
- runtime.newFixnum(field.getMod()),
93
+ runtime.newString(typeName),
94
+ runtime.newFixnum(mod),
87
95
  name);
88
96
 
89
97
  if (!type.isNil()) types.fastASet(name, type);
@@ -144,7 +152,7 @@ public class PostgreSQLResult extends JdbcResult {
144
152
  * @return ActiveRecord::Result object with the data from this result set
145
153
  * @throws SQLException can be caused by postgres generating its type map
146
154
  */
147
- @Override
155
+ @Override @SuppressWarnings("unchecked")
148
156
  public IRubyObject toARResult(final ThreadContext context) throws SQLException {
149
157
  RubyClass BinaryDataClass = null;
150
158
  int rowCount = 0;
@@ -163,7 +171,7 @@ public class PostgreSQLResult extends JdbcResult {
163
171
  RubyArray row = (RubyArray) values.eltInternal(rowIndex);
164
172
  IRubyObject value = row.eltInternal(columnIndex);
165
173
  if (value != context.nil) {
166
- row.eltInternalSet(columnIndex, (IRubyObject) BinaryDataClass.newInstance(context, value, Block.NULL_BLOCK));
174
+ row.eltInternalSet(columnIndex, BinaryDataClass.newInstance(context, value, Block.NULL_BLOCK));
167
175
  }
168
176
  }
169
177
  }
@@ -281,6 +281,30 @@ public class PostgreSQLRubyJdbcConnection extends arjdbc.jdbc.RubyJdbcConnection
281
281
  return mapExecuteResult(context, connection, resultSet).toARResult(context);
282
282
  }
283
283
 
284
+ @Override
285
+ protected void setArrayParameter(final ThreadContext context,
286
+ final Connection connection, final PreparedStatement statement,
287
+ final int index, final IRubyObject value,
288
+ final IRubyObject attribute, final int type) throws SQLException {
289
+
290
+ final String typeName = resolveArrayBaseTypeName(context, attribute);
291
+ final RubyArray valueForDB = (RubyArray) value.callMethod(context, "values");
292
+
293
+ Object[] values;
294
+ switch (typeName) {
295
+ case "datetime":
296
+ case "timestamp": {
297
+ values = PgDateTimeUtils.timestampStringArray(context, valueForDB);
298
+ break;
299
+ }
300
+ default:
301
+ values = valueForDB.toArray();
302
+ break;
303
+ }
304
+
305
+ statement.setArray(index, connection.createArrayOf(typeName, values));
306
+ }
307
+
284
308
  @Override
285
309
  protected void setBlobParameter(final ThreadContext context,
286
310
  final Connection connection, final PreparedStatement statement,
@@ -304,47 +328,9 @@ public class PostgreSQLRubyJdbcConnection extends arjdbc.jdbc.RubyJdbcConnection
304
328
  final Connection connection, final PreparedStatement statement,
305
329
  final int index, IRubyObject value,
306
330
  final IRubyObject attribute, final int type) throws SQLException {
307
-
308
- if ( value instanceof RubyFloat ) {
309
- final double doubleValue = ( (RubyFloat) value ).getValue();
310
- if ( Double.isInfinite(doubleValue) ) {
311
- setTimestampInfinity(statement, index, doubleValue);
312
- return;
313
- }
314
- }
315
-
316
- RubyTime timeValue = toTime(context, value);
317
-
318
- final Timestamp timestamp;
319
-
320
- if (timeValue.getDateTime().getYear() > 0) {
321
- timeValue = timeInDefaultTimeZone(context, timeValue);
322
- DateTime dateTime = timeValue.getDateTime();
323
- timestamp = new Timestamp(dateTime.getMillis());
324
-
325
- if (timeValue.getNSec() > 0) timestamp.setNanos((int) (timestamp.getNanos() + timeValue.getNSec()));
326
-
327
- statement.setTimestamp(index, timestamp, getCalendar(dateTime.getZone()));
328
- }
329
- else {
330
- setTimestampBC(statement, index, timeValue);
331
- }
332
- }
333
-
334
- private static void setTimestampBC(final PreparedStatement statement,
335
- final int index, final RubyTime timeValue) throws SQLException {
336
- DateTime dateTime = timeValue.getDateTime();
337
- @SuppressWarnings("deprecated")
338
- Timestamp timestamp = new Timestamp(dateTime.getYear() - 1900,
339
- dateTime.getMonthOfYear() - 1,
340
- dateTime.getDayOfMonth(),
341
- dateTime.getHourOfDay(),
342
- dateTime.getMinuteOfHour(),
343
- dateTime.getSecondOfMinute(),
344
- dateTime.getMillisOfSecond() * 1_000_000 + (int) timeValue.getNSec()
345
- );
346
-
347
- statement.setObject(index, timestamp);
331
+ // PGJDBC uses strings internally anyway, so using Timestamp doesn't do any good
332
+ String tsString = PgDateTimeUtils.timestampValueToString(context, value, null, true);
333
+ statement.setObject(index, tsString, Types.OTHER);
348
334
  }
349
335
 
350
336
  private static void setTimestampInfinity(final PreparedStatement statement,
@@ -366,7 +352,8 @@ public class PostgreSQLRubyJdbcConnection extends arjdbc.jdbc.RubyJdbcConnection
366
352
  final int index, IRubyObject value,
367
353
  final IRubyObject attribute, final int type) throws SQLException {
368
354
  // to handle more fractional second precision than (default) 59.123 only
369
- super.setTimestampParameter(context, connection, statement, index, value, attribute, type);
355
+ String timeStr = DateTimeUtils.timeString(context, value, getDefaultTimeZone(context), true);
356
+ statement.setObject(index, timeStr, Types.OTHER);
370
357
  }
371
358
 
372
359
  @Override
@@ -420,8 +407,7 @@ public class PostgreSQLRubyJdbcConnection extends arjdbc.jdbc.RubyJdbcConnection
420
407
  break;
421
408
 
422
409
  case "enum":
423
- // FIXME: This doesn't work but it gives a better error message than letting it be treated as a PGobject
424
- statement.setObject(index, value.toString());
410
+ statement.setObject(index, value.toString(), Types.OTHER);
425
411
  break;
426
412
 
427
413
  case "interval":