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

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.
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