activerecord-jdbc-adapter 51.2-java → 51.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.
@@ -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
- }