activerecord-jdbc-adapter 1.3.7 → 1.3.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +33 -3
  3. data/Appraisals +11 -5
  4. data/Gemfile +21 -15
  5. data/History.md +31 -1
  6. data/lib/active_record/connection_adapters/mariadb_adapter.rb +1 -0
  7. data/lib/arel/visitors/firebird.rb +7 -10
  8. data/lib/arel/visitors/h2.rb +9 -0
  9. data/lib/arel/visitors/sql_server.rb +21 -2
  10. data/lib/arjdbc/h2/adapter.rb +31 -2
  11. data/lib/arjdbc/h2/connection_methods.rb +1 -1
  12. data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
  13. data/lib/arjdbc/jdbc/column.rb +2 -1
  14. data/lib/arjdbc/mssql/adapter.rb +40 -23
  15. data/lib/arjdbc/mssql/column.rb +4 -4
  16. data/lib/arjdbc/mysql/adapter.rb +36 -10
  17. data/lib/arjdbc/mysql/column.rb +12 -7
  18. data/lib/arjdbc/mysql/connection_methods.rb +53 -21
  19. data/lib/arjdbc/oracle/adapter.rb +22 -5
  20. data/lib/arjdbc/postgresql/adapter.rb +54 -18
  21. data/lib/arjdbc/postgresql/base/array_parser.rb +95 -0
  22. data/lib/arjdbc/postgresql/base/oid.rb +460 -0
  23. data/lib/arjdbc/postgresql/column.rb +50 -15
  24. data/lib/arjdbc/postgresql/oid_types.rb +126 -0
  25. data/lib/arjdbc/tasks/h2_database_tasks.rb +4 -2
  26. data/lib/arjdbc/version.rb +1 -1
  27. data/rakelib/02-test.rake +3 -30
  28. data/src/java/arjdbc/derby/DerbyModule.java +0 -8
  29. data/src/java/arjdbc/derby/DerbyRubyJdbcConnection.java +1 -0
  30. data/src/java/arjdbc/h2/H2RubyJdbcConnection.java +2 -0
  31. data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +8 -8
  32. data/src/java/arjdbc/mssql/MSSQLModule.java +50 -19
  33. data/src/java/arjdbc/mssql/MSSQLRubyJdbcConnection.java +1 -0
  34. data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +6 -6
  35. data/src/java/arjdbc/oracle/OracleModule.java +1 -1
  36. data/src/java/arjdbc/oracle/OracleRubyJdbcConnection.java +66 -2
  37. data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +23 -10
  38. data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +1 -0
  39. data/src/java/arjdbc/util/CallResultSet.java +826 -0
  40. data/src/java/arjdbc/util/QuotingUtils.java +14 -7
  41. metadata +8 -3
  42. data/lib/arjdbc/postgresql/array_parser.rb +0 -89
@@ -24,8 +24,8 @@ module ArJdbc
24
24
  require 'pg_array_parser'
25
25
  include PgArrayParser
26
26
  rescue LoadError
27
- require 'arjdbc/postgresql/array_parser'
28
- include ArrayParser
27
+ require 'arjdbc/postgresql/base/array_parser'
28
+ include ActiveRecord::ConnectionAdapters::PostgreSQL::ArrayParser
29
29
  end if AR4_COMPAT
30
30
 
31
31
  include Cast
@@ -33,8 +33,21 @@ module ArJdbc
33
33
  end
34
34
  end
35
35
 
36
+ # @private
37
+ def oid_type
38
+ @oid_type ||= begin
39
+ raise "oid not defined" unless oid = (@oid ||= nil)
40
+ @adapter.get_oid_type(oid.to_i, @fmod.to_i, name)
41
+ end
42
+ end if AR4_COMPAT
43
+
44
+ def accessor; oid_type.accessor end if AR4_COMPAT
45
+
36
46
  ( attr_accessor :array; def array?; array; end ) if AR4_COMPAT
37
47
 
48
+ def number?; !array && super end if AR4_COMPAT
49
+ def text?; !array && super end if AR4_COMPAT
50
+
38
51
  # Extracts the value from a PostgreSQL column default definition.
39
52
  #
40
53
  # @override JdbcColumn#default_value
@@ -354,7 +367,7 @@ module ArJdbc
354
367
  when 'infinity' then 1.0 / 0.0
