activerecord-jdbc-adapter 0.7.2 → 0.8
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +14 -0
- data/{LICENSE → LICENSE.txt} +2 -2
- data/Manifest.txt +4 -1
- data/Rakefile +2 -2
- data/lib/active_record/connection_adapters/jdbc_adapter.rb +26 -11
- data/lib/jdbc_adapter/jdbc.rake +78 -0
- data/lib/jdbc_adapter/jdbc_adapter_internal.jar +0 -0
- data/lib/jdbc_adapter/jdbc_hsqldb.rb +11 -0
- data/lib/jdbc_adapter/jdbc_mysql.rb +6 -5
- data/lib/jdbc_adapter/jdbc_postgre.rb +35 -1
- data/lib/jdbc_adapter/rake_tasks.rb +8 -80
- data/lib/jdbc_adapter/version.rb +1 -1
- data/src/java/jdbc_adapter/JdbcAdapterInternalService.java +41 -48
- data/src/java/jdbc_adapter/JdbcDerbySpec.java +67 -69
- data/src/java/jdbc_adapter/JdbcMySQLSpec.java +16 -20
- data/test/db/derby.rb +0 -1
- data/test/models/reserved_word.rb +18 -0
- data/test/postgres_reserved_test.rb +22 -0
- data/test/simple.rb +1 -1
- metadata +7 -3
data/History.txt
CHANGED
@@ -1,3 +1,17 @@
|
|
1
|
+
== 0.8
|
2
|
+
|
3
|
+
- NOTE: This release is only compatible with JRuby 1.1RC3 or later.
|
4
|
+
- Because of recent API changes in trunk in preparation for JRuby 1.1, this release is not
|
5
|
+
backward compatible with previous JRuby releases. Hence the version bump.
|
6
|
+
- Internal: convert Java methods to be defined with annotations
|
7
|
+
- Fix problem with reserved words coming back pre-quoted from #indexes in postgres
|
8
|
+
- JRUBY-2205: Fix N^2 allocation of bytelists for mysql quoting (taw)
|
9
|
+
- Attempt a fix for Rubyforge 18059
|
10
|
+
- Upgrade derby to 10.3.2.1
|
11
|
+
- Fix db:create etc. in the case where JDBC is loaded in Rails' preinitializer.rb
|
12
|
+
- Fix db:drop to actually work
|
13
|
+
- Fix for Rubyforge #11567 (Matt Williams)
|
14
|
+
|
1
15
|
== 0.7.2
|
2
16
|
|
3
17
|
- JRUBY-1905: add_column for derby, hsqldb, and postgresql (Stephen Bannasch)
|
data/{LICENSE → LICENSE.txt}
RENAMED
@@ -1,5 +1,5 @@
|
|
1
|
-
Copyright (c) 2006-
|
2
|
-
Copyright (c) 2006-
|
1
|
+
Copyright (c) 2006-2008 Nick Sieger <nick@nicksieger.com>
|
2
|
+
Copyright (c) 2006-2008 Ola Bini <ola.bini@gmail.com>
|
3
3
|
|
4
4
|
Permission is hereby granted, free of charge, to any person obtaining
|
5
5
|
a copy of this software and associated documentation files (the
|
data/Manifest.txt
CHANGED
@@ -2,7 +2,7 @@ History.txt
|
|
2
2
|
Manifest.txt
|
3
3
|
README.txt
|
4
4
|
Rakefile
|
5
|
-
LICENSE
|
5
|
+
LICENSE.txt
|
6
6
|
lib/active_record/connection_adapters/derby_adapter.rb
|
7
7
|
lib/active_record/connection_adapters/h2_adapter.rb
|
8
8
|
lib/active_record/connection_adapters/hsqldb_adapter.rb
|
@@ -60,11 +60,14 @@ test/models/add_not_null_column_to_table.rb
|
|
60
60
|
test/models/auto_id.rb
|
61
61
|
test/models/data_types.rb
|
62
62
|
test/models/entry.rb
|
63
|
+
test/models/reserved_word.rb
|
63
64
|
test/mysql_multibyte_test.rb
|
64
65
|
test/mysql_simple_test.rb
|
65
66
|
test/oracle_simple_test.rb
|
67
|
+
test/postgres_reserved_test.rb
|
66
68
|
test/postgres_simple_test.rb
|
67
69
|
test/simple.rb
|
70
|
+
lib/jdbc_adapter/jdbc.rake
|
68
71
|
src/java/jdbc_adapter/JdbcAdapterInternalService.java
|
69
72
|
src/java/jdbc_adapter/JdbcConnectionFactory.java
|
70
73
|
src/java/jdbc_adapter/JdbcDerbySpec.java
|
data/Rakefile
CHANGED
@@ -20,7 +20,7 @@ task :java_compile do
|
|
20
20
|
pkg_classes = File.join(*%w(pkg classes))
|
21
21
|
jar_name = File.join(*%w(lib jdbc_adapter jdbc_adapter_internal.jar))
|
22
22
|
mkdir_p pkg_classes
|
23
|
-
sh "javac -target 1.
|
23
|
+
sh "javac -target 1.5 -source 1.5 -d pkg/classes #{java_classpath_arg} #{FileList['src/java/**/*.java'].join(' ')}"
|
24
24
|
sh "jar cf #{jar_name} -C #{pkg_classes} ."
|
25
25
|
end
|
26
26
|
file "lib/jdbc_adapter/jdbc_adapter_internal.jar" => :java_compile
|
@@ -87,7 +87,7 @@ end
|
|
87
87
|
|
88
88
|
|
89
89
|
MANIFEST = FileList["History.txt", "Manifest.txt", "README.txt",
|
90
|
-
"Rakefile", "LICENSE", "lib/**/*.rb", "lib/jdbc_adapter/jdbc_adapter_internal.jar", "test/**/*.rb",
|
90
|
+
"Rakefile", "LICENSE.txt", "lib/**/*.rb", "lib/jdbc_adapter/jdbc_adapter_internal.jar", "test/**/*.rb",
|
91
91
|
"lib/**/*.rake", "src/**/*.java"]
|
92
92
|
|
93
93
|
file "Manifest.txt" => :manifest
|
@@ -342,19 +342,19 @@ module ActiveRecord
|
|
342
342
|
next unless index_name
|
343
343
|
index_name.downcase!
|
344
344
|
column_name = resultset.get_string(Jdbc::IndexMetaData::COLUMN_NAME).downcase
|
345
|
-
|
345
|
+
|
346
346
|
next if primary_keys.include? column_name
|
347
|
-
|
347
|
+
|
348
348
|
# We are working on a new index
|
349
349
|
if current_index != index_name
|
350
350
|
current_index = index_name
|
351
351
|
table_name = resultset.get_string(Jdbc::IndexMetaData::TABLE_NAME).downcase
|
352
352
|
non_unique = resultset.get_boolean(Jdbc::IndexMetaData::NON_UNIQUE)
|
353
|
-
|
353
|
+
|
354
354
|
# empty list for column names, we'll add to that in just a bit
|
355
355
|
indexes << IndexDefinition.new(table_name, index_name, !non_unique, [])
|
356
356
|
end
|
357
|
-
|
357
|
+
|
358
358
|
# One or more columns can be associated with an index
|
359
359
|
indexes.last.columns << column_name
|
360
360
|
end
|
@@ -404,7 +404,19 @@ module ActiveRecord
|
|
404
404
|
|
405
405
|
end
|
406
406
|
|
407
|
+
module ShadowCoreMethods
|
408
|
+
def alias_chained_method(meth, feature, target)
|
409
|
+
if instance_methods.include?("#{meth}_without_#{feature}")
|
410
|
+
alias_method "#{meth}_without_#{feature}".to_sym, target
|
411
|
+
else
|
412
|
+
alias_method meth, target
|
413
|
+
end
|
414
|
+
end
|
415
|
+
end
|
416
|
+
|
407
417
|
class JdbcAdapter < AbstractAdapter
|
418
|
+
extend ShadowCoreMethods
|
419
|
+
|
408
420
|
attr_reader :config
|
409
421
|
|
410
422
|
ADAPTER_TYPES = ::JdbcSpec.constants.map{|c|
|
@@ -484,14 +496,15 @@ module ActiveRecord
|
|
484
496
|
@connection.reconnect!
|
485
497
|
@connection
|
486
498
|
end
|
487
|
-
|
499
|
+
|
488
500
|
def disconnect!
|
489
501
|
@connection.disconnect!
|
490
502
|
end
|
491
503
|
|
492
|
-
def
|
504
|
+
def jdbc_select_all(sql, name = nil)
|
493
505
|
select(sql, name)
|
494
506
|
end
|
507
|
+
alias_chained_method :select_all, :query_cache, :jdbc_select_all
|
495
508
|
|
496
509
|
def select_rows(sql, name = nil)
|
497
510
|
rows = []
|
@@ -508,8 +521,7 @@ module ActiveRecord
|
|
508
521
|
_execute(sql,name)
|
509
522
|
end
|
510
523
|
end
|
511
|
-
|
512
|
-
|
524
|
+
|
513
525
|
# we need to do it this way, to allow Rails stupid tests to always work
|
514
526
|
# even if we define a new execute method. Instead of mixing in a new
|
515
527
|
# execute, an _execute should be mixed in.
|
@@ -523,18 +535,21 @@ module ActiveRecord
|
|
523
535
|
end
|
524
536
|
end
|
525
537
|
|
526
|
-
def
|
538
|
+
def jdbc_update(sql, name = nil) #:nodoc:
|
527
539
|
execute(sql, name)
|
528
540
|
end
|
541
|
+
alias_chained_method :update, :query_dirty, :jdbc_update
|
529
542
|
|
530
|
-
def
|
543
|
+
def jdbc_insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
|
531
544
|
id = execute(sql, name = nil)
|
532
545
|
id_value || id
|
533
546
|
end
|
547
|
+
alias_chained_method :insert, :query_dirty, :jdbc_insert
|
534
548
|
|
535
|
-
def
|
549
|
+
def jdbc_columns(table_name, name = nil)
|
536
550
|
@connection.columns(table_name.to_s)
|
537
551
|
end
|
552
|
+
alias_chained_method :columns, :query_cache, :jdbc_columns
|
538
553
|
|
539
554
|
def tables
|
540
555
|
@connection.tables
|
@@ -0,0 +1,78 @@
|
|
1
|
+
def redefine_task(*args, &block)
|
2
|
+
task_name = Hash === args.first ? args.first.keys[0] : args.first
|
3
|
+
existing_task = Rake.application.lookup task_name
|
4
|
+
if existing_task
|
5
|
+
class << existing_task; public :instance_variable_set; end
|
6
|
+
existing_task.instance_variable_set "@prerequisites", FileList[]
|
7
|
+
existing_task.instance_variable_set "@actions", []
|
8
|
+
end
|
9
|
+
task(*args, &block)
|
10
|
+
end
|
11
|
+
|
12
|
+
namespace :db do
|
13
|
+
redefine_task :create => :environment do
|
14
|
+
create_database(ActiveRecord::Base.configurations[RAILS_ENV])
|
15
|
+
end
|
16
|
+
|
17
|
+
class << self; alias_method :previous_create_database, :create_database; end
|
18
|
+
def create_database(config)
|
19
|
+
begin
|
20
|
+
ActiveRecord::Base.establish_connection(config)
|
21
|
+
ActiveRecord::Base.connection
|
22
|
+
rescue
|
23
|
+
begin
|
24
|
+
url = config['url']
|
25
|
+
if url
|
26
|
+
if url =~ /^(.*\/)/
|
27
|
+
url = $1
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
ActiveRecord::Base.establish_connection(config.merge({'database' => nil, 'url' => url}))
|
32
|
+
ActiveRecord::Base.connection.create_database(config['database'])
|
33
|
+
ActiveRecord::Base.establish_connection(config)
|
34
|
+
rescue
|
35
|
+
previous_create_database(config)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
redefine_task :drop => :environment do
|
41
|
+
config = ActiveRecord::Base.configurations[RAILS_ENV]
|
42
|
+
begin
|
43
|
+
ActiveRecord::Base.establish_connection(config)
|
44
|
+
db = ActiveRecord::Base.connection.database_name
|
45
|
+
ActiveRecord::Base.connection.drop_database(db)
|
46
|
+
rescue
|
47
|
+
drop_database(config)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
namespace :structure do
|
52
|
+
redefine_task :dump => :environment do
|
53
|
+
abcs = ActiveRecord::Base.configurations
|
54
|
+
ActiveRecord::Base.establish_connection(abcs[RAILS_ENV])
|
55
|
+
File.open("db/#{RAILS_ENV}_structure.sql", "w+") { |f| f << ActiveRecord::Base.connection.structure_dump }
|
56
|
+
if ActiveRecord::Base.connection.supports_migrations?
|
57
|
+
File.open("db/#{RAILS_ENV}_structure.sql", "a") { |f| f << ActiveRecord::Base.connection.dump_schema_information }
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
namespace :test do
|
62
|
+
redefine_task :clone_structure => [ "db:structure:dump", "db:test:purge" ] do
|
63
|
+
abcs = ActiveRecord::Base.configurations
|
64
|
+
ActiveRecord::Base.establish_connection(:test)
|
65
|
+
ActiveRecord::Base.connection.execute('SET foreign_key_checks = 0') if abcs["test"]["adapter"] =~ /mysql/i
|
66
|
+
IO.readlines("db/#{RAILS_ENV}_structure.sql").join.split(";\n\n").each do |ddl|
|
67
|
+
ActiveRecord::Base.connection.execute(ddl)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
redefine_task :purge => :environment do
|
72
|
+
abcs = ActiveRecord::Base.configurations
|
73
|
+
ActiveRecord::Base.establish_connection(:test)
|
74
|
+
db = ActiveRecord::Base.connection.database_name
|
75
|
+
ActiveRecord::Base.connection.recreate_database(db)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
Binary file
|
@@ -157,6 +157,17 @@ module ::JdbcSpec
|
|
157
157
|
Integer(select_value("SELECT IDENTITY() FROM #{table}"))
|
158
158
|
end
|
159
159
|
|
160
|
+
# Override normal #_execute: See Rubyforge #11567
|
161
|
+
def _execute(sql, name = nil)
|
162
|
+
if ::ActiveRecord::ConnectionAdapters::JdbcConnection::select?(sql)
|
163
|
+
@connection.execute_query(sql)
|
164
|
+
elsif ::ActiveRecord::ConnectionAdapters::JdbcConnection::insert?(sql)
|
165
|
+
insert(sql, name)
|
166
|
+
else
|
167
|
+
@connection.execute_update(sql)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
160
171
|
def add_limit_offset!(sql, options) #:nodoc:
|
161
172
|
offset = options[:offset] || 0
|
162
173
|
bef = sql[7..-1]
|
@@ -6,9 +6,6 @@ module ::JdbcSpec
|
|
6
6
|
|
7
7
|
module ActiveRecordExtensions
|
8
8
|
def mysql_connection(config)
|
9
|
-
if config[:socket]
|
10
|
-
warn "AR-JDBC MySQL on JRuby does not support sockets"
|
11
|
-
end
|
12
9
|
config[:port] ||= 3306
|
13
10
|
if config[:url]
|
14
11
|
config[:url] = config[:url]['?'] ? "#{config[:url]}&#{MySQL::URL_OPTIONS}" : "#{config[:url]}?#{MySQL::URL_OPTIONS}"
|
@@ -147,8 +144,12 @@ module ::JdbcSpec
|
|
147
144
|
create_database(name)
|
148
145
|
end
|
149
146
|
|
150
|
-
def create_database(name) #:nodoc:
|
151
|
-
|
147
|
+
def create_database(name, options = {}) #:nodoc:
|
148
|
+
if options[:collation]
|
149
|
+
execute "CREATE DATABASE `#{name}` DEFAULT CHARACTER SET `#{options[:charset] || 'utf8'}` COLLATE `#{options[:collation]}`"
|
150
|
+
else
|
151
|
+
execute "CREATE DATABASE `#{name}` DEFAULT CHARACTER SET `#{options[:charset] || 'utf8'}`"
|
152
|
+
end
|
152
153
|
end
|
153
154
|
|
154
155
|
def drop_database(name) #:nodoc:
|
@@ -177,7 +177,41 @@ module ::JdbcSpec
|
|
177
177
|
end
|
178
178
|
@connection.columns_internal(table_name, name, schema_name)
|
179
179
|
end
|
180
|
-
|
180
|
+
|
181
|
+
# From postgresql_adapter.rb
|
182
|
+
def indexes(table_name, name = nil)
|
183
|
+
result = select_rows(<<-SQL, name)
|
184
|
+
SELECT i.relname, d.indisunique, a.attname
|
185
|
+
FROM pg_class t, pg_class i, pg_index d, pg_attribute a
|
186
|
+
WHERE i.relkind = 'i'
|
187
|
+
AND d.indexrelid = i.oid
|
188
|
+
AND d.indisprimary = 'f'
|
189
|
+
AND t.oid = d.indrelid
|
190
|
+
AND t.relname = '#{table_name}'
|
191
|
+
AND a.attrelid = t.oid
|
192
|
+
AND ( d.indkey[0]=a.attnum OR d.indkey[1]=a.attnum
|
193
|
+
OR d.indkey[2]=a.attnum OR d.indkey[3]=a.attnum
|
194
|
+
OR d.indkey[4]=a.attnum OR d.indkey[5]=a.attnum
|
195
|
+
OR d.indkey[6]=a.attnum OR d.indkey[7]=a.attnum
|
196
|
+
OR d.indkey[8]=a.attnum OR d.indkey[9]=a.attnum )
|
197
|
+
ORDER BY i.relname
|
198
|
+
SQL
|
199
|
+
|
200
|
+
current_index = nil
|
201
|
+
indexes = []
|
202
|
+
|
203
|
+
result.each do |row|
|
204
|
+
if current_index != row[0]
|
205
|
+
indexes << ::ActiveRecord::ConnectionAdapters::IndexDefinition.new(table_name, row[0], row[1] == "t", [])
|
206
|
+
current_index = row[0]
|
207
|
+
end
|
208
|
+
|
209
|
+
indexes.last.columns << row[2]
|
210
|
+
end
|
211
|
+
|
212
|
+
indexes
|
213
|
+
end
|
214
|
+
|
181
215
|
def last_insert_id(table, sequence_name)
|
182
216
|
Integer(select_value("SELECT currval('#{sequence_name}')"))
|
183
217
|
end
|
@@ -1,82 +1,10 @@
|
|
1
|
-
if defined?(
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
end
|
10
|
-
task(*args, &block)
|
11
|
-
end
|
12
|
-
|
13
|
-
namespace :db do
|
14
|
-
redefine_task :create => :environment do
|
15
|
-
create_database(ActiveRecord::Base.configurations[RAILS_ENV])
|
16
|
-
end
|
17
|
-
|
18
|
-
def create_database(config)
|
19
|
-
begin
|
20
|
-
ActiveRecord::Base.establish_connection(config)
|
21
|
-
ActiveRecord::Base.connection
|
22
|
-
rescue
|
23
|
-
begin
|
24
|
-
url = config['url']
|
25
|
-
if url
|
26
|
-
if url =~ /^(.*\/)/
|
27
|
-
url = $1
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
ActiveRecord::Base.establish_connection(config.merge({'database' => nil, 'url' => url}))
|
32
|
-
ActiveRecord::Base.connection.create_database(config['database'])
|
33
|
-
ActiveRecord::Base.establish_connection(config)
|
34
|
-
rescue
|
35
|
-
if (config['driver'] || config['adapter']) =~ /postgr/
|
36
|
-
`createdb "#{config['database']}" -E utf8`
|
37
|
-
else
|
38
|
-
warn "couldn't create database #{config['database']}"
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
redefine_task :drop => :environment do
|
45
|
-
begin
|
46
|
-
config = ActiveRecord::Base.configurations[environment_name]
|
47
|
-
ActiveRecord::Base.establish_connection(config)
|
48
|
-
db = ActiveRecord::Base.connection.database_name
|
49
|
-
ActiveRecord::Base.connection.recreate_database(db)
|
50
|
-
rescue
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
namespace :structure do
|
55
|
-
redefine_task :dump => :environment do
|
56
|
-
abcs = ActiveRecord::Base.configurations
|
57
|
-
ActiveRecord::Base.establish_connection(abcs[RAILS_ENV])
|
58
|
-
File.open("db/#{RAILS_ENV}_structure.sql", "w+") { |f| f << ActiveRecord::Base.connection.structure_dump }
|
59
|
-
if ActiveRecord::Base.connection.supports_migrations?
|
60
|
-
File.open("db/#{RAILS_ENV}_structure.sql", "a") { |f| f << ActiveRecord::Base.connection.dump_schema_information }
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
64
|
-
namespace :test do
|
65
|
-
redefine_task :clone_structure => [ "db:structure:dump", "db:test:purge" ] do
|
66
|
-
abcs = ActiveRecord::Base.configurations
|
67
|
-
ActiveRecord::Base.establish_connection(:test)
|
68
|
-
ActiveRecord::Base.connection.execute('SET foreign_key_checks = 0') if abcs["test"]["adapter"] =~ /mysql/i
|
69
|
-
IO.readlines("db/#{RAILS_ENV}_structure.sql").join.split(";\n\n").each do |ddl|
|
70
|
-
ActiveRecord::Base.connection.execute(ddl)
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
redefine_task :purge => :environment do
|
75
|
-
abcs = ActiveRecord::Base.configurations
|
76
|
-
ActiveRecord::Base.establish_connection(:test)
|
77
|
-
db = ActiveRecord::Base.connection.database_name
|
78
|
-
ActiveRecord::Base.connection.recreate_database(db)
|
79
|
-
end
|
80
|
-
end
|
1
|
+
if defined?(Rake.application) && Rake.application && ENV["SKIP_AR_JDBC_RAKE_REDEFINES"].nil?
|
2
|
+
jdbc_rakefile = File.dirname(__FILE__) + "/jdbc.rake"
|
3
|
+
if Rake.application.lookup("environment")
|
4
|
+
# rails tasks already defined; load the override tasks now
|
5
|
+
load jdbc_rakefile
|
6
|
+
else
|
7
|
+
# rails tasks not loaded yet; load as an import
|
8
|
+
Rake.application.add_import(jdbc_rakefile)
|
81
9
|
end
|
82
10
|
end
|
data/lib/jdbc_adapter/version.rb
CHANGED
@@ -59,14 +59,13 @@ import org.jruby.RubyObjectAdapter;
|
|
59
59
|
import org.jruby.RubyString;
|
60
60
|
import org.jruby.RubySymbol;
|
61
61
|
import org.jruby.RubyTime;
|
62
|
-
import org.jruby.
|
63
|
-
exceptions.RaiseException;
|
62
|
+
import org.jruby.anno.JRubyMethod;
|
63
|
+
import org.jruby.exceptions.RaiseException;
|
64
64
|
import org.jruby.javasupport.Java;
|
65
65
|
import org.jruby.javasupport.JavaEmbedUtils;
|
66
66
|
import org.jruby.javasupport.JavaObject;
|
67
67
|
import org.jruby.runtime.Arity;
|
68
68
|
import org.jruby.runtime.Block;
|
69
|
-
import org.jruby.runtime.CallbackFactory;
|
70
69
|
import org.jruby.runtime.ThreadContext;
|
71
70
|
import org.jruby.runtime.builtin.IRubyObject;
|
72
71
|
import org.jruby.runtime.load.BasicLibraryService;
|
@@ -76,43 +75,14 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
|
|
76
75
|
private static RubyObjectAdapter rubyApi;
|
77
76
|
|
78
77
|
public boolean basicLoad(final Ruby runtime) throws IOException {
|
79
|
-
|
78
|
+
RubyModule jdbcConnection = ((RubyModule)(runtime.getModule("ActiveRecord").getConstant("ConnectionAdapters"))).
|
80
79
|
defineClassUnder("JdbcConnection",runtime.getObject(),runtime.getObject().getAllocator());
|
81
|
-
|
82
|
-
CallbackFactory cf = runtime.callbackFactory(JdbcAdapterInternalService.class);
|
83
|
-
cJdbcConn.defineMethod("unmarshal_result",cf.getSingletonMethod("unmarshal_result", IRubyObject.class));
|
84
|
-
cJdbcConn.defineMethod("with_connection_retry_guard",cf.getSingletonMethod("with_connection_retry_guard"));
|
85
|
-
cJdbcConn.defineFastMethod("connection",cf.getFastSingletonMethod("connection"));
|
86
|
-
cJdbcConn.defineFastMethod("reconnect!",cf.getFastSingletonMethod("reconnect"));
|
87
|
-
cJdbcConn.defineFastMethod("disconnect!",cf.getFastSingletonMethod("disconnect"));
|
88
|
-
cJdbcConn.defineFastMethod("execute_update",cf.getFastSingletonMethod("execute_update", IRubyObject.class));
|
89
|
-
cJdbcConn.defineFastMethod("execute_query",cf.getFastOptSingletonMethod("execute_query"));
|
90
|
-
cJdbcConn.defineFastMethod("execute_insert",cf.getFastSingletonMethod("execute_insert", IRubyObject.class));
|
91
|
-
cJdbcConn.defineFastMethod("execute_id_insert",cf.getFastSingletonMethod("execute_id_insert", IRubyObject.class, IRubyObject.class));
|
92
|
-
cJdbcConn.defineFastMethod("primary_keys",cf.getFastSingletonMethod("primary_keys", IRubyObject.class));
|
93
|
-
cJdbcConn.defineFastMethod("set_native_database_types",cf.getFastSingletonMethod("set_native_database_types"));
|
94
|
-
cJdbcConn.defineFastMethod("native_database_types",cf.getFastSingletonMethod("native_database_types"));
|
95
|
-
cJdbcConn.defineFastMethod("begin",cf.getFastSingletonMethod("begin"));
|
96
|
-
cJdbcConn.defineFastMethod("commit",cf.getFastSingletonMethod("commit"));
|
97
|
-
cJdbcConn.defineFastMethod("rollback",cf.getFastSingletonMethod("rollback"));
|
98
|
-
cJdbcConn.defineFastMethod("database_name",cf.getFastSingletonMethod("database_name"));
|
99
|
-
cJdbcConn.defineFastMethod("columns",cf.getFastOptSingletonMethod("columns_internal"));
|
100
|
-
cJdbcConn.defineFastMethod("columns_internal",cf.getFastOptSingletonMethod("columns_internal"));
|
101
|
-
cJdbcConn.defineFastMethod("tables",cf.getFastOptSingletonMethod("tables"));
|
102
|
-
|
103
|
-
cJdbcConn.defineFastMethod("insert_bind",cf.getFastOptSingletonMethod("insert_bind"));
|
104
|
-
cJdbcConn.defineFastMethod("update_bind",cf.getFastOptSingletonMethod("update_bind"));
|
105
|
-
|
106
|
-
cJdbcConn.defineFastMethod("write_large_object",cf.getFastOptSingletonMethod("write_large_object"));
|
107
|
-
|
108
|
-
cJdbcConn.getMetaClass().defineFastMethod("insert?",cf.getFastSingletonMethod("insert_p", IRubyObject.class));
|
109
|
-
cJdbcConn.getMetaClass().defineFastMethod("select?",cf.getFastSingletonMethod("select_p", IRubyObject.class));
|
110
|
-
|
80
|
+
jdbcConnection.defineAnnotatedMethods(JdbcAdapterInternalService.class);
|
111
81
|
RubyModule jdbcSpec = runtime.getOrCreateModule("JdbcSpec");
|
112
82
|
|
113
83
|
rubyApi = JavaEmbedUtils.newObjectAdapter();
|
114
|
-
JdbcMySQLSpec.load(
|
115
|
-
JdbcDerbySpec.load(
|
84
|
+
JdbcMySQLSpec.load(jdbcSpec);
|
85
|
+
JdbcDerbySpec.load(jdbcSpec, rubyApi);
|
116
86
|
return true;
|
117
87
|
}
|
118
88
|
|
@@ -132,6 +102,7 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
|
|
132
102
|
return p;
|
133
103
|
}
|
134
104
|
|
105
|
+
@JRubyMethod(name = "insert?", required = 1, meta = true)
|
135
106
|
public static IRubyObject insert_p(IRubyObject recv, IRubyObject _sql) {
|
136
107
|
ByteList bl = rubyApi.convertToRubyString(_sql).getByteList();
|
137
108
|
|
@@ -170,6 +141,7 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
|
|
170
141
|
return recv.getRuntime().getFalse();
|
171
142
|
}
|
172
143
|
|
144
|
+
@JRubyMethod(name = "select?", required = 1, meta = true)
|
173
145
|
public static IRubyObject select_p(IRubyObject recv, IRubyObject _sql) {
|
174
146
|
ByteList bl = rubyApi.convertToRubyString(_sql).getByteList();
|
175
147
|
|
@@ -225,6 +197,7 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
|
|
225
197
|
return recv.getRuntime().getFalse();
|
226
198
|
}
|
227
199
|
|
200
|
+
@JRubyMethod(name = "connection")
|
228
201
|
public static IRubyObject connection(IRubyObject recv) {
|
229
202
|
Connection c = getConnection(recv);
|
230
203
|
if (c == null) {
|
@@ -233,16 +206,19 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
|
|
233
206
|
return rubyApi.getInstanceVariable(recv, "@connection");
|
234
207
|
}
|
235
208
|
|
209
|
+
@JRubyMethod(name = "disconnect!")
|
236
210
|
public static IRubyObject disconnect(IRubyObject recv) {
|
237
211
|
setConnection(recv, null);
|
238
212
|
return recv;
|
239
213
|
}
|
240
214
|
|
215
|
+
@JRubyMethod(name = "reconnect!")
|
241
216
|
public static IRubyObject reconnect(IRubyObject recv) {
|
242
217
|
setConnection(recv, getConnectionFactory(recv).newConnection());
|
243
218
|
return recv;
|
244
219
|
}
|
245
220
|
|
221
|
+
@JRubyMethod(name = "with_connection_retry_guard", frame = true)
|
246
222
|
public static IRubyObject with_connection_retry_guard(final IRubyObject recv, final Block block) {
|
247
223
|
return withConnectionAndRetry(recv, new SQLBlock() {
|
248
224
|
public IRubyObject call(Connection c) throws SQLException {
|
@@ -323,6 +299,7 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
|
|
323
299
|
};
|
324
300
|
}
|
325
301
|
|
302
|
+
@JRubyMethod(name = "tables", rest = true)
|
326
303
|
public static IRubyObject tables(final IRubyObject recv, IRubyObject[] args) {
|
327
304
|
final Ruby runtime = recv.getRuntime();
|
328
305
|
final String catalog = getCatalog(args);
|
@@ -371,10 +348,12 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
|
|
371
348
|
return types;
|
372
349
|
}
|
373
350
|
|
351
|
+
@JRubyMethod(name = "native_database_types")
|
374
352
|
public static IRubyObject native_database_types(IRubyObject recv) {
|
375
353
|
return rubyApi.getInstanceVariable(recv, "@tps");
|
376
354
|
}
|
377
355
|
|
356
|
+
@JRubyMethod(name = "set_native_database_types")
|
378
357
|
public static IRubyObject set_native_database_types(IRubyObject recv) throws SQLException, IOException {
|
379
358
|
Ruby runtime = recv.getRuntime();
|
380
359
|
IRubyObject types = unmarshal_result_downcase(recv, getConnection(recv).getMetaData().getTypeInfo());
|
@@ -384,6 +363,7 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
|
|
384
363
|
return runtime.getNil();
|
385
364
|
}
|
386
365
|
|
366
|
+
@JRubyMethod(name = "database_name")
|
387
367
|
public static IRubyObject database_name(IRubyObject recv) throws SQLException {
|
388
368
|
String name = getConnection(recv).getCatalog();
|
389
369
|
if(null == name) {
|
@@ -395,11 +375,13 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
|
|
395
375
|
return recv.getRuntime().newString(name);
|
396
376
|
}
|
397
377
|
|
378
|
+
@JRubyMethod(name = "begin")
|
398
379
|
public static IRubyObject begin(IRubyObject recv) throws SQLException {
|
399
380
|
getConnection(recv).setAutoCommit(false);
|
400
381
|
return recv.getRuntime().getNil();
|
401
382
|
}
|
402
383
|
|
384
|
+
@JRubyMethod(name = "commit")
|
403
385
|
public static IRubyObject commit(IRubyObject recv) throws SQLException {
|
404
386
|
try {
|
405
387
|
getConnection(recv).commit();
|
@@ -409,6 +391,7 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
|
|
409
391
|
}
|
410
392
|
}
|
411
393
|
|
394
|
+
@JRubyMethod(name = "rollback")
|
412
395
|
public static IRubyObject rollback(IRubyObject recv) throws SQLException {
|
413
396
|
try {
|
414
397
|
getConnection(recv).rollback();
|
@@ -418,6 +401,7 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
|
|
418
401
|
}
|
419
402
|
}
|
420
403
|
|
404
|
+
@JRubyMethod(name = {"columns", "columns_internal"}, required = 1, optional = 2)
|
421
405
|
public static IRubyObject columns_internal(final IRubyObject recv, final IRubyObject[] args) throws SQLException, IOException {
|
422
406
|
return withConnectionAndRetry(recv, new SQLBlock() {
|
423
407
|
public IRubyObject call(Connection c) throws SQLException {
|
@@ -549,6 +533,7 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
|
|
549
533
|
}
|
550
534
|
}
|
551
535
|
|
536
|
+
@JRubyMethod(name = "primary_keys", required = 1)
|
552
537
|
public static IRubyObject primary_keys(final IRubyObject recv, final IRubyObject _table_name) throws SQLException {
|
553
538
|
return withConnectionAndRetry(recv, new SQLBlock() {
|
554
539
|
public IRubyObject call(Connection c) throws SQLException {
|
@@ -580,6 +565,7 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
|
|
580
565
|
});
|
581
566
|
}
|
582
567
|
|
568
|
+
@JRubyMethod(name = "execute_id_insert", required = 2)
|
583
569
|
public static IRubyObject execute_id_insert(IRubyObject recv, final IRubyObject sql, final IRubyObject id) throws SQLException {
|
584
570
|
return withConnectionAndRetry(recv, new SQLBlock() {
|
585
571
|
public IRubyObject call(Connection c) throws SQLException {
|
@@ -595,6 +581,7 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
|
|
595
581
|
});
|
596
582
|
}
|
597
583
|
|
584
|
+
@JRubyMethod(name = "execute_update", required = 1)
|
598
585
|
public static IRubyObject execute_update(final IRubyObject recv, final IRubyObject sql) throws SQLException {
|
599
586
|
return withConnectionAndRetry(recv, new SQLBlock() {
|
600
587
|
public IRubyObject call(Connection c) throws SQLException {
|
@@ -614,6 +601,7 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
|
|
614
601
|
});
|
615
602
|
}
|
616
603
|
|
604
|
+
@JRubyMethod(name = "execute_query", rest = true)
|
617
605
|
public static IRubyObject execute_query(final IRubyObject recv, IRubyObject[] args) throws SQLException, IOException {
|
618
606
|
final IRubyObject sql = args[0];
|
619
607
|
final int maxrows;
|
@@ -643,6 +631,7 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
|
|
643
631
|
});
|
644
632
|
}
|
645
633
|
|
634
|
+
@JRubyMethod(name = "execute_insert", required = 1)
|
646
635
|
public static IRubyObject execute_insert(final IRubyObject recv, final IRubyObject sql) throws SQLException {
|
647
636
|
return withConnectionAndRetry(recv, new SQLBlock() {
|
648
637
|
public IRubyObject call(Connection c) throws SQLException {
|
@@ -735,6 +724,7 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
|
|
735
724
|
return runtime.newArray(results);
|
736
725
|
}
|
737
726
|
|
727
|
+
@JRubyMethod(name = "unmarshal_result", required = 1)
|
738
728
|
public static IRubyObject unmarshal_result(IRubyObject recv, IRubyObject resultset, Block row_filter) throws SQLException, IOException {
|
739
729
|
Ruby runtime = recv.getRuntime();
|
740
730
|
ResultSet rs = intoResultSet(resultset);
|
@@ -897,7 +887,8 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
|
|
897
887
|
|
898
888
|
private final static DateFormat FORMAT = new SimpleDateFormat("%y-%M-%d %H:%m:%s");
|
899
889
|
|
900
|
-
private static void setValue(PreparedStatement ps, int index, Ruby runtime,
|
890
|
+
private static void setValue(PreparedStatement ps, int index, Ruby runtime, ThreadContext context,
|
891
|
+
IRubyObject value, IRubyObject type) throws SQLException {
|
901
892
|
final int tp = getTypeValueFor(runtime, type);
|
902
893
|
if(value.isNil()) {
|
903
894
|
ps.setNull(index, tp);
|
@@ -907,7 +898,7 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
|
|
907
898
|
switch(tp) {
|
908
899
|
case Types.VARCHAR:
|
909
900
|
case Types.CLOB:
|
910
|
-
ps.setString(index, RubyString.objAsString(value).toString());
|
901
|
+
ps.setString(index, RubyString.objAsString(context, value).toString());
|
911
902
|
break;
|
912
903
|
case Types.INTEGER:
|
913
904
|
ps.setLong(index, RubyNumeric.fix2long(value));
|
@@ -920,10 +911,10 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
|
|
920
911
|
case Types.DATE:
|
921
912
|
if(!(value instanceof RubyTime)) {
|
922
913
|
try {
|
923
|
-
Date dd = FORMAT.parse(RubyString.objAsString(value).toString());
|
914
|
+
Date dd = FORMAT.parse(RubyString.objAsString(context, value).toString());
|
924
915
|
ps.setTimestamp(index, new java.sql.Timestamp(dd.getTime()), Calendar.getInstance());
|
925
916
|
} catch(Exception e) {
|
926
|
-
ps.setString(index, RubyString.objAsString(value).toString());
|
917
|
+
ps.setString(index, RubyString.objAsString(context, value).toString());
|
927
918
|
}
|
928
919
|
} else {
|
929
920
|
RubyTime rubyTime = (RubyTime) value;
|
@@ -944,27 +935,28 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
|
|
944
935
|
}
|
945
936
|
}
|
946
937
|
|
947
|
-
private static void setValuesOnPS(PreparedStatement ps, Ruby runtime,
|
938
|
+
private static void setValuesOnPS(PreparedStatement ps, Ruby runtime, ThreadContext context,
|
939
|
+
IRubyObject values, IRubyObject types) throws SQLException {
|
948
940
|
RubyArray vals = (RubyArray)values;
|
949
941
|
RubyArray tps = (RubyArray)types;
|
950
942
|
|
951
943
|
for(int i=0, j=vals.getLength(); i<j; i++) {
|
952
|
-
setValue(ps, i+1, runtime, vals.eltInternal(i), tps.eltInternal(i));
|
944
|
+
setValue(ps, i+1, runtime, context, vals.eltInternal(i), tps.eltInternal(i));
|
953
945
|
}
|
954
946
|
}
|
955
947
|
|
956
948
|
/*
|
957
949
|
* sql, values, types, name = nil, pk = nil, id_value = nil, sequence_name = nil
|
958
950
|
*/
|
959
|
-
|
951
|
+
@JRubyMethod(name = "insert_bind", required = 3, rest = true)
|
952
|
+
public static IRubyObject insert_bind(final ThreadContext context, IRubyObject recv, final IRubyObject[] args) throws SQLException {
|
960
953
|
final Ruby runtime = recv.getRuntime();
|
961
|
-
Arity.checkArgumentCount(runtime, args, 3, 7);
|
962
954
|
return withConnectionAndRetry(recv, new SQLBlock() {
|
963
955
|
public IRubyObject call(Connection c) throws SQLException {
|
964
956
|
PreparedStatement ps = null;
|
965
957
|
try {
|
966
958
|
ps = c.prepareStatement(rubyApi.convertToRubyString(args[0]).toString(), Statement.RETURN_GENERATED_KEYS);
|
967
|
-
setValuesOnPS(ps, runtime, args[1], args[2]);
|
959
|
+
setValuesOnPS(ps, runtime, context, args[1], args[2]);
|
968
960
|
ps.executeUpdate();
|
969
961
|
return unmarshal_id_result(runtime, ps.getGeneratedKeys());
|
970
962
|
} finally {
|
@@ -980,7 +972,8 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
|
|
980
972
|
/*
|
981
973
|
* sql, values, types, name = nil
|
982
974
|
*/
|
983
|
-
|
975
|
+
@JRubyMethod(name = "update_bind", required = 3, rest = true)
|
976
|
+
public static IRubyObject update_bind(final ThreadContext context, IRubyObject recv, final IRubyObject[] args) throws SQLException {
|
984
977
|
final Ruby runtime = recv.getRuntime();
|
985
978
|
Arity.checkArgumentCount(runtime, args, 3, 4);
|
986
979
|
return withConnectionAndRetry(recv, new SQLBlock() {
|
@@ -988,7 +981,7 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
|
|
988
981
|
PreparedStatement ps = null;
|
989
982
|
try {
|
990
983
|
ps = c.prepareStatement(rubyApi.convertToRubyString(args[0]).toString());
|
991
|
-
setValuesOnPS(ps, runtime, args[1], args[2]);
|
984
|
+
setValuesOnPS(ps, runtime, context, args[1], args[2]);
|
992
985
|
ps.executeUpdate();
|
993
986
|
} finally {
|
994
987
|
try {
|
@@ -1004,10 +997,10 @@ public class JdbcAdapterInternalService implements BasicLibraryService {
|
|
1004
997
|
/*
|
1005
998
|
* (is binary?, colname, tablename, primary key, id, value)
|
1006
999
|
*/
|
1000
|
+
@JRubyMethod(name = "write_large_object", required = 6)
|
1007
1001
|
public static IRubyObject write_large_object(IRubyObject recv, final IRubyObject[] args)
|
1008
1002
|
throws SQLException, IOException {
|
1009
1003
|
final Ruby runtime = recv.getRuntime();
|
1010
|
-
Arity.checkArgumentCount(runtime, args, 6, 6);
|
1011
1004
|
return withConnectionAndRetry(recv, new SQLBlock() {
|
1012
1005
|
public IRubyObject call(Connection c) throws SQLException {
|
1013
1006
|
String sql = "UPDATE " + rubyApi.convertToRubyString(args[2])
|
@@ -35,83 +35,76 @@ import org.jruby.RubyBigDecimal;
|
|
35
35
|
import org.jruby.RubyRange;
|
36
36
|
import org.jruby.RubyNumeric;
|
37
37
|
|
38
|
-
import org.jruby.runtime.Arity;
|
39
|
-
import org.jruby.runtime.CallbackFactory;
|
40
|
-
import org.jruby.runtime.MethodIndex;
|
41
38
|
import org.jruby.runtime.builtin.IRubyObject;
|
42
39
|
|
43
40
|
import org.jruby.util.ByteList;
|
44
41
|
|
45
42
|
import java.sql.SQLException;
|
46
43
|
import org.jruby.RubyObjectAdapter;
|
44
|
+
import org.jruby.anno.JRubyMethod;
|
45
|
+
import org.jruby.runtime.ThreadContext;
|
47
46
|
|
48
47
|
public class JdbcDerbySpec {
|
49
48
|
private static RubyObjectAdapter rubyApi;
|
50
|
-
public static void load(
|
49
|
+
public static void load(RubyModule jdbcSpec, RubyObjectAdapter adapter) {
|
51
50
|
RubyModule derby = jdbcSpec.defineModuleUnder("Derby");
|
52
|
-
|
53
|
-
derby.
|
54
|
-
|
55
|
-
derby.defineFastMethod("_execute",cf.getFastOptSingletonMethod("_execute"));
|
56
|
-
derby.defineFastMethod("add_limit_offset!",cf.getFastSingletonMethod("add_limit_offset", IRubyObject.class, IRubyObject.class));
|
57
|
-
derby.defineFastMethod("select_all",cf.getFastOptSingletonMethod("select_all"));
|
58
|
-
derby.defineFastMethod("select_one",cf.getFastOptSingletonMethod("select_one"));
|
59
|
-
RubyModule col = derby.defineModuleUnder("Column");
|
60
|
-
col.defineFastMethod("type_cast",cf.getFastSingletonMethod("type_cast", IRubyObject.class));
|
51
|
+
derby.defineAnnotatedMethods(JdbcDerbySpec.class);
|
52
|
+
RubyModule column = derby.defineModuleUnder("Column");
|
53
|
+
column.defineAnnotatedMethods(Column.class);
|
61
54
|
rubyApi = adapter;
|
62
55
|
}
|
63
56
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
Ruby runtime = recv.getRuntime();
|
57
|
+
public static class Column {
|
58
|
+
@JRubyMethod(name = "type_cast", required = 1)
|
59
|
+
public static IRubyObject type_cast(IRubyObject recv, IRubyObject value) {
|
60
|
+
Ruby runtime = recv.getRuntime();
|
69
61
|
|
70
|
-
|
71
|
-
|
72
|
-
|
62
|
+
if (value.isNil() || ((value instanceof RubyString) && value.toString().trim().equalsIgnoreCase("null"))) {
|
63
|
+
return runtime.getNil();
|
64
|
+
}
|
73
65
|
|
74
|
-
|
66
|
+
String type = rubyApi.getInstanceVariable(recv, "@type").toString();
|
75
67
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
68
|
+
switch (type.charAt(0)) {
|
69
|
+
case 's': //string
|
70
|
+
return value;
|
71
|
+
case 't': //text, timestamp, time
|
72
|
+
if (type.equals("text")) {
|
73
|
+
return value;
|
74
|
+
} else {
|
75
|
+
return rubyApi.callMethod(recv, "cast_to_time", value);
|
76
|
+
}
|
77
|
+
case 'i': //integer
|
78
|
+
case 'p': //primary key
|
79
|
+
if (value.respondsTo("to_i")) {
|
80
|
+
return rubyApi.callMethod(value, "to_i");
|
81
|
+
} else {
|
82
|
+
return runtime.newFixnum(value.isTrue() ? 1 : 0);
|
83
|
+
}
|
84
|
+
case 'd': //decimal, datetime, date
|
85
|
+
if (type.equals("datetime")) {
|
86
|
+
return rubyApi.callMethod(recv, "cast_to_date_or_time", value);
|
87
|
+
} else if (type.equals("date")) {
|
88
|
+
return rubyApi.callMethod(recv.getMetaClass(), "string_to_date", value);
|
89
|
+
} else {
|
90
|
+
return rubyApi.callMethod(recv.getMetaClass(), "value_to_decimal", value);
|
91
|
+
}
|
92
|
+
case 'f': //float
|
93
|
+
return rubyApi.callMethod(value, "to_f");
|
94
|
+
case 'b': //binary, boolean
|
95
|
+
if (type.equals("binary")) {
|
96
|
+
return rubyApi.callMethod(recv, "value_to_binary", value);
|
97
|
+
} else {
|
98
|
+
return rubyApi.callMethod(recv.getMetaClass(), "value_to_boolean", value);
|
99
|
+
}
|
107
100
|
}
|
101
|
+
return value;
|
108
102
|
}
|
109
|
-
return value;
|
110
103
|
}
|
111
104
|
|
112
|
-
|
105
|
+
@JRubyMethod(name = "quote", required = 1, optional = 1)
|
106
|
+
public static IRubyObject quote(ThreadContext context, IRubyObject recv, IRubyObject[] args) {
|
113
107
|
Ruby runtime = recv.getRuntime();
|
114
|
-
Arity.checkArgumentCount(runtime, args, 1, 2);
|
115
108
|
IRubyObject value = args[0];
|
116
109
|
if (args.length > 1) {
|
117
110
|
IRubyObject col = args[1];
|
@@ -128,21 +121,21 @@ public class JdbcDerbySpec {
|
|
128
121
|
if (only_digits((RubyString)value)) {
|
129
122
|
return value;
|
130
123
|
} else {
|
131
|
-
return super_quote(recv, runtime, value, col);
|
124
|
+
return super_quote(context, recv, runtime, value, col);
|
132
125
|
}
|
133
126
|
}
|
134
127
|
} else if ((value instanceof RubyFloat) || (value instanceof RubyFixnum) || (value instanceof RubyBignum)) {
|
135
128
|
if (type == runtime.newSymbol("string")) {
|
136
|
-
return quote_string_with_surround(runtime, "'", RubyString.objAsString(value), "'");
|
129
|
+
return quote_string_with_surround(runtime, "'", RubyString.objAsString(context, value), "'");
|
137
130
|
}
|
138
131
|
}
|
139
132
|
}
|
140
|
-
return super_quote(recv, runtime, value, runtime.getNil());
|
133
|
+
return super_quote(context, recv, runtime, value, runtime.getNil());
|
141
134
|
}
|
142
135
|
|
143
136
|
private final static ByteList NULL = new ByteList("NULL".getBytes());
|
144
137
|
|
145
|
-
|
138
|
+
private static IRubyObject super_quote(ThreadContext context, IRubyObject recv, Ruby runtime, IRubyObject value, IRubyObject col) {
|
146
139
|
if (value.respondsTo("quoted_id")) {
|
147
140
|
return rubyApi.callMethod(value, "quoted_id");
|
148
141
|
}
|
@@ -151,11 +144,11 @@ public class JdbcDerbySpec {
|
|
151
144
|
RubyModule multibyteChars = (RubyModule)
|
152
145
|
((RubyModule) ((RubyModule) runtime.getModule("ActiveSupport")).getConstant("Multibyte")).getConstantAt("Chars");
|
153
146
|
if (value instanceof RubyString || rubyApi.isKindOf(value, multibyteChars)) {
|
154
|
-
RubyString svalue = RubyString.objAsString(value);
|
147
|
+
RubyString svalue = RubyString.objAsString(context, value);
|
155
148
|
if (type == runtime.newSymbol("binary") && col.getType().respondsTo("string_to_binary")) {
|
156
149
|
return quote_string_with_surround(runtime, "'", (RubyString)(rubyApi.callMethod(col.getType(), "string_to_binary", svalue)), "'");
|
157
150
|
} else if (type == runtime.newSymbol("integer") || type == runtime.newSymbol("float")) {
|
158
|
-
return RubyString.objAsString(((type == runtime.newSymbol("integer")) ?
|
151
|
+
return RubyString.objAsString(context, ((type == runtime.newSymbol("integer")) ?
|
159
152
|
rubyApi.callMethod(svalue, "to_i") :
|
160
153
|
rubyApi.callMethod(svalue, "to_f")));
|
161
154
|
} else {
|
@@ -168,11 +161,11 @@ public class JdbcDerbySpec {
|
|
168
161
|
(type == runtime.newSymbol(":integer")) ? runtime.newString("1") : rubyApi.callMethod(recv, "quoted_true") :
|
169
162
|
(type == runtime.newSymbol(":integer")) ? runtime.newString("0") : rubyApi.callMethod(recv, "quoted_false"));
|
170
163
|
} else if((value instanceof RubyFloat) || (value instanceof RubyFixnum) || (value instanceof RubyBignum)) {
|
171
|
-
return RubyString.objAsString(value);
|
164
|
+
return RubyString.objAsString(context, value);
|
172
165
|
} else if(value instanceof RubyBigDecimal) {
|
173
166
|
return rubyApi.callMethod(value, "to_s", runtime.newString("F"));
|
174
167
|
} else if (rubyApi.isKindOf(value, runtime.getModule("Date"))) {
|
175
|
-
return quote_string_with_surround(runtime, "'", RubyString.objAsString(value), "'");
|
168
|
+
return quote_string_with_surround(runtime, "'", RubyString.objAsString(context, value), "'");
|
176
169
|
} else if (rubyApi.isKindOf(value, runtime.getModule("Time")) || rubyApi.isKindOf(value, runtime.getModule("DateTime"))) {
|
177
170
|
return quote_string_with_surround(runtime, "'", (RubyString)(rubyApi.callMethod(recv, "quoted_date", value)), "'");
|
178
171
|
} else {
|
@@ -182,7 +175,7 @@ public class JdbcDerbySpec {
|
|
182
175
|
|
183
176
|
private final static ByteList TWO_SINGLE = new ByteList(new byte[]{'\'','\''});
|
184
177
|
|
185
|
-
|
178
|
+
private static IRubyObject quote_string_with_surround(Ruby runtime, String before, RubyString string, String after) {
|
186
179
|
ByteList input = string.getByteList();
|
187
180
|
ByteList output = new ByteList(before.getBytes());
|
188
181
|
for(int i = input.begin; i< input.begin + input.realSize; i++) {
|
@@ -203,7 +196,7 @@ public class JdbcDerbySpec {
|
|
203
196
|
|
204
197
|
private final static byte[] HEX = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
|
205
198
|
|
206
|
-
|
199
|
+
private static IRubyObject hexquote_string_with_surround(Ruby runtime, String before, RubyString string, String after) {
|
207
200
|
ByteList input = string.getByteList();
|
208
201
|
ByteList output = new ByteList(before.getBytes());
|
209
202
|
for(int i = input.begin; i< input.begin + input.realSize; i++) {
|
@@ -232,6 +225,7 @@ public class JdbcDerbySpec {
|
|
232
225
|
return true;
|
233
226
|
}
|
234
227
|
|
228
|
+
@JRubyMethod(name = "quote_string", required = 1)
|
235
229
|
public static IRubyObject quote_string(IRubyObject recv, IRubyObject string) {
|
236
230
|
boolean replacementFound = false;
|
237
231
|
ByteList bl = ((RubyString) string).getByteList();
|
@@ -259,10 +253,12 @@ public class JdbcDerbySpec {
|
|
259
253
|
}
|
260
254
|
}
|
261
255
|
|
256
|
+
@JRubyMethod(name = "select_all", rest = true)
|
262
257
|
public static IRubyObject select_all(IRubyObject recv, IRubyObject[] args) {
|
263
258
|
return rubyApi.callMethod(recv, "execute", args);
|
264
259
|
}
|
265
260
|
|
261
|
+
@JRubyMethod(name = "select_one", rest = true)
|
266
262
|
public static IRubyObject select_one(IRubyObject recv, IRubyObject[] args) {
|
267
263
|
IRubyObject limit = rubyApi.getInstanceVariable(recv, "@limit");
|
268
264
|
if (limit == null || limit.isNil()) {
|
@@ -276,6 +272,7 @@ public class JdbcDerbySpec {
|
|
276
272
|
}
|
277
273
|
}
|
278
274
|
|
275
|
+
@JRubyMethod(name = "add_limit_offset!", required = 2)
|
279
276
|
public static IRubyObject add_limit_offset(IRubyObject recv, IRubyObject sql, IRubyObject options) {
|
280
277
|
IRubyObject limit = rubyApi.callMethod(options, "[]", recv.getRuntime().newSymbol("limit"));
|
281
278
|
rubyApi.setInstanceVariable(recv, "@limit",limit);
|
@@ -283,7 +280,8 @@ public class JdbcDerbySpec {
|
|
283
280
|
return rubyApi.setInstanceVariable(recv, "@offset",offset);
|
284
281
|
}
|
285
282
|
|
286
|
-
|
283
|
+
@JRubyMethod(name = "_execute", required = 1, optional = 1)
|
284
|
+
public static IRubyObject _execute(ThreadContext context, IRubyObject recv, IRubyObject[] args) throws SQLException, java.io.IOException {
|
287
285
|
Ruby runtime = recv.getRuntime();
|
288
286
|
try {
|
289
287
|
IRubyObject conn = rubyApi.getInstanceVariable(recv, "@connection");
|
@@ -302,11 +300,11 @@ public class JdbcDerbySpec {
|
|
302
300
|
IRubyObject range;
|
303
301
|
IRubyObject max;
|
304
302
|
if (limit == null || limit.isNil() || RubyNumeric.fix2int(limit) == -1) {
|
305
|
-
range = RubyRange.newRange(runtime, offset, runtime.newFixnum(-1), false);
|
303
|
+
range = RubyRange.newRange(runtime, context, offset, runtime.newFixnum(-1), false);
|
306
304
|
max = RubyFixnum.zero(runtime);
|
307
305
|
} else {
|
308
306
|
IRubyObject v1 = rubyApi.callMethod(offset, "+", limit);
|
309
|
-
range = RubyRange.newRange(runtime, offset, v1, true);
|
307
|
+
range = RubyRange.newRange(runtime, context, offset, v1, true);
|
310
308
|
max = rubyApi.callMethod(v1, "+", RubyFixnum.one(runtime));
|
311
309
|
}
|
312
310
|
IRubyObject result = JdbcAdapterInternalService.execute_query(conn, new IRubyObject[]{args[0], max});
|
@@ -28,16 +28,15 @@ import org.jruby.Ruby;
|
|
28
28
|
import org.jruby.RubyModule;
|
29
29
|
import org.jruby.RubyString;
|
30
30
|
|
31
|
-
import org.jruby.
|
31
|
+
import org.jruby.anno.JRubyMethod;
|
32
32
|
import org.jruby.runtime.builtin.IRubyObject;
|
33
33
|
|
34
34
|
import org.jruby.util.ByteList;
|
35
35
|
|
36
36
|
public class JdbcMySQLSpec {
|
37
|
-
public static void load(
|
37
|
+
public static void load(RubyModule jdbcSpec) {
|
38
38
|
RubyModule mysql = jdbcSpec.defineModuleUnder("MySQL");
|
39
|
-
|
40
|
-
mysql.defineFastMethod("quote_string",cf.getFastSingletonMethod("quote_string",IRubyObject.class));
|
39
|
+
mysql.defineAnnotatedMethods(JdbcMySQLSpec.class);
|
41
40
|
}
|
42
41
|
|
43
42
|
private final static ByteList ZERO = new ByteList(new byte[]{'\\','0'});
|
@@ -48,9 +47,11 @@ public class JdbcMySQLSpec {
|
|
48
47
|
private final static ByteList SINGLE = new ByteList(new byte[]{'\\','\''});
|
49
48
|
private final static ByteList ESCAPE = new ByteList(new byte[]{'\\','\\'});
|
50
49
|
|
50
|
+
@JRubyMethod(name = "quote_string", required = 1)
|
51
51
|
public static IRubyObject quote_string(IRubyObject recv, IRubyObject string) {
|
52
|
-
boolean replacementFound = false;
|
53
52
|
ByteList bl = ((RubyString) string).getByteList();
|
53
|
+
ByteList blNew = new ByteList();
|
54
|
+
int startOfExtend = bl.begin;
|
54
55
|
|
55
56
|
for(int i = bl.begin; i < bl.begin + bl.realSize; i++) {
|
56
57
|
ByteList rep = null;
|
@@ -64,23 +65,18 @@ public class JdbcMySQLSpec {
|
|
64
65
|
case '\\': rep = ESCAPE; break;
|
65
66
|
default: continue;
|
66
67
|
}
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
bl = new ByteList(bl);
|
72
|
-
replacementFound = true;
|
73
|
-
}
|
74
|
-
|
75
|
-
bl.replace(i, 1, rep);
|
76
|
-
i+=1;
|
68
|
+
if(i > startOfExtend)
|
69
|
+
blNew.append(bl, startOfExtend, i-startOfExtend);
|
70
|
+
blNew.append(rep, 0, 2);
|
71
|
+
startOfExtend = i+1;
|
77
72
|
}
|
78
|
-
|
79
|
-
if(
|
80
|
-
|
73
|
+
// Nothing changed, can return original
|
74
|
+
if (startOfExtend == bl.begin) {
|
75
|
+
return string;
|
81
76
|
}
|
77
|
+
if (bl.begin + bl.realSize > startOfExtend)
|
78
|
+
blNew.append(bl, startOfExtend, bl.begin + bl.realSize - startOfExtend);
|
82
79
|
|
83
|
-
|
84
|
-
return recv.getRuntime().newStringShared(bl);
|
80
|
+
return recv.getRuntime().newStringShared(blNew);
|
85
81
|
}
|
86
82
|
}
|
data/test/db/derby.rb
CHANGED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'active_record'
|
3
|
+
|
4
|
+
class CreateReservedWords < ActiveRecord::Migration
|
5
|
+
def self.up
|
6
|
+
create_table "reserved_words", :force => true do |t|
|
7
|
+
t.column :position, :integer
|
8
|
+
t.column :select, :integer
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.down
|
13
|
+
drop_table "reserved_words"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class ReservedWord < ActiveRecord::Base
|
18
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'jdbc_common'
|
2
|
+
require 'db/postgres'
|
3
|
+
require 'models/reserved_word'
|
4
|
+
|
5
|
+
class PostgresReservedWordsTest < Test::Unit::TestCase
|
6
|
+
def setup
|
7
|
+
CreateReservedWords.up
|
8
|
+
end
|
9
|
+
def teardown
|
10
|
+
CreateReservedWords.down
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_quote_reserved_word_column
|
14
|
+
columns = ReservedWord.column_names - ["id"]
|
15
|
+
ReservedWord.connection.add_index :reserved_words, columns
|
16
|
+
indexes = ReservedWord.connection.indexes("reserved_words")
|
17
|
+
assert_equal 1, indexes.size
|
18
|
+
columns.each do |c|
|
19
|
+
assert indexes[0].columns.include?(c), "#{indexes[0].columns.inspect} does not include #{c.inspect}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/test/simple.rb
CHANGED
@@ -87,7 +87,7 @@ module SimpleTestMethods
|
|
87
87
|
|
88
88
|
indexes = @connection.indexes(:entries)
|
89
89
|
assert_equal(1, indexes.size)
|
90
|
-
assert_equal "entries", indexes.first.table
|
90
|
+
assert_equal "entries", indexes.first.table.to_s
|
91
91
|
assert_equal index_name, indexes.first.name
|
92
92
|
assert !indexes.first.unique
|
93
93
|
assert_equal ["updated_on"], indexes.first.columns
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activerecord-jdbc-adapter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: "0.8"
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nick Sieger, Ola Bini and JRuby contributors
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-
|
12
|
+
date: 2008-03-19 00:00:00 -05:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -23,12 +23,13 @@ extra_rdoc_files:
|
|
23
23
|
- History.txt
|
24
24
|
- Manifest.txt
|
25
25
|
- README.txt
|
26
|
+
- LICENSE.txt
|
26
27
|
files:
|
27
28
|
- History.txt
|
28
29
|
- Manifest.txt
|
29
30
|
- README.txt
|
30
31
|
- Rakefile
|
31
|
-
- LICENSE
|
32
|
+
- LICENSE.txt
|
32
33
|
- lib/active_record/connection_adapters/derby_adapter.rb
|
33
34
|
- lib/active_record/connection_adapters/h2_adapter.rb
|
34
35
|
- lib/active_record/connection_adapters/hsqldb_adapter.rb
|
@@ -86,11 +87,14 @@ files:
|
|
86
87
|
- test/models/auto_id.rb
|
87
88
|
- test/models/data_types.rb
|
88
89
|
- test/models/entry.rb
|
90
|
+
- test/models/reserved_word.rb
|
89
91
|
- test/mysql_multibyte_test.rb
|
90
92
|
- test/mysql_simple_test.rb
|
91
93
|
- test/oracle_simple_test.rb
|
94
|
+
- test/postgres_reserved_test.rb
|
92
95
|
- test/postgres_simple_test.rb
|
93
96
|
- test/simple.rb
|
97
|
+
- lib/jdbc_adapter/jdbc.rake
|
94
98
|
- src/java/jdbc_adapter/JdbcAdapterInternalService.java
|
95
99
|
- src/java/jdbc_adapter/JdbcConnectionFactory.java
|
96
100
|
- src/java/jdbc_adapter/JdbcDerbySpec.java
|