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.
- 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
|
-
}
|