activerecord-jdbc-adapter 50.8-java → 51.1-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +1 -2
  3. data/.travis.yml +26 -51
  4. data/Gemfile +3 -1
  5. data/README.md +9 -11
  6. data/Rakefile +15 -78
  7. data/activerecord-jdbc-adapter.gemspec +2 -2
  8. data/lib/active_record/connection_adapters/mssql_adapter.rb +1 -0
  9. data/lib/active_record/connection_adapters/sqlserver_adapter.rb +1 -0
  10. data/lib/arjdbc/abstract/core.rb +4 -12
  11. data/lib/arjdbc/abstract/database_statements.rb +4 -10
  12. data/lib/arjdbc/abstract/statement_cache.rb +4 -4
  13. data/lib/arjdbc/abstract/transaction_support.rb +2 -9
  14. data/lib/arjdbc/jdbc.rb +4 -0
  15. data/lib/arjdbc/jdbc/column.rb +11 -5
  16. data/lib/arjdbc/jdbc/connection_methods.rb +9 -2
  17. data/lib/arjdbc/jdbc/error.rb +1 -1
  18. data/lib/arjdbc/jdbc/jdbc.rake +4 -0
  19. data/lib/arjdbc/mssql.rb +7 -0
  20. data/lib/arjdbc/mssql/adapter.rb +804 -0
  21. data/lib/arjdbc/mssql/column.rb +200 -0
  22. data/lib/arjdbc/mssql/connection_methods.rb +79 -0
  23. data/lib/arjdbc/mssql/explain_support.rb +99 -0
  24. data/lib/arjdbc/mssql/limit_helpers.rb +231 -0
  25. data/lib/arjdbc/mssql/lock_methods.rb +77 -0
  26. data/lib/arjdbc/mssql/types.rb +343 -0
  27. data/lib/arjdbc/mssql/utils.rb +82 -0
  28. data/lib/arjdbc/mysql/adapter.rb +14 -11
  29. data/lib/arjdbc/mysql/connection_methods.rb +9 -18
  30. data/lib/arjdbc/postgresql/adapter.rb +108 -59
  31. data/lib/arjdbc/postgresql/column.rb +3 -6
  32. data/lib/arjdbc/postgresql/connection_methods.rb +3 -12
  33. data/lib/arjdbc/postgresql/oid_types.rb +14 -93
  34. data/lib/arjdbc/sqlite3/adapter.rb +171 -140
  35. data/lib/arjdbc/sqlite3/connection_methods.rb +1 -2
  36. data/lib/arjdbc/tasks/database_tasks.rb +36 -16
  37. data/lib/arjdbc/tasks/databases.rake +75 -32
  38. data/lib/arjdbc/tasks/databases3.rake +215 -0
  39. data/lib/arjdbc/tasks/databases4.rake +39 -0
  40. data/lib/arjdbc/version.rb +1 -1
  41. data/rakelib/01-tomcat.rake +2 -2
  42. data/rakelib/02-test.rake +3 -0
  43. data/rakelib/compile.rake +70 -0
  44. data/rakelib/db.rake +7 -21
  45. data/rakelib/rails.rake +4 -5
  46. data/src/java/arjdbc/ArJdbcModule.java +15 -5
  47. data/src/java/arjdbc/derby/DerbyRubyJdbcConnection.java +2 -2
  48. data/src/java/arjdbc/jdbc/ConnectionFactory.java +87 -0
  49. data/src/java/arjdbc/jdbc/DataSourceConnectionFactory.java +1 -0
  50. data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +41 -120
  51. data/src/java/arjdbc/mssql/MSSQLRubyJdbcConnection.java +14 -310
  52. data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +2 -2
  53. data/src/java/arjdbc/postgresql/ByteaUtils.java +1 -0
  54. data/src/java/arjdbc/postgresql/PgResultSetMetaDataWrapper.java +23 -0
  55. data/src/java/arjdbc/postgresql/PostgreSQLResult.java +13 -21
  56. data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +46 -41
  57. data/src/java/arjdbc/util/DateTimeUtils.java +5 -141
  58. data/src/java/arjdbc/util/QuotingUtils.java +7 -6
  59. data/src/java/arjdbc/util/StringHelper.java +20 -6
  60. metadata +25 -16
  61. data/src/java/arjdbc/jdbc/RubyConnectionFactory.java +0 -61
  62. data/src/java/arjdbc/postgresql/PgDateTimeUtils.java +0 -52
