saturnflyer-activerecord-jdbc-adapter 0.9.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (183) hide show
  1. data/.gitignore +16 -0
  2. data/History.txt +225 -0
  3. data/LICENSE.txt +21 -0
  4. data/README.txt +161 -0
  5. data/Rakefile +28 -0
  6. data/VERSION +1 -0
  7. data/activerecord-jdbc-adapter.gemspec +277 -0
  8. data/adapters/derby/LICENSE.txt +21 -0
  9. data/adapters/derby/README.txt +5 -0
  10. data/adapters/derby/Rakefile +31 -0
  11. data/adapters/derby/lib/active_record/connection_adapters/jdbcderby_adapter.rb +30 -0
  12. data/adapters/h2/History.txt +0 -0
  13. data/adapters/h2/LICENSE.txt +21 -0
  14. data/adapters/h2/README.txt +5 -0
  15. data/adapters/h2/Rakefile +31 -0
  16. data/adapters/h2/lib/active_record/connection_adapters/jdbch2_adapter.rb +30 -0
  17. data/adapters/hsqldb/History.txt +0 -0
  18. data/adapters/hsqldb/LICENSE.txt +21 -0
  19. data/adapters/hsqldb/README.txt +5 -0
  20. data/adapters/hsqldb/Rakefile +31 -0
  21. data/adapters/hsqldb/lib/active_record/connection_adapters/jdbchsqldb_adapter.rb +30 -0
  22. data/adapters/mysql/History.txt +0 -0
  23. data/adapters/mysql/LICENSE.txt +21 -0
  24. data/adapters/mysql/README.txt +5 -0
  25. data/adapters/mysql/Rakefile +31 -0
  26. data/adapters/mysql/lib/active_record/connection_adapters/jdbcmysql_adapter.rb +30 -0
  27. data/adapters/postgresql/History.txt +0 -0
  28. data/adapters/postgresql/LICENSE.txt +21 -0
  29. data/adapters/postgresql/README.txt +5 -0
  30. data/adapters/postgresql/Rakefile +31 -0
  31. data/adapters/postgresql/lib/active_record/connection_adapters/jdbcpostgresql_adapter.rb +30 -0
  32. data/adapters/sqlite3/LICENSE.txt +21 -0
  33. data/adapters/sqlite3/README.txt +5 -0
  34. data/adapters/sqlite3/Rakefile +31 -0
  35. data/adapters/sqlite3/lib/active_record/connection_adapters/jdbcsqlite3_adapter.rb +30 -0
  36. data/bench/bench_attributes.rb +13 -0
  37. data/bench/bench_attributes_new.rb +14 -0
  38. data/bench/bench_create.rb +12 -0
  39. data/bench/bench_find_all.rb +12 -0
  40. data/bench/bench_find_all_mt.rb +25 -0
  41. data/bench/bench_model.rb +85 -0
  42. data/bench/bench_new.rb +12 -0
  43. data/bench/bench_new_valid.rb +12 -0
  44. data/bench/bench_valid.rb +13 -0
  45. data/drivers/derby/LICENSE.txt +1 -0
  46. data/drivers/derby/README.txt +6 -0
  47. data/drivers/derby/Rakefile +26 -0
  48. data/drivers/derby/lib/derby-10.5.3.0.jar +0 -0
  49. data/drivers/derby/lib/jdbc/derby.rb +11 -0
  50. data/drivers/h2/History.txt +0 -0
  51. data/drivers/h2/LICENSE.txt +2 -0
  52. data/drivers/h2/README.txt +6 -0
  53. data/drivers/h2/Rakefile +26 -0
  54. data/drivers/h2/lib/h2-1.1.107.jar +0 -0
  55. data/drivers/h2/lib/jdbc/h2.rb +10 -0
  56. data/drivers/hsqldb/History.txt +0 -0
  57. data/drivers/hsqldb/LICENSE.txt +2 -0
  58. data/drivers/hsqldb/README.txt +6 -0
  59. data/drivers/hsqldb/Rakefile +26 -0
  60. data/drivers/hsqldb/lib/hsqldb-1.8.0.7.jar +0 -0
  61. data/drivers/hsqldb/lib/jdbc/hsqldb.rb +10 -0
  62. data/drivers/mysql/History.txt +0 -0
  63. data/drivers/mysql/LICENSE.txt +1 -0
  64. data/drivers/mysql/README.txt +6 -0
  65. data/drivers/mysql/Rakefile +26 -0
  66. data/drivers/mysql/lib/jdbc/mysql.rb +10 -0
  67. data/drivers/mysql/lib/mysql-connector-java-5.0.4-bin.jar +0 -0
  68. data/drivers/postgres/History.txt +7 -0
  69. data/drivers/postgres/LICENSE.txt +12 -0
  70. data/drivers/postgres/README.txt +5 -0
  71. data/drivers/postgres/Rakefile +27 -0
  72. data/drivers/postgres/lib/jdbc/postgres.rb +25 -0
  73. data/drivers/postgres/lib/postgresql-8.3-604.jdbc3.jar +0 -0
  74. data/drivers/postgres/lib/postgresql-8.3-604.jdbc4.jar +0 -0
  75. data/drivers/sqlite3/LICENSE.txt +13 -0
  76. data/drivers/sqlite3/README.txt +6 -0
  77. data/drivers/sqlite3/Rakefile +26 -0
  78. data/drivers/sqlite3/lib/jdbc/sqlite3.rb +10 -0
  79. data/drivers/sqlite3/lib/sqlitejdbc-3.6.3.054.jar +0 -0
  80. data/lib/active_record/connection_adapters/cachedb_adapter.rb +1 -0
  81. data/lib/active_record/connection_adapters/derby_adapter.rb +13 -0
  82. data/lib/active_record/connection_adapters/h2_adapter.rb +13 -0
  83. data/lib/active_record/connection_adapters/hsqldb_adapter.rb +13 -0
  84. data/lib/active_record/connection_adapters/informix_adapter.rb +1 -0
  85. data/lib/active_record/connection_adapters/jdbc_adapter.rb +637 -0
  86. data/lib/active_record/connection_adapters/jdbc_adapter_spec.rb +14 -0
  87. data/lib/active_record/connection_adapters/jndi_adapter.rb +1 -0
  88. data/lib/active_record/connection_adapters/mysql_adapter.rb +13 -0
  89. data/lib/active_record/connection_adapters/oracle_adapter.rb +1 -0
  90. data/lib/active_record/connection_adapters/postgresql_adapter.rb +13 -0
  91. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +13 -0
  92. data/lib/jdbc_adapter.rb +27 -0
  93. data/lib/jdbc_adapter/jdbc.rake +104 -0
  94. data/lib/jdbc_adapter/jdbc_cachedb.rb +33 -0
  95. data/lib/jdbc_adapter/jdbc_db2.rb +191 -0
  96. data/lib/jdbc_adapter/jdbc_derby.rb +421 -0
  97. data/lib/jdbc_adapter/jdbc_firebird.rb +109 -0
  98. data/lib/jdbc_adapter/jdbc_hsqldb.rb +210 -0
  99. data/lib/jdbc_adapter/jdbc_informix.rb +147 -0
  100. data/lib/jdbc_adapter/jdbc_mimer.rb +141 -0
  101. data/lib/jdbc_adapter/jdbc_mssql.rb +333 -0
  102. data/lib/jdbc_adapter/jdbc_mysql.rb +233 -0
  103. data/lib/jdbc_adapter/jdbc_oracle.rb +374 -0
  104. data/lib/jdbc_adapter/jdbc_postgre.rb +483 -0
  105. data/lib/jdbc_adapter/jdbc_sqlite3.rb +360 -0
  106. data/lib/jdbc_adapter/jdbc_sybase.rb +50 -0
  107. data/lib/jdbc_adapter/missing_functionality_helper.rb +85 -0
  108. data/lib/jdbc_adapter/rake_tasks.rb +10 -0
  109. data/lib/jdbc_adapter/tsql_helper.rb +60 -0
  110. data/lib/jdbc_adapter/version.rb +5 -0
  111. data/pom.xml +57 -0
  112. data/rakelib/compile.rake +23 -0
  113. data/rakelib/package.rake +73 -0
  114. data/rakelib/rails.rake +41 -0
  115. data/src/java/jdbc_adapter/JdbcAdapterInternalService.java +53 -0
  116. data/src/java/jdbc_adapter/JdbcConnectionFactory.java +36 -0
  117. data/src/java/jdbc_adapter/JdbcDerbySpec.java +293 -0
  118. data/src/java/jdbc_adapter/JdbcMySQLSpec.java +133 -0
  119. data/src/java/jdbc_adapter/MssqlRubyJdbcConnection.java +71 -0
  120. data/src/java/jdbc_adapter/PostgresRubyJdbcConnection.java +55 -0
  121. data/src/java/jdbc_adapter/RubyJdbcConnection.java +1163 -0
  122. data/src/java/jdbc_adapter/SQLBlock.java +27 -0
  123. data/src/java/jdbc_adapter/Sqlite3RubyJdbcConnection.java +41 -0
  124. data/test/activerecord/connection_adapters/type_conversion_test.rb +31 -0
  125. data/test/activerecord/connections/native_jdbc_mysql/connection.rb +25 -0
  126. data/test/activerecord/jall.sh +7 -0
  127. data/test/activerecord/jtest.sh +3 -0
  128. data/test/cachedb_simple_test.rb +6 -0
  129. data/test/db/cachedb.rb +9 -0
  130. data/test/db/db2.rb +9 -0
  131. data/test/db/derby.rb +14 -0
  132. data/test/db/h2.rb +11 -0
  133. data/test/db/hsqldb.rb +12 -0
  134. data/test/db/informix.rb +11 -0
  135. data/test/db/jdbc.rb +11 -0
  136. data/test/db/jndi_config.rb +30 -0
  137. data/test/db/logger.rb +3 -0
  138. data/test/db/mssql.rb +9 -0
  139. data/test/db/mysql.rb +10 -0
  140. data/test/db/oracle.rb +34 -0
  141. data/test/db/postgres.rb +9 -0
  142. data/test/db/sqlite3.rb +15 -0
  143. data/test/db2_simple_test.rb +10 -0
  144. data/test/derby_migration_test.rb +21 -0
  145. data/test/derby_multibyte_test.rb +12 -0
  146. data/test/derby_simple_test.rb +12 -0
  147. data/test/generic_jdbc_connection_test.rb +9 -0
  148. data/test/h2_simple_test.rb +6 -0
  149. data/test/has_many_through.rb +79 -0
  150. data/test/hsqldb_simple_test.rb +6 -0
  151. data/test/informix_simple_test.rb +48 -0
  152. data/test/jdbc_adapter/jdbc_db2_test.rb +26 -0
  153. data/test/jdbc_adapter/jdbc_sybase_test.rb +33 -0
  154. data/test/jdbc_common.rb +24 -0
  155. data/test/jndi_callbacks_test.rb +38 -0
  156. data/test/jndi_test.rb +35 -0
  157. data/test/manualTestDatabase.rb +191 -0
  158. data/test/minirunit.rb +109 -0
  159. data/test/minirunit/testConnect.rb +14 -0
  160. data/test/minirunit/testH2.rb +73 -0
  161. data/test/minirunit/testHsqldb.rb +73 -0
  162. data/test/minirunit/testLoadActiveRecord.rb +3 -0
  163. data/test/minirunit/testMysql.rb +83 -0
  164. data/test/minirunit/testRawSelect.rb +24 -0
  165. data/test/models/add_not_null_column_to_table.rb +12 -0
  166. data/test/models/auto_id.rb +18 -0
  167. data/test/models/data_types.rb +28 -0
  168. data/test/models/entry.rb +23 -0
  169. data/test/models/mixed_case.rb +20 -0
  170. data/test/models/reserved_word.rb +18 -0
  171. data/test/mssql_simple_test.rb +6 -0
  172. data/test/mysql_multibyte_test.rb +10 -0
  173. data/test/mysql_nonstandard_primary_key_test.rb +43 -0
  174. data/test/mysql_simple_test.rb +26 -0
  175. data/test/oracle_simple_test.rb +29 -0
  176. data/test/postgres_mixed_case_test.rb +19 -0
  177. data/test/postgres_nonseq_pkey_test.rb +40 -0
  178. data/test/postgres_reserved_test.rb +22 -0
  179. data/test/postgres_simple_test.rb +12 -0
  180. data/test/simple.rb +397 -0
  181. data/test/sqlite3_simple_test.rb +179 -0
  182. data/test/sybase_jtds_simple_test.rb +6 -0
  183. metadata +294 -0
