activerecord-jdbc-adapter 0.7.2 → 0.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.
- 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
|