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.
- checksums.yaml +5 -5
- data/.travis.yml +36 -15
- data/lib/arjdbc/abstract/database_statements.rb +2 -2
- data/lib/arjdbc/abstract/statement_cache.rb +4 -4
- data/lib/arjdbc/db2/adapter.rb +2 -52
- data/lib/arjdbc/mysql/adapter.rb +8 -0
- data/lib/arjdbc/postgresql/adapter.rb +1 -62
- data/lib/arjdbc/postgresql/oid_types.rb +81 -7
- data/lib/arjdbc/version.rb +1 -1
- data/rakelib/rails.rake +4 -3
- data/src/java/arjdbc/ArJdbcModule.java +5 -15
- data/src/java/arjdbc/derby/DerbyRubyJdbcConnection.java +2 -2
- data/src/java/arjdbc/jdbc/ConnectionFactory.java +0 -87
- data/src/java/arjdbc/jdbc/DataSourceConnectionFactory.java +0 -1
- data/src/java/arjdbc/jdbc/RubyConnectionFactory.java +61 -0
- data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +47 -19
- data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +2 -2
- data/src/java/arjdbc/postgresql/PgDateTimeUtils.java +52 -0
- data/src/java/arjdbc/postgresql/PostgreSQLResult.java +21 -13
- data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +30 -44
- data/src/java/arjdbc/util/DateTimeUtils.java +119 -0
- data/src/java/arjdbc/util/QuotingUtils.java +6 -7
- metadata +5 -4
- data/src/java/arjdbc/postgresql/PgResultSetMetaDataWrapper.java +0 -23
@@ -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
|
-
|
310
|
-
|
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
|
-
|
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
|
-
|
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.
|
76
|
-
quotedBytes.
|
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.
|
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.
|
114
|
-
quoted.
|
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.
|
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:
|
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/
|
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.
|
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
|
-
}
|