activerecord-jdbc-adapter 51.2-java → 51.3-java

Sign up to get free protection for your applications and to get access to all the features.
@@ -282,6 +282,30 @@ public class PostgreSQLRubyJdbcConnection extends arjdbc.jdbc.RubyJdbcConnection
282
282
  return mapExecuteResult(context, connection, resultSet).toARResult(context);
283
283
  }
284
284
 
285
+ @Override
286
+ protected void setArrayParameter(final ThreadContext context,
287
+ final Connection connection, final PreparedStatement statement,
288
+ final int index, final IRubyObject value,
289
+ final IRubyObject attribute, final int type) throws SQLException {
290
+
291
+ final String typeName = resolveArrayBaseTypeName(context, attribute);
292
+ final RubyArray valueForDB = (RubyArray) value.callMethod(context, "values");
293
+
294
+ Object[] values;
295
+ switch (typeName) {
296
+ case "datetime":
297
+ case "timestamp": {
298
+ values = PgDateTimeUtils.timestampStringArray(context, valueForDB);
299
+ break;
300
+ }
301
+ default:
302
+ values = valueForDB.toArray();
303
+ break;
304
+ }
305
+
306
+ statement.setArray(index, connection.createArrayOf(typeName, values));
307
+ }
308
+
285
309
  @Override
286
310
  protected void setBlobParameter(final ThreadContext context,
287
311
  final Connection connection, final PreparedStatement statement,
@@ -305,47 +329,9 @@ public class PostgreSQLRubyJdbcConnection extends arjdbc.jdbc.RubyJdbcConnection
305
329
  final Connection connection, final PreparedStatement statement,
306
330
  final int index, IRubyObject value,
307
331
  final IRubyObject attribute, final int type) throws SQLException {
308
-
309
- if ( value instanceof RubyFloat ) {
310
- final double doubleValue = ( (RubyFloat) value ).getValue();
311
- if ( Double.isInfinite(doubleValue) ) {
312
- setTimestampInfinity(statement, index, doubleValue);
313
- return;
314
- }
315
- }
316
-
317
- RubyTime timeValue = toTime(context, value);
318
-
319
- final Timestamp timestamp;
320
-
321
- if (timeValue.getDateTime().getYear() > 0) {
322
- timeValue = timeInDefaultTimeZone(context, timeValue);
323
- DateTime dateTime = timeValue.getDateTime();
324
- timestamp = new Timestamp(dateTime.getMillis());
325
-
326
- if (timeValue.getNSec() > 0) timestamp.setNanos((int) (timestamp.getNanos() + timeValue.getNSec()));
327
-
328
- statement.setTimestamp(index, timestamp, getCalendar(dateTime.getZone()));
329
- }
330
- else {
331
- setTimestampBC(statement, index, timeValue);
332
- }
333
- }
334
-
335
- private static void setTimestampBC(final PreparedStatement statement,
336
- final int index, final RubyTime timeValue) throws SQLException {
337
- DateTime dateTime = timeValue.getDateTime();
338
- @SuppressWarnings("deprecated")
339
- Timestamp timestamp = new Timestamp(dateTime.getYear() - 1900,
340
- dateTime.getMonthOfYear() - 1,
341
- dateTime.getDayOfMonth(),
342
- dateTime.getHourOfDay(),
343
- dateTime.getMinuteOfHour(),
344
- dateTime.getSecondOfMinute(),
345
- dateTime.getMillisOfSecond() * 1_000_000 + (int) timeValue.getNSec()
346
- );
347
-
348
- statement.setObject(index, timestamp);
332
+ // PGJDBC uses strings internally anyway, so using Timestamp doesn't do any good
333
+ String tsString = PgDateTimeUtils.timestampValueToString(context, value, null, true);
334
+ statement.setObject(index, tsString, Types.OTHER);
349
335
  }
350
336
 
351
337
  private static void setTimestampInfinity(final PreparedStatement statement,
@@ -367,7 +353,8 @@ public class PostgreSQLRubyJdbcConnection extends arjdbc.jdbc.RubyJdbcConnection
367
353
  final int index, IRubyObject value,
368
354
  final IRubyObject attribute, final int type) throws SQLException {
369
355
  // to handle more fractional second precision than (default) 59.123 only
370
- super.setTimestampParameter(context, connection, statement, index, value, attribute, type);
356
+ String timeStr = DateTimeUtils.timeString(context, value, getDefaultTimeZone(context), true);
357
+ statement.setObject(index, timeStr, Types.OTHER);
371
358
  }