355
368
  when '-infinity' then -1.0 / 0.0
356
369
  when / BC$/
357
- super("-" + string.sub(/ BC$/, ""))
370
+ super("-#{string.sub(/ BC$/, "")}")
358
371
  else
359
372
  super
360
373
  end
@@ -376,9 +389,11 @@ module ArJdbc
376
389
  end
377
390
  end if AR4_COMPAT
378
391
 
379
- def hstore_to_string(object)
392
+ def hstore_to_string(object, array_member = false)
380
393
  if Hash === object
381
- object.map { |k,v| "#{escape_hstore(k)}=>#{escape_hstore(v)}" }.join(',')
394
+ string = object.map { |k, v| "#{escape_hstore(k)}=>#{escape_hstore(v)}" }.join(',')
395
+ string = escape_hstore(string) if array_member
396
+ string
382
397
  else
383
398
  object
384
399
  end
@@ -388,10 +403,10 @@ module ArJdbc
388
403
  if string.nil?
389
404
  nil
390
405
  elsif String === string
391
- Hash[string.scan(HstorePair).map { |k,v|
392
- v = v.upcase == 'NULL' ? nil : v.gsub(/^"(.*)"$/,'\1').gsub(/\\(.)/, '\1')
393
- k = k.gsub(/^"(.*)"$/,'\1').gsub(/\\(.)/, '\1')
394
- [k,v]
406
+ Hash[string.scan(HstorePair).map { |k, v|
407
+ v = v.upcase == 'NULL' ? nil : v.gsub(/\A"(.*)"\Z/m,'\1').gsub(/\\(.)/, '\1')
408
+ k = k.gsub(/\A"(.*)"\Z/m,'\1').gsub(/\\(.)/, '\1')
409
+ [k, v]
395
410
  }]
396
411
  else
397
412
  string
@@ -406,7 +421,7 @@ module ArJdbc
406
421
  end
407
422
  end
408
423
 
409
- def array_to_string(value, column, adapter, should_be_quoted = false)
424
+ def array_to_string(value, column, adapter)
410
425
  casted_values = value.map do |val|
411
426
  if String === val
412
427
  if val == "NULL"
@@ -439,7 +454,11 @@ module ArJdbc
439
454
  if string.nil?
440
455
  nil
441
456
  elsif String === string
442
- IPAddr.new(string)
457
+ begin
458
+ IPAddr.new(string)
459
+ rescue ArgumentError
460
+ nil
461
+ end
443
462
  else
444
463
  string
445
464
  end
@@ -454,9 +473,9 @@ module ArJdbc
454
473
  end
455
474
 
456
475
  # @note Only used for default values - we get a "parsed" array from JDBC.
457
- def string_to_array(string, column)
476
+ def string_to_array(string, column_or_oid)
458
477
  return string unless String === string
459
- parse_pg_array(string).map { |val| column.type_cast(val, column.type) }
478
+ parse_pg_array(string).map { |val| type_cast_array(column_or_oid, val) }
460
479
  end
461
480
 
462
481
  private
@@ -480,12 +499,28 @@ module ArJdbc
480
499
  end
481
500
  end
482
501
 
502
+ ARRAY_ESCAPE = "\\" * 2 * 2 # escape the backslash twice for PG arrays
503
+
483
504
  def quote_and_escape(value)
484
505
  case value
485
- when "NULL"
506
+ when "NULL", Numeric
486
507
  value
487
508
  else
488
- "\"#{value.gsub(/(["\\])/, '\\\\\1')}\""
509
+ value = value.gsub(/\\/, ARRAY_ESCAPE)
510
+ value.gsub!(/"/,"\\\"")
511
+ "\"#{value}\""
512
+ end
513
+ end
514
+
515
+ def type_cast_array(oid, value)
516
+ if ::Array === value
517
+ value.map { |item| type_cast_array(oid, item) }
518
+ else
519
+ if oid.is_a?(Column)
520
+ oid.type_cast value, oid.type # column.type
521
+ else
522
+ oid.type_cast value
523
+ end
489
524
  end
490
525
  end
491
526
 