@@ -27,6 +27,7 @@ package arjdbc.postgresql;
27
27
 
28
28
  import arjdbc.jdbc.Callable;
29
29
  import arjdbc.jdbc.DriverWrapper;
30
+ import arjdbc.postgresql.PostgreSQLResult;
30
31
  import arjdbc.util.DateTimeUtils;
31
32
  import arjdbc.util.StringHelper;
32
33
 
@@ -54,7 +55,6 @@ import org.joda.time.DateTimeZone;
54
55
  import org.jruby.*;
55
56
  import org.jruby.anno.JRubyMethod;
56
57
  import org.jruby.exceptions.RaiseException;
57
- import org.jruby.ext.bigdecimal.RubyBigDecimal;
58
58
  import org.jruby.javasupport.JavaUtil;
59
59
  import org.jruby.runtime.ObjectAllocator;
60
60
  import org.jruby.runtime.ThreadContext;
@@ -100,7 +100,6 @@ public class PostgreSQLRubyJdbcConnection extends arjdbc.jdbc.RubyJdbcConnection
100
100
  POSTGRES_JDBC_TYPE_FOR.put("line", Types.OTHER);
101
101
  POSTGRES_JDBC_TYPE_FOR.put("lseg", Types.OTHER);
102
102
  POSTGRES_JDBC_TYPE_FOR.put("ltree", Types.OTHER);
103
- POSTGRES_JDBC_TYPE_FOR.put("money", Types.OTHER);
104
103
  POSTGRES_JDBC_TYPE_FOR.put("numrange", Types.OTHER);
105
104
  POSTGRES_JDBC_TYPE_FOR.put("path", Types.OTHER);
106
105
  POSTGRES_JDBC_TYPE_FOR.put("point", Types.OTHER);
@@ -281,30 +280,6 @@ public class PostgreSQLRubyJdbcConnection extends arjdbc.jdbc.RubyJdbcConnection
281
280
  return mapExecuteResult(context, connection, resultSet).toARResult(context);
282
281
  }
283
282
 
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
-
308
283
  @Override
309
284
  protected void setBlobParameter(final ThreadContext context,
310
285
  final Connection connection, final PreparedStatement statement,
@@ -328,9 +303,47 @@ public class PostgreSQLRubyJdbcConnection extends arjdbc.jdbc.RubyJdbcConnection
328
303
  final Connection connection, final PreparedStatement statement,
329
304
  final int index, IRubyObject value,
330
305
  final IRubyObject attribute, final int type) throws SQLException {
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);
306
+
307
+ if ( value instanceof RubyFloat ) {
308
+ final double doubleValue = ( (RubyFloat) value ).getValue();
309
+ if ( Double.isInfinite(doubleValue) ) {
310
+ setTimestampInfinity(statement, index, doubleValue);
311
+ return;
312
+ }
313
+ }
314
+
315
+ RubyTime timeValue = toTime(context, value);
316
+
317
+ final Timestamp timestamp;
318
+
319
+ if (timeValue.getDateTime().getYear() > 0) {
320
+ timeValue = timeInDefaultTimeZone(context, timeValue);
321
+ DateTime dateTime = timeValue.getDateTime();
322
+ timestamp = new Timestamp(dateTime.getMillis());
323
+
324
+ if (timeValue.getNSec() > 0) timestamp.setNanos((int) (timestamp.getNanos() + timeValue.getNSec()));
325
+
326
+ statement.setTimestamp(index, timestamp, getCalendar(dateTime.getZone()));
327
+ }
328
+ else {
329
+ setTimestampBC(statement, index, timeValue);
330
+ }
331
+ }
332
+
333
+ private static void setTimestampBC(final PreparedStatement statement,
334
+ final int index, final RubyTime timeValue) throws SQLException {
335
+ DateTime dateTime = timeValue.getDateTime();
336
+ @SuppressWarnings("deprecated")
337
+ Timestamp timestamp = new Timestamp(dateTime.getYear() - 1900,
338
+ dateTime.getMonthOfYear() - 1,
339
+ dateTime.getDayOfMonth(),
340
+ dateTime.getHourOfDay(),
341
+ dateTime.getMinuteOfHour(),
342
+ dateTime.getSecondOfMinute(),
343
+ dateTime.getMillisOfSecond() * 1_000_000 + (int) timeValue.getNSec()
344
+ );
345
+
346
+ statement.setObject(index, timestamp);
334
347
  }