372
359
 
373
360
  @Override
@@ -421,8 +408,7 @@ public class PostgreSQLRubyJdbcConnection extends arjdbc.jdbc.RubyJdbcConnection
421
408
  break;
422
409
 
423
410
  case "enum":
424
- // FIXME: This doesn't work but it gives a better error message than letting it be treated as a PGobject
425
- statement.setObject(index, value.toString());
411
+ statement.setObject(index, value.toString(), Types.OTHER);
426
412
  break;
427
413
 
428
414
  case "interval":
@@ -28,6 +28,7 @@ import java.sql.Time;
28
28
  import java.sql.Timestamp;
29
29
  import java.util.TimeZone;
30
30
 
31
+ import org.joda.time.Chronology;
31
32
  import org.joda.time.DateTime;
32
33
  import org.joda.time.DateTimeZone;
33
34
  import org.joda.time.chrono.ISOChronology;
@@ -40,6 +41,7 @@ import org.jruby.runtime.Block;
40
41
  import org.jruby.runtime.ThreadContext;
41
42
  import org.jruby.runtime.builtin.IRubyObject;
42
43
  import org.jruby.util.ByteList;
44
+ import org.jruby.util.TypeConverter;
43
45
 
44
46
  import static arjdbc.util.StringHelper.decByte;
45
47
 
@@ -48,6 +50,17 @@ import static arjdbc.util.StringHelper.decByte;
48
50
  * @author kares
49
51
  */