@@ -0,0 +1,126 @@
1
+ require 'arjdbc/postgresql/base/oid' # 'active_record/connection_adapters/postgresql/oid'
2
+ require 'thread'
3
+
4
+ module ArJdbc
5
+ module PostgreSQL
6
+ module OIDTypes
7
+
8
+ OID = ActiveRecord::ConnectionAdapters::PostgreSQL::OID
9
+
10
+ def get_oid_type(oid, fmod, column_name)
11
+ type_map.fetch(oid, fmod) {
12
+ warn "unknown OID #{oid}: failed to recognize type of '#{column_name}'. It will be treated as String."
13
+ type_map[oid] = OID::Identity.new
14
+ }
15
+ end
16
+
17
+ # @override
18
+ def enable_extension(name)
19
+ result = super(name)
20
+ @extensions = nil
21
+ reload_type_map
22
+ result
23
+ end
24
+
25
+ # @override
26
+ def disable_extension(name)
27
+ result = super(name)
28
+ @extensions = nil
29
+ reload_type_map
30
+ result
31
+ end
32
+
33
+ # @override
34
+ def extensions
35
+ @extensions ||= super
36
+ end
37
+
38
+ private
39
+
40
+ @@type_map_cache = {}
41
+ @@type_map_cache_lock = Mutex.new
42
+
43
+ # @private
44
+ class OID::TypeMap
45
+ def dup
46
+ dup = super # make sure @mapping is not shared
47
+ dup.instance_variable_set(:@mapping, @mapping.dup)
48
+ dup
49
+ end
50
+ end
51
+
52
+ def type_map
53
+ # NOTE: our type_map is lazy since it's only used for `adapter.accessor`
54
+ @type_map ||= begin
55
+ if type_map = @@type_map_cache[ type_cache_key ]
56
+ type_map.dup
57
+ else
58
+ type_map = OID::TypeMap.new
59
+ initialize_type_map(type_map)
60
+ cache_type_map(type_map)
61
+ type_map
62
+ end
63
+ end
64
+ end
65
+
66
+ def reload_type_map
67
+ if ( @type_map ||= nil )
68
+ @type_map.clear
69
+ initialize_type_map(@type_map)
70
+ end
71
+ end
72
+
73
+ def cache_type_map(type_map)
74
+ @@type_map_cache_lock.synchronize do
75
+ @@type_map_cache[ type_cache_key ] = type_map
76
+ end
77
+ end
78
+
79
+ def type_cache_key
80
+ config.hash + ( 7 * extensions.hash )
81
+ end
82
+
83
+ def add_oid(row, records_by_oid, type_map)
84
+ return type_map if type_map.key? row['type_elem'].to_i
85
+
86
+ if OID.registered_type? typname = row['typname']
87
+ # this composite type is explicitly registered
88
+ vector = OID::NAMES[ typname ]
89
+ else
90
+ # use the default for composite types
91
+ unless type_map.key? typelem = row['typelem'].to_i
92
+ add_oid records_by_oid[ row['typelem'] ], records_by_oid, type_map
93
+ end
94
+
95
+ vector = OID::Vector.new row['typdelim'], type_map[typelem]
96
+ end
97
+
98
+ type_map[ row['oid'].to_i ] = vector
99
+ type_map
100
+ end
101
+
102
+ def initialize_type_map(type_map)
103
+ result = execute('SELECT oid, typname, typelem, typdelim, typinput FROM pg_type', 'SCHEMA')
104
+ leaves, nodes = result.partition { |row| row['typelem'].to_s == '0' }
105
+ # populate the leaf nodes
106
+ leaves.find_all { |row| OID.registered_type? row['typname'] }.each do |row|
107
+ type_map[ row['oid'].to_i ] = OID::NAMES[ row['typname'] ]
108
+ end
109
+
110
+ records_by_oid = result.group_by { |row| row['oid'] }
111
+
112
+ arrays, nodes = nodes.partition { |row| row['typinput'] == 'array_in' }
113
+
114
+ # populate composite types
115
+ nodes.each { |row| add_oid row, records_by_oid, type_map }
116
+
117
+ # populate array types
118
+ arrays.find_all { |row| type_map.key? row['typelem'].to_i }.each do |row|
119
+ array = OID::Array.new type_map[ row['typelem'].to_i ]
120
+ type_map[ row['oid'].to_i ] = array
121
+ end
122
+ end
123
+
124
+ end
125
+ end
126
+ end
@@ -20,8 +20,10 @@ module ArJdbc
20
20
  # @override
21
21
  def delete_database_files(config)