335
348
 
336
349
  private static void setTimestampInfinity(final PreparedStatement statement,
@@ -352,8 +365,7 @@ public class PostgreSQLRubyJdbcConnection extends arjdbc.jdbc.RubyJdbcConnection
352
365
  final int index, IRubyObject value,
353
366
  final IRubyObject attribute, final int type) throws SQLException {
354
367
  // to handle more fractional second precision than (default) 59.123 only
355
- String timeStr = DateTimeUtils.timeString(context, value, getDefaultTimeZone(context), true);
356
- statement.setObject(index, timeStr, Types.OTHER);
368
+ super.setTimestampParameter(context, connection, statement, index, value, attribute, type);
357
369
  }
358
370
 
359
371
  @Override
@@ -407,7 +419,8 @@ public class PostgreSQLRubyJdbcConnection extends arjdbc.jdbc.RubyJdbcConnection
407
419
  break;
408
420
 
409
421
  case "enum":
410
- statement.setObject(index, value.toString(), Types.OTHER);
422
+ // FIXME: This doesn't work but it gives a better error message than letting it be treated as a PGobject
423
+ statement.setObject(index, value.toString());
411
424
  break;
412
425
 
413
426
  case "interval":
@@ -428,14 +441,6 @@ public class PostgreSQLRubyJdbcConnection extends arjdbc.jdbc.RubyJdbcConnection
428
441
  }
429
442
  break;
430
443
 
431
- case "money":
432
- if (value instanceof RubyBigDecimal) {
433
- statement.setBigDecimal(index, ((RubyBigDecimal) value).getValue());
434
- } else {
435
- setPGobjectParameter(statement, index, value, columnType);
436
- }
437
- break;
438
-
439
444
  case "lseg":
440
445
  pointValues = parseDoubles(value);
441
446
  statement.setObject(index, new PGlseg(pointValues[0], pointValues[1], pointValues[2], pointValues[3]));
@@ -480,7 +485,7 @@ public class PostgreSQLRubyJdbcConnection extends arjdbc.jdbc.RubyJdbcConnection
480
485
  return points;
481
486
  }
482
487
 