50
52
  public abstract class DateTimeUtils {
53
+ public static RubyTime toTime(final ThreadContext context, final IRubyObject value) {
54
+ if (!(value instanceof RubyTime)) { // unlikely
55
+ return (RubyTime) TypeConverter.convertToTypeWithCheck(value, context.runtime.getTime(), "to_time");
56
+ }
57
+ return (RubyTime) value;
58
+ }
59
+
60
+ public static DateTime dateTimeInZone(final DateTime dateTime, final DateTimeZone zone) {
61
+ if (zone == dateTime.getZone()) return dateTime;
62
+ return dateTime.withZone(zone);
63
+ }
51
64
 
52
65
  @SuppressWarnings("deprecation")
53
66
  public static ByteList timeToString(final Time time) {
@@ -577,4 +590,110 @@ public abstract class DateTimeUtils {
577
590
  return n;
578
591
  }
579
592
 
593
+
594
+ private static final char[] ZEROS = {'0', '0', '0', '0', '0', '0'};
595
+ private static final char[][] NUMBERS;
596
+
597
+ static {
598
+ // maximum value is 60 (seconds)
599
+ NUMBERS = new char[60][];
600
+ for (int i = 0; i < NUMBERS.length; i++) {
601
+ NUMBERS[i] = ((i < 10 ? "0" : "") + Integer.toString(i)).toCharArray();
602
+ }
603
+ }
604
+
605
+ /**
606
+ * Converts a ruby timestamp to a java string, optionally with timezone and timezone adjustment
607
+ * @param context
608
+ * @param value the ruby value, typically a Time
609
+ * @param zone DateTimeZone to adjust to, optional
610
+ * @param withZone include timezone in the string?
611
+ * @return timestamp as string
612
+ */
613
+ public static String timestampTimeToString(final ThreadContext context,
614
+ final IRubyObject value, DateTimeZone zone, boolean withZone) {
615
+ RubyTime timeValue = toTime(context, value);
616
+ DateTime dt = timeValue.getDateTime();
617
+
618
+ StringBuilder sb = new StringBuilder(36);
619
+
620
+ int year = dt.getYear();
621
+ if (year <= 0) {
622
+ year--;
623
+ } else if (zone != null) {
624
+ dt = dateTimeInZone(dt, zone);
625
+ year = dt.getYear();
626
+ }
627
+
628
+ Chronology chrono = dt.getChronology();
629
+ long millis = dt.getMillis();
630
+
631
+ // always use 4 digits for year to avoid short dates being misinterpreted
632
+ sb.append(Math.abs(year));
633
+ int lead = 4 - sb.length();
634
+ if (lead > 0) sb.insert(0, ZEROS, 0, lead);
635
+ sb.append('-');
636
+ sb.append(NUMBERS[chrono.monthOfYear().get(millis)]);
637
+ sb.append('-');
638
+ sb.append(NUMBERS[chrono.dayOfMonth().get(millis)]);
639
+ if (year < 0) sb.append(" BC");
640
+ sb.append(' ');
641
+
642
+ appendTime(sb, chrono, millis, (int) timeValue.getUSec(), withZone);
643
+
644
+ return sb.toString();
645
+ }
646
+
647
+ /**
648
+ * Converts a ruby time to a java string, optionally with timezone and timezone adjustment
649
+ * @param context
650
+ * @param value the ruby value, typically a Time
651
+ * @param zone DateTimeZone to adjust to, optional
652
+ * @param withZone include timezone in the string?
653
+ * @return time as string
654
+ */
655
+ public static String timeString(final ThreadContext context,
656
+ final IRubyObject value, DateTimeZone zone, boolean withZone) {
657
+ StringBuilder sb = new StringBuilder(21);
658
+ RubyTime timeValue = toTime(context, value);
659
+ DateTime dt = timeValue.getDateTime();
660
+ if (zone != null) dt = dateTimeInZone(dt, zone);
661
+
662
+ appendTime(sb, dt.getChronology(), dt.getMillis(), (int) timeValue.getUSec(), withZone);
663
+ return sb.toString();
664
+ }
665
+
666
+ private static void appendTime(StringBuilder sb, Chronology chrono,
667
+ long millis, int usec, boolean withZone) {
668
+ sb.append(NUMBERS[chrono.hourOfDay().get(millis)]);
669
+ sb.append(':');
670
+ sb.append(NUMBERS[chrono.minuteOfHour().get(millis)]);
671
+ sb.append(':');
672
+ sb.append(NUMBERS[chrono.secondOfMinute().get(millis)]);
673
+
674
+ // PG has microsecond resolution. Change when nanos are required
675
+ int micros = chrono.millisOfSecond().get(millis) * 1000 + usec;
676
+ if (micros > 0) {
677
+ sb.append('.');
678
+
679
+ int len = sb.length();
680
+ sb.append(micros);
681
+ int lead = 6 - (sb.length() - len);
682
+ if (lead > 0) sb.insert(len, ZEROS, 0, lead);
683
+
684
+ for (int end = sb.length() - 1; sb.charAt(end) == '0'; end--) {
685
+ sb.setLength(end);
686
+ }
687
+ }
688
+
689
+ if (withZone) {
690
+ int offset = chrono.getZone().getOffset(millis) / 1000;
691
+ int absoff = Math.abs(offset);
692
+ int hours = absoff / 3600;
693
+ int mins = (absoff - hours * 3600) / 60;
694
+
695
+ sb.append(offset < 0 ? '-' : '+');
696
+ sb.append(NUMBERS[hours]).append(':').append(NUMBERS[mins]);
697
+ }
698
+ }
580
699
  }
@@ -52,7 +52,6 @@ public abstract class QuotingUtils {
52
52
  return quoteCharWith(context, string, value, quote, 0, 8);
53
53
  }
54
54
 
55
- @SuppressWarnings("deprecation")
56
55
  public static RubyString quoteCharWith(
57
56
  final ThreadContext context,
58
57
  final RubyString string,
@@ -72,8 +71,8 @@ public abstract class QuotingUtils {
72
71
  new byte[realSize + newOffset + newSizeDiff],
73
72
  stringBytes.getEncoding(), false
74
73
  );
75
- quotedBytes.begin = newOffset;
76
- quotedBytes.realSize = 0;
74
+ quotedBytes.setBegin(newOffset);
75
+ quotedBytes.setRealSize(0);
77
76
  }
78
77
  quotedBytes.append(bytes, appendFrom, i - appendFrom);
79
78
  quotedBytes.append(quote).append(value); // e.g. "'" => "''"
@@ -88,7 +87,6 @@ public abstract class QuotingUtils {
88
87
  return context.runtime.newString(quotedBytes);
89
88
  }
90
89
 
91
- @SuppressWarnings("deprecation")
92
90
  public static RubyString quoteCharAndDecorateWith(
93
91
  final ThreadContext context, final RubyString string,
94
92
  final char value, final char quote,
@@ -102,7 +100,7 @@ public abstract class QuotingUtils {
102
100
  final ByteList quoted = new ByteList(
103
101
  new byte[realSize + 2], string.getEncoding(), false
104
102
  );
105
- quoted.begin = 0; quoted.realSize = 0;
103
+ quoted.setRealSize(0);
106
104
  quoted.append(prefix);
107
105
  quoted.append(str.unsafeBytes(), str.getBegin(), realSize);
108
106
  quoted.append(suffix);
@@ -110,8 +108,9 @@ public abstract class QuotingUtils {
110
108
  }
111
109
  // we got a new string with a reserve of 1 byte front and back :
112
110
  final ByteList quoted = quotedString.getByteList();
113
- quoted.begin = 0; // setBegin invalidates
114
- quoted.bytes[0] = prefix; quoted.realSize++;
111
+ quoted.setBegin(0);
112
+ quoted.unsafeBytes()[0] = prefix;
113
+ quoted.setRealSize(quoted.getRealSize() + 1);
115
114
  quoted.append(suffix);
116
115
  return quotedString;
117
116
  }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerecord-jdbc-adapter
3
3
  version: !ruby/object:Gem::Version
4
- version: '51.2'
4
+ version: '51.3'
5
5
  platform: java
6
6
  authors:
7
7
  - Nick Sieger, Ola Bini, Karol Bucek and JRuby contributors
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-09-13 00:00:00.000000000 Z
11
+ date: 2019-04-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
@@ -197,6 +197,7 @@ files:
197
197
  - src/java/arjdbc/jdbc/DriverConnectionFactory.java
198
198
  - src/java/arjdbc/jdbc/DriverWrapper.java
199
199
  - src/java/arjdbc/jdbc/JdbcResult.java
200
+ - src/java/arjdbc/jdbc/RubyConnectionFactory.java
200
201
  - src/java/arjdbc/jdbc/RubyJdbcConnection.java
201
202
  - src/java/arjdbc/mssql/MSSQLModule.java
202
203
  - src/java/arjdbc/mssql/MSSQLRubyJdbcConnection.java
@@ -205,7 +206,7 @@ files:
205
206
  - src/java/arjdbc/oracle/OracleModule.java
206
207
  - src/java/arjdbc/oracle/OracleRubyJdbcConnection.java
207
208
  - src/java/arjdbc/postgresql/ByteaUtils.java
208
- - src/java/arjdbc/postgresql/PgResultSetMetaDataWrapper.java
209
+ - src/java/arjdbc/postgresql/PgDateTimeUtils.java
209
210
  - src/java/arjdbc/postgresql/PostgreSQLModule.java
210
211
  - src/java/arjdbc/postgresql/PostgreSQLResult.java
211
212
  - src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java
@@ -242,7 +243,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
242
243
  version: '0'
243
244
  requirements: []
244
245
  rubyforge_project:
245
- rubygems_version: 2.6.14.1
246
+ rubygems_version: 2.7.9
246
247
  signing_key:
247
248
  specification_version: 4
248
249
  summary: JDBC adapter for ActiveRecord, for use within JRuby on Rails.
@@ -1,23 +0,0 @@
1
- /*
2
- * A class to loosen restrictions on the PgResultSetMetaData class,
3
- * we need to be able to get the field and the method is currently set to "package".
4
- */
5
- package org.postgresql.jdbc;
6
-
7
- import java.sql.SQLException;
8
- import org.postgresql.core.BaseConnection;
9
- import org.postgresql.core.Field;
10
- import org.postgresql.jdbc.PgResultSetMetaData;
11
-
12
- public class PgResultSetMetaDataWrapper {
13
-
14
- private final PgResultSetMetaData metaData;
15
-
16
- public PgResultSetMetaDataWrapper(PgResultSetMetaData metaData) {
17
- this.metaData = metaData;
18
- }
19
-
20
- public Field getField(int i) throws SQLException {
21
- return this.metaData.getField(i);
22
- }
23
- }