22
22
  return unless db_base = database_base_name(config)
23
- db_files = [ "#{db_base}.h2.db", "#{db_base}.lock.db", "#{db_base}.trace.db" ]
24
- db_files.each { |file| File.delete(file) if File.exist?(file) }
23
+ for suffix in [ '.h2,db', '.mv.db', '.lock.db', '.trace.db' ]
24
+ db_file = "#{db_base}#{suffix}"
25
+ File.delete(db_file) if File.exist?(db_file)
26
+ end
25
27
  end
26
28
 
27
29
  end
@@ -1,5 +1,5 @@
1
1
  module ArJdbc
2
- VERSION = "1.3.7"
2
+ VERSION = "1.3.8"
3
3
  # @deprecated
4
4
  module Version
5
5
  # @private 1.2.x compatibility
@@ -47,16 +47,6 @@ task 'test_appraisal_hint' do
47
47
  end
48
48
  end
49
49
 
50
- desc "Run unit tests (not connecting to a DB)."
51
- Rake::TestTask.new(:test_unit) do |test_task|
52
- test_task.test_files = FileList["test/unit*_test.rb"] + FileList["test/unit/*_test.rb"]
53
- test_task.libs << 'lib' if defined?(JRUBY_VERSION)
54
- test_task.libs << 'test'
55
- test_task.verbose = true if $VERBOSE
56
- set_test_task_compat_version test_task
57
- end
58
- task :test_units => :test_unit # alias
59
-
60
50
  Rake::TestTask.class_eval { attr_reader :test_files }
61
51
 
62
52
  def test_task_for(adapter, options = {})
@@ -95,12 +85,14 @@ test_task_for :H2, :desc => 'Run tests against H2 database engine'
95
85
  test_task_for :HSQLDB, :desc => 'Run tests against HyperSQL (Java) database'
96
86
  test_task_for :MSSQL, :driver => :jtds, :database_name => 'MS-SQL (SQLServer)'
97
87
  test_task_for :MySQL, :prereqs => 'db:mysql'
98
- test_task_for :PostgreSQL, :prereqs => 'db:postgresql', :driver => 'postgres'
88
+ test_task_for :PostgreSQL, :driver => 'postgres', :prereqs => 'db:postgresql'
99
89
  task :test_postgres => :test_postgresql # alias
100
90
  test_task_for :SQLite3
101
91
  task :test_sqlite => :test_sqlite3 # alias
102
92
  test_task_for :Firebird
103
93
 
94
+ test_task_for :MariaDB, :prereqs => 'db:mysql', :files => FileList["test/db/mysql/*_test.rb"]
95
+
104
96
  # ensure driver for these DBs is on your class-path
105
97
  [ :Oracle, :DB2, :Informix, :CacheDB ].each do |adapter|
106
98
  test_task_for adapter, :desc => "Run tests against #{adapter} (ensure driver is on class-path)"
@@ -136,22 +128,3 @@ end
136
128
  #task :test_sybase_jtds => :test_sybase # alias
137
129
  #test_task_for :Sybase, :name => 'sybase_jconnect',
138
130
  # :desc => "Run tests against Sybase (ensure jConnect driver is on class-path)"
139
-
140
- Rake::TraceOutput.module_eval do
141
-
142
- # NOTE: avoid TypeError: String can't be coerced into Fixnum
143
- # due this method getting some strings == [ 1 ] argument ...
144
- def trace_on(out, *strings)
145
- sep = $\ || "\n"
146
- if strings.empty?
147
- output = sep
148
- else
149
- output = strings.map { |s|
150
- next if s.nil?; s = s.to_s
151
- s =~ /#{sep}$/ ? s : s + sep
152
- }.join
153
- end
154
- out.print(output)
155
- end
156
-
157
- end
@@ -171,14 +171,6 @@ public class DerbyModule {
171
171
  return RubyString.newString(context.getRuntime(), BYTES_0);
172
172
  }
173
173
 