483
- private static Double[] parseDoubles(IRubyObject value) {
488
+ private Double[] parseDoubles(IRubyObject value) {
484
489
  Matcher matches = doubleValuePattern.matcher(value.toString());
485
490
  ArrayList<Double> doubles = new ArrayList<Double>(4); // Paths and polygons may be larger but this covers points/circles/boxes/line segments
486
491
 
@@ -28,10 +28,8 @@ import java.sql.Time;
28
28
  import java.sql.Timestamp;
29
29
  import java.util.TimeZone;
30
30
 
31
- import org.joda.time.Chronology;
32
31
  import org.joda.time.DateTime;
33
32
  import org.joda.time.DateTimeZone;
34
- import org.joda.time.chrono.GJChronology;
35
33
  import org.joda.time.chrono.ISOChronology;
36
34
  import org.jruby.Ruby;
37
35
  import org.jruby.RubyFloat;
@@ -42,7 +40,6 @@ import org.jruby.runtime.Block;
42
40
  import org.jruby.runtime.ThreadContext;
43
41
  import org.jruby.runtime.builtin.IRubyObject;
44
42
  import org.jruby.util.ByteList;
45
- import org.jruby.util.TypeConverter;
46
43
 
47
44
  import static arjdbc.util.StringHelper.decByte;
48
45
 
@@ -52,20 +49,6 @@ import static arjdbc.util.StringHelper.decByte;
52
49
  */
53
50
  public abstract class DateTimeUtils {
54
51
 
55
- private static final GJChronology CHRONO_ITALY_UTC = GJChronology.getInstance(DateTimeZone.UTC);
56
-
57
- public static RubyTime toTime(final ThreadContext context, final IRubyObject value) {
58
- if (!(value instanceof RubyTime)) { // unlikely
59
- return (RubyTime) TypeConverter.convertToTypeWithCheck(value, context.runtime.getTime(), "to_time");
60
- }
61
- return (RubyTime) value;
62
- }
63
-
64
- public static DateTime dateTimeInZone(final DateTime dateTime, final DateTimeZone zone) {
65
- if (zone == dateTime.getZone()) return dateTime;
66
- return dateTime.withZone(zone);
67
- }
68
-
69
52
  @SuppressWarnings("deprecation")
70
53
  public static ByteList timeToString(final Time time) {
71
54
  final ByteList str = new ByteList(8); // hh:mm:ss
@@ -221,11 +204,9 @@ public abstract class DateTimeUtils {
221
204
  final int hours = time.getHours();
222
205
  final int minutes = time.getMinutes();
223
206
  final int seconds = time.getSeconds();
224
- int nanos = time.getNanos(); // max 999-999-999
225
- final int millis = nanos / 1000000;
226
- nanos = nanos % 1000000;
207
+ final int nanos = time.getNanos(); // max 999-999-999
227
208
 
228
- DateTime dateTime = new DateTime(2000, 1, 1, hours, minutes, seconds, millis, defaultZone);
209
+ DateTime dateTime = new DateTime(2000, 1, 1, hours, minutes, seconds, defaultZone);
229
210
  return RubyTime.newTime(context.runtime, dateTime, nanos);
230
211
  }
231
212
 
@@ -238,11 +219,9 @@ public abstract class DateTimeUtils {
238
219
  final int hours = timestamp.getHours();
239
220
  final int minutes = timestamp.getMinutes();
240
221
  final int seconds = timestamp.getSeconds();
241
- int nanos = timestamp.getNanos(); // max 999-999-999
242
- final int millis = nanos / 1000000;
243
- nanos = nanos % 1000000;
222
+ final int nanos = timestamp.getNanos(); // max 999-999-999
244
223
 
245
- DateTime dateTime = new DateTime(year, month, day, hours, minutes, seconds, millis, defaultZone);
224
+ DateTime dateTime = new DateTime(year, month, day, hours, minutes, seconds, 0, defaultZone);
246
225
  return RubyTime.newTime(context.runtime, dateTime, nanos);
247
226
  }
248
227
 
@@ -267,15 +246,6 @@ public abstract class DateTimeUtils {
267
246
  return newDate(context, year, month, day, ISOChronology.getInstance(zone));
268
247
  }
269
248
 
270
- @SuppressWarnings("deprecation")
271
- public static IRubyObject newDate(final ThreadContext context, final Date date) {
272
- final int year = date.getYear() + 1900;
273
- final int month = date.getMonth() + 1;
274
- final int day = date.getDate();
275
-
276
- return newDate(context, year, month, day, CHRONO_ITALY_UTC);
277
- }
278
-
279
249
  // @Deprecated
280
250
  public static Timestamp convertToTimestamp(final RubyFloat value) {
281
251
  final Timestamp timestamp = new Timestamp(value.getLongValue() * 1000); // millis
@@ -570,7 +540,7 @@ public abstract class DateTimeUtils {
570
540
  }
571
541
 
572
542
  private static IRubyObject newDate(final ThreadContext context, final int year, final int month, final int day,
573
- final Chronology chronology) {
543
+ final ISOChronology chronology) {
574
544
  // NOTE: JRuby really needs a native date.rb until than its a bit costly going from ...
575
545
  // java.sql.Date -> allocating a DateTime proxy, help a bit by shooting at the internals
576
546
  //
@@ -607,110 +577,4 @@ public abstract class DateTimeUtils {
607
577
  return n;
608
578
  }
609
579
 
610
-
611
- private static final char[] ZEROS = {'0', '0', '0', '0', '0', '0'};
612
- private static final char[][] NUMBERS;
613
-
614
- static {
615
- // maximum value is 60 (seconds)
616
- NUMBERS = new char[60][];
617
- for (int i = 0; i < NUMBERS.length; i++) {
618
- NUMBERS[i] = ((i < 10 ? "0" : "") + Integer.toString(i)).toCharArray();
619
- }
620
- }
621
-
622
- /**
623
- * Converts a ruby timestamp to a java string, optionally with timezone and timezone adjustment
624
- * @param context
625
- * @param value the ruby value, typically a Time
626
- * @param zone DateTimeZone to adjust to, optional
627
- * @param withZone include timezone in the string?
628
- * @return timestamp as string
629
- */
630
- public static String timestampTimeToString(final ThreadContext context,
631
- final IRubyObject value, DateTimeZone zone, boolean withZone) {
632
- RubyTime timeValue = toTime(context, value);
633
- DateTime dt = timeValue.getDateTime();
634
-
635
- StringBuilder sb = new StringBuilder(36);
636
-
637
- int year = dt.getYear();
638
- if (year <= 0) {
639
- year--;
640
- } else if (zone != null) {
641
- dt = dateTimeInZone(dt, zone);
642
- year = dt.getYear();
643
- }
644
-
645
- Chronology chrono = dt.getChronology();
646
- long millis = dt.getMillis();
647
-
648
- // always use 4 digits for year to avoid short dates being misinterpreted
649
- sb.append(Math.abs(year));
650
- int lead = 4 - sb.length();
651
- if (lead > 0) sb.insert(0, ZEROS, 0, lead);
652
- sb.append('-');
653
- sb.append(NUMBERS[chrono.monthOfYear().get(millis)]);
654
- sb.append('-');
655
- sb.append(NUMBERS[chrono.dayOfMonth().get(millis)]);
656
- if (year < 0) sb.append(" BC");
657
- sb.append(' ');
658
-
659
- appendTime(sb, chrono, millis, (int) timeValue.getUSec(), withZone);
660
-
661
- return sb.toString();
662
- }
663
-
664
- /**
665
- * Converts a ruby time to a java string, optionally with timezone and timezone adjustment
666
- * @param context
667
- * @param value the ruby value, typically a Time
668
- * @param zone DateTimeZone to adjust to, optional
669
- * @param withZone include timezone in the string?
670
- * @return time as string
671
- */
672
- public static String timeString(final ThreadContext context,
673
- final IRubyObject value, DateTimeZone zone, boolean withZone) {
674
- StringBuilder sb = new StringBuilder(21);
675
- RubyTime timeValue = toTime(context, value);
676
- DateTime dt = timeValue.getDateTime();
677
- if (zone != null) dt = dateTimeInZone(dt, zone);
678
-
679
- appendTime(sb, dt.getChronology(), dt.getMillis(), (int) timeValue.getUSec(), withZone);
680
- return sb.toString();
681
- }
682
-
683
- private static void appendTime(StringBuilder sb, Chronology chrono,
684
- long millis, int usec, boolean withZone) {
685
- sb.append(NUMBERS[chrono.hourOfDay().get(millis)]);
686
- sb.append(':');
687
- sb.append(NUMBERS[chrono.minuteOfHour().get(millis)]);
688
- sb.append(':');
689
- sb.append(NUMBERS[chrono.secondOfMinute().get(millis)]);
690
-
691
- // PG has microsecond resolution. Change when nanos are required
692
- int micros = chrono.millisOfSecond().get(millis) * 1000 + usec;
693
- if (micros > 0) {
694
- sb.append('.');
695
-
696
- int len = sb.length();
697
- sb.append(micros);
698
- int lead = 6 - (sb.length() - len);
699
- if (lead > 0) sb.insert(len, ZEROS, 0, lead);
700
-
701
- for (int end = sb.length() - 1; sb.charAt(end) == '0'; end--) {
702
- sb.setLength(end);
703
- }
704
- }
705
-
706
- if (withZone) {
707
- int offset = chrono.getZone().getOffset(millis) / 1000;
708
- int absoff = Math.abs(offset);
709
- int hours = absoff / 3600;
710
- int mins = (absoff - hours * 3600) / 60;
711
-
712
- sb.append(offset < 0 ? '-' : '+');
713
- sb.append(NUMBERS[hours]).append(':').append(NUMBERS[mins]);
714
- }
715
- }
716
580
  }
@@ -52,6 +52,7 @@ public abstract class QuotingUtils {
52
52
  return quoteCharWith(context, string, value, quote, 0, 8);
53
53
  }
54
54
 
55
+ @SuppressWarnings("deprecation")
55
56
  public static RubyString quoteCharWith(
56
57
  final ThreadContext context,
57
58
  final RubyString string,
@@ -71,8 +72,8 @@ public abstract class QuotingUtils {
71
72
  new byte[realSize + newOffset + newSizeDiff],
72
73
  stringBytes.getEncoding(), false
73
74
  );
74
- quotedBytes.setBegin(newOffset);
75
- quotedBytes.setRealSize(0);
75
+ quotedBytes.begin = newOffset;
76
+ quotedBytes.realSize = 0;
76
77
  }
77
78
  quotedBytes.append(bytes, appendFrom, i - appendFrom);
78
79
  quotedBytes.append(quote).append(value); // e.g. "'" => "''"
@@ -87,6 +88,7 @@ public abstract class QuotingUtils {
87
88
  return context.runtime.newString(quotedBytes);
88
89
  }
89
90
 
91
+ @SuppressWarnings("deprecation")
90
92
  public static RubyString quoteCharAndDecorateWith(
91
93
  final ThreadContext context, final RubyString string,
92
94
  final char value, final char quote,
@@ -100,7 +102,7 @@ public abstract class QuotingUtils {
100
102
  final ByteList quoted = new ByteList(
101
103
  new byte[realSize + 2], string.getEncoding(), false
102
104
  );
103
- quoted.setRealSize(0);
105
+ quoted.begin = 0; quoted.realSize = 0;
104
106
  quoted.append(prefix);
105
107
  quoted.append(str.unsafeBytes(), str.getBegin(), realSize);
106
108
  quoted.append(suffix);
@@ -108,9 +110,8 @@ public abstract class QuotingUtils {
108
110
  }
109
111
  // we got a new string with a reserve of 1 byte front and back :
110
112
  final ByteList quoted = quotedString.getByteList();
111
- quoted.setBegin(0);
112
- quoted.unsafeBytes()[0] = prefix;
113
- quoted.setRealSize(quoted.getRealSize() + 1);
113
+ quoted.begin = 0; // setBegin invalidates
114
+ quoted.bytes[0] = prefix; quoted.realSize++;
114
115
  quoted.append(suffix);
115
116
  return quotedString;
116
117
  }
@@ -25,9 +25,12 @@ package arjdbc.util;
25
25
 
26
26
  import java.io.IOException;
27
27
  import java.io.InputStream;
28
+ import java.nio.charset.Charset;
28
29
 
29
30
  import org.jcodings.Encoding;
31
+ import org.jcodings.specific.UTF8Encoding;
30
32
  import org.jruby.Ruby;
33
+ import org.jruby.RubyEncoding;
31
34
  import org.jruby.RubyString;
32
35
  import org.jruby.util.ByteList;
33
36
 
@@ -58,6 +61,18 @@ public abstract class StringHelper {
58
61
  return RubyString.newString(runtime, new ByteList(bytes, false));
59
62
  }
60
63
 
64
+ private static final Charset ASCII_CHARSET = Charset.forName("ISO-8859-1");
65
+
66
+ public static RubyString newASCIIString(final Ruby runtime, final String str) {
67
+ final ByteList byteList = new ByteList(str.getBytes(ASCII_CHARSET), false);
68
+ return RubyString.newString(runtime, byteList);
69
+ }
70
+
71
+ public static RubyString newUTF8String(final Ruby runtime, final byte[] bytes) {
72
+ final ByteList byteList = new ByteList(bytes, false);
73
+ return RubyString.newString(runtime, byteList, UTF8Encoding.INSTANCE);
74
+ }
75
+
61
76
  public static RubyString newDefaultInternalString(final Ruby runtime, final byte[] bytes) {
62
77
  final ByteList byteList = new ByteList(bytes, false);
63
78
  Encoding enc = runtime.getDefaultInternalEncoding();
@@ -68,19 +83,18 @@ public abstract class StringHelper {
68
83
  public static RubyString newDefaultInternalString(final Ruby runtime, final CharSequence str) {
69
84
  Encoding enc = runtime.getDefaultInternalEncoding();
70
85
  if (enc == null) enc = runtime.getEncodingService().getJavaDefault();
71
- return new RubyString(runtime, runtime.getString(), str, enc);
86
+ return RubyString.newString(runtime, new ByteList(RubyEncoding.encode(str, enc.getCharset()), enc));
72
87
  }
73
88
 
74
- // NOTE: a 'better' RubyString.newInternalFromJavaExternal - to be back-ported in JRuby 9.2
75
89
  public static RubyString newDefaultInternalString(final Ruby runtime, final String str) {
76
- Encoding enc = runtime.getDefaultInternalEncoding();
77
- if (enc == null) enc = runtime.getEncodingService().getJavaDefault();
78
- return RubyString.newString(runtime, str, enc);
90
+ return RubyString.newInternalFromJavaExternal(runtime, str);
79
91
  }
80
92
 
81
93
  public static int readBytes(final ByteList output, final InputStream input)
82
94
  throws IOException {
83
- return readBytes(output, input, output.unsafeBytes().length - output.getBegin());
95
+ @SuppressWarnings("deprecation") // capacity :
96
+ final int buffSize = output.bytes.length - output.begin;
97
+ return readBytes(output, input, buffSize);
84
98
  }
85
99
 
86
100
  public static int readBytes(final ByteList output, final InputStream input, int buffSize)