activerecord-jdbc-adapter 1.0.0.beta1-java → 1.0.0.beta2-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. data/History.txt +37 -0
  2. data/Manifest.txt +8 -0
  3. data/README.txt +41 -88
  4. data/lib/active_record/connection_adapters/mysql2_adapter.rb +1 -0
  5. data/lib/arel/engines/sql/compilers/hsqldb_compiler.rb +9 -0
  6. data/lib/arel/engines/sql/compilers/mssql_compiler.rb +34 -0
  7. data/lib/arjdbc/db2/adapter.rb +232 -52
  8. data/lib/arjdbc/derby/adapter.rb +28 -1
  9. data/lib/arjdbc/derby/connection_methods.rb +1 -1
  10. data/lib/arjdbc/discover.rb +1 -1
  11. data/lib/arjdbc/firebird/adapter.rb +26 -0
  12. data/lib/arjdbc/h2/adapter.rb +13 -0
  13. data/lib/arjdbc/hsqldb/adapter.rb +8 -6
  14. data/lib/arjdbc/informix/adapter.rb +4 -0
  15. data/lib/arjdbc/jdbc/adapter.rb +27 -5
  16. data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
  17. data/lib/arjdbc/jdbc/connection.rb +76 -45
  18. data/lib/arjdbc/jdbc/jdbc.rake +22 -20
  19. data/lib/arjdbc/jdbc/type_converter.rb +9 -2
  20. data/lib/arjdbc/mssql/adapter.rb +102 -24
  21. data/lib/arjdbc/mssql/connection_methods.rb +19 -2
  22. data/lib/arjdbc/mssql/tsql_helper.rb +1 -0
  23. data/lib/arjdbc/mysql/adapter.rb +6 -0
  24. data/lib/arjdbc/mysql/connection_methods.rb +8 -7
  25. data/lib/arjdbc/oracle/adapter.rb +8 -6
  26. data/lib/arjdbc/postgresql/adapter.rb +51 -19
  27. data/lib/arjdbc/version.rb +1 -1
  28. data/lib/jdbc_adapter/rake_tasks.rb +3 -0
  29. data/rails_generators/templates/lib/tasks/jdbc.rake +2 -2
  30. data/rakelib/package.rake +2 -0
  31. data/rakelib/test.rake +6 -3
  32. data/src/java/arjdbc/derby/DerbyModule.java +30 -1
  33. data/src/java/arjdbc/informix/InformixRubyJdbcConnection.java +74 -0
  34. data/src/java/arjdbc/jdbc/AdapterJavaService.java +7 -3
  35. data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +45 -30
  36. data/src/java/arjdbc/mssql/MssqlRubyJdbcConnection.java +54 -1
  37. data/src/java/arjdbc/oracle/OracleRubyJdbcConnection.java +85 -0
  38. data/test/abstract_db_create.rb +6 -1
  39. data/test/db/jndi_config.rb +20 -10
  40. data/test/db2_simple_test.rb +34 -1
  41. data/test/derby_simple_test.rb +78 -0
  42. data/test/generic_jdbc_connection_test.rb +21 -1
  43. data/test/jndi_callbacks_test.rb +2 -1
  44. data/test/jndi_test.rb +1 -11
  45. data/test/models/entry.rb +20 -0
  46. data/test/mssql_limit_offset_test.rb +28 -0
  47. data/test/mssql_simple_test.rb +7 -1
  48. data/test/mysql_info_test.rb +49 -6
  49. data/test/mysql_simple_test.rb +4 -0
  50. data/test/oracle_simple_test.rb +3 -47
  51. data/test/oracle_specific_test.rb +83 -0
  52. data/test/postgres_db_create_test.rb +6 -0
  53. data/test/postgres_drop_db_test.rb +16 -0
  54. data/test/postgres_simple_test.rb +17 -0
  55. data/test/postgres_table_alias_length_test.rb +15 -0
  56. data/test/simple.rb +17 -4
  57. metadata +33 -7
data/History.txt CHANGED
@@ -1,5 +1,11 @@
1
1
  == 1.0.0
2
2
 
3
+ - Thanks to David Kellum, Dmitry Denisov, Dwayne Litzenberger, Gregor
4
+ Schmidt, James Walker, John Duff, Joshua Suggs, Nicholas J Kreucher,
5
+ Peter Donald, Geoff Longman, and Ryan Bell for their contributions
6
+ to this release.
7
+ - BIG set of DB2 updates (Thanks Nick Kreucher)
8
+ - Deprecate jdbc_adapter/rake_tasks
3
9
  - (1.0.0.beta1)
4
10
  - Make database-specific extensions only load when necessary
5
11
  - Allow for discovery of database extensions outside of ar-jdbc
@@ -8,6 +14,37 @@
8
14
  - Get AR's own tests running as close to 100% as possible. MySQL is
9
15
  currently 100%, SQLite3 is close.
10
16
  - JRUBY-4876: Bump up Derby's max index name length (Uwe Kubosch)
