tgbyte-activerecord-jdbc-adapter 1.2.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +22 -0
- data/.travis.yml +8 -0
- data/Gemfile +14 -0
- data/Gemfile.lock +40 -0
- data/History.txt +488 -0
- data/LICENSE.txt +21 -0
- data/README.rdoc +199 -0
- data/Rakefile +60 -0
- data/activerecord-jdbc-adapter.gemspec +23 -0
- data/bench/bench_attributes.rb +13 -0
- data/bench/bench_attributes_new.rb +14 -0
- data/bench/bench_create.rb +12 -0
- data/bench/bench_find_all.rb +12 -0
- data/bench/bench_find_all_mt.rb +25 -0
- data/bench/bench_model.rb +85 -0
- data/bench/bench_new.rb +12 -0
- data/bench/bench_new_valid.rb +12 -0
- data/bench/bench_valid.rb +13 -0
- data/lib/active_record/connection_adapters/derby_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/h2_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/hsqldb_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/informix_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/jdbc_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/jndi_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/mssql_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/mysql_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/oracle_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +1 -0
- data/lib/activerecord-jdbc-adapter.rb +8 -0
- data/lib/arel/engines/sql/compilers/db2_compiler.rb +9 -0
- data/lib/arel/engines/sql/compilers/derby_compiler.rb +6 -0
- data/lib/arel/engines/sql/compilers/h2_compiler.rb +6 -0
- data/lib/arel/engines/sql/compilers/hsqldb_compiler.rb +15 -0
- data/lib/arel/engines/sql/compilers/jdbc_compiler.rb +6 -0
- data/lib/arel/engines/sql/compilers/mssql_compiler.rb +46 -0
- data/lib/arel/visitors/compat.rb +13 -0
- data/lib/arel/visitors/db2.rb +17 -0
- data/lib/arel/visitors/derby.rb +32 -0
- data/lib/arel/visitors/firebird.rb +24 -0
- data/lib/arel/visitors/hsqldb.rb +26 -0
- data/lib/arel/visitors/sql_server.rb +46 -0
- data/lib/arjdbc.rb +24 -0
- data/lib/arjdbc/db2.rb +2 -0
- data/lib/arjdbc/db2/adapter.rb +510 -0
- data/lib/arjdbc/derby.rb +7 -0
- data/lib/arjdbc/derby/adapter.rb +358 -0
- data/lib/arjdbc/derby/connection_methods.rb +19 -0
- data/lib/arjdbc/discover.rb +92 -0
- data/lib/arjdbc/firebird.rb +2 -0
- data/lib/arjdbc/firebird/adapter.rb +136 -0
- data/lib/arjdbc/h2.rb +4 -0
- data/lib/arjdbc/h2/adapter.rb +54 -0
- data/lib/arjdbc/h2/connection_methods.rb +13 -0
- data/lib/arjdbc/hsqldb.rb +4 -0
- data/lib/arjdbc/hsqldb/adapter.rb +184 -0
- data/lib/arjdbc/hsqldb/connection_methods.rb +15 -0
- data/lib/arjdbc/informix.rb +3 -0
- data/lib/arjdbc/informix/adapter.rb +138 -0
- data/lib/arjdbc/informix/connection_methods.rb +11 -0
- data/lib/arjdbc/jdbc.rb +2 -0
- data/lib/arjdbc/jdbc/adapter.rb +356 -0
- data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
- data/lib/arjdbc/jdbc/base_ext.rb +15 -0
- data/lib/arjdbc/jdbc/callbacks.rb +44 -0
- data/lib/arjdbc/jdbc/column.rb +47 -0
- data/lib/arjdbc/jdbc/compatibility.rb +51 -0
- data/lib/arjdbc/jdbc/connection.rb +134 -0
- data/lib/arjdbc/jdbc/connection_methods.rb +16 -0
- data/lib/arjdbc/jdbc/core_ext.rb +24 -0
- data/lib/arjdbc/jdbc/discover.rb +18 -0
- data/lib/arjdbc/jdbc/driver.rb +35 -0
- data/lib/arjdbc/jdbc/extension.rb +47 -0
- data/lib/arjdbc/jdbc/java.rb +14 -0
- data/lib/arjdbc/jdbc/jdbc.rake +131 -0
- data/lib/arjdbc/jdbc/missing_functionality_helper.rb +88 -0
- data/lib/arjdbc/jdbc/quoted_primary_key.rb +28 -0
- data/lib/arjdbc/jdbc/railtie.rb +9 -0
- data/lib/arjdbc/jdbc/rake_tasks.rb +10 -0
- data/lib/arjdbc/jdbc/require_driver.rb +16 -0
- data/lib/arjdbc/jdbc/type_converter.rb +126 -0
- data/lib/arjdbc/mimer.rb +2 -0
- data/lib/arjdbc/mimer/adapter.rb +142 -0
- data/lib/arjdbc/mssql.rb +4 -0
- data/lib/arjdbc/mssql/adapter.rb +477 -0
- data/lib/arjdbc/mssql/connection_methods.rb +31 -0
- data/lib/arjdbc/mssql/limit_helpers.rb +101 -0
- data/lib/arjdbc/mssql/lock_helpers.rb +72 -0
- data/lib/arjdbc/mssql/tsql_helper.rb +61 -0
- data/lib/arjdbc/mysql.rb +4 -0
- data/lib/arjdbc/mysql/adapter.rb +505 -0
- data/lib/arjdbc/mysql/connection_methods.rb +28 -0
- data/lib/arjdbc/oracle.rb +3 -0
- data/lib/arjdbc/oracle/adapter.rb +428 -0
- data/lib/arjdbc/oracle/connection_methods.rb +12 -0
- data/lib/arjdbc/postgresql.rb +4 -0
- data/lib/arjdbc/postgresql/adapter.rb +825 -0
- data/lib/arjdbc/postgresql/connection_methods.rb +23 -0
- data/lib/arjdbc/sqlite3.rb +4 -0
- data/lib/arjdbc/sqlite3/adapter.rb +389 -0
- data/lib/arjdbc/sqlite3/connection_methods.rb +35 -0
- data/lib/arjdbc/sybase.rb +2 -0
- data/lib/arjdbc/sybase/adapter.rb +46 -0
- data/lib/arjdbc/version.rb +8 -0
- data/lib/generators/jdbc/USAGE +10 -0
- data/lib/generators/jdbc/jdbc_generator.rb +9 -0
- data/lib/jdbc_adapter.rb +2 -0
- data/lib/jdbc_adapter/rake_tasks.rb +3 -0
- data/lib/jdbc_adapter/version.rb +3 -0
- data/lib/pg.rb +26 -0
- data/pom.xml +57 -0
- data/rails_generators/jdbc_generator.rb +15 -0
- data/rails_generators/templates/config/initializers/jdbc.rb +7 -0
- data/rails_generators/templates/lib/tasks/jdbc.rake +8 -0
- data/rakelib/bundler_ext.rb +11 -0
- data/rakelib/compile.rake +23 -0
- data/rakelib/db.rake +39 -0
- data/rakelib/rails.rake +41 -0
- data/src/java/arjdbc/db2/DB2RubyJdbcConnection.java +62 -0
- data/src/java/arjdbc/derby/DerbyModule.java +324 -0
- data/src/java/arjdbc/h2/H2RubyJdbcConnection.java +70 -0
- data/src/java/arjdbc/informix/InformixRubyJdbcConnection.java +74 -0
- data/src/java/arjdbc/jdbc/AdapterJavaService.java +68 -0
- data/src/java/arjdbc/jdbc/JdbcConnectionFactory.java +36 -0
- data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +1326 -0
- data/src/java/arjdbc/jdbc/SQLBlock.java +48 -0
- data/src/java/arjdbc/mssql/MssqlRubyJdbcConnection.java +127 -0
- data/src/java/arjdbc/mysql/MySQLModule.java +134 -0
- data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +161 -0
- data/src/java/arjdbc/oracle/OracleRubyJdbcConnection.java +85 -0
- data/src/java/arjdbc/postgresql/PostgresqlRubyJdbcConnection.java +82 -0
- data/src/java/arjdbc/sqlite3/Sqlite3RubyJdbcConnection.java +126 -0
- data/test/abstract_db_create.rb +135 -0
- data/test/activerecord/connection_adapters/type_conversion_test.rb +31 -0
- data/test/activerecord/connections/native_jdbc_mysql/connection.rb +25 -0
- data/test/activerecord/jall.sh +7 -0
- data/test/activerecord/jtest.sh +3 -0
- data/test/db/db2.rb +11 -0
- data/test/db/derby.rb +12 -0
- data/test/db/h2.rb +11 -0
- data/test/db/hsqldb.rb +13 -0
- data/test/db/informix.rb +11 -0
- data/test/db/jdbc.rb +12 -0
- data/test/db/jndi_config.rb +40 -0
- data/test/db/logger.rb +3 -0
- data/test/db/mssql.rb +9 -0
- data/test/db/mysql.rb +10 -0
- data/test/db/oracle.rb +34 -0
- data/test/db/postgres.rb +9 -0
- data/test/db/sqlite3.rb +11 -0
- data/test/db2_reset_column_information_test.rb +8 -0
- data/test/db2_simple_test.rb +66 -0
- data/test/derby_migration_test.rb +68 -0
- data/test/derby_multibyte_test.rb +12 -0
- data/test/derby_reset_column_information_test.rb +8 -0
- data/test/derby_row_locking_test.rb +9 -0
- data/test/derby_simple_test.rb +139 -0
- data/test/generic_jdbc_connection_test.rb +29 -0
- data/test/h2_change_column_test.rb +68 -0
- data/test/h2_simple_test.rb +41 -0
- data/test/has_many_through.rb +79 -0
- data/test/helper.rb +87 -0
- data/test/hsqldb_simple_test.rb +6 -0
- data/test/informix_simple_test.rb +48 -0
- data/test/jdbc_common.rb +28 -0
- data/test/jndi_callbacks_test.rb +36 -0
- data/test/jndi_test.rb +25 -0
- data/test/manualTestDatabase.rb +191 -0
- data/test/models/add_not_null_column_to_table.rb +9 -0
- data/test/models/auto_id.rb +15 -0
- data/test/models/data_types.rb +30 -0
- data/test/models/entry.rb +40 -0
- data/test/models/mixed_case.rb +22 -0
- data/test/models/reserved_word.rb +15 -0
- data/test/models/string_id.rb +17 -0
- data/test/models/thing.rb +16 -0
- data/test/models/validates_uniqueness_of_string.rb +19 -0
- data/test/mssql_db_create_test.rb +26 -0
- data/test/mssql_identity_insert_test.rb +19 -0
- data/test/mssql_ignore_system_views_test.rb +27 -0
- data/test/mssql_legacy_types_test.rb +58 -0
- data/test/mssql_limit_offset_test.rb +136 -0
- data/test/mssql_multibyte_test.rb +18 -0
- data/test/mssql_null_test.rb +14 -0
- data/test/mssql_reset_column_information_test.rb +8 -0
- data/test/mssql_row_locking_sql_test.rb +159 -0
- data/test/mssql_row_locking_test.rb +9 -0
- data/test/mssql_simple_test.rb +55 -0
- data/test/mysql_db_create_test.rb +27 -0
- data/test/mysql_index_length_test.rb +58 -0
- data/test/mysql_info_test.rb +123 -0
- data/test/mysql_multibyte_test.rb +10 -0
- data/test/mysql_nonstandard_primary_key_test.rb +42 -0
- data/test/mysql_reset_column_information_test.rb +8 -0
- data/test/mysql_simple_test.rb +125 -0
- data/test/oracle_reset_column_information_test.rb +8 -0
- data/test/oracle_simple_test.rb +18 -0
- data/test/oracle_specific_test.rb +83 -0
- data/test/postgres_db_create_test.rb +32 -0
- data/test/postgres_drop_db_test.rb +16 -0
- data/test/postgres_information_schema_leak_test.rb +29 -0
- data/test/postgres_mixed_case_test.rb +29 -0
- data/test/postgres_native_type_mapping_test.rb +89 -0
- data/test/postgres_nonseq_pkey_test.rb +38 -0
- data/test/postgres_reserved_test.rb +22 -0
- data/test/postgres_reset_column_information_test.rb +8 -0
- data/test/postgres_schema_search_path_test.rb +48 -0
- data/test/postgres_simple_test.rb +167 -0
- data/test/postgres_table_alias_length_test.rb +15 -0
- data/test/postgres_type_conversion_test.rb +34 -0
- data/test/row_locking.rb +90 -0
- data/test/simple.rb +717 -0
- data/test/sqlite3_reset_column_information_test.rb +8 -0
- data/test/sqlite3_simple_test.rb +316 -0
- data/test/sybase_jtds_simple_test.rb +28 -0
- data/test/sybase_reset_column_information_test.rb +8 -0
- metadata +275 -0
data/bench/bench_new.rb
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require 'arjdbc/derby'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require 'arjdbc/h2'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require 'arjdbc/hsqldb'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require 'arjdbc/informix'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require 'arjdbc/jdbc'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require 'arjdbc/jdbc'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require 'arjdbc/mssql'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require 'arjdbc/mysql'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require 'arjdbc/mysql'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require 'arjdbc/oracle'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require 'arjdbc/postgresql'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require 'arjdbc/sqlite3'
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module Arel
|
|
2
|
+
module SqlCompiler
|
|
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
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
module Arel
|
|
2
|
+
module SqlCompiler
|
|
3
|
+
class MsSQLCompiler < GenericCompiler
|
|
4
|
+
def select_sql
|
|
5
|
+
projections = @relation.projections
|
|
6
|
+
offset = relation.skipped
|
|
7
|
+
limit = relation.taken
|
|
8
|
+
if Count === projections.first && projections.size == 1 &&
|
|
9
|
+
(relation.taken.present? || relation.wheres.present?) && relation.joins(self).blank?
|
|
10
|
+
subquery = [
|
|
11
|
+
"SELECT * FROM #{relation.from_clauses}", build_clauses
|
|
12
|
+
].join ' '
|
|
13
|
+
@engine.connection.add_limit_offset!(subquery, :limit => limit, :offset => offset) if offset || limit
|
|
14
|
+
query = "SELECT COUNT(*) AS count_id FROM (#{subquery}) AS subquery"
|
|
15
|
+
else
|
|
16
|
+
query = [
|
|
17
|
+
"SELECT #{relation.select_clauses.join(', ')}",
|
|
18
|
+
"FROM #{relation.from_clauses}",
|
|
19
|
+
build_clauses
|
|
20
|
+
].compact.join ' '
|
|
21
|
+
@engine.connection.add_limit_offset!(query, :limit => limit, :offset => offset) if offset || limit
|
|
22
|
+
end
|
|
23
|
+
query
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def build_clauses
|
|
27
|
+
joins = relation.joins(self)
|
|
28
|
+
wheres = relation.where_clauses
|
|
29
|
+
groups = relation.group_clauses
|
|
30
|
+
havings = relation.having_clauses
|
|
31
|
+
orders = relation.order_clauses
|
|
32
|
+
|
|
33
|
+
clauses = [ "",
|
|
34
|
+
joins,
|
|
35
|
+
("WHERE #{wheres.join(' AND ')}" unless wheres.empty?),
|
|
36
|
+
("GROUP BY #{groups.join(', ')}" unless groups.empty?),
|
|
37
|
+
("HAVING #{havings.join(' AND ')}" unless havings.empty?),
|
|
38
|
+
("ORDER BY #{orders.join(', ')}" unless orders.empty?)
|
|
39
|
+
].compact.join ' '
|
|
40
|
+
|
|
41
|
+
clauses << " #{locked}" unless locked.blank?
|
|
42
|
+
clauses unless clauses.blank?
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
require 'arel/visitors/compat'
|
|
2
|
+
|
|
3
|
+
module Arel
|
|
4
|
+
module Visitors
|
|
5
|
+
class DB2 < Arel::Visitors::ToSql
|
|
6
|
+
def visit_Arel_Nodes_SelectStatement o
|
|
7
|
+
add_limit_offset([o.cores.map { |x| visit_Arel_Nodes_SelectCore x }.join,
|
|
8
|
+
("ORDER BY #{o.orders.map { |x| visit x }.join(', ')}" unless o.orders.empty?),
|
|
9
|
+
].compact.join(' '), o)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def add_limit_offset(sql, o)
|
|
13
|
+
@connection.replace_limit_offset! sql, limit_for(o.limit), o.offset && o.offset.value
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
require 'arel/visitors/compat'
|
|
2
|
+
|
|
3
|
+
module Arel
|
|
4
|
+
module Visitors
|
|
5
|
+
class Derby < Arel::Visitors::ToSql
|
|
6
|
+
def visit_Arel_Nodes_SelectStatement o
|
|
7
|
+
[
|
|
8
|
+
o.cores.map { |x| visit(x) }.join,
|
|
9
|
+
("ORDER BY #{o.orders.map { |x| visit x }.join(', ')}" unless o.orders.empty?),
|
|
10
|
+
(visit(o.offset) if o.offset),
|
|
11
|
+
(visit(o.limit) if o.limit),
|
|
12
|
+
(visit(o.lock) if o.lock),
|
|
13
|
+
].compact.join ' '
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def visit_Arel_Nodes_Limit o
|
|
17
|
+
"FETCH FIRST #{limit_for(o)} ROWS ONLY"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def visit_Arel_Nodes_Offset o
|
|
21
|
+
"OFFSET #{visit o.value} ROWS"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# This generates SELECT...FOR UPDATE, but it will only work if the
|
|
25
|
+
# current transaction isolation level is set to SERIALIZABLE. Otherwise,
|
|
26
|
+
# locks aren't held for the entire transaction.
|
|
27
|
+
def visit_Arel_Nodes_Lock o
|
|
28
|
+
visit o.expr
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
require 'arel/visitors/compat'
|
|
2
|
+
|
|
3
|
+
module Arel
|
|
4
|
+
module Visitors
|
|
5
|
+
class Firebird < Arel::Visitors::ToSql
|
|
6
|
+
def visit_Arel_Nodes_SelectStatement o
|
|
7
|
+
lim_off = [
|
|
8
|
+
("FIRST #{visit(o.limit.expr)}" if o.limit),
|
|
9
|
+
("SKIP #{visit(o.offset.expr)}" if o.offset)
|
|
10
|
+
].compact.join(' ').strip
|
|
11
|
+
|
|
12
|
+
sql = [
|
|
13
|
+
o.cores.map { |x| visit_Arel_Nodes_SelectCore x }.join,
|
|
14
|
+
("ORDER BY #{o.orders.map { |x| visit x }.join(', ')}" unless o.orders.empty?),
|
|
15
|
+
].compact.join ' '
|
|
16
|
+
|
|
17
|
+
sql.sub!(/\A(\s*SELECT\s)/i, '\&' + lim_off + ' ') unless lim_off.empty?
|
|
18
|
+
|
|
19
|
+
sql
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
require 'arel/visitors/compat'
|
|
2
|
+
|
|
3
|
+
module Arel
|
|
4
|
+
module Visitors
|
|
5
|
+
class HSQLDB < Arel::Visitors::ToSql
|
|
6
|
+
def visit_Arel_Nodes_SelectStatement o
|
|
7
|
+
[
|
|
8
|
+
limit_offset(o.cores.map { |x| visit_Arel_Nodes_SelectCore x }.join, o),
|
|
9
|
+
("ORDER BY #{o.orders.map { |x| visit x }.join(', ')}" unless o.orders.empty?),
|
|
10
|
+
].compact.join ' '
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def limit_offset sql, o
|
|
14
|
+
offset = o.offset || 0
|
|
15
|
+
bef = sql[7..-1]
|
|
16
|
+
if limit = o.limit
|
|
17
|
+
"SELECT LIMIT #{offset} #{limit_for(limit)} #{bef}"
|
|
18
|
+
elsif offset > 0
|
|
19
|
+
"SELECT LIMIT #{offset} 0 #{bef}"
|
|
20
|
+
else
|
|
21
|
+
sql
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
require 'arel/visitors/compat'
|
|
2
|
+
|
|
3
|
+
module Arel
|
|
4
|
+
module Visitors
|
|
5
|
+
class SQLServer < Arel::Visitors::ToSql
|
|
6
|
+
include ArJdbc::MsSQL::LimitHelpers::SqlServerReplaceLimitOffset
|
|
7
|
+
include ArJdbc::MsSQL::LockHelpers::SqlServerAddLock
|
|
8
|
+
|
|
9
|
+
def select_count? o
|
|
10
|
+
sel = o.cores.length == 1 && o.cores.first
|
|
11
|
+
projections = sel && sel.projections.length == 1 && sel.projections
|
|
12
|
+
projections && Arel::Nodes::Count === projections.first
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Need to mimic the subquery logic in ARel 1.x for select count with limit
|
|
16
|
+
# See arel/engines/sql/compilers/mssql_compiler.rb for details
|
|
17
|
+
def visit_Arel_Nodes_SelectStatement o
|
|
18
|
+
order = "ORDER BY #{o.orders.map { |x| visit x }.join(', ')}" unless o.orders.empty?
|
|
19
|
+
if o.limit
|
|
20
|
+
if select_count?(o)
|
|
21
|
+
subquery = true
|
|
22
|
+
sql = o.cores.map do |x|
|
|
23
|
+
x = x.dup
|
|
24
|
+
x.projections = [Arel::Nodes::SqlLiteral.new("*")]
|
|
25
|
+
visit_Arel_Nodes_SelectCore x
|
|
26
|
+
end.join
|
|
27
|
+
else
|
|
28
|
+
sql = o.cores.map { |x| visit_Arel_Nodes_SelectCore x }.join
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
order ||= "ORDER BY #{@connection.determine_order_clause(sql)}"
|
|
32
|
+
replace_limit_offset!(sql, limit_for(o.limit).to_i, o.offset && o.offset.value.to_i, order)
|
|
33
|
+
sql = "SELECT COUNT(*) AS count_id FROM (#{sql}) AS subquery" if subquery
|
|
34
|
+
else
|
|
35
|
+
sql = super
|
|
36
|
+
end
|
|
37
|
+
add_lock!(sql, :lock => o.lock && true)
|
|
38
|
+
sql
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
class SQLServer2000 < SQLServer
|
|
43
|
+
include ArJdbc::MsSQL::LimitHelpers::SqlServer2000ReplaceLimitOffset
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
data/lib/arjdbc.rb
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
if defined?(JRUBY_VERSION)
|
|
2
|
+
begin
|
|
3
|
+
require 'active_record/version'
|
|
4
|
+
if ActiveRecord::VERSION::MAJOR < 2
|
|
5
|
+
if defined?(RAILS_CONNECTION_ADAPTERS)
|
|
6
|
+
RAILS_CONNECTION_ADAPTERS << %q(jdbc)
|
|
7
|
+
else
|
|
8
|
+
RAILS_CONNECTION_ADAPTERS = %w(jdbc)
|
|
9
|
+
end
|
|
10
|
+
if ActiveRecord::VERSION::MAJOR == 1 && ActiveRecord::VERSION::MINOR == 14
|
|
11
|
+
require 'arjdbc/jdbc'
|
|
12
|
+
end
|
|
13
|
+
else
|
|
14
|
+
require 'active_record'
|
|
15
|
+
require 'arjdbc/jdbc'
|
|
16
|
+
end
|
|
17
|
+
rescue LoadError
|
|
18
|
+
warn "activerecord-jdbc-adapter requires ActiveRecord at runtime"
|
|
19
|
+
end
|
|
20
|
+
else
|
|
21
|
+
warn "activerecord-jdbc-adapter is for use with JRuby only"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
require 'arjdbc/version'
|
data/lib/arjdbc/db2.rb
ADDED
|
@@ -0,0 +1,510 @@
|
|
|
1
|
+
module ArJdbc
|
|
2
|
+
module DB2
|
|
3
|
+
def self.extended(base)
|
|
4
|
+
if base.zos?
|
|
5
|
+
unless @lob_callback_added
|
|
6
|
+
ActiveRecord::Base.class_eval do
|
|
7
|
+
def after_save_with_db2zos_blob
|
|
8
|
+
lobfields = self.class.columns.select { |c| c.sql_type =~ /blob|clob/i }
|
|
9
|
+
lobfields.each do |c|
|
|
10
|
+
value = self[c.name]
|
|
11
|
+
value = value.to_yaml if unserializable_attribute?(c.name, c)
|
|
12
|
+
next if value.nil?
|
|
13
|
+
connection.write_large_object(c.type == :binary, c.name, self.class.table_name, self.class.primary_key, quote_value(id), value)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
ActiveRecord::Base.after_save :after_save_with_db2zos_blob
|
|
19
|
+
|
|
20
|
+
@lob_callback_added = true
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def self.column_selector
|
|
26
|
+
[ /(db2|as400|zos)/i,
|
|
27
|
+
lambda { |cfg, column| column.extend(::ArJdbc::DB2::Column) } ]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def self.jdbc_connection_class
|
|
31
|
+
::ActiveRecord::ConnectionAdapters::DB2JdbcConnection
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
module Column
|
|
35
|
+
def type_cast(value)
|
|
36
|
+
return nil if value.nil? || value =~ /^\s*null\s*$/i
|
|
37
|
+
case type
|
|
38
|
+
when :string then value
|
|
39
|
+
when :integer then defined?(value.to_i) ? value.to_i : (value ? 1 : 0)
|
|
40
|
+
when :primary_key then defined?(value.to_i) ? value.to_i : (value ? 1 : 0)
|
|
41
|
+
when :float then value.to_f
|
|
42
|
+
when :datetime then ArJdbc::DB2::Column.cast_to_date_or_time(value)
|
|
43
|
+
when :date then ArJdbc::DB2::Column.cast_to_date_or_time(value)
|
|
44
|
+
when :timestamp then ArJdbc::DB2::Column.cast_to_time(value)
|
|
45
|
+
when :time then ArJdbc::DB2::Column.cast_to_time(value)
|
|
46
|
+
# TODO AS400 stores binary strings in EBCDIC (CCSID 65535), need to convert back to ASCII
|
|
47
|
+
else
|
|
48
|
+
super
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def type_cast_code(var_name)
|
|
53
|
+
case type
|
|
54
|
+
when :datetime then "ArJdbc::DB2::Column.cast_to_date_or_time(#{var_name})"
|
|
55
|
+
when :date then "ArJdbc::DB2::Column.cast_to_date_or_time(#{var_name})"
|
|
56
|
+
when :timestamp then "ArJdbc::DB2::Column.cast_to_time(#{var_name})"
|
|
57
|
+
when :time then "ArJdbc::DB2::Column.cast_to_time(#{var_name})"
|
|
58
|
+
else
|
|
59
|
+
super
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def self.cast_to_date_or_time(value)
|
|
64
|
+
return value if value.is_a? Date
|
|
65
|
+
return nil if value.blank?
|
|
66
|
+
guess_date_or_time((value.is_a? Time) ? value : cast_to_time(value))
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def self.cast_to_time(value)
|
|
70
|
+
return value if value.is_a? Time
|
|
71
|
+
# AS400 returns a 2 digit year, LUW returns a 4 digit year, so comp = true to help out AS400
|
|
72
|
+
time = DateTime.parse(value).to_time rescue nil
|
|
73
|
+
return nil unless time
|
|
74
|
+
time_array = [time.year, time.month, time.day, time.hour, time.min, time.sec]
|
|
75
|
+
time_array[0] ||= 2000; time_array[1] ||= 1; time_array[2] ||= 1;
|
|
76
|
+
Time.send(ActiveRecord::Base.default_timezone, *time_array) rescue nil
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def self.guess_date_or_time(value)
|
|
80
|
+
(value.hour == 0 and value.min == 0 and value.sec == 0) ?
|
|
81
|
+
Date.new(value.year, value.month, value.day) : value
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
private
|
|
85
|
+
# <b>DEPRECATED:</b> SMALLINT is now used for boolean field types. Please
|
|
86
|
+
# convert your tables using DECIMAL(5) for boolean values to SMALLINT instead.
|
|
87
|
+
def use_decimal5_for_boolean
|
|
88
|
+
warn "[DEPRECATION] using DECIMAL(5) for boolean is deprecated. Convert your columns to SMALLINT instead."
|
|
89
|
+
:boolean
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.apdv.java.doc/doc/rjvjdata.html
|
|
93
|
+
def simplified_type(field_type)
|
|
94
|
+
case field_type
|
|
95
|
+
# old jdbc_db2.rb used decimal(5,0) as boolean
|
|
96
|
+
when /^smallint/i then :boolean
|
|
97
|
+
when /^decimal\(5\)$/i then use_decimal5_for_boolean
|
|
98
|
+
when /^real/i then :float
|
|
99
|
+
when /^timestamp/i then :datetime
|
|
100
|
+
else
|
|
101
|
+
super
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Post process default value from JDBC into a Rails-friendly format (columns{-internal})
|
|
106
|
+
def default_value(value)
|
|
107
|
+
# IBM i (AS400) will return an empty string instead of null for no default
|
|
108
|
+
return nil if value.blank?
|
|
109
|
+
|
|
110
|
+
# string defaults are surrounded by single quotes
|
|
111
|
+
return $1 if value =~ /^'(.*)'$/
|
|
112
|
+
|
|
113
|
+
value
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def _execute(sql, name = nil)
|
|
118
|
+
if ActiveRecord::ConnectionAdapters::JdbcConnection::select?(sql)
|
|
119
|
+
@connection.execute_query(sql)
|
|
120
|
+
elsif ActiveRecord::ConnectionAdapters::JdbcConnection::insert?(sql)
|
|
121
|
+
(@connection.execute_insert(sql) or last_insert_id(sql)).to_i
|
|
122
|
+
else
|
|
123
|
+
@connection.execute_update(sql)
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# holy moly batman! all this to tell AS400 "yes i am sure"
|
|
128
|
+
def execute_and_auto_confirm(sql)
|
|
129
|
+
begin
|
|
130
|
+
@connection.execute_update "call qsys.qcmdexc('QSYS/CHGJOB INQMSGRPY(*SYSRPYL)',0000000031.00000)"
|
|
131
|
+
@connection.execute_update "call qsys.qcmdexc('ADDRPYLE SEQNBR(9876) MSGID(CPA32B2) RPY(''I'')',0000000045.00000)"
|
|
132
|
+
rescue Exception => e
|
|
133
|
+
raise "Could not call CHGJOB INQMSGRPY(*SYSRPYL) and ADDRPYLE SEQNBR(9876) MSGID(CPA32B2) RPY('I').\n" +
|
|
134
|
+
"Do you have authority to do this?\n\n" + e.to_s
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
r = execute sql
|
|
138
|
+
|
|
139
|
+
begin
|
|
140
|
+
@connection.execute_update "call qsys.qcmdexc('QSYS/CHGJOB INQMSGRPY(*DFT)',0000000027.00000)"
|
|
141
|
+
@connection.execute_update "call qsys.qcmdexc('RMVRPYLE SEQNBR(9876)',0000000021.00000)"
|
|
142
|
+
rescue Exception => e
|
|
143
|
+
raise "Could not call CHGJOB INQMSGRPY(*DFT) and RMVRPYLE SEQNBR(9876).\n" +
|
|
144
|
+
"Do you have authority to do this?\n\n" + e.to_s
|
|
145
|
+
end
|
|
146
|
+
r
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def last_insert_id(sql)
|
|
150
|
+
table_name = sql.split(/\s/)[2]
|
|
151
|
+
result = select(ActiveRecord::Base.send(:sanitize_sql,
|
|
152
|
+
%[select IDENTITY_VAL_LOCAL() as last_insert_id from #{table_name}],
|
|
153
|
+
nil))
|
|
154
|
+
result.last['last_insert_id']
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def modify_types(tp)
|
|
158
|
+
tp[:primary_key] = 'int not null generated by default as identity (start with 1) primary key'
|
|
159
|
+
tp[:string][:limit] = 255
|
|
160
|
+
tp[:integer][:limit] = nil
|
|
161
|
+
tp[:boolean] = {:name => "smallint"}
|
|
162
|
+
tp
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def type_to_sql(type, limit = nil, precision = nil, scale = nil)
|
|
166
|
+
limit = nil if type.to_sym == :integer
|
|
167
|
+
super(type, limit, precision, scale)
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def adapter_name
|
|
171
|
+
'DB2'
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def self.arel2_visitors(config)
|
|
175
|
+
require 'arel/visitors/db2'
|
|
176
|
+
{}.tap {|v| %w(db2 as400).each {|a| v[a] = ::Arel::Visitors::DB2 } }
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def add_limit_offset!(sql, options)
|
|
180
|
+
replace_limit_offset!(sql, options[:limit], options[:offset])
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def create_table(name, options = {}) #:nodoc:
|
|
185
|
+
if zos?
|
|
186
|
+
table_definition = ActiveRecord::ConnectionAdapters::TableDefinition.new(self)
|
|
187
|
+
|
|
188
|
+
table_definition.primary_key(options[:primary_key] || ActiveRecord::Base.get_primary_key(name)) unless options[:id] == false
|
|
189
|
+
|
|
190
|
+
yield table_definition
|
|
191
|
+
|
|
192
|
+
# Clobs in DB2 Host have to be created after the Table with an auxiliary Table.
|
|
193
|
+
# First: Save them for later in Array "clobs"
|
|
194
|
+
clobs =table_definition.columns.select { |x| x.type == "text" }
|
|
195
|
+
|
|
196
|
+
# Second: and delete them from the original Colums-Array
|
|
197
|
+
table_definition.columns.delete_if { |x| x.type=="text" }
|
|
198
|
+
|
|
199
|
+
if options[:force] && table_exists?(name)
|
|
200
|
+
super.drop_table(name, options)
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
create_sql = "CREATE#{' TEMPORARY' if options[:temporary]} TABLE "
|
|
204
|
+
create_sql << "#{quote_table_name(name)} ("
|
|
205
|
+
create_sql << table_definition.to_sql
|
|
206
|
+
create_sql << ") #{options[:options]}"
|
|
207
|
+
create_sql << " IN #{@config[:database]}.#{@config[:tablespace]}"
|
|
208
|
+
|
|
209
|
+
execute create_sql
|
|
210
|
+
|
|
211
|
+
clobs.each do |clob_column|
|
|
212
|
+
execute "ALTER TABLE #{name+" ADD COLUMN "+clob_column.name.to_s+" clob"}"
|
|
213
|
+
execute "CREATE AUXILIARY TABLE #{name+"_"+clob_column.name.to_s+"_CD_"} IN #{@config[:database]}.#{@config[:lob_tablespaces][name.split(".")[1]]} STORES #{name} COLUMN "+clob_column.name.to_s
|
|
214
|
+
execute "CREATE UNIQUE INDEX #{name+"_"+clob_column.name.to_s+"_CD_"} ON #{name+"_"+clob_column.name.to_s+"_CD_"};"
|
|
215
|
+
end
|
|
216
|
+
else
|
|
217
|
+
super(name, options)
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
def replace_limit_offset!(sql, limit, offset)
|
|
222
|
+
if limit
|
|
223
|
+
limit = limit.to_i
|
|
224
|
+
if !offset
|
|
225
|
+
if limit == 1
|
|
226
|
+
sql << " FETCH FIRST ROW ONLY"
|
|
227
|
+
else
|
|
228
|
+
sql << " FETCH FIRST #{limit} ROWS ONLY"
|
|
229
|
+
end
|
|
230
|
+
else
|
|
231
|
+
offset = offset.to_i
|
|
232
|
+
sql.gsub!(/SELECT/i, 'SELECT B.* FROM (SELECT A.*, row_number() over () AS internal$rownum FROM (SELECT')
|
|
233
|
+
sql << ") A ) B WHERE B.internal$rownum > #{offset} AND B.internal$rownum <= #{limit + offset}"
|
|
234
|
+
end
|
|
235
|
+
end
|
|
236
|
+
sql
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
def pk_and_sequence_for(table)
|
|
240
|
+
# In JDBC/DB2 side, only upcase names of table and column are handled.
|
|
241
|
+
keys = super(table.upcase)
|
|
242
|
+
if keys && keys[0]
|
|
243
|
+
# In ActiveRecord side, only downcase names of table and column are handled.
|
|
244
|
+
keys[0] = keys[0].downcase
|
|
245
|
+
end
|
|
246
|
+
keys
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
def quote_column_name(column_name)
|
|
250
|
+
column_name
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
def quote(value, column = nil) # :nodoc:
|
|
254
|
+
if column && column.respond_to?(:primary) && column.primary && column.klass != String
|
|
255
|
+
return value.to_i.to_s
|
|
256
|
+
end
|
|
257
|
+
if column && (column.type == :decimal || column.type == :integer) && value
|
|
258
|
+
return value.to_s
|
|
259
|
+
end
|
|
260
|
+
case value
|
|
261
|
+
when String
|
|
262
|
+
if column && column.type == :binary
|
|
263
|
+
"BLOB('#{quote_string(value)}')"
|
|
264
|
+
else
|
|
265
|
+
if zos? && column.type == :text
|
|
266
|
+
"'if_you_see_this_value_the_after_save_hook_in_db2_zos_adapter_went_wrong'"
|
|
267
|
+
else
|
|
268
|
+
"'#{quote_string(value)}'"
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
else super
|
|
272
|
+
end
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
def quote_string(string)
|
|
276
|
+
string.gsub(/'/, "''") # ' (for ruby-mode)
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
def quoted_true
|
|
280
|
+
'1'
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
def quoted_false
|
|
284
|
+
'0'
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
def reorg_table(table_name)
|
|
288
|
+
unless as400?
|
|
289
|
+
@connection.execute_update "call sysproc.admin_cmd ('REORG TABLE #{table_name}')"
|
|
290
|
+
end
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
def recreate_database(name)
|
|
294
|
+
tables.each {|table| drop_table("#{db2_schema}.#{table}")}
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
def add_index(table_name, column_name, options = {})
|
|
298
|
+
if (!zos? || (table_name.to_s == ActiveRecord::Migrator.schema_migrations_table_name.to_s))
|
|
299
|
+
super
|
|
300
|
+
else
|
|
301
|
+
statement ="CREATE"
|
|
302
|
+
statement << " UNIQUE " if options[:unique]
|
|
303
|
+
statement << " INDEX "+"#{ActiveRecord::Base.table_name_prefix}#{options[:name]} "
|
|
304
|
+
|
|
305
|
+
statement << " ON #{table_name}(#{column_name})"
|
|
306
|
+
|
|
307
|
+
execute statement
|
|
308
|
+
end
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
def remove_index(table_name, options = { })
|
|
313
|
+
execute "DROP INDEX #{quote_column_name(index_name(table_name, options))}"
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
# http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.admin.dbobj.doc/doc/t0020130.html
|
|
317
|
+
# ...not supported on IBM i, so we raise in this case
|
|
318
|
+
def rename_column(table_name, column_name, new_column_name) #:nodoc:
|
|
319
|
+
if as400?
|
|
320
|
+
raise NotImplementedError, "rename_column is not supported on IBM i"
|
|
321
|
+
else
|
|
322
|
+
execute "ALTER TABLE #{table_name} RENAME COLUMN #{column_name} TO #{new_column_name}"
|
|
323
|
+
reorg_table(table_name)
|
|
324
|
+
end
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
def change_column_null(table_name, column_name, null)
|
|
328
|
+
if null
|
|
329
|
+
execute_and_auto_confirm "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} DROP NOT NULL"
|
|
330
|
+
else
|
|
331
|
+
execute_and_auto_confirm "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} SET NOT NULL"
|
|
332
|
+
end
|
|
333
|
+
reorg_table(table_name)
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
def change_column_default(table_name, column_name, default)
|
|
337
|
+
if default.nil?
|
|
338
|
+
execute_and_auto_confirm "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} DROP DEFAULT"
|
|
339
|
+
else
|
|
340
|
+
execute_and_auto_confirm "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} SET WITH DEFAULT #{quote(default)}"
|
|
341
|
+
end
|
|
342
|
+
reorg_table(table_name)
|
|
343
|
+
end
|
|
344
|
+
|
|
345
|
+
def change_column(table_name, column_name, type, options = {})
|
|
346
|
+
data_type = type_to_sql(type, options[:limit], options[:precision], options[:scale])
|
|
347
|
+
sql = "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} SET DATA TYPE #{data_type}"
|
|
348
|
+
as400? ? execute_and_auto_confirm(sql) : execute(sql)
|
|
349
|
+
reorg_table(table_name)
|
|
350
|
+
|
|
351
|
+
if options.include?(:default) and options.include?(:null)
|
|
352
|
+
# which to run first?
|
|
353
|
+
if options[:null] or options[:default].nil?
|
|
354
|
+
change_column_null(table_name, column_name, options[:null])
|
|
355
|
+
change_column_default(table_name, column_name, options[:default])
|
|
356
|
+
else
|
|
357
|
+
change_column_default(table_name, column_name, options[:default])
|
|
358
|
+
change_column_null(table_name, column_name, options[:null])
|
|
359
|
+
end
|
|
360
|
+
elsif options.include?(:default)
|
|
361
|
+
change_column_default(table_name, column_name, options[:default])
|
|
362
|
+
elsif options.include?(:null)
|
|
363
|
+
change_column_null(table_name, column_name, options[:null])
|
|
364
|
+
end
|
|
365
|
+
end
|
|
366
|
+
|
|
367
|
+
# http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.admin.dbobj.doc/doc/t0020132.html
|
|
368
|
+
def remove_column(table_name, column_name) #:nodoc:
|
|
369
|
+
sql = "ALTER TABLE #{table_name} DROP COLUMN #{column_name}"
|
|
370
|
+
|
|
371
|
+
as400? ? execute_and_auto_confirm(sql) : execute(sql)
|
|
372
|
+
reorg_table(table_name)
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
# http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.sql.ref.doc/doc/r0000980.html
|
|
376
|
+
def rename_table(name, new_name) #:nodoc:
|
|
377
|
+
execute "RENAME TABLE #{name} TO #{new_name}"
|
|
378
|
+
reorg_table(new_name)
|
|
379
|
+
end
|
|
380
|
+
|
|
381
|
+
def tables
|
|
382
|
+
@connection.tables(nil, db2_schema, nil, ["TABLE"])
|
|
383
|
+
end
|
|
384
|
+
|
|
385
|
+
# only record precision and scale for types that can set
|
|
386
|
+
# them via CREATE TABLE:
|
|
387
|
+
# http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.sql.ref.doc/doc/r0000927.html
|
|
388
|
+
HAVE_LIMIT = %w(FLOAT DECFLOAT CHAR VARCHAR CLOB BLOB NCHAR NCLOB DBCLOB GRAPHIC VARGRAPHIC) #TIMESTAMP
|
|
389
|
+
HAVE_PRECISION = %w(DECIMAL NUMERIC)
|
|
390
|
+
HAVE_SCALE = %w(DECIMAL NUMERIC)
|
|
391
|
+
|
|
392
|
+
def columns(table_name, name = nil)
|
|
393
|
+
cols = @connection.columns(table_name, name, db2_schema)
|
|
394
|
+
|
|
395
|
+
if zos?
|
|
396
|
+
# Remove the mighty db2_generated_rowid_for_lobs from the list of columns
|
|
397
|
+
cols = cols.reject { |col| "db2_generated_rowid_for_lobs" == col.name }
|
|
398
|
+
end
|
|
399
|
+
# scrub out sizing info when CREATE TABLE doesn't support it
|
|
400
|
+
# but JDBC reports it (doh!)
|
|
401
|
+
for col in cols
|
|
402
|
+
base_sql_type = col.sql_type.sub(/\(.*/, "").upcase
|
|
403
|
+
col.limit = nil unless HAVE_LIMIT.include?(base_sql_type)
|
|
404
|
+
col.precision = nil unless HAVE_PRECISION.include?(base_sql_type)
|
|
405
|
+
#col.scale = nil unless HAVE_SCALE.include?(base_sql_type)
|
|
406
|
+
end
|
|
407
|
+
|
|
408
|
+
cols
|
|
409
|
+
end
|
|
410
|
+
|
|
411
|
+
def jdbc_columns(table_name, name = nil)
|
|
412
|
+
columns(table_name, name)
|
|
413
|
+
end
|
|
414
|
+
|
|
415
|
+
def indexes(table_name, name = nil)
|
|
416
|
+
@connection.indexes(table_name, name, db2_schema)
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
def add_quotes(name)
|
|
420
|
+
return name unless name
|
|
421
|
+
%Q{"#{name}"}
|
|
422
|
+
end
|
|
423
|
+
|
|
424
|
+
def strip_quotes(str)
|
|
425
|
+
return str unless str
|
|
426
|
+
return str unless /^(["']).*\1$/ =~ str
|
|
427
|
+
str[1..-2]
|
|
428
|
+
end
|
|
429
|
+
|
|
430
|
+
def expand_double_quotes(name)
|
|
431
|
+
return name unless name && name['"']
|
|
432
|
+
name.gsub(/"/,'""')
|
|
433
|
+
end
|
|
434
|
+
|
|
435
|
+
def structure_dump #:nodoc:
|
|
436
|
+
definition=""
|
|
437
|
+
rs = @connection.connection.meta_data.getTables(nil,db2_schema.upcase,nil,["TABLE"].to_java(:string))
|
|
438
|
+
while rs.next
|
|
439
|
+
tname = rs.getString(3)
|
|
440
|
+
definition << "CREATE TABLE #{tname} (\n"
|
|
441
|
+
rs2 = @connection.connection.meta_data.getColumns(nil,db2_schema.upcase,tname,nil)
|
|
442
|
+
first_col = true
|
|
443
|
+
while rs2.next
|
|
444
|
+
col_name = add_quotes(rs2.getString(4));
|
|
445
|
+
default = ""
|
|
446
|
+
d1 = rs2.getString(13)
|
|
447
|
+
# IBM i (as400 toolbox driver) will return an empty string if there is no default
|
|
448
|
+
if @config[:url] =~ /^jdbc:as400:/
|
|
449
|
+
default = !d1.blank? ? " DEFAULT #{d1}" : ""
|
|
450
|
+
else
|
|
451
|
+
default = d1 ? " DEFAULT #{d1}" : ""
|
|
452
|
+
end
|
|
453
|
+
|
|
454
|
+
type = rs2.getString(6)
|
|
455
|
+
col_precision = rs2.getString(7)
|
|
456
|
+
col_scale = rs2.getString(9)
|
|
457
|
+
col_size = ""
|
|
458
|
+
if HAVE_SCALE.include?(type) and col_scale
|
|
459
|
+
col_size = "(#{col_precision},#{col_scale})"
|
|
460
|
+
elsif (HAVE_LIMIT + HAVE_PRECISION).include?(type) and col_precision
|
|
461
|
+
col_size = "(#{col_precision})"
|
|
462
|
+
end
|
|
463
|
+
nulling = (rs2.getString(18) == 'NO' ? " NOT NULL" : "")
|
|
464
|
+
create_col_string = add_quotes(expand_double_quotes(strip_quotes(col_name))) +
|
|
465
|
+
" " +
|
|
466
|
+
type +
|
|
467
|
+
col_size +
|
|
468
|
+
"" +
|
|
469
|
+
nulling +
|
|
470
|
+
default
|
|
471
|
+
if !first_col
|
|
472
|
+
create_col_string = ",\n #{create_col_string}"
|
|
473
|
+
else
|
|
474
|
+
create_col_string = " #{create_col_string}"
|
|
475
|
+
end
|
|
476
|
+
|
|
477
|
+
definition << create_col_string
|
|
478
|
+
|
|
479
|
+
first_col = false
|
|
480
|
+
end
|
|
481
|
+
definition << ");\n\n"
|
|
482
|
+
end
|
|
483
|
+
definition
|
|
484
|
+
end
|
|
485
|
+
|
|
486
|
+
def zos?
|
|
487
|
+
@config[:driver] == "com.ibm.db2.jcc.DB2Driver"
|
|
488
|
+
end
|
|
489
|
+
|
|
490
|
+
private
|
|
491
|
+
def as400?
|
|
492
|
+
@config[:url] =~ /^jdbc:as400:/
|
|
493
|
+
end
|
|
494
|
+
|
|
495
|
+
def db2_schema
|
|
496
|
+
if @config[:schema].blank?
|
|
497
|
+
if as400?
|
|
498
|
+
# AS400 implementation takes schema from library name (last part of url)
|
|
499
|
+
schema = @config[:url].split('/').last.strip
|
|
500
|
+
(schema[-1..-1] == ";") ? schema.chop : schema
|
|
501
|
+
else
|
|
502
|
+
# LUW implementation uses schema name of username by default
|
|
503
|
+
@config[:username] or ENV['USER']
|
|
504
|
+
end
|
|
505
|
+
else
|
|
506
|
+
@config[:schema]
|
|
507
|
+
end
|
|
508
|
+
end
|
|
509
|
+
end
|
|
510
|
+
end
|