activerecord-jdbc-adapter 1.3.7 → 1.3.8
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 +4 -4
- data/.travis.yml +33 -3
- data/Appraisals +11 -5
- data/Gemfile +21 -15
- data/History.md +31 -1
- data/lib/active_record/connection_adapters/mariadb_adapter.rb +1 -0
- data/lib/arel/visitors/firebird.rb +7 -10
- data/lib/arel/visitors/h2.rb +9 -0
- data/lib/arel/visitors/sql_server.rb +21 -2
- data/lib/arjdbc/h2/adapter.rb +31 -2
- data/lib/arjdbc/h2/connection_methods.rb +1 -1
- data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
- data/lib/arjdbc/jdbc/column.rb +2 -1
- data/lib/arjdbc/mssql/adapter.rb +40 -23
- data/lib/arjdbc/mssql/column.rb +4 -4
- data/lib/arjdbc/mysql/adapter.rb +36 -10
- data/lib/arjdbc/mysql/column.rb +12 -7
- data/lib/arjdbc/mysql/connection_methods.rb +53 -21
- data/lib/arjdbc/oracle/adapter.rb +22 -5
- data/lib/arjdbc/postgresql/adapter.rb +54 -18
- data/lib/arjdbc/postgresql/base/array_parser.rb +95 -0
- data/lib/arjdbc/postgresql/base/oid.rb +460 -0
- data/lib/arjdbc/postgresql/column.rb +50 -15
- data/lib/arjdbc/postgresql/oid_types.rb +126 -0
- data/lib/arjdbc/tasks/h2_database_tasks.rb +4 -2
- data/lib/arjdbc/version.rb +1 -1
- data/rakelib/02-test.rake +3 -30
- data/src/java/arjdbc/derby/DerbyModule.java +0 -8
- data/src/java/arjdbc/derby/DerbyRubyJdbcConnection.java +1 -0
- data/src/java/arjdbc/h2/H2RubyJdbcConnection.java +2 -0
- data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +8 -8
- data/src/java/arjdbc/mssql/MSSQLModule.java +50 -19
- data/src/java/arjdbc/mssql/MSSQLRubyJdbcConnection.java +1 -0
- data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +6 -6
- data/src/java/arjdbc/oracle/OracleModule.java +1 -1
- data/src/java/arjdbc/oracle/OracleRubyJdbcConnection.java +66 -2
- data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +23 -10
- data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +1 -0
- data/src/java/arjdbc/util/CallResultSet.java +826 -0
- data/src/java/arjdbc/util/QuotingUtils.java +14 -7
- metadata +8 -3
- 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("
|
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(
|
393
|
-
k = k.gsub(
|
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
|
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
|
-
|
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,
|
476
|
+
def string_to_array(string, column_or_oid)
|
458
477
|
return string unless String === string
|
459
|
-
parse_pg_array(string).map { |val|
|
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
|
-
|
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
|
-
|
24
|
-
|
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
|
data/lib/arjdbc/version.rb
CHANGED
data/rakelib/02-test.rake
CHANGED
@@ -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, :
|
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
|
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>
|
2863
|
+
final List<String> primaryKeyNames = new ArrayList<String>(4);
|
2864
2864
|
while ( primaryKeys.next() ) {
|
2865
|
-
|
2865
|
+
primaryKeyNames.add( primaryKeys.getString(COLUMN_NAME) );
|
2866
2866
|
}
|
2867
2867
|
|
2868
|
-
final
|
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.
|
2880
|
+
columns.append(column);
|
2881
2881
|
|
2882
|
-
if (
|
2882
|
+
if ( primaryKeyNames.contains(colName) ) {
|
2883
2883
|
column.callMethod(context, "primary=", runtime.getTrue());
|
2884
2884
|
}
|
2885
2885
|
}
|
2886
|
-
return
|
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
|
50
|
-
public static IRubyObject quote_string(
|
51
|
-
|
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
|
58
|
-
public static IRubyObject quoted_true(
|
59
|
-
|
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
|
65
|
-
public static IRubyObject quoted_false(
|
66
|
-
|
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
|
}
|