@@ -0,0 +1,14 @@
1
+
2
+ require 'jdbc_adapter/jdbc_mimer'
3
+ require 'jdbc_adapter/jdbc_hsqldb'
4
+ require 'jdbc_adapter/jdbc_oracle'
5
+ require 'jdbc_adapter/jdbc_postgre'
6
+ require 'jdbc_adapter/jdbc_mysql'
7
+ require 'jdbc_adapter/jdbc_derby'
8
+ require 'jdbc_adapter/jdbc_firebird'
9
+ require 'jdbc_adapter/jdbc_db2'
10
+ require 'jdbc_adapter/jdbc_mssql'
11
+ require 'jdbc_adapter/jdbc_cachedb'
12
+ require 'jdbc_adapter/jdbc_sqlite3'
13
+ require 'jdbc_adapter/jdbc_sybase'
14
+ require 'jdbc_adapter/jdbc_informix'
@@ -0,0 +1 @@
1
+ require 'active_record/connection_adapters/jdbc_adapter'
@@ -0,0 +1,13 @@
1
+ tried_gem = false
2
+ begin
3
+ require "jdbc/mysql"
4
+ rescue LoadError
5
+ unless tried_gem
6
+ require 'rubygems'
7
+ gem "jdbc-mysql"
8
+ tried_gem = true
9
+ retry
10
+ end
11
+ # trust that the mysql jar is already present
12
+ end
13
+ require 'active_record/connection_adapters/jdbc_adapter'
@@ -0,0 +1 @@
1
+ require 'active_record/connection_adapters/jdbc_adapter'
@@ -0,0 +1,13 @@
1
+ tried_gem = false
2
+ begin
3
+ require "jdbc/postgres"
4
+ rescue LoadError
5
+ unless tried_gem
6
+ require 'rubygems'
7
+ gem "jdbc-postgres"
8
+ tried_gem = true
9
+ retry
10
+ end
11
+ # trust that the postgres jar is already present
12
+ end
13
+ require 'active_record/connection_adapters/jdbc_adapter'
@@ -0,0 +1,13 @@
1
+ tried_gem = false
2
+ begin
3
+ require "jdbc/sqlite3"
4
+ rescue LoadError
5
+ unless tried_gem
6
+ require 'rubygems'
7
+ gem "jdbc-sqlite3"
8
+ tried_gem = true
9
+ retry
10
+ end
11
+ # trust that the sqlite jar is already present
12
+ end
13
+ require 'active_record/connection_adapters/jdbc_adapter'
@@ -0,0 +1,27 @@
1
+ if RUBY_PLATFORM =~ /java/
2
+ begin
3
+ tried_gem ||= false
4
+ require 'active_record/version'
5
+ rescue LoadError
6
+ raise if tried_gem
7
+ require 'rubygems'
8
+ gem 'activerecord'
9
+ tried_gem = true
10
+ retry
11
+ end
12
+ if ActiveRecord::VERSION::MAJOR < 2
13
+ if defined?(RAILS_CONNECTION_ADAPTERS)
14
+ RAILS_CONNECTION_ADAPTERS << %q(jdbc)
15
+ else
16
+ RAILS_CONNECTION_ADAPTERS = %w(jdbc)
17
+ end
18
+ if ActiveRecord::VERSION::MAJOR == 1 && ActiveRecord::VERSION::MINOR == 14
19
+ require 'active_record/connection_adapters/jdbc_adapter'
20
+ end
21
+ else
22
+ require 'active_record'
23
+ require 'active_record/connection_adapters/jdbc_adapter'
24
+ end
25
+ else
26
+ warn "ActiveRecord-JDBC is for use with JRuby only"
27
+ end
@@ -0,0 +1,104 @@
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
6
+ public :instance_variable_set
7
+ attr_reader :actions
8
+ end
9
+ existing_task.instance_variable_set "@prerequisites", FileList[]
10
+ existing_task.actions.shift
11
+ enhancements = existing_task.actions
12
+ existing_task.instance_variable_set "@actions", []
13
+ end
14
+ redefined_task = task(*args, &block)
15
+ enhancements.each {|enhancement| redefined_task.actions << enhancement}
16
+ end
17
+
18
+ namespace :db do
19
+ if Rake::Task["db:create"]
20
+ redefine_task :create => :environment do
21
+ create_database(ActiveRecord::Base.configurations[RAILS_ENV])
22
+ end
23
+
24
+ class << self; alias_method :previous_create_database, :create_database; end
25
+ def create_database(config)
26
+ begin
27
+ ActiveRecord::Base.establish_connection(config)
28
+ ActiveRecord::Base.connection
29
+ rescue
30
+ begin
31
+ url = config['url']
32
+ if url
33
+ if url =~ /^(.*\/)/
34
+ url = $1
35
+ end
36
+ end
37
+
38
+ ActiveRecord::Base.establish_connection(config.merge({'database' => nil, 'url' => url}))
39
+ ActiveRecord::Base.connection.create_database(config['database'])
40
+ ActiveRecord::Base.establish_connection(config)
41
+ rescue
42
+ previous_create_database(config)
43
+ end
44
+ end
45
+ end
46
+
47
+ redefine_task :drop => :environment do
48
+ config = ActiveRecord::Base.configurations[RAILS_ENV]
49
+ begin
50
+ ActiveRecord::Base.establish_connection(config)
51
+ db = ActiveRecord::Base.connection.database_name
52
+ ActiveRecord::Base.connection.drop_database(db)
53
+ rescue
54
+ drop_database(config)
55
+ end
56
+ end
57
+ end
58
+
59
+ namespace :structure do
60
+ redefine_task :dump => :environment do
61
+ abcs = ActiveRecord::Base.configurations
62
+ ActiveRecord::Base.establish_connection(abcs[RAILS_ENV])
63
+ File.open("db/#{RAILS_ENV}_structure.sql", "w+") { |f| f << ActiveRecord::Base.connection.structure_dump }
64
+ if ActiveRecord::Base.connection.supports_migrations?
65
+ File.open("db/#{RAILS_ENV}_structure.sql", "a") { |f| f << ActiveRecord::Base.connection.dump_schema_information }
66
+ end
67
+ end
68
+ end
69
+
70
+ namespace :test do
71
+ redefine_task :clone_structure => [ "db:structure:dump", "db:test:purge" ] do
72
+ abcs = ActiveRecord::Base.configurations
73
+ abcs['test']['pg_params'] = '?allowEncodingChanges=true' if abcs['test']['adapter'] =~ /postgresql/i
74
+ ActiveRecord::Base.establish_connection(abcs["test"])
75
+ ActiveRecord::Base.connection.execute('SET foreign_key_checks = 0') if abcs["test"]["adapter"] =~ /mysql/i
76
+ IO.readlines("db/#{RAILS_ENV}_structure.sql").join.split(";\n\n").each do |ddl|
77
+ begin
78
+ ActiveRecord::Base.connection.execute(ddl.chomp(';'))
79
+ rescue Exception => ex
80
+ puts ex.message
81
+ end
82
+ end
83
+ end
84
+
85
+ redefine_task :purge => :environment do
86
+ abcs = ActiveRecord::Base.configurations
87
+ config = abcs['test'].dup
88
+ if config['adapter'] =~ /postgresql/i
89
+ if config['url']
90
+ db = config['url'][/\/([^\/]*)$/, 1]
91
+ config['url'][/\/([^\/]*)$/, 1] = 'postgres' if db
92
+ else
93
+ db = config['database']
94
+ config['database'] = 'postgres'
95
+ end
96
+ ActiveRecord::Base.establish_connection(config)
97
+ else
98
+ ActiveRecord::Base.establish_connection(config)
99
+ db = ActiveRecord::Base.connection.database_name
100
+ end
101
+ ActiveRecord::Base.connection.recreate_database(db)
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,33 @@
1
+ require 'jdbc_adapter/tsql_helper'
2
+
3
+ module ::JdbcSpec
4
+ module ActiveRecordExtensions
5
+ def cachedb_connection( config )
6
+ config[:port] ||= 1972
7
+ config[:url] ||= "jdbc:Cache://#{config[:host]}:#{config[:port]}/#{ config[:database]}"
8
+ config[:driver] ||= "com.intersys.jdbc.CacheDriver"
9
+ jdbc_connection( config )
10
+ end
11
+ end
12
+
13
+ module CacheDB
14
+ include TSqlMethods
15
+
16
+ def self.adapter_matcher(name, *)
17
+ name =~ /cache/i ? self : false
18
+ end
19
+
20
+ def self.column_selector
21
+ [ /cache/i, lambda { | cfg, col | col.extend( ::JdbcSpec::CacheDB::Column ) } ]
22
+ end
23
+
24
+ module Column
25
+ end
26
+
27
+ def create_table(name, options = { })
28
+ super(name, options)
29
+ primary_key = options[:primary_key] || "id"
30
+ execute "ALTER TABLE #{name} ADD CONSTRAINT #{name}_PK PRIMARY KEY(#{primary_key})" unless options[:id] == false
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,191 @@
1
+ module JdbcSpec
2
+ module DB2
3
+ def self.adapter_matcher(name, config)
4
+ if name =~ /db2/i
5
+ return config[:url] =~ /^jdbc:derby:net:/ ? ::JdbcSpec::Derby : self
6
+ end
7
+ false
8
+ end
9
+
10
+ def self.adapter_selector
11
+ [/db2/i, lambda {|cfg,adapt|
12
+ if cfg[:url] =~ /^jdbc:derby:net:/
13
+ adapt.extend(::JdbcSpec::Derby)
14
+ else
15
+ adapt.extend(::JdbcSpec::DB2)
16
+ end }]
17
+ end
18
+
19
+ module Column
20
+ def type_cast(value)
21
+ return nil if value.nil? || value =~ /^\s*null\s*$/i
22
+ case type
23
+ when :string then value
24
+ when :integer then defined?(value.to_i) ? value.to_i : (value ? 1 : 0)
25
+ when :primary_key then defined?(value.to_i) ? value.to_i : (value ? 1 : 0)
26
+ when :float then value.to_f
27
+ when :datetime then cast_to_date_or_time(value)
28
+ when :timestamp then cast_to_time(value)
29
+ when :time then cast_to_time(value)
30
+ else value
31
+ end
32
+ end
33
+ def cast_to_date_or_time(value)
34
+ return value if value.is_a? Date
35
+ return nil if value.blank?
36
+ guess_date_or_time((value.is_a? Time) ? value : cast_to_time(value))
37
+ end
38
+
39
+ def cast_to_time(value)
40
+ return value if value.is_a? Time
41
+ time_array = ParseDate.parsedate value
42
+ time_array[0] ||= 2000; time_array[1] ||= 1; time_array[2] ||= 1;
43
+ Time.send(ActiveRecord::Base.default_timezone, *time_array) rescue nil
44
+ end
45
+
46
+ def guess_date_or_time(value)
47
+ (value.hour == 0 and value.min == 0 and value.sec == 0) ?
48
+ Date.new(value.year, value.month, value.day) : value
49
+ end
50
+ end
51
+
52
+ def modify_types(tp)
53
+ tp[:primary_key] = 'int not null generated by default as identity (start with 1) primary key'
54
+ tp[:string][:limit] = 255
55
+ tp[:integer][:limit] = nil
56
+ tp[:boolean][:limit] = nil
57
+ tp
58
+ end
59
+
60
+ def add_limit_offset!(sql, options)
61
+ if limit = options[:limit]
62
+ offset = options[:offset] || 0
63
+ sql.gsub!(/SELECT/i, 'SELECT B.* FROM (SELECT A.*, row_number() over () AS internal$rownum FROM (SELECT')
64
+ sql << ") A ) B WHERE B.internal$rownum > #{offset} AND B.internal$rownum <= #{limit + offset}"
65
+ end
66
+ end
67
+
68
+ def quote_column_name(column_name)
69
+ column_name
70
+ end
71
+
72
+ def quote(value, column = nil) # :nodoc:
73
+ if column && column.type == :primary_key
74
+ return value.to_s
75
+ end
76
+ if column && (column.type == :decimal || column.type == :integer) && value
77
+ return value.to_s
78
+ end
79
+ case value
80
+ when String
81
+ if column && column.type == :binary
82
+ "BLOB('#{quote_string(value)}')"
83
+ else
84
+ "'#{quote_string(value)}'"
85
+ end
86
+ else super
87
+ end
88
+ end
89
+
90
+ def quote_string(string)
91
+ string.gsub(/'/, "''") # ' (for ruby-mode)
92
+ end
93
+
94
+ def quoted_true
95
+ '1'
96
+ end
97
+
98
+ def quoted_false
99
+ '0'
100
+ end
101
+
102
+ def recreate_database(name)
103
+ do_not_drop = ["stmg_dbsize_info","hmon_atm_info","hmon_collection","policy"]
104
+ tables.each do |table|
105
+ unless do_not_drop.include?(table)
106
+ drop_table(table)
107
+ end
108
+ end
109
+ end
110
+
111
+ def remove_index(table_name, options = { })
112
+ execute "DROP INDEX #{quote_column_name(index_name(table_name, options))}"
113
+ end
114
+
115
+ # This method makes tests pass without understanding why.
116
+ # Don't use this in production.
117
+ def columns(table_name, name = nil)
118
+ super.select do |col|
119
+ # strip out "magic" columns from DB2 (?)
120
+ !/rolename|roleid|create_time|auditpolicyname|auditpolicyid|remarks/.match(col.name)
121
+ end
122
+ end
123
+
124
+ def add_quotes(name)
125
+ return name unless name
126
+ %Q{"#{name}"}
127
+ end
128
+
129
+ def strip_quotes(str)
130
+ return str unless str
131
+ return str unless /^(["']).*\1$/ =~ str
132
+ str[1..-2]
133
+ end
134
+
135
+ def expand_double_quotes(name)
136
+ return name unless name && name['"']
137
+ name.gsub(/"/,'""')
138
+ end
139
+
140
+
141
+ def structure_dump #:nodoc:
142
+ definition=""
143
+ rs = @connection.connection.meta_data.getTables(nil,nil,nil,["TABLE"].to_java(:string))
144
+ while rs.next
145
+ tname = rs.getString(3)
146
+ definition << "CREATE TABLE #{tname} (\n"
147
+ rs2 = @connection.connection.meta_data.getColumns(nil,nil,tname,nil)
148
+ first_col = true
149
+ while rs2.next
150
+ col_name = add_quotes(rs2.getString(4));
151
+ default = ""
152
+ d1 = rs2.getString(13)
153
+ default = d1 ? " DEFAULT #{d1}" : ""
154
+
155
+ type = rs2.getString(6)
156
+ col_size = rs2.getString(7)
157
+ nulling = (rs2.getString(18) == 'NO' ? " NOT NULL" : "")
158
+ create_col_string = add_quotes(expand_double_quotes(strip_quotes(col_name))) +
159
+ " " +
160
+ type +
161
+ "" +
162
+ nulling +
163
+ default
164
+ if !first_col
165
+ create_col_string = ",\n #{create_col_string}"
166
+ else
167
+ create_col_string = " #{create_col_string}"
168
+ end
169
+
170
+ definition << create_col_string
171
+
172
+ first_col = false
173
+ end
174
+ definition << ");\n\n"
175
+ end
176
+ definition
177
+ end
178
+
179
+ def dump_schema_information
180
+ begin
181
+ if (current_schema = ActiveRecord::Migrator.current_version) > 0
182
+ #TODO: Find a way to get the DB2 instace name to properly form the statement
183
+ return "INSERT INTO DB2INST2.SCHEMA_INFO (version) VALUES (#{current_schema})"
184
+ end
185
+ rescue ActiveRecord::StatementInvalid
186
+ # No Schema Info
187
+ end
188
+ end
189
+
190
+ end
191
+ end
@@ -0,0 +1,421 @@
1
+ require 'jdbc_adapter/missing_functionality_helper'
2
+
3
+ module ::JdbcSpec
4
+ module ActiveRecordExtensions
5
+ def derby_connection(config)
6
+ config[:url] ||= "jdbc:derby:#{config[:database]};create=true"
7
+ config[:driver] ||= "org.apache.derby.jdbc.EmbeddedDriver"
8
+ embedded_driver(config)
9
+ end
10
+ end
11
+
12
+ module Derby
13
+ def self.adapter_matcher(name, *)
14
+ name =~ /derby/i ? self : false
15
+ end
16
+
17
+ def self.column_selector
18
+ [/derby/i, lambda {|cfg,col| col.extend(::JdbcSpec::Derby::Column)}]
19
+ end
20
+
21
+ def self.monkey_rails
22
+ unless @already_monkeyd
23
+ # Needed because Rails is broken wrt to quoting of
24
+ # some values. Most databases are nice about it,
25
+ # but not Derby. The real issue is that you can't
26
+ # compare a CHAR value to a NUMBER column.
27
+ ::ActiveRecord::Associations::ClassMethods.module_eval do
28
+ private
29
+
30
+ def select_limited_ids_list(options, join_dependency)
31
+ connection.select_all(
32
+ construct_finder_sql_for_association_limiting(options, join_dependency),
33
+ "#{name} Load IDs For Limited Eager Loading"
34
+ ).collect { |row| connection.quote(row[primary_key], columns_hash[primary_key]) }.join(", ")
35
+ end
36
+ end
37
+
38
+ @already_monkeyd = true
39
+ end
40
+ end
41
+
42
+ def self.extended(*args)
43
+ monkey_rails
44
+ end
45
+
46
+ def self.included(*args)
47
+ monkey_rails
48
+ end
49
+
50
+ module Column
51
+ def simplified_type(field_type)
52
+ return :boolean if field_type =~ /smallint/i
53
+ return :float if field_type =~ /real/i
54
+ super
55
+ end
56
+
57
+ # Post process default value from JDBC into a Rails-friendly format (columns{-internal})
58
+ def default_value(value)
59
+ # jdbc returns column default strings with actual single quotes around the value.
60
+ return $1 if value =~ /^'(.*)'$/
61
+
62
+ value
63
+ end
64
+ end
65
+
66
+ def adapter_name #:nodoc:
67
+ 'Derby'
68
+ end
69
+
70
+ include JdbcSpec::MissingFunctionalityHelper
71
+
72
+ # Convert the speficied column type to a SQL string. In Derby, :integers cannot specify
73
+ # a limit.
74
+ def type_to_sql(type, limit = nil, precision = nil, scale = nil) #:nodoc:
75
+ return super unless type == :integer
76
+
77
+ native = native_database_types[type.to_s.downcase.to_sym]
78
+ native.is_a?(Hash) ? native[:name] : native
79
+ end
80
+
81
+ def modify_types(tp)
82
+ tp[:primary_key] = "int generated by default as identity NOT NULL PRIMARY KEY"
83
+ tp[:integer][:limit] = nil
84
+ tp[:string][:limit] = 256
85
+ tp[:boolean] = {:name => "smallint"}
86
+ tp
87
+ end
88
+
89
+ # Override default -- fix case where ActiveRecord passes :default => nil, :null => true
90
+ def add_column_options!(sql, options)
91
+ options.delete(:default) if options.has_key?(:default) && options[:default].nil?
92
+ options.delete(:null) if options.has_key?(:null) && (options[:null].nil? || options[:null] == true)
93
+ super
94
+ end
95
+
96
+ def classes_for_table_name(table)
97
+ ActiveRecord::Base.send(:subclasses).select {|klass| klass.table_name == table}
98
+ end
99
+
100
+ # Set the sequence to the max value of the table's column.
101
+ def reset_sequence!(table, column, sequence = nil)
102
+ mpk = select_value("SELECT MAX(#{quote_column_name(column)}) FROM #{quote_table_name(table)}")
103
+ execute("ALTER TABLE #{quote_table_name(table)} ALTER COLUMN #{quote_column_name(column)} RESTART WITH #{mpk.to_i + 1}")
104
+ end
105
+
106
+ def reset_pk_sequence!(table, pk = nil, sequence = nil)
107
+ klasses = classes_for_table_name(table)
108
+ klass = klasses.nil? ? nil : klasses.first
109
+ pk = klass.primary_key unless klass.nil?
110
+ if pk && klass.columns_hash[pk].type == :integer
111
+ reset_sequence!(klass.table_name, pk)
112
+ end
113
+ end
114
+
115
+ def primary_key(table_name) #:nodoc:
116
+ primary_keys(table_name).first
117
+ end
118
+
119
+ def remove_index(table_name, options) #:nodoc:
120
+ execute "DROP INDEX #{index_name(table_name, options)}"
121
+ end
122
+
123
+ def rename_table(name, new_name)
124
+ execute "RENAME TABLE #{name} TO #{new_name}"
125
+ end
126
+
127
+ COLUMN_INFO_STMT = "SELECT C.COLUMNNAME, C.REFERENCEID, C.COLUMNNUMBER FROM SYS.SYSCOLUMNS C, SYS.SYSTABLES T WHERE T.TABLEID = '%s' AND T.TABLEID = C.REFERENCEID ORDER BY C.COLUMNNUMBER"
128
+
129
+ COLUMN_TYPE_STMT = "SELECT COLUMNDATATYPE, COLUMNDEFAULT FROM SYS.SYSCOLUMNS WHERE REFERENCEID = '%s' AND COLUMNNAME = '%s'"
130
+
131
+ AUTO_INC_STMT = "SELECT AUTOINCREMENTSTART, AUTOINCREMENTINC, COLUMNNAME, REFERENCEID, COLUMNDEFAULT FROM SYS.SYSCOLUMNS WHERE REFERENCEID = '%s' AND COLUMNNAME = '%s'"
132
+ AUTO_INC_STMT2 = "SELECT AUTOINCREMENTSTART, AUTOINCREMENTINC, COLUMNNAME, REFERENCEID, COLUMNDEFAULT FROM SYS.SYSCOLUMNS WHERE REFERENCEID = (SELECT T.TABLEID FROM SYS.SYSTABLES T WHERE T.TABLENAME = '%s') AND COLUMNNAME = '%s'"
133
+
134
+ def add_quotes(name)
135
+ return name unless name
136
+ %Q{"#{name}"}
137
+ end
138
+
139
+ def strip_quotes(str)
140
+ return str unless str
141
+ return str unless /^(["']).*\1$/ =~ str
142
+ str[1..-2]
143
+ end
144
+
145
+ def expand_double_quotes(name)
146
+ return name unless name && name['"']
147
+ name.gsub(/"/,'""')
148
+ end
149
+
150
+ def reinstate_auto_increment(name, refid, coldef)
151
+ stmt = AUTO_INC_STMT % [refid, strip_quotes(name)]
152
+ data = execute(stmt).first
153
+ if data
154
+ start = data['autoincrementstart']
155
+ if start
156
+ coldef << " GENERATED " << (data['columndefault'].nil? ? "ALWAYS" : "BY DEFAULT ")
157
+ coldef << "AS IDENTITY (START WITH "
158
+ coldef << start
159
+ coldef << ", INCREMENT BY "
160
+ coldef << data['autoincrementinc']
161
+ coldef << ")"
162
+ return true
163
+ end
164
+ end
165
+ false
166
+ end
167
+
168
+ def reinstate_auto_increment(name, refid, coldef)
169
+ stmt = AUTO_INC_STMT % [refid, strip_quotes(name)]
170
+ data = execute(stmt).first
171
+ if data
172
+ start = data['autoincrementstart']
173
+ if start
174
+ coldef << " GENERATED " << (data['columndefault'].nil? ? "ALWAYS" : "BY DEFAULT ")
175
+ coldef << "AS IDENTITY (START WITH "
176
+ coldef << start
177
+ coldef << ", INCREMENT BY "
178
+ coldef << data['autoincrementinc']
179
+ coldef << ")"
180
+ return true
181
+ end
182
+ end
183
+ false
184
+ end
185
+
186
+ def auto_increment_stmt(tname, cname)
187
+ stmt = AUTO_INC_STMT2 % [tname, strip_quotes(cname)]
188
+ data = execute(stmt).first
189
+ if data
190
+ start = data['autoincrementstart']
191
+ if start
192
+ coldef = ""
193
+ coldef << " GENERATED " << (data['columndefault'].nil? ? "ALWAYS" : "BY DEFAULT ")
194
+ coldef << "AS IDENTITY (START WITH "
195
+ coldef << start
196
+ coldef << ", INCREMENT BY "
197
+ coldef << data['autoincrementinc']
198
+ coldef << ")"
199
+ return coldef
200
+ end
201
+ end
202
+ ""
203
+ end
204
+
205
+
206
+ def add_column(table_name, column_name, type, options = {})
207
+ if option_not_null = options[:null] == false
208
+ option_not_null = options.delete(:null)
209
+ end
210
+ add_column_sql = "ALTER TABLE #{quote_table_name(table_name)} ADD #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
211
+ add_column_options!(add_column_sql, options)
212
+ execute(add_column_sql)
213
+ if option_not_null
214
+ alter_column_sql = "ALTER TABLE #{quote_table_name(table_name)} ALTER #{quote_column_name(column_name)} NOT NULL"
215
+ end
216
+ end
217
+
218
+ def execute(sql, name = nil)
219
+ if sql =~ /^\s*(UPDATE|INSERT)/i
220
+ i = sql =~ /\swhere\s/im
221
+ if i
222
+ sql[i..-1] = sql[i..-1].gsub(/!=\s*NULL/, 'IS NOT NULL').gsub(/=\sNULL/i, 'IS NULL')
223
+ end
224
+ else
225
+ sql.gsub!(/= NULL/i, 'IS NULL')
226
+ end
227
+ super
228
+ end
229
+
230
+
231
+ # I don't think this method is ever called ??? (stepheneb)
232
+ def create_column(name, refid, colno)
233
+ stmt = COLUMN_TYPE_STMT % [refid, strip_quotes(name)]
234
+ coldef = ""
235
+ data = execute(stmt).first
236
+ if data
237
+ coldef << add_quotes(expand_double_quotes(strip_quotes(name)))
238
+ coldef << " "
239
+ coldef << data['columndatatype']
240
+ if !reinstate_auto_increment(name, refid, coldef) && data['columndefault']
241
+ coldef << " DEFAULT " << data['columndefault']
242
+ end
243
+ end
244
+ coldef
245
+ end
246
+
247
+ SIZEABLE = %w(VARCHAR CLOB BLOB)
248
+
249
+ def structure_dump #:nodoc:
250
+ definition=""
251
+ rs = @connection.connection.meta_data.getTables(nil,nil,nil,["TABLE"].to_java(:string))
252
+ while rs.next
253
+ tname = rs.getString(3)
254
+ definition << "CREATE TABLE #{tname} (\n"
255
+ rs2 = @connection.connection.meta_data.getColumns(nil,nil,tname,nil)
256
+ first_col = true
257
+ while rs2.next
258
+ col_name = add_quotes(rs2.getString(4));
259
+ default = ""
260
+ d1 = rs2.getString(13)
261
+ if d1 =~ /^GENERATED_/
262
+ default = auto_increment_stmt(tname, col_name)
263
+ elsif d1
264
+ default = " DEFAULT #{d1}"
265
+ end
266
+
267
+ type = rs2.getString(6)
268
+ col_size = rs2.getString(7)
269
+ nulling = (rs2.getString(18) == 'NO' ? " NOT NULL" : "")
270
+ create_col_string = add_quotes(expand_double_quotes(strip_quotes(col_name))) +
271
+ " " +
272
+ type +
273
+ (SIZEABLE.include?(type) ? "(#{col_size})" : "") +
274
+ nulling +
275
+ default
276
+ if !first_col
277
+ create_col_string = ",\n #{create_col_string}"
278
+ else
279
+ create_col_string = " #{create_col_string}"
280
+ end
281
+
282
+ definition << create_col_string
283
+
284
+ first_col = false
285
+ end
286
+ definition << ");\n\n"
287
+ end
288
+ definition
289
+ end
290
+
291
+ # Support for removing columns added via derby bug issue:
292
+ # https://issues.apache.org/jira/browse/DERBY-1489
293
+ #
294
+ # This feature has not made it into a formal release and is not in Java 6.
295
+ # If the normal strategy fails we fall back on a strategy by creating a new
296
+ # table without the new column and there after moving the data to the new
297
+ #
298
+ def remove_column(table_name, column_name)
299
+ begin
300
+ execute "ALTER TABLE #{table_name} DROP COLUMN #{column_name} RESTRICT"
301
+ rescue
302
+ alter_table(table_name) do |definition|
303
+ definition.columns.delete(definition[column_name])
304
+ end
305
+ end
306
+ end
307
+
308
+ # Notes about changing in Derby:
309
+ # http://db.apache.org/derby/docs/10.2/ref/rrefsqlj81859.html#rrefsqlj81859__rrefsqlj37860)
310
+ #
311
+ # We support changing columns using the strategy outlined in:
312
+ # https://issues.apache.org/jira/browse/DERBY-1515
313
+ #
314
+ # This feature has not made it into a formal release and is not in Java 6. We will
315
+ # need to conditionally support this somehow (supposed to arrive for 10.3.0.0)
316
+ def change_column(table_name, column_name, type, options = {})
317
+ # null/not nulling is easy, handle that separately
318
+ if options.include?(:null)
319
+ # This seems to only work with 10.2 of Derby
320
+ if options.delete(:null) == false
321
+ execute "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} NOT NULL"
322
+ else
323
+ execute "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} NULL"
324
+ end
325
+ end
326
+
327
+ # anything left to do?
328
+ unless options.empty?
329
+ begin
330
+ execute "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} SET DATA TYPE #{type_to_sql(type, options[:limit])}"
331
+ rescue
332
+ transaction do
333
+ temp_new_column_name = "#{column_name}_newtype"
334
+ # 1) ALTER TABLE t ADD COLUMN c1_newtype NEWTYPE;
335
+ add_column table_name, temp_new_column_name, type, options
336
+ # 2) UPDATE t SET c1_newtype = c1;
337
+ execute "UPDATE #{table_name} SET #{temp_new_column_name} = CAST(#{column_name} AS #{type_to_sql(type, options[:limit])})"
338
+ # 3) ALTER TABLE t DROP COLUMN c1;
339
+ remove_column table_name, column_name
340
+ # 4) ALTER TABLE t RENAME COLUMN c1_newtype to c1;
341
+ rename_column table_name, temp_new_column_name, column_name
342
+ end
343
+ end
344
+ end
345
+ end
346
+
347
+ # Support for renaming columns:
348
+ # https://issues.apache.org/jira/browse/DERBY-1490
349
+ #
350
+ # This feature is expect to arrive in version 10.3.0.0:
351
+ # http://wiki.apache.org/db-derby/DerbyTenThreeRelease)
352
+ #
353
+ def rename_column(table_name, column_name, new_column_name) #:nodoc:
354
+ begin
355
+ execute "ALTER TABLE #{table_name} ALTER RENAME COLUMN #{column_name} TO #{new_column_name}"
356
+ rescue
357
+ alter_table(table_name, :rename => {column_name => new_column_name})
358
+ end
359
+ end
360
+
361
+ def primary_keys(table_name)
362
+ @connection.primary_keys table_name.to_s.upcase
363
+ end
364
+
365
+ def columns(table_name, name=nil)
366
+ @connection.columns_internal(table_name.to_s, name, derby_schema)
367
+ end
368
+
369
+ def tables
370
+ @connection.tables(nil, derby_schema)
371
+ end
372
+
373
+ def recreate_database(db_name)
374
+ tables.each do |t|
375
+ drop_table t
376
+ end
377
+ end
378
+
379
+ # For DDL it appears you can quote "" column names, but in queries (like insert it errors out?)
380
+ def quote_column_name(name) #:nodoc:
381
+ name = name.to_s
382
+ if /^(references|integer|key|group|year)$/i =~ name
383
+ %Q{"#{name.upcase}"}
384
+ elsif /[A-Z]/ =~ name && /[a-z]/ =~ name
385
+ %Q{"#{name}"}
386
+ elsif name =~ /[\s-]/
387
+ %Q{"#{name.upcase}"}
388
+ elsif name =~ /^[_\d]/
389
+ %Q{"#{name.upcase}"}
390
+ else
391
+ name
392
+ end
393
+ end
394
+
395
+ def quoted_true
396
+ '1'
397
+ end
398
+
399
+ def quoted_false
400
+ '0'
401
+ end
402
+
403
+ def add_limit_offset!(sql, options) #:nodoc:
404
+ if options[:offset]
405
+ sql << " OFFSET #{options[:offset]} ROWS"
406
+ end
407
+ if options[:limit]
408
+ #ROWS/ROW and FIRST/NEXT mean the same
409
+ sql << " FETCH FIRST #{options[:limit]} ROWS ONLY"
410
+ end
411
+ end
412
+
413
+ private
414
+ # Derby appears to define schemas using the username
415
+ def derby_schema
416
+ @config[:username].to_s
417
+ end
418
+ end
419
+ end
420
+
421
+