174
- private static RubyString quoteBoolean(final Ruby runtime, final IRubyObject value) {
175
- return value.isTrue() ? runtime.newString(BYTES_1) : runtime.newString(BYTES_0);
176
- }
177
-
178
- private static boolean isMultibyteChars(final Ruby runtime, final IRubyObject value) {
179
- return getMultibyteChars(runtime).isInstance(value);
180
- }
181
-
182
174
  private static RubyModule getMultibyteChars(final Ruby runtime) {
183
175
  return (RubyModule) ((RubyModule) runtime.getModule("ActiveSupport").
184
176
  getConstant("Multibyte")).getConstantAt("Chars");
@@ -46,6 +46,7 @@ import org.jruby.util.ByteList;
46
46
  * @author kares
47
47
  */
48
48
  public class DerbyRubyJdbcConnection extends RubyJdbcConnection {
49
+ private static final long serialVersionUID = 4809475910953623325L;
49
50
 
50
51
  protected DerbyRubyJdbcConnection(Ruby runtime, RubyClass metaClass) {
51
52
  super(runtime, metaClass);
@@ -37,6 +37,8 @@ import org.jruby.runtime.builtin.IRubyObject;
37
37
  * @author nicksieger
38
38
  */
39
39
  public class H2RubyJdbcConnection extends RubyJdbcConnection {
40
+ private static final long serialVersionUID = -2652911264521657428L;
41
+
40
42
  protected H2RubyJdbcConnection(Ruby runtime, RubyClass metaClass) {
41
43
  super(runtime, metaClass);
42
44
  }
@@ -1300,7 +1300,7 @@ public class RubyJdbcConnection extends RubyObject {
1300
1300
  final boolean binary = // column.type == :binary
1301
1301
  column.callMethod(context, "type").toString() == (Object) "binary";
1302
1302
 
1303
- final RubyClass recordClass = record.getMetaClass(); // record.class
1303
+ final IRubyObject recordClass = record.callMethod(context, "class");
1304
1304
  final IRubyObject adapter = recordClass.callMethod(context, "connection");
1305
1305
 
1306
1306
  IRubyObject columnName = column.callMethod(context, "name");
@@ -1314,7 +1314,7 @@ public class RubyJdbcConnection extends RubyObject {
1314
1314
 
1315
1315
  final IRubyObject id = record.callMethod(context, "id"); // record.id
1316
1316
 
1317
- int count = updateLobValue(context,
1317
+ final int count = updateLobValue(context,
1318
1318
  tableName.toString(), columnName.toString(), column,
1319
1319
  idKey.toString(), id, idColumn, value, binary
1320
1320
  );
@@ -2860,12 +2860,12 @@ public class RubyJdbcConnection extends RubyObject {
2860
2860
  final Ruby runtime = context.getRuntime();
2861
2861
  final IRubyObject jdbcColumn = getJdbcColumnClass(context);
2862
2862
 
2863
- final List<String> primarykeyNames = new ArrayList<String>();
2863
+ final List<String> primaryKeyNames = new ArrayList<String>(4);
2864
2864
  while ( primaryKeys.next() ) {
2865
- primarykeyNames.add( primaryKeys.getString(COLUMN_NAME) );
2865
+ primaryKeyNames.add( primaryKeys.getString(COLUMN_NAME) );
2866
2866
  }
2867
2867
 
2868
- final List<IRubyObject> columns = new ArrayList<IRubyObject>();
2868
+ final RubyArray columns = runtime.newArray();
2869
2869
  final IRubyObject config = getInstanceVariable("@config");
2870
2870
  while ( results.next() ) {
2871
2871
  final String colName = results.getString(COLUMN_NAME);
@@ -2877,13 +2877,13 @@ public class RubyJdbcConnection extends RubyObject {
2877
2877
  RubyString.newUnicodeString( runtime, typeFromResultSet(results) ),
2878
2878
  runtime.newBoolean( ! results.getString(IS_NULLABLE).trim().equals("NO") )
2879
2879
  });
2880
- columns.add(column);
2880
+ columns.append(column);
2881
2881
 
2882
- if ( primarykeyNames.contains(colName) ) {
2882
+ if ( primaryKeyNames.contains(colName) ) {
2883
2883
  column.callMethod(context, "primary=", runtime.getTrue());
2884
2884
  }
2885
2885
  }
2886
- return runtime.newArray(columns);
2886
+ return columns;
2887
2887
  }
2888
2888
 
2889
2889
  protected IRubyObject mapGeneratedKeys(
@@ -25,47 +25,78 @@ package arjdbc.mssql;
25
25
 
26
26
  import static arjdbc.util.QuotingUtils.BYTES_0;
27
27
  import static arjdbc.util.QuotingUtils.BYTES_1;
28
+ import static arjdbc.util.QuotingUtils.quoteCharWith;
28
29
  import static arjdbc.util.QuotingUtils.quoteSingleQuotesWithFallback;
29
30
 
30
31
  import org.jruby.RubyModule;
31
32
  import org.jruby.RubyString;
32
33
  import org.jruby.anno.JRubyMethod;
33
34
  import org.jruby.runtime.ThreadContext;
35
+ import org.jruby.runtime.Visibility;
34
36
  import org.jruby.runtime.builtin.IRubyObject;
37
+ import org.jruby.util.ByteList;
35
38
 
36
39
  /**
37
40
  * ArJdbc::MSSQL
38
- *
41
+ *
39
42
  * @author kares
40
43
  */
41
44
  public class MSSQLModule {
42
-
45
+
43
46
  public static RubyModule load(final RubyModule arJdbc) {
44
47
  RubyModule mssql = arJdbc.defineModuleUnder("MSSQL");
45
48
  mssql.defineAnnotatedMethods( MSSQLModule.class );
46
49
  return mssql;
47
50
  }
48
-
49
- @JRubyMethod(name = "quote_string", required = 1, frame = false)
50
- public static IRubyObject quote_string(
51
- final ThreadContext context,
52
- final IRubyObject self,
53
- final IRubyObject string) {
51
+
52
+ @JRubyMethod(name = "quote_string", required = 1)
53
+ public static IRubyObject quote_string(final ThreadContext context,
54
+ final IRubyObject self, final IRubyObject string) {
54
55
  return quoteSingleQuotesWithFallback(context, string);
55
56
  }
56
-
57
- @JRubyMethod(name = "quoted_true", required = 0, frame = false)
58
- public static IRubyObject quoted_true(
59
- final ThreadContext context,
60
- final IRubyObject self) {
57
+
58
+ @JRubyMethod(name = "quoted_true", required = 0)
59
+ public static IRubyObject quoted_true(final ThreadContext context,
60
+ final IRubyObject self) {
61
61
  return RubyString.newString(context.getRuntime(), BYTES_1);
62
62
  }
63
-
64
- @JRubyMethod(name = "quoted_false", required = 0, frame = false)
65
- public static IRubyObject quoted_false(
66
- final ThreadContext context,
67
- final IRubyObject self) {
63
+
64
+ @JRubyMethod(name = "quoted_false", required = 0)
65
+ public static IRubyObject quoted_false(final ThreadContext context,
66
+ final IRubyObject self) {
68
67
  return RubyString.newString(context.getRuntime(), BYTES_0);
69
68
  }
70
-
69
+
70
+ // part =~ /^\[.*\]$/ ? part : "[#{part.gsub(']', ']]')}]"
71
+ @SuppressWarnings("deprecation")
72
+ @JRubyMethod(required = 1, visibility = Visibility.PRIVATE)
73
+ public static IRubyObject quote_name_part(final ThreadContext context,
74
+ final IRubyObject self, final IRubyObject part) {
75
+
76
+ final RubyString partString = ((RubyString) part);
77
+ final ByteList str = partString.getByteList();
78
+ if ( str.charAt(0) == '[' && str.charAt(str.length() - 1) == ']' ) {
79
+ return part; // part =~ /^\[.*\]$/ ? part
80
+ }
81
+ final RubyString quotedString = // part.gsub(']', ']]')
82
+ quoteCharWith(context, partString, ']', ']', 1, 4 + 1);
83
+ if ( quotedString == partString ) {
84
+ final int realSize = str.getRealSize();
85
+ final ByteList quoted = new ByteList(
86
+ new byte[realSize + 2], partString.getEncoding(), false
87
+ );
88
+ quoted.begin = 0; quoted.realSize = 0;
89
+ quoted.append('[');
90
+ quoted.append(str.unsafeBytes(), str.getBegin(), realSize);
91
+ quoted.append(']');
92
+ return context.getRuntime().newString(quoted);
93
+ }
94
+ // we got a new string with a reserve of 1 byte front and back :
95
+ final ByteList quoted = quotedString.getByteList();
96
+ quoted.begin = 0; // setBegin invalidates
97
+ quoted.bytes[0] = '['; quoted.realSize++;
98
+ quoted.append(']');
99
+ return quotedString;
100
+ }
101
+
71
102
  }