activerecord-jdbc-adapter 50.2-java → 50.3-java

Sign up to get free protection for your applications and to get access to all the features.
@@ -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":