17
+ - (1.0.0.beta2)
18
+ - 98 commits since beta1
19
+ - MSSQL updates from dlitz and realityforge
20
+ - ACTIVERECORD_JDBC-131: Fix string slug issue for DB2 (Youhei Kondou)
21
+ - JRUBY-1642: Don't use H2 INFORMATION_SCHEMA in table or column
22
+ searches
23
+ - JRUBY-4972: Attempt to deal with type(0)/:limit => 0 by not setting
24
+ it808e213 JRUBY-5040: Fix issue with limits on timestamps in MySQL
25
+ - JRUBY-3555: Allow setting Derby schema with 'schema:' option917ebd9
26
+ ACTIVERECORD_JDBC-98: Make sure we actuall raise an error when
27
+ inappropriately configured
28
+ - ACTIVERECORD_JDBC-112: Add schema dumper tests for already-fixed
29
+ MySQL type limits
30
+ - ACTIVERECORD_JDBC-113: Fix PG float precision issue2c6b1aa No longer
31
+ need M[ys]SQL escape hatch on case-sensitive test
32
+ - ACTIVERECORD_JDBC-103: Fix decimal options for PG add/change column
33
+ (Michael Pitman)
34
+ - ACTIVERECORD_JDBC-127: Fix quoting of Date vs. Time(stamp) for
35
+ Oracle (Lenny Marks)
36
+ - Oracle: Sort out theNUMBER vs NUMBER(x) vs NUMBER(x,y) situation.
37
+ - JRUBY-3051: Think we finally got the PG mixed-case patches applied.
38
+ - JRUBY-5081: Consolidate code for dropping DB via postgres
39
+ - ACTIVERECORD_JDBC-101: Add override of LONGVARCHAR => CLOB for
40
+ informix
41
+ - ACTIVERECORD_JDBC-107: Fix MySQL update_all issue on AR 2.3
42
+ - ACTIVERECORD_JDBC-124: Filter out special _row_num column
43
+ - ACTIVERECORD_JDBC-126: Fix sql 2000 limit/offset per Michael Pitman
44
+ - ACTIVERECORD_JDBC-125: Add tweak to limit/offset code for HABTM
45
+ queries (alex b)
46
+ - ACTIVERECORD_JDBC-129: Don't have limits for text, binary or bit
47
+ fields
11
48
 
12
49
  == 0.9.7
13
50
 
data/Manifest.txt CHANGED
@@ -15,6 +15,7 @@ lib/active_record/connection_adapters/informix_adapter.rb
15
15
  lib/active_record/connection_adapters/jdbc_adapter.rb
16
16
  lib/active_record/connection_adapters/jndi_adapter.rb
17
17
  lib/active_record/connection_adapters/mssql_adapter.rb
18
+ lib/active_record/connection_adapters/mysql2_adapter.rb
18
19
  lib/active_record/connection_adapters/mysql_adapter.rb
19
20
  lib/active_record/connection_adapters/oracle_adapter.rb
20
21
  lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -24,6 +25,7 @@ lib/arel/engines/sql/compilers/derby_compiler.rb
24
25
  lib/arel/engines/sql/compilers/h2_compiler.rb
25
26
  lib/arel/engines/sql/compilers/hsqldb_compiler.rb
26
27
  lib/arel/engines/sql/compilers/jdbc_compiler.rb
28
+ lib/arel/engines/sql/compilers/mssql_compiler.rb
27
29
  lib/arjdbc/cachedb.rb
28
30
  lib/arjdbc/db2.rb
29
31
  lib/arjdbc/derby.rb
@@ -84,6 +86,7 @@ lib/arjdbc/sqlite3/adapter.rb
84
86
  lib/arjdbc/sqlite3/connection_methods.rb
85
87
  lib/arjdbc/sybase/adapter.rb
86
88
  lib/generators/jdbc/jdbc_generator.rb
89
+ lib/jdbc_adapter/rake_tasks.rb
87
90
  lib/jdbc_adapter/version.rb
88
91
  lib/arjdbc/jdbc/adapter_java.jar
89
92
  test/abstract_db_create.rb
@@ -114,13 +117,16 @@ test/mysql_multibyte_test.rb
114
117
  test/mysql_nonstandard_primary_key_test.rb
115
118
  test/mysql_simple_test.rb
116
119
  test/oracle_simple_test.rb
120
+ test/oracle_specific_test.rb
117
121
  test/pick_rails_version.rb
118
122
  test/postgres_db_create_test.rb
123
+ test/postgres_drop_db_test.rb
119
124
  test/postgres_mixed_case_test.rb
120
125
  test/postgres_nonseq_pkey_test.rb
121
126
  test/postgres_reserved_test.rb
122
127
  test/postgres_schema_search_path_test.rb
123
128
  test/postgres_simple_test.rb
129
+ test/postgres_table_alias_length_test.rb
124
130
  test/simple.rb
125
131
  test/sqlite3_simple_test.rb
126
132
  test/sybase_jtds_simple_test.rb
@@ -150,12 +156,14 @@ test/models/string_id.rb
150
156
  test/models/validates_uniqueness_of_string.rb
151
157
  lib/arjdbc/jdbc/jdbc.rake
152
158
  src/java/arjdbc/derby/DerbyModule.java
159
+ src/java/arjdbc/informix/InformixRubyJdbcConnection.java
153
160
  src/java/arjdbc/jdbc/AdapterJavaService.java
154
161
  src/java/arjdbc/jdbc/JdbcConnectionFactory.java
155
162
  src/java/arjdbc/jdbc/RubyJdbcConnection.java
156
163
  src/java/arjdbc/jdbc/SQLBlock.java
157
164
  src/java/arjdbc/mssql/MssqlRubyJdbcConnection.java
158
165
  src/java/arjdbc/mysql/MySQLModule.java
166
+ src/java/arjdbc/oracle/OracleRubyJdbcConnection.java
159
167
  src/java/arjdbc/postgresql/PostgresqlRubyJdbcConnection.java
160
168
  src/java/arjdbc/sqlite3/Sqlite3RubyJdbcConnection.java
161
169
  rakelib/compile.rake
data/README.txt CHANGED
@@ -2,39 +2,11 @@ activerecord-jdbc-adapter is a database adapter for Rails' ActiveRecord
2
2
  component that can be used with JRuby[http://www.jruby.org/]. It allows use of
3
3
  virtually any JDBC-compliant database with your JRuby on Rails application.
4
4
 
5
- == Project Info
6
-
7
- * Mailing Lists: http://kenai.com/projects/activerecord-jdbc/lists
8
- * Issues: http://kenai.com/jira/browse/ACTIVERECORD_JDBC
9
- * Source: git://kenai.com/activerecord-jdbc~main
10
- git://github.com/nicksieger/activerecord-jdbc-adapter.git
11
-
12
5
  == Databases
13
6
 
14
- What's there, and what is not there:
15
-
16
- * MySQL - Complete support
17
- * PostgreSQL - Complete support
18
- * Oracle - Complete support
19
- * Microsoft SQL Server - Complete support
20
- * DB2 - Complete, except for the migrations:
21
- * change_column
22
- * change_column_default
23
- * remove_column
24
- * rename_column
25
- * add_index
26
- * remove_index
27
- * rename_table
28
- * FireBird - Complete, except for change_column_default and rename_column
29
- * Derby - Complete, except for:
30
- * change_column
31
- * change_column_default
32
- * remove_column
33
- * rename_column
34
- * HSQLDB - Complete
35
- * H2 - Complete
36
- * SQLite3 - work in progress
37
- * Informix - Fairly complete support, all tests pass and migrations appear to work. Comments welcome.
7
+ Activerecord-jdbc-adapter provides full or nearly full support for:
8
+ MySQL, PostgreSQL, SQLite3, Oracle, Microsoft SQL Server, DB2,
9
+ FireBird, Derby, HSQLDB, H2, and Informix.
38
10
 
39
11
  Other databases will require testing and likely a custom configuration module.
40
12
  Please join the activerecord-jdbc
@@ -48,7 +20,7 @@ support for more databases.
48
20
  To use activerecord-jdbc-adapter with JRuby on Rails:
49
21
 
50
22
  1. Choose the adapter you wish to gem install. The following pre-packaged
51
- adapters are available:
23
+ adapters are available:
52
24
 
53
25
  * base jdbc (<tt>activerecord-jdbc-adapter</tt>). Supports all available databases via JDBC, but requires you to download and manually install the database vendor's JDBC driver .jar file.
54
26
  * mysql (<tt>activerecord-jdbcmysql-adapter</tt>)
@@ -60,54 +32,33 @@ To use activerecord-jdbc-adapter with JRuby on Rails:
60
32
  * mssql (<tt>activerecord-jdbcmssql-adapter</tt>)
61
33
 
62
34
  2a. For Rails 3, if you're generating a new application, use the
63
- following command to generate your application:
35
+ following command to generate your application:
64
36
 
65
- jruby -S rails myapp -m http://jruby.org/rails3.rb
37
+ jruby -S rails new sweetapp -m http://jruby.org/rails3.rb
66
38
 
67
- 2b. Otherwise, you'll need to run the "jdbc" generator to prepare your
68
- Rails application for JDBC.
39
+ 2b. Otherwise, you'll need to perform some extra configuration steps
40
+ to prepare your Rails application for JDBC.
69
41
 
70
- If you're using Rails 3, first you'll need to modify your Gemfile
71
- to use the activerecord-jdbc-adapter gem under JRuby. Change your
72
- Gemfile to look like the following (using sqlite3 as an example):
42
+ If you're using Rails 3, you'll need to modify your Gemfile to use the
43
+ activerecord-jdbc-adapter gem under JRuby. Change your Gemfile to look
44
+ like the following (using sqlite3 as an example):
73
45
 
74
46
  if defined?(JRUBY_VERSION)
75
- gem 'activerecord-jdbc-adapter', :require => false
76
- gem 'jdbc-sqlite3, :require => false
47
+ gem 'activerecord-jdbc-adapter'
48
+ gem 'jdbc-sqlite3'
77
49
  else
78
- gem sqlite3-ruby', :require => 'sqlite3'
50
+ gem 'sqlite3-ruby', :require => 'sqlite3'
79
51
  end
80
52
 
81
- Next, run the generator. With Rails 3:
82
-
83
- jruby script/rails generate jdbc
84
-
85
- With Rails 2:
53
+ If you're using Rails 2:
86
54
 
87
55
  jruby script/generate jdbc
88
-
89
- The initializer and rake task files generated are guarded such that
90
- they won't be loaded if you still run your application under C Ruby.
91
-
92
- Legacy: If you're using Rails prior to version 2.0, you'll need to
93
- add one-time setup to your config/environment.rb file in your Rails
94
- application. Add the following lines just before the
95
- <code>Rails::Initializer</code>. (If you're using
96
- activerecord-jdbc-adapter under the old gem name used in versions
97
- 0.5 and earlier (ActiveRecord-JDBC), replace
98
- 'activerecord-jdbc-adapter' with 'ActiveRecord-JDBC' below.)
99
-
100
- if RUBY_PLATFORM =~ /java/
101
- require 'rubygems'
102
- gem 'activerecord-jdbc-adapter'
103
- require 'jdbc_adapter'
104
- end
105
56
 
106
57
  3. Configure your database.yml in the normal Rails style.
107
58
 
108
- Legacy configuration: If you use one of the convenience
109
- 'activerecord-jdbcXXX-adapter' adapters, you can still put a 'jdbc'
110
- prefix in front of the database adapter name as below.
59
+ Legacy configuration: If you use one of the convenience
60
+ 'activerecord-jdbcXXX-adapter' adapters, you can still put a 'jdbc'
61
+ prefix in front of the database adapter name as below.
111
62
 
112
63
  development:
113
64
  adapter: jdbcmysql
@@ -116,8 +67,8 @@ To use activerecord-jdbc-adapter with JRuby on Rails:
116
67
  hostname: localhost
117
68
  database: weblog_development
118
69
 
119
- For other databases, you'll need to know the database driver class
120
- and URL. Example:
70
+ For other databases, you'll need to know the database driver class and
71
+ URL. Example:
121
72
 
122
73
  development:
123
74
  adapter: jdbc
@@ -126,11 +77,11 @@ To use activerecord-jdbc-adapter with JRuby on Rails:
126
77
  driver: com.mysql.jdbc.Driver
127
78
  url: jdbc:mysql://localhost:3306/weblog_development
128
79
 
129
- For JNDI data sources, you may simply specify the database type
130
- using the adapter key and the JNDI location as follows:
80
+ For JNDI data sources, you may simply specify the JNDI location as follows
81
+ (the adapter will be automatically detected):
131
82
 
132
83
  production:
133
- adapter: mysql
84
+ adapter: jdbc
134
85
  jndi: jdbc/mysqldb
135
86
 
136
87
  === Standalone, with ActiveRecord
@@ -139,27 +90,19 @@ To use activerecord-jdbc-adapter with JRuby on Rails:
139
90
 
140
91
  jruby -S gem install activerecord-jdbc-adapter
141
92
 
142
- If you wish to use the adapter for a specific database, you can install it
143
- directly and a driver gem will be installed as well:
93
+ If you wish to use the adapter for a specific database, you can
94
+ install it directly and a driver gem will be installed as well:
144
95
 
145
96
  jruby -S gem install activerecord-jdbcderby-adapter
146
97
 
147
- 2. If using ActiveRecord 2.0 (Rails 2.0) or greater, you can skip to the next
148
- step. Otherwise, ensure the following code gets executed in your script:
149
-
150
- require 'rubygems'
151
- gem 'activerecord-jdbc-adapter'
152
- require 'jdbc_adapter'
153
- require 'active_record'
154
-
155
- 3. After this you can establish a JDBC connection like this:
98
+ 2. After this you can establish a JDBC connection like this:
156
99
 
157
100
  ActiveRecord::Base.establish_connection(
158
101
  :adapter => 'jdbcderby',
159
102
  :database => "db/my-database"
160
103
  )
161
104
 
162
- or like this (but requires that you manually put the driver jar on the classpath):
105
+ or like this (but requires that you manually put the driver jar on the classpath):
163
106
 
164
107
  ActiveRecord::Base.establish_connection(
165
108
  :adapter => 'jdbc',
@@ -179,12 +122,22 @@ Please file bug reports at
179
122
  http://kenai.com/jira/browse/ACTIVERECORD_JDBC. If you're not sure if
180
123
  something's a bug, feel free to pre-report it on the mailing lists.
181
124
 
125
+ == Project Info
126
+
127
+ * Mailing Lists: http://kenai.com/projects/activerecord-jdbc/lists
128
+ * Issues: http://kenai.com/jira/browse/ACTIVERECORD_JDBC
129
+ * Source:
130
+ git://github.com/nicksieger/activerecord-jdbc-adapter.git
131
+ git://kenai.com/activerecord-jdbc~main
132
+
182
133
  == Running AR-JDBC's Tests
183
134
 
184
- Drivers for 6 open-source databases are included. Provided you have MySQL
185
- installed, you can simply type <tt>jruby -S rake</tt> to run the tests. A
186
- database named <tt>weblog_development</tt> is needed beforehand with a
187
- connection user of "blog" and an empty password.
135
+ Drivers for 6 open-source databases are included. Provided you have
136
+ MySQL installed, you can simply type <tt>jruby -S rake</tt> to run the
137
+ tests. A database named <tt>weblog_development</tt> is needed
138
+ beforehand with a connection user of "blog" and an empty password. You
139
+ alse need to grant "blog" create privileges on
140
+ 'test_rake_db_create.*'.
188
141
 
189
142
  If you also have PostgreSQL available, those tests will be run if the
190
143
  `psql' executable can be found. Also ensure you have a database named
@@ -0,0 +1 @@
1
+ require 'arjdbc/mysql'
@@ -1,6 +1,15 @@
1
1
  module Arel
2
2
  module SqlCompiler
3
3
  class HsqldbCompiler < GenericCompiler
4
+ def select_sql
5
+ # HSQLDB needs to add LIMIT in right after SELECT
6
+ query = super
7
+ offset = relation.skipped
8
+ limit = relation.taken
9
+ @engine.connection.add_limit_offset!(query, :limit => limit,
10
+ :offset => offset) if offset || limit
11
+ query
12
+ end
4
13
  end
5
14
  end
6
15
  end
@@ -0,0 +1,34 @@
1
+ module Arel
2
+ module SqlCompiler
3
+ class MsSQLCompiler < GenericCompiler
4
+ def select_sql
5
+ query = super
6
+
7
+ offset = relation.skipped
8
+ limit = relation.taken
9
+ @engine.connection.add_limit_offset!(query, :limit => limit, :offset => offset) if offset || limit
10
+
11
+ query
12
+ end
13
+
14
+ def build_clauses
15
+ joins = relation.joins(self)
16
+ wheres = relation.where_clauses
17
+ groups = relation.group_clauses
18
+ havings = relation.having_clauses
19
+ orders = relation.order_clauses
20
+
21
+ clauses = [ "",
22
+ joins,
23
+ ("WHERE #{wheres.join(' AND ')}" unless wheres.empty?),
24
+ ("GROUP BY #{groups.join(', ')}" unless groups.empty?),
25
+ ("HAVING #{havings.join(' AND ')}" unless havings.empty?),
26
+ ("ORDER BY #{orders.join(', ')}" unless orders.empty?)
27
+ ].compact.join ' '
28
+
29
+ clauses << " #{locked}" unless locked.blank?
30
+ clauses unless clauses.blank?
31
+ end
32
+ end
33
+ end
34
+ end
@@ -1,8 +1,8 @@
1
1
  module ArJdbc
2
2
  module DB2
3
- def self.extended(obj)
4
- # Ignore these 4 system tables
5
- ActiveRecord::SchemaDumper.ignore_tables |= %w{hmon_atm_info hmon_collection policy stmg_dbsize_info}
3
+ def self.column_selector
4
+ [ /(db2|as400)/i,
5
+ lambda { |cfg, column| column.extend(::ArJdbc::DB2::Column) } ]
6
6
  end
7
7
 
8
8
  module Column
@@ -13,48 +13,114 @@ module ArJdbc
13
13
  when :integer then defined?(value.to_i) ? value.to_i : (value ? 1 : 0)
14
14
  when :primary_key then defined?(value.to_i) ? value.to_i : (value ? 1 : 0)
15
15
  when :float then value.to_f
16
- when :datetime then cast_to_date_or_time(value)
17
- when :timestamp then cast_to_time(value)
18
- when :time then cast_to_time(value)
19
- else value
16
+ when :datetime then ArJdbc::DB2::Column.cast_to_date_or_time(value)
17
+ when :date then ArJdbc::DB2::Column.cast_to_date_or_time(value)
18
+ when :timestamp then ArJdbc::DB2::Column.cast_to_time(value)
19
+ when :time then ArJdbc::DB2::Column.cast_to_time(value)
20
+ # TODO AS400 stores binary strings in EBCDIC (CCSID 65535), need to convert back to ASCII
21
+ else
22
+ super
20
23
  end
21
24
  end
22
- def cast_to_date_or_time(value)
25
+
26
+ def type_cast_code(var_name)
27
+ case type
28
+ when :datetime then "ArJdbc::DB2::Column.cast_to_date_or_time(#{var_name})"
29
+ when :date then "ArJdbc::DB2::Column.cast_to_date_or_time(#{var_name})"
30
+ when :timestamp then "ArJdbc::DB2::Column.cast_to_time(#{var_name})"
31
+ when :time then "ArJdbc::DB2::Column.cast_to_time(#{var_name})"
32
+ else
33
+ super
34
+ end
35
+ end
36
+
37
+ def self.cast_to_date_or_time(value)
23
38
  return value if value.is_a? Date
24
39
  return nil if value.blank?
25
40
  guess_date_or_time((value.is_a? Time) ? value : cast_to_time(value))
26
41
  end
27
42
 
28
- def cast_to_time(value)
43
+ def self.cast_to_time(value)
29
44
  return value if value.is_a? Time
30
- time_array = ParseDate.parsedate value
45
+ # AS400 returns a 2 digit year, LUW returns a 4 digit year, so comp = true to help out AS400
46
+ time_array = ParseDate.parsedate(value, true)
31
47
  time_array[0] ||= 2000; time_array[1] ||= 1; time_array[2] ||= 1;
32
48
  Time.send(ActiveRecord::Base.default_timezone, *time_array) rescue nil
33
49
  end
34
50
 
35
- def guess_date_or_time(value)
51
+ def self.guess_date_or_time(value)
36
52
  (value.hour == 0 and value.min == 0 and value.sec == 0) ?
37
53
  Date.new(value.year, value.month, value.day) : value
38
54
  end
55
+
56
+ private
57
+ # <b>DEPRECATED:</b> SMALLINT is now used for boolean field types. Please
58
+ # convert your tables using DECIMAL(5) for boolean values to SMALLINT instead.
59
+ def use_decimal5_for_boolean
60
+ warn "[DEPRECATION] using DECIMAL(5) for boolean is deprecated. Convert your columns to SMALLINT instead."
61
+ :boolean
62
+ end
63
+
64
+ # http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.apdv.java.doc/doc/rjvjdata.html
65
+ def simplified_type(field_type)
66
+ case field_type
67
+ # old jdbc_db2.rb used decimal(5,0) as boolean
68
+ when /^smallint/i then :boolean
69
+ when /^decimal\(5\)$/i then use_decimal5_for_boolean
70
+ when /^real/i then :float
71
+ when /^timestamp/i then :datetime
72
+ else
73
+ super
74
+ end
75
+ end
76
+
77
+ # Post process default value from JDBC into a Rails-friendly format (columns{-internal})
78
+ def default_value(value)
79
+ # IBM i (AS400) will return an empty string instead of null for no default
80
+ return nil if value.blank?
81
+
82
+ # string defaults are surrounded by single quotes
83
+ return $1 if value =~ /^'(.*)'$/
84
+
85
+ value
86
+ end
39
87
  end
40
88
 
41
- def insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
42
- id = super
43
- unless id
44
- table_name = sql.split(/\s/)[2]
45
- result = select(ActiveRecord::Base.send(:sanitize_sql,
46
- %[select IDENTITY_VAL_LOCAL() as last_insert_id from #{table_name}],
47
- nil))
48
- id = result.last['last_insert_id']
89
+ def _execute(sql, name = nil)
90
+ if ActiveRecord::ConnectionAdapters::JdbcConnection::select?(sql)
91
+ @connection.execute_query(sql)
92
+ elsif ActiveRecord::ConnectionAdapters::JdbcConnection::insert?(sql)
93
+ (@connection.execute_insert(sql) or last_insert_id(sql)).to_i
94
+ else
95
+ @connection.execute_update(sql)
96
+ end
97
+ end
98
+
99
+ # holy moly batman! all this to tell AS400 "yes i am sure"
100
+ def execute_and_auto_confirm(sql)
101
+ @connection.execute_update "call qsys.qcmdexc('QSYS/CHGJOB INQMSGRPY(*SYSRPYL)',0000000031.00000)"
102
+ begin
103
+ @connection.execute_update "call qsys.qcmdexc('ADDRPYLE SEQNBR(9876) MSGID(CPA32B2) RPY(''I'')',0000000045.00000)"
104
+ execute sql
105
+ ensure
106
+ @connection.execute_update "call qsys.qcmdexc('QSYS/CHGJOB INQMSGRPY(*DFT)',0000000027.00000)"
107
+ @connection.execute_update "call qsys.qcmdexc('RMVRPYLE SEQNBR(9876)',0000000021.00000) "
49
108
  end
50
- id
109
+ end
110
+
111
+ def last_insert_id(sql)
112
+ table_name = sql.split(/\s/)[2]
113
+ result = select(ActiveRecord::Base.send(:sanitize_sql,
114
+ %[select IDENTITY_VAL_LOCAL() as last_insert_id from #{table_name}],
115
+ nil))
116
+ result.last['last_insert_id']
51
117
  end
52
118
 
53
119
  def modify_types(tp)
54
120
  tp[:primary_key] = 'int not null generated by default as identity (start with 1) primary key'
55
121
  tp[:string][:limit] = 255
56
- tp[:integer][:limit] = nil
57
- tp[:boolean][:limit] = nil
122
+ tp[:integer] = {:limit => nil}
123
+ tp[:boolean] = {:name => "smallint"}
58
124
  tp
59
125
  end
60
126
 
@@ -63,17 +129,24 @@ module ArJdbc
63
129
  end
64
130
 
65
131
  def add_limit_offset!(sql, options)
66
- if limit = options[:limit]
67
- offset = options[:offset] || 0
132
+ limit, offset = options[:limit], options[:offset]
133
+ if limit && !offset
134
+ if limit == 1
135
+ sql << " FETCH FIRST ROW ONLY"
136
+ else
137
+ sql << " FETCH FIRST #{sanitize_limit(limit)} ROWS ONLY"
138
+ end
139
+ elsif limit && offset
68
140
  sql.gsub!(/SELECT/i, 'SELECT B.* FROM (SELECT A.*, row_number() over () AS internal$rownum FROM (SELECT')
69
- sql << ") A ) B WHERE B.internal$rownum > #{offset} AND B.internal$rownum <= #{limit + offset}"
141
+ sql << ") A ) B WHERE B.internal$rownum > #{offset} AND B.internal$rown
142
+ um <= #{sanitize_limit(limit) + offset}"
70
143
  end
71
144
  end
72
145
 
73
146
  def pk_and_sequence_for(table)
74
147
  # In JDBC/DB2 side, only upcase names of table and column are handled.
75
148
  keys = super(table.upcase)
76
- if keys[0]
149
+ if keys && keys[0]
77
150
  # In ActiveRecord side, only downcase names of table and column are handled.
78
151
  keys[0] = keys[0].downcase
79
152
  end
@@ -85,8 +158,8 @@ module ArJdbc
85
158
  end
86
159
 
87
160
  def quote(value, column = nil) # :nodoc:
88
- if column && column.type == :primary_key
89
- return value.to_s
161
+ if column && column.respond_to?(:primary) && column.primary && column.klass != String
162
+ return value.to_i.to_s
90
163
  end
91
164
  if column && (column.type == :decimal || column.type == :integer) && value
92
165
  return value.to_s
@@ -114,26 +187,113 @@ module ArJdbc
114
187
  '0'
115
188
  end
116
189
 
117
- def recreate_database(name)
118
- do_not_drop = ["stmg_dbsize_info","hmon_atm_info","hmon_collection","policy"]
119
- tables.each do |table|
120
- unless do_not_drop.include?(table)
121
- drop_table(table)
122
- end
190
+ def reorg_table(table_name)
191
+ unless as400?
192
+ @connection.execute_update "call sysproc.admin_cmd ('REORG TABLE #{table_name}')"
123
193
  end
124
194
  end
125
195
 
196
+ def recreate_database(name)
197
+ tables.each {|table| drop_table("#{db2_schema}.#{table}")}
198
+ end
199
+
126
200
  def remove_index(table_name, options = { })
127
201
  execute "DROP INDEX #{quote_column_name(index_name(table_name, options))}"
128
202
  end
129
203
 
130
- # This method makes tests pass without understanding why.
131
- # Don't use this in production.
204
+ # http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.admin.dbobj.doc/doc/t0020130.html
205
+ # ...not supported on IBM i, so we raise in this case
206
+ def rename_column(table_name, column_name, new_column_name) #:nodoc:
207
+ if as400?
208
+ raise NotImplementedError, "rename_column is not supported on IBM i"
209
+ else
210
+ execute "ALTER TABLE #{table_name} RENAME COLUMN #{column_name} TO #{new_column_name}"
211
+ reorg_table(table_name)
212
+ end
213
+ end
214
+
215
+ def change_column_null(table_name, column_name, null)
216
+ if null
217
+ execute "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} DROP NOT NULL"
218
+ else
219
+ execute "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} SET NOT NULL"
220
+ end
221
+ reorg_table(table_name)
222
+ end
223
+
224
+ def change_column_default(table_name, column_name, default)
225
+ if default.nil?
226
+ execute "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} DROP DEFAULT"
227
+ else
228
+ execute "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} SET WITH DEFAULT #{quote(default)}"
229
+ end
230
+ reorg_table(table_name)
231
+ end
232
+
233
+ def change_column(table_name, column_name, type, options = {})
234
+ data_type = type_to_sql(type, options[:limit], options[:precision], options[:scale])
235
+ sql = "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} SET DATA TYPE #{data_type}"
236
+ as400? ? execute_and_auto_confirm(sql) : execute(sql)
237
+ reorg_table(table_name)
238
+
239
+ if options.include?(:default) and options.include?(:null)
240
+ # which to run first?
241
+ if options[:null] or options[:default].nil?
242
+ change_column_null(table_name, column_name, options[:null])
243
+ change_column_default(table_name, column_name, options[:default])
244
+ else
245
+ change_column_default(table_name, column_name, options[:default])
246
+ change_column_null(table_name, column_name, options[:null])
247
+ end
248
+ elsif options.include?(:default)
249
+ change_column_default(table_name, column_name, options[:default])
250
+ elsif options.include?(:null)
251
+ change_column_null(table_name, column_name, options[:null])
252
+ end
253
+ end
254
+
255
+ # http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.admin.dbobj.doc/doc/t0020132.html
256
+ def remove_column(table_name, column_name) #:nodoc:
257
+ sql = "ALTER TABLE #{table_name} DROP COLUMN #{column_name}"
258
+
259
+ as400? ? execute_and_auto_confirm(sql) : execute(sql)
260
+ reorg_table(table_name)
261
+ end
262
+
263
+ # http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.sql.ref.doc/doc/r0000980.html
264
+ def rename_table(name, new_name) #:nodoc:
265
+ execute "RENAME TABLE #{name} TO #{new_name}"
266
+ reorg_table(table_name)
267
+ end
268
+
269
+ def tables
270
+ @connection.tables(nil, db2_schema, nil, ["TABLE"])
271
+ end
272
+
273
+ # only record precision and scale for types that can set
274
+ # them via CREATE TABLE:
275
+ # http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.sql.ref.doc/doc/r0000927.html
276
+ HAVE_LIMIT = %w(FLOAT DECFLOAT CHAR VARCHAR CLOB BLOB NCHAR NCLOB DBCLOB GRAPHIC VARGRAPHIC) #TIMESTAMP
277
+ HAVE_PRECISION = %w(DECIMAL NUMERIC)
278
+ HAVE_SCALE = %w(DECIMAL NUMERIC)
279
+
132
280
  def columns(table_name, name = nil)
133
- super.select do |col|
134
- # strip out "magic" columns from DB2 (?)
135
- !/rolename|roleid|create_time|auditpolicyname|auditpolicyid|remarks/.match(col.name)
281
+ cols = @connection.columns(table_name, name, db2_schema)
282
+
283
+ # scrub out sizing info when CREATE TABLE doesn't support it
284
+ # but JDBC reports it (doh!)
285
+ for col in cols
286
+ base_sql_type = col.sql_type.sub(/\(.*/, "").upcase
287
+ col.limit = nil unless HAVE_LIMIT.include?(base_sql_type)
288
+ col.precision = nil unless HAVE_PRECISION.include?(base_sql_type)
289
+ #col.scale = nil unless HAVE_SCALE.include?(base_sql_type)
136
290
  end
291
+
292
+ cols
293
+ end
294
+
295
+ def indexes(table_name, name = nil)
296
+ @connection.indexes(table_name, name, db2_schema)
137
297
  end
138
298
 
139
299
  def add_quotes(name)
@@ -152,27 +312,39 @@ module ArJdbc
152
312
  name.gsub(/"/,'""')
153
313
  end
154
314
 
155
-
156
315
  def structure_dump #:nodoc:
157
316
  definition=""
158
- rs = @connection.connection.meta_data.getTables(nil,nil,nil,["TABLE"].to_java(:string))
317
+ rs = @connection.connection.meta_data.getTables(nil,db2_schema.upcase,nil,["TABLE"].to_java(:string))
159
318
  while rs.next
160
319
  tname = rs.getString(3)
161
320
  definition << "CREATE TABLE #{tname} (\n"
162
- rs2 = @connection.connection.meta_data.getColumns(nil,nil,tname,nil)
321
+ rs2 = @connection.connection.meta_data.getColumns(nil,db2_schema.upcase,tname,nil)
163
322
  first_col = true
164
323
  while rs2.next
165
324
  col_name = add_quotes(rs2.getString(4));
166
325
  default = ""
167
326
  d1 = rs2.getString(13)
168
- default = d1 ? " DEFAULT #{d1}" : ""
327
+ # IBM i (as400 toolbox driver) will return an empty string if there is no default
328
+ if @config[:url] =~ /^jdbc:as400:/
329
+ default = !d1.blank? ? " DEFAULT #{d1}" : ""
330
+ else
331
+ default = d1 ? " DEFAULT #{d1}" : ""
332
+ end
169
333
 
170
334
  type = rs2.getString(6)
171
- col_size = rs2.getString(7)
335
+ col_precision = rs2.getString(7)
336
+ col_scale = rs2.getString(9)
337
+ col_size = ""
338
+ if HAVE_SCALE.include?(type) and col_scale
339
+ col_size = "(#{col_precision},#{col_scale})"
340
+ elsif (HAVE_LIMIT + HAVE_PRECISION).include?(type) and col_precision
341
+ col_size = "(#{col_precision})"
342
+ end
172
343
  nulling = (rs2.getString(18) == 'NO' ? " NOT NULL" : "")
173
344
  create_col_string = add_quotes(expand_double_quotes(strip_quotes(col_name))) +
174
345
  " " +
175
346
  type +
347
+ col_size +
176
348
  "" +
177
349
  nulling +
178
350
  default
@@ -191,16 +363,24 @@ module ArJdbc
191
363
  definition
192
364
  end
193
365
 
194
- def dump_schema_information
195
- begin
196
- if (current_schema = ActiveRecord::Migrator.current_version) > 0
197
- #TODO: Find a way to get the DB2 instace name to properly form the statement
198
- return "INSERT INTO DB2INST2.SCHEMA_INFO (version) VALUES (#{current_schema})"
366
+ private
367
+ def as400?
368
+ @config[:url] =~ /^jdbc:as400:/
369
+ end
370
+
371
+ def db2_schema
372
+ if @config[:schema].blank?
373
+ if as400?
374
+ # AS400 implementation takes schema from library name (last part of url)
375
+ schema = @config[:url].split('/').last.strip
376
+ (schema[-1..-1] == ";") ? schema.chop : schema
377
+ else
378
+ # LUW implementation uses schema name of username by default
379
+ @config[:username] or ENV['USER']
199
380
  end
200
- rescue ActiveRecord::StatementInvalid
201
- # No Schema Info
381
+ else
382
+ @config[:schema]
202
383
  end
203
384
  end
204
-
205
385
  end
206
386
  end