activerecord-jdbc-adapter-ficoh 1.3.21-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.
- checksums.yaml +7 -0
- data/.gitignore +35 -0
- data/.travis.yml +462 -0
- data/.yardopts +4 -0
- data/Appraisals +36 -0
- data/CONTRIBUTING.md +49 -0
- data/Gemfile +68 -0
- data/History.md +1191 -0
- data/LICENSE.txt +25 -0
- data/README.md +277 -0
- data/RUNNING_TESTS.md +88 -0
- data/Rakefile +298 -0
- data/Rakefile.jdbc +20 -0
- data/activerecord-jdbc-adapter.gemspec +63 -0
- data/lib/active_record/connection_adapters/as400_adapter.rb +2 -0
- data/lib/active_record/connection_adapters/db2_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/derby_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/firebird_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/mariadb_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/active_record/connection_adapters/sqlserver_adapter.rb +1 -0
- data/lib/activerecord-jdbc-adapter.rb +1 -0
- data/lib/arel/visitors/compat.rb +64 -0
- data/lib/arel/visitors/db2.rb +137 -0
- data/lib/arel/visitors/derby.rb +112 -0
- data/lib/arel/visitors/firebird.rb +79 -0
- data/lib/arel/visitors/h2.rb +25 -0
- data/lib/arel/visitors/hsqldb.rb +32 -0
- data/lib/arel/visitors/postgresql_jdbc.rb +6 -0
- data/lib/arel/visitors/sql_server.rb +225 -0
- data/lib/arel/visitors/sql_server/ng42.rb +293 -0
- data/lib/arjdbc.rb +22 -0
- data/lib/arjdbc/db2.rb +4 -0
- data/lib/arjdbc/db2/adapter.rb +802 -0
- data/lib/arjdbc/db2/as400.rb +137 -0
- data/lib/arjdbc/db2/column.rb +177 -0
- data/lib/arjdbc/db2/connection_methods.rb +45 -0
- data/lib/arjdbc/derby.rb +3 -0
- data/lib/arjdbc/derby/active_record_patch.rb +13 -0
- data/lib/arjdbc/derby/adapter.rb +567 -0
- data/lib/arjdbc/derby/connection_methods.rb +16 -0
- data/lib/arjdbc/derby/schema_creation.rb +15 -0
- data/lib/arjdbc/discover.rb +104 -0
- data/lib/arjdbc/firebird.rb +4 -0
- data/lib/arjdbc/firebird/adapter.rb +468 -0
- data/lib/arjdbc/firebird/connection_methods.rb +20 -0
- data/lib/arjdbc/h2.rb +3 -0
- data/lib/arjdbc/h2/adapter.rb +335 -0
- data/lib/arjdbc/h2/connection_methods.rb +22 -0
- data/lib/arjdbc/hsqldb.rb +3 -0
- data/lib/arjdbc/hsqldb/adapter.rb +304 -0
- data/lib/arjdbc/hsqldb/connection_methods.rb +23 -0
- data/lib/arjdbc/hsqldb/explain_support.rb +35 -0
- data/lib/arjdbc/hsqldb/schema_creation.rb +11 -0
- data/lib/arjdbc/informix.rb +5 -0
- data/lib/arjdbc/informix/adapter.rb +160 -0
- data/lib/arjdbc/informix/connection_methods.rb +9 -0
- data/lib/arjdbc/jdbc.rb +62 -0
- data/lib/arjdbc/jdbc/adapter.rb +997 -0
- data/lib/arjdbc/jdbc/adapter_require.rb +46 -0
- data/lib/arjdbc/jdbc/arel_support.rb +149 -0
- data/lib/arjdbc/jdbc/base_ext.rb +34 -0
- data/lib/arjdbc/jdbc/callbacks.rb +52 -0
- data/lib/arjdbc/jdbc/column.rb +83 -0
- data/lib/arjdbc/jdbc/connection.rb +26 -0
- data/lib/arjdbc/jdbc/connection_methods.rb +59 -0
- data/lib/arjdbc/jdbc/driver.rb +44 -0
- data/lib/arjdbc/jdbc/error.rb +75 -0
- data/lib/arjdbc/jdbc/extension.rb +69 -0
- data/lib/arjdbc/jdbc/java.rb +13 -0
- data/lib/arjdbc/jdbc/type_cast.rb +154 -0
- data/lib/arjdbc/jdbc/type_converter.rb +142 -0
- data/lib/arjdbc/mssql.rb +7 -0
- data/lib/arjdbc/mssql/adapter.rb +822 -0
- data/lib/arjdbc/mssql/column.rb +207 -0
- data/lib/arjdbc/mssql/connection_methods.rb +72 -0
- data/lib/arjdbc/mssql/explain_support.rb +99 -0
- data/lib/arjdbc/mssql/limit_helpers.rb +231 -0
- data/lib/arjdbc/mssql/lock_methods.rb +77 -0
- data/lib/arjdbc/mssql/types.rb +343 -0
- data/lib/arjdbc/mssql/utils.rb +82 -0
- data/lib/arjdbc/mysql.rb +3 -0
- data/lib/arjdbc/mysql/adapter.rb +998 -0
- data/lib/arjdbc/mysql/bulk_change_table.rb +150 -0
- data/lib/arjdbc/mysql/column.rb +167 -0
- data/lib/arjdbc/mysql/connection_methods.rb +137 -0
- data/lib/arjdbc/mysql/explain_support.rb +82 -0
- data/lib/arjdbc/mysql/schema_creation.rb +58 -0
- data/lib/arjdbc/oracle.rb +4 -0
- data/lib/arjdbc/oracle/adapter.rb +968 -0
- data/lib/arjdbc/oracle/column.rb +136 -0
- data/lib/arjdbc/oracle/connection_methods.rb +21 -0
- data/lib/arjdbc/postgresql.rb +3 -0
- data/lib/arjdbc/postgresql/_bc_time_cast_patch.rb +21 -0
- data/lib/arjdbc/postgresql/adapter.rb +1498 -0
- data/lib/arjdbc/postgresql/base/array_parser.rb +95 -0
- data/lib/arjdbc/postgresql/base/oid.rb +412 -0
- data/lib/arjdbc/postgresql/base/pgconn.rb +8 -0
- data/lib/arjdbc/postgresql/base/schema_definitions.rb +132 -0
- data/lib/arjdbc/postgresql/column.rb +640 -0
- data/lib/arjdbc/postgresql/connection_methods.rb +44 -0
- data/lib/arjdbc/postgresql/explain_support.rb +53 -0
- data/lib/arjdbc/postgresql/oid/bytea.rb +3 -0
- data/lib/arjdbc/postgresql/oid_types.rb +265 -0
- data/lib/arjdbc/postgresql/schema_creation.rb +60 -0
- data/lib/arjdbc/railtie.rb +11 -0
- data/lib/arjdbc/sqlite3.rb +3 -0
- data/lib/arjdbc/sqlite3/adapter.rb +654 -0
- data/lib/arjdbc/sqlite3/connection_methods.rb +36 -0
- data/lib/arjdbc/sqlite3/explain_support.rb +29 -0
- data/lib/arjdbc/sybase.rb +2 -0
- data/lib/arjdbc/sybase/adapter.rb +47 -0
- data/lib/arjdbc/tasks.rb +13 -0
- data/lib/arjdbc/tasks/database_tasks.rb +66 -0
- data/lib/arjdbc/tasks/databases.rake +91 -0
- data/lib/arjdbc/tasks/databases3.rake +239 -0
- data/lib/arjdbc/tasks/databases4.rake +39 -0
- data/lib/arjdbc/tasks/db2_database_tasks.rb +104 -0
- data/lib/arjdbc/tasks/derby_database_tasks.rb +95 -0
- data/lib/arjdbc/tasks/h2_database_tasks.rb +31 -0
- data/lib/arjdbc/tasks/hsqldb_database_tasks.rb +70 -0
- data/lib/arjdbc/tasks/jdbc_database_tasks.rb +169 -0
- data/lib/arjdbc/tasks/mssql_database_tasks.rb +46 -0
- data/lib/arjdbc/tasks/oracle/enhanced_structure_dump.rb +297 -0
- data/lib/arjdbc/tasks/oracle_database_tasks.rb +65 -0
- data/lib/arjdbc/util/quoted_cache.rb +60 -0
- data/lib/arjdbc/util/serialized_attributes.rb +98 -0
- data/lib/arjdbc/util/table_copier.rb +108 -0
- data/lib/arjdbc/version.rb +8 -0
- data/lib/generators/jdbc/USAGE +9 -0
- data/lib/generators/jdbc/jdbc_generator.rb +17 -0
- data/pom.xml +285 -0
- data/rails_generators/jdbc_generator.rb +15 -0
- data/rails_generators/templates/config/initializers/jdbc.rb +10 -0
- data/rails_generators/templates/lib/tasks/jdbc.rake +11 -0
- data/rakelib/01-tomcat.rake +51 -0
- data/rakelib/02-test.rake +151 -0
- data/rakelib/bundler_ext.rb +11 -0
- data/rakelib/db.rake +58 -0
- data/rakelib/rails.rake +77 -0
- data/src/java/arjdbc/ArJdbcModule.java +288 -0
- data/src/java/arjdbc/db2/DB2Module.java +77 -0
- data/src/java/arjdbc/db2/DB2RubyJdbcConnection.java +128 -0
- data/src/java/arjdbc/derby/DerbyModule.java +180 -0
- data/src/java/arjdbc/derby/DerbyRubyJdbcConnection.java +153 -0
- data/src/java/arjdbc/firebird/FirebirdRubyJdbcConnection.java +190 -0
- data/src/java/arjdbc/h2/H2Module.java +50 -0
- data/src/java/arjdbc/h2/H2RubyJdbcConnection.java +86 -0
- data/src/java/arjdbc/hsqldb/HSQLDBModule.java +74 -0
- data/src/java/arjdbc/informix/InformixRubyJdbcConnection.java +76 -0
- data/src/java/arjdbc/jdbc/AdapterJavaService.java +43 -0
- data/src/java/arjdbc/jdbc/Callable.java +44 -0
- data/src/java/arjdbc/jdbc/ConnectionFactory.java +77 -0
- data/src/java/arjdbc/jdbc/DataSourceConnectionFactory.java +156 -0
- data/src/java/arjdbc/jdbc/DriverConnectionFactory.java +63 -0
- data/src/java/arjdbc/jdbc/DriverWrapper.java +128 -0
- data/src/java/arjdbc/jdbc/JdbcConnectionFactory.java +32 -0
- data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +4541 -0
- data/src/java/arjdbc/jdbc/SQLBlock.java +54 -0
- data/src/java/arjdbc/jdbc/WithResultSet.java +37 -0
- data/src/java/arjdbc/mssql/MSSQLModule.java +91 -0
- data/src/java/arjdbc/mssql/MSSQLRubyJdbcConnection.java +193 -0
- data/src/java/arjdbc/mysql/MySQLModule.java +140 -0
- data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +456 -0
- data/src/java/arjdbc/oracle/OracleModule.java +81 -0
- data/src/java/arjdbc/oracle/OracleRubyJdbcConnection.java +477 -0
- data/src/java/arjdbc/postgresql/ByteaUtils.java +171 -0
- data/src/java/arjdbc/postgresql/DriverImplementation.java +78 -0
- data/src/java/arjdbc/postgresql/PGDriverImplementation.java +535 -0
- data/src/java/arjdbc/postgresql/PostgreSQLModule.java +189 -0
- data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +489 -0
- data/src/java/arjdbc/sqlite3/SQLite3Module.java +93 -0
- data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +405 -0
- data/src/java/arjdbc/util/CallResultSet.java +826 -0
- data/src/java/arjdbc/util/DateTimeUtils.java +517 -0
- data/src/java/arjdbc/util/NumberUtils.java +50 -0
- data/src/java/arjdbc/util/ObjectSupport.java +65 -0
- data/src/java/arjdbc/util/QuotingUtils.java +139 -0
- data/src/java/arjdbc/util/StringCache.java +60 -0
- data/src/java/arjdbc/util/StringHelper.java +155 -0
- metadata +288 -0
@@ -0,0 +1,137 @@
|
|
1
|
+
require 'arjdbc/db2/adapter'
|
2
|
+
|
3
|
+
module ArJdbc
|
4
|
+
module AS400
|
5
|
+
include DB2
|
6
|
+
|
7
|
+
# @private
|
8
|
+
def self.extended(adapter); DB2.extended(adapter); end
|
9
|
+
|
10
|
+
# @private
|
11
|
+
def self.initialize!
|
12
|
+
ArJdbc.deprecate "AS400 support is hard to maintain on our end and will be removed," <<
|
13
|
+
" we recommend that you use the standalone activerecord-jdbcas400-adapter gem instead."
|
14
|
+
return DB2.initialize!
|
15
|
+
end
|
16
|
+
|
17
|
+
# @see ActiveRecord::ConnectionAdapters::JdbcAdapter#jdbc_connection_class
|
18
|
+
def self.jdbc_connection_class; DB2.jdbc_connection_class; end
|
19
|
+
|
20
|
+
# @see ActiveRecord::ConnectionAdapters::Jdbc::ArelSupport
|
21
|
+
def self.arel_visitor_type(config = nil); DB2.arel_visitor_type(config); end
|
22
|
+
|
23
|
+
def self.column_selector
|
24
|
+
[ /as400/i, lambda { |config, column| column.extend(Column) } ]
|
25
|
+
end
|
26
|
+
|
27
|
+
# Boolean emulation can be disabled using :
|
28
|
+
#
|
29
|
+
# ArJdbc::AS400.emulate_booleans = false
|
30
|
+
#
|
31
|
+
def self.emulate_booleans; DB2.emulate_booleans; end
|
32
|
+
def self.emulate_booleans=(emulate); DB2.emulate_booleans = emulate; end
|
33
|
+
|
34
|
+
ADAPTER_NAME = 'AS400'.freeze
|
35
|
+
|
36
|
+
def adapter_name
|
37
|
+
ADAPTER_NAME
|
38
|
+
end
|
39
|
+
|
40
|
+
# @override
|
41
|
+
def prefetch_primary_key?(table_name = nil)
|
42
|
+
# TRUE if the table has no identity column
|
43
|
+
names = table_name.upcase.split(".")
|
44
|
+
sql = "SELECT 1 FROM SYSIBM.SQLPRIMARYKEYS WHERE "
|
45
|
+
sql << "TABLE_SCHEM = '#{names.first}' AND " if names.size == 2
|
46
|
+
sql << "TABLE_NAME = '#{names.last}'"
|
47
|
+
select_one(sql).nil?
|
48
|
+
end
|
49
|
+
|
50
|
+
# @override
|
51
|
+
def rename_column(table_name, column_name, new_column_name)
|
52
|
+
raise NotImplementedError, "rename_column is not supported on IBM iSeries"
|
53
|
+
end
|
54
|
+
|
55
|
+
# @override
|
56
|
+
def execute_table_change(sql, table_name, name = nil)
|
57
|
+
execute_and_auto_confirm(sql, name)
|
58
|
+
end
|
59
|
+
|
60
|
+
# holy moly batman! all this to tell AS400 "yes i am sure"
|
61
|
+
def execute_and_auto_confirm(sql, name = nil)
|
62
|
+
|
63
|
+
begin
|
64
|
+
@connection.execute_update "call qsys.qcmdexc('QSYS/CHGJOB INQMSGRPY(*SYSRPYL)',0000000031.00000)"
|
65
|
+
@connection.execute_update "call qsys.qcmdexc('ADDRPYLE SEQNBR(9876) MSGID(CPA32B2) RPY(''I'')',0000000045.00000)"
|
66
|
+
rescue Exception => e
|
67
|
+
raise "Could not call CHGJOB INQMSGRPY(*SYSRPYL) and ADDRPYLE SEQNBR(9876) MSGID(CPA32B2) RPY('I').\n" +
|
68
|
+
"Do you have authority to do this?\n\n#{e.inspect}"
|
69
|
+
end
|
70
|
+
|
71
|
+
begin
|
72
|
+
result = execute(sql, name)
|
73
|
+
rescue Exception
|
74
|
+
raise
|
75
|
+
else
|
76
|
+
# Return if all work fine
|
77
|
+
result
|
78
|
+
ensure
|
79
|
+
|
80
|
+
# Ensure default configuration restoration
|
81
|
+
begin
|
82
|
+
@connection.execute_update "call qsys.qcmdexc('QSYS/CHGJOB INQMSGRPY(*DFT)',0000000027.00000)"
|
83
|
+
@connection.execute_update "call qsys.qcmdexc('RMVRPYLE SEQNBR(9876)',0000000021.00000)"
|
84
|
+
rescue Exception => e
|
85
|
+
raise "Could not call CHGJOB INQMSGRPY(*DFT) and RMVRPYLE SEQNBR(9876).\n" +
|
86
|
+
"Do you have authority to do this?\n\n#{e.inspect}"
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
end
|
91
|
+
private :execute_and_auto_confirm
|
92
|
+
|
93
|
+
# disable all schemas browsing when default schema is specified
|
94
|
+
def table_exists?(name)
|
95
|
+
return false unless name
|
96
|
+
schema ? @connection.table_exists?(name, schema) : @connection.table_exists?(name)
|
97
|
+
end
|
98
|
+
|
99
|
+
DRIVER_NAME = 'com.ibm.as400.access.AS400JDBCDriver'.freeze
|
100
|
+
|
101
|
+
# @private
|
102
|
+
# @deprecated no longer used
|
103
|
+
def as400?
|
104
|
+
true
|
105
|
+
end
|
106
|
+
|
107
|
+
private
|
108
|
+
|
109
|
+
# @override
|
110
|
+
def db2_schema
|
111
|
+
@db2_schema = false unless defined? @db2_schema
|
112
|
+
return @db2_schema if @db2_schema != false
|
113
|
+
@db2_schema =
|
114
|
+
if config[:schema].present?
|
115
|
+
config[:schema]
|
116
|
+
elsif config[:jndi].present?
|
117
|
+
# Only found method to set db2_schema from jndi
|
118
|
+
result = select_one("SELECT CURRENT_SCHEMA FROM SYSIBM.SYSDUMMY1")
|
119
|
+
schema = result['00001']
|
120
|
+
# If the connection uses the library list schema name will be nil
|
121
|
+
if schema == '*LIBL'
|
122
|
+
schema = nil
|
123
|
+
end
|
124
|
+
schema
|
125
|
+
else
|
126
|
+
# AS400 implementation takes schema from library name (last part of URL)
|
127
|
+
# jdbc:as400://localhost/schema;naming=system;libraries=lib1,lib2
|
128
|
+
schema = nil
|
129
|
+
split = config[:url].split('/')
|
130
|
+
# Return nil if schema isn't defined
|
131
|
+
schema = split.last.split(';').first.strip if split.size == 4
|
132
|
+
schema
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,177 @@
|
|
1
|
+
module ArJdbc
|
2
|
+
module DB2
|
3
|
+
|
4
|
+
# @see ActiveRecord::ConnectionAdapters::JdbcColumn#column_types
|
5
|
+
def self.column_selector
|
6
|
+
[ /(db2|zos)/i, lambda { |config, column| column.extend(ColumnMethods) } ]
|
7
|
+
end
|
8
|
+
|
9
|
+
# @private
|
10
|
+
# @see ActiveRecord::ConnectionAdapters::JdbcColumn
|
11
|
+
module ColumnMethods
|
12
|
+
|
13
|
+
# @private
|
14
|
+
def self.included(base)
|
15
|
+
# NOTE: assumes a standalone DB2Column class
|
16
|
+
class << base; include Cast; end
|
17
|
+
end
|
18
|
+
|
19
|
+
# @deprecated use `self.class.string_to_time`
|
20
|
+
def self.cast_to_date_or_time(value)
|
21
|
+
return value if value.is_a? Date
|
22
|
+
return nil if value.blank?
|
23
|
+
# https://github.com/jruby/activerecord-jdbc-adapter/commit/c225126e025df2e98ba3386c67e2a5bc5e5a73e6
|
24
|
+
return Time.now if value =~ /^CURRENT/
|
25
|
+
guess_date_or_time((value.is_a? Time) ? value : cast_to_time(value))
|
26
|
+
rescue
|
27
|
+
value
|
28
|
+
end
|
29
|
+
|
30
|
+
# @deprecated use `self.class.string_to_time` or `self.class.string_to_dummy_time`
|
31
|
+
def self.cast_to_time(value)
|
32
|
+
return value if value.is_a? Time
|
33
|
+
# AS400 returns a 2 digit year, LUW returns a 4 digit year
|
34
|
+
time = DateTime.parse(value).to_time rescue nil
|
35
|
+
return nil unless time
|
36
|
+
time_array = [time.year, time.month, time.day, time.hour, time.min, time.sec]
|
37
|
+
time_array[0] ||= 2000; time_array[1] ||= 1; time_array[2] ||= 1;
|
38
|
+
Time.send(ActiveRecord::Base.default_timezone, *time_array) rescue nil
|
39
|
+
end
|
40
|
+
|
41
|
+
# @deprecated
|
42
|
+
# @private
|
43
|
+
def self.guess_date_or_time(value)
|
44
|
+
return value if value.is_a? Date
|
45
|
+
( value && value.hour == 0 && value.min == 0 && value.sec == 0 ) ?
|
46
|
+
Date.new(value.year, value.month, value.day) : value
|
47
|
+
end
|
48
|
+
|
49
|
+
# @override
|
50
|
+
def type_cast(value)
|
51
|
+
return nil if value.nil? || value == 'NULL' || value =~ /^\s*NULL\s*$/i
|
52
|
+
case type
|
53
|
+
when :string then value
|
54
|
+
when :integer then value.respond_to?(:to_i) ? value.to_i : (value ? 1 : 0)
|
55
|
+
when :primary_key then value.respond_to?(:to_i) ? value.to_i : (value ? 1 : 0)
|
56
|
+
when :float then value.to_f
|
57
|
+
when :date then self.class.string_to_date(value)
|
58
|
+
when :datetime then self.class.string_to_time(value)
|
59
|
+
when :timestamp then self.class.string_to_time(value)
|
60
|
+
when :time then self.class.string_to_dummy_time(value)
|
61
|
+
# TODO AS400 stores binary strings in EBCDIC (CCSID 65535), need to convert back to ASCII
|
62
|
+
else
|
63
|
+
super
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# @override
|
68
|
+
def type_cast_code(var_name)
|
69
|
+
case type
|
70
|
+
when :date then "#{self.class.name}.string_to_date(#{var_name})"
|
71
|
+
when :datetime then "#{self.class.name}.string_to_time(#{var_name})"
|
72
|
+
when :timestamp then "#{self.class.name}.string_to_time(#{var_name})"
|
73
|
+
when :time then "#{self.class.name}.string_to_dummy_time(#{var_name})"
|
74
|
+
else
|
75
|
+
super
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
def simplified_type(field_type)
|
82
|
+
case field_type
|
83
|
+
when /^decimal\(1\)$/i then DB2.emulate_booleans? ? :boolean : :integer
|
84
|
+
when /smallint/i then DB2.emulate_booleans? ? :boolean : :integer
|
85
|
+
when /boolean/i then :boolean
|
86
|
+
when /^real|double/i then :float
|
87
|
+
when /int|serial/i then :integer
|
88
|
+
# if a numeric column has no scale, lets treat it as an integer.
|
89
|
+
# The AS400 rpg guys do this ALOT since they have no integer datatype ...
|
90
|
+
when /decimal|numeric|decfloat/i
|
91
|
+
extract_scale(field_type) == 0 ? :integer : :decimal
|
92
|
+
when /timestamp/i then :timestamp
|
93
|
+
when /datetime/i then :datetime
|
94
|
+
when /time/i then :time
|
95
|
+
when /date/i then :date
|
96
|
+
# DB2 provides three data types to store these data objects as strings of up to 2 GB in size:
|
97
|
+
# Character large objects (CLOBs)
|
98
|
+
# Use the CLOB data type to store SBCS or mixed data, such as documents that contain
|
99
|
+
# single character set. Use this data type if your data is larger (or might grow larger)
|
100
|
+
# than the VARCHAR data type permits.
|
101
|
+
# Double-byte character large objects (DBCLOBs)
|
102
|
+
# Use the DBCLOB data type to store large amounts of DBCS data, such as documents that
|
103
|
+
# use a DBCS character set.
|
104
|
+
# Binary large objects (BLOBs)
|
105
|
+
# Use the BLOB data type to store large amounts of noncharacter data, such as pictures,
|
106
|
+
# voice, and mixed media.
|
107
|
+
when /clob|text/i then :text # handles DBCLOB
|
108
|
+
when /^long varchar/i then :text # :limit => 32700
|
109
|
+
when /blob|binary/i then :binary
|
110
|
+
# varchar () for bit data, char () for bit data, long varchar for bit data
|
111
|
+
when /for bit data/i then :binary
|
112
|
+
when /xml/i then :xml
|
113
|
+
when /graphic/i then :graphic # vargraphic, long vargraphic
|
114
|
+
when /rowid/i then :rowid # rowid is a supported datatype on z/OS and i/5
|
115
|
+
else
|
116
|
+
super
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
# Post process default value from JDBC into a Rails-friendly format (columns{-internal})
|
121
|
+
def default_value(value)
|
122
|
+
# IBM i (AS400) will return an empty string instead of null for no default
|
123
|
+
return nil if value.blank?
|
124
|
+
|
125
|
+
# string defaults are surrounded by single quotes
|
126
|
+
return $1 if value =~ /^'(.*)'$/
|
127
|
+
|
128
|
+
value
|
129
|
+
end
|
130
|
+
|
131
|
+
module Cast
|
132
|
+
|
133
|
+
# @override
|
134
|
+
def string_to_date(value)
|
135
|
+
return nil unless value = current_date_time_parse(value)
|
136
|
+
|
137
|
+
super
|
138
|
+
end
|
139
|
+
|
140
|
+
# @override
|
141
|
+
def string_to_time(value)
|
142
|
+
return nil unless value = current_date_time_parse(value)
|
143
|
+
|
144
|
+
super
|
145
|
+
end
|
146
|
+
|
147
|
+
# @override
|
148
|
+
def string_to_dummy_time(value)
|
149
|
+
return nil unless value = current_date_time_parse(value)
|
150
|
+
|
151
|
+
super
|
152
|
+
end
|
153
|
+
|
154
|
+
private
|
155
|
+
|
156
|
+
def current_date_time_parse(value)
|
157
|
+
return value unless value.is_a?(String)
|
158
|
+
return nil if value.empty?
|
159
|
+
return Time.now if value.index('CURRENT') == 0
|
160
|
+
|
161
|
+
return value
|
162
|
+
end
|
163
|
+
|
164
|
+
end
|
165
|
+
|
166
|
+
end
|
167
|
+
|
168
|
+
def self.const_missing(name)
|
169
|
+
if name.to_sym == :Column
|
170
|
+
ArJdbc.deprecate("#{self.name}::Column will change to refer to the actual column class, please use ColumnMethods instead", :once)
|
171
|
+
return ColumnMethods
|
172
|
+
end
|
173
|
+
super
|
174
|
+
end
|
175
|
+
|
176
|
+
end
|
177
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
ArJdbc::ConnectionMethods.module_eval do
|
2
|
+
# @note Assumes DB2 driver (*db2jcc.jar*) is on class-path.
|
3
|
+
def db2_connection(config)
|
4
|
+
config[:adapter_spec] ||= ::ArJdbc::DB2
|
5
|
+
config[:adapter_class] = ActiveRecord::ConnectionAdapters::DB2Adapter unless config.key?(:adapter_class)
|
6
|
+
|
7
|
+
return jndi_connection(config) if jndi_config?(config)
|
8
|
+
|
9
|
+
config[:url] ||= begin
|
10
|
+
if config[:host] # Type 4 URL: jdbc:db2://server:port/database
|
11
|
+
config[:port] ||= 50000
|
12
|
+
"jdbc:db2://#{config[:host]}:#{config[:port]}/#{config[:database]}"
|
13
|
+
else # Type 2 URL: jdbc:db2:database
|
14
|
+
"jdbc:db2:#{config[:database]}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
config[:driver] ||= ::ArJdbc::DB2::DRIVER_NAME
|
18
|
+
config[:connection_alive_sql] ||= 'SELECT 1 FROM syscat.tables FETCH FIRST 1 ROWS ONLY'
|
19
|
+
jdbc_connection(config)
|
20
|
+
end
|
21
|
+
alias_method :jdbcdb2_connection, :db2_connection
|
22
|
+
|
23
|
+
# @note Assumes AS400 driver (*jt400.jar*) is on class-path.
|
24
|
+
def as400_connection(config)
|
25
|
+
config[:adapter_spec] ||= ::ArJdbc::AS400
|
26
|
+
|
27
|
+
return jndi_connection(config) if config[:jndi]
|
28
|
+
|
29
|
+
config[:url] ||= begin
|
30
|
+
# jdbc:as400://[host]
|
31
|
+
url = 'jdbc:as400://'
|
32
|
+
url << config[:host] if config[:host]
|
33
|
+
# jdbc:as400://myiSeries;database name=IASP1
|
34
|
+
url << ";database name=#{config[:database]}" if config[:database]
|
35
|
+
# jdbc:as400://[host];proxy server=HODServerName:proxyServerPort
|
36
|
+
url << ";proxy server=#{config[:proxy]}" if config[:proxy]
|
37
|
+
url
|
38
|
+
end
|
39
|
+
require 'arjdbc/db2/as400'
|
40
|
+
config[:driver] ||= ::ArJdbc::AS400::DRIVER_NAME
|
41
|
+
config[:connection_alive_sql] ||= 'SELECT 1 FROM sysibm.tables FETCH FIRST 1 ROWS ONLY'
|
42
|
+
jdbc_connection(config)
|
43
|
+
end
|
44
|
+
alias_method :jdbcas400_connection, :as400_connection
|
45
|
+
end
|
data/lib/arjdbc/derby.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# Needed because Rails is broken wrt to quoting of some values.
|
2
|
+
# Most databases are nice about it, but not Derby.
|
3
|
+
# The real issue is that you can't compare a CHAR value to a NUMBER column.
|
4
|
+
ActiveRecord::Associations::ClassMethods.module_eval do
|
5
|
+
private
|
6
|
+
def select_limited_ids_list(options, join_dependency)
|
7
|
+
return super unless connection.is_a?(ArJdbc::Derby)
|
8
|
+
connection.select_all(
|
9
|
+
construct_finder_sql_for_association_limiting(options, join_dependency),
|
10
|
+
"#{name} Load IDs For Limited Eager Loading"
|
11
|
+
).collect { |row| connection.quote(row[primary_key], columns_hash[primary_key]) }.join(", ")
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,567 @@
|
|
1
|
+
ArJdbc.load_java_part :Derby
|
2
|
+
|
3
|
+
require 'arjdbc/util/table_copier'
|
4
|
+
require 'arjdbc/derby/schema_creation' # AR 4.x
|
5
|
+
|
6
|
+
module ArJdbc
|
7
|
+
module Derby
|
8
|
+
include Util::TableCopier
|
9
|
+
|
10
|
+
def self.extended(adapter)
|
11
|
+
require 'arjdbc/derby/active_record_patch'
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.included(base)
|
15
|
+
require 'arjdbc/derby/active_record_patch'
|
16
|
+
end
|
17
|
+
|
18
|
+
JdbcConnection = ::ActiveRecord::ConnectionAdapters::DerbyJdbcConnection
|
19
|
+
|
20
|
+
# @deprecated
|
21
|
+
# @see ActiveRecord::ConnectionAdapters::JdbcAdapter#jdbc_connection_class
|
22
|
+
def self.jdbc_connection_class; JdbcConnection end
|
23
|
+
|
24
|
+
# @see ActiveRecord::ConnectionAdapters::JdbcColumn#column_types
|
25
|
+
def self.column_selector
|
26
|
+
[ /derby/i, lambda { |config, column| column.extend(ColumnMethods) } ]
|
27
|
+
end
|
28
|
+
|
29
|
+
def jdbc_column_class; ::ActiveRecord::ConnectionAdapters::DerbyAdapter::Column end
|
30
|
+
|
31
|
+
# @private
|
32
|
+
@@emulate_booleans = true
|
33
|
+
|
34
|
+
# Boolean emulation can be disabled using :
|
35
|
+
#
|
36
|
+
# ArJdbc::Derby.emulate_booleans = false
|
37
|
+
#
|
38
|
+
def self.emulate_booleans?; @@emulate_booleans; end
|
39
|
+
# @deprecated Use {#emulate_booleans?} instead.
|
40
|
+
def self.emulate_booleans; @@emulate_booleans; end
|
41
|
+
# @see #emulate_booleans?
|
42
|
+
def self.emulate_booleans=(emulate); @@emulate_booleans = emulate; end
|
43
|
+
|
44
|
+
# @private
|
45
|
+
# @note Part of this module is implemented in "native" Java.
|
46
|
+
# @see ActiveRecord::ConnectionAdapters::JdbcColumn
|
47
|
+
module ColumnMethods
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def extract_limit(sql_type)
|
52
|
+
case @sql_type = sql_type.downcase
|
53
|
+
when /^smallint/i then @sql_type = 'smallint'; limit = 2
|
54
|
+
when /^bigint/i then @sql_type = 'bigint'; limit = 8
|
55
|
+
when /^double/i then @sql_type = 'double'; limit = 8 # DOUBLE PRECISION
|
56
|
+
when /^real/i then @sql_type = 'real'; limit = 4
|
57
|
+
when /^integer/i then @sql_type = 'integer'; limit = 4
|
58
|
+
when /^datetime/i then @sql_type = 'datetime'; limit = nil
|
59
|
+
when /^timestamp/i then @sql_type = 'timestamp'; limit = nil
|
60
|
+
when /^time/i then @sql_type = 'time'; limit = nil
|
61
|
+
when /^date/i then @sql_type = 'date'; limit = nil
|
62
|
+
when /^xml/i then @sql_type = 'xml'; limit = nil
|
63
|
+
else
|
64
|
+
limit = super
|
65
|
+
# handle maximum length for a VARCHAR string :
|
66
|
+
limit = 32672 if ! limit && @sql_type.index('varchar') == 0
|
67
|
+
end
|
68
|
+
limit
|
69
|
+
end
|
70
|
+
|
71
|
+
def simplified_type(field_type)
|
72
|
+
case field_type
|
73
|
+
when /^smallint/i then Derby.emulate_booleans? ? :boolean : :integer
|
74
|
+
when /^bigint|int/i then :integer
|
75
|
+
when /^real|double/i then :float
|
76
|
+
when /^dec/i then # DEC is a DECIMAL alias
|
77
|
+
extract_scale(field_type) == 0 ? :integer : :decimal
|
78
|
+
when /^timestamp/i then :datetime
|
79
|
+
when /^xml/i then :xml
|
80
|
+
when 'long varchar' then :text
|
81
|
+
when /for bit data/i then :binary
|
82
|
+
# :name=>"long varchar for bit data", :limit=>32700
|
83
|
+
# :name=>"varchar() for bit data", :limit=>32672
|
84
|
+
# :name=>"char() for bit data", :limit=>254}
|
85
|
+
else
|
86
|
+
super
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# Post process default value from JDBC into a Rails-friendly format (columns{-internal})
|
91
|
+
def default_value(value)
|
92
|
+
# JDBC returns column default strings with actual single quotes around the value.
|
93
|
+
return $1 if value =~ /^'(.*)'$/
|
94
|
+
return nil if value == "GENERATED_BY_DEFAULT"
|
95
|
+
value
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
|
100
|
+
# @see ActiveRecord::ConnectionAdapters::Jdbc::ArelSupport
|
101
|
+
def self.arel_visitor_type(config = nil)
|
102
|
+
require 'arel/visitors/derby'; ::Arel::Visitors::Derby
|
103
|
+
end
|
104
|
+
|
105
|
+
ADAPTER_NAME = 'Derby'.freeze
|
106
|
+
|
107
|
+
def adapter_name
|
108
|
+
ADAPTER_NAME
|
109
|
+
end
|
110
|
+
|
111
|
+
def configure_connection
|
112
|
+
# must be done or SELECT...FOR UPDATE won't work how we expect :
|
113
|
+
if tx_isolation = config[:transaction_isolation]
|
114
|
+
@connection.transaction_isolation = tx_isolation
|
115
|
+
end
|
116
|
+
# if a user name was specified upon connection, the user's name is the
|
117
|
+
# default schema for the connection, if a schema with that name exists
|
118
|
+
set_schema(config[:schema]) if config[:schema]
|
119
|
+
end
|
120
|
+
|
121
|
+
def index_name_length
|
122
|
+
128
|
123
|
+
end
|
124
|
+
|
125
|
+
NATIVE_DATABASE_TYPES = {
|
126
|
+
:primary_key => "int GENERATED BY DEFAULT AS identity NOT NULL PRIMARY KEY",
|
127
|
+
:string => { :name => "varchar", :limit => 255 }, # 32672
|
128
|
+
:text => { :name => "clob" }, # 2,147,483,647
|
129
|
+
:char => { :name => "char", :limit => 254 }, # JDBC :limit => 254
|
130
|
+
:binary => { :name => "blob" }, # 2,147,483,647
|
131
|
+
:float => { :name => "float", :limit => 8 }, # DOUBLE PRECISION
|
132
|
+
:real => { :name => "real", :limit => 4 }, # JDBC :limit => 23
|
133
|
+
:double => { :name => "double", :limit => 8 }, # JDBC :limit => 52
|
134
|
+
:decimal => { :name => "decimal", :precision => 5, :scale => 0 }, # JDBC :limit => 31
|
135
|
+
:numeric => { :name => "decimal", :precision => 5, :scale => 0 }, # JDBC :limit => 31
|
136
|
+
:integer => { :name => "integer", :limit => 4 }, # JDBC :limit => 10
|
137
|
+
:smallint => { :name => "smallint", :limit => 2 }, # JDBC :limit => 5
|
138
|
+
:bigint => { :name => "bigint", :limit => 8 }, # JDBC :limit => 19
|
139
|
+
:date => { :name => "date" },
|
140
|
+
:time => { :name => "time" },
|
141
|
+
:datetime => { :name => "timestamp" },
|
142
|
+
:timestamp => { :name => "timestamp" },
|
143
|
+
:xml => { :name => "xml" },
|
144
|
+
:boolean => { :name => "smallint", :limit => 1 }, # TODO boolean (since 10.7)
|
145
|
+
:object => { :name => "object" },
|
146
|
+
}
|
147
|
+
|
148
|
+
# @private
|
149
|
+
def initialize_type_map(m)
|
150
|
+
super
|
151
|
+
m.register_type(%r(smallint)i) do |sql_type|
|
152
|
+
if Derby.emulate_booleans?
|
153
|
+
ActiveRecord::Type::Boolean.new
|
154
|
+
else
|
155
|
+
ActiveRecord::Type::Integer.new(:limit => 1)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
m.alias_type %r(real)i, 'float'
|
159
|
+
end if AR42
|
160
|
+
|
161
|
+
def reset_column_information
|
162
|
+
initialize_type_map(type_map)
|
163
|
+
end if AR42
|
164
|
+
|
165
|
+
# @override
|
166
|
+
def native_database_types
|
167
|
+
NATIVE_DATABASE_TYPES
|
168
|
+
end
|
169
|
+
|
170
|
+
# Ensure the savepoint name is unused before creating it.
|
171
|
+
# @override
|
172
|
+
def create_savepoint(name = current_savepoint_name(true))
|
173
|
+
release_savepoint(name) if @connection.marked_savepoint_names.include?(name)
|
174
|
+
super(name)
|
175
|
+
end
|
176
|
+
|
177
|
+
# @override
|
178
|
+
def quote(value, column = nil)
|
179
|
+
return super if column && ArJdbc::AR42 && column.cast_type.is_a?(ActiveRecord::Type::Serialized)
|
180
|
+
return value.quoted_id if value.respond_to?(:quoted_id)
|
181
|
+
return value if sql_literal?(value)
|
182
|
+
return 'NULL' if value.nil?
|
183
|
+
|
184
|
+
column_type = column && column.type
|
185
|
+
if column_type == :string || column_type == :text
|
186
|
+
# Derby is not permissive
|
187
|
+
# e.g. sending an Integer to a VARCHAR column will fail
|
188
|
+
case value
|
189
|
+
when BigDecimal then value = value.to_s('F')
|
190
|
+
when Numeric then value = value.to_s
|
191
|
+
when true, false then value = value.to_s
|
192
|
+
when Date, Time then value = quoted_date(value)
|
193
|
+
else # on 2.3 attribute serialization needs to_yaml here
|
194
|
+
value = value.to_s if ActiveRecord::VERSION::MAJOR >= 3
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
case value
|
199
|
+
when String, ActiveSupport::Multibyte::Chars
|
200
|
+
if column_type == :text
|
201
|
+
"CAST('#{quote_string(value)}' AS CLOB)"
|
202
|
+
elsif column_type == :binary
|
203
|
+
"CAST(X'#{quote_binary(value)}' AS BLOB)"
|
204
|
+
elsif column_type == :xml
|
205
|
+
"XMLPARSE(DOCUMENT '#{quote_string(value)}' PRESERVE WHITESPACE)"
|
206
|
+
elsif column_type == :integer
|
207
|
+
value.to_i
|
208
|
+
elsif column_type == :float
|
209
|
+
value.to_f
|
210
|
+
else
|
211
|
+
"'#{quote_string(value)}'"
|
212
|
+
end
|
213
|
+
else
|
214
|
+
super
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
# @override
|
219
|
+
def quoted_date(value)
|
220
|
+
if value.acts_like?(:time) && value.respond_to?(:usec)
|
221
|
+
usec = sprintf("%06d", value.usec)
|
222
|
+
value = ::ActiveRecord::Base.default_timezone == :utc ? value.getutc : value.getlocal
|
223
|
+
"#{value.strftime("%Y-%m-%d %H:%M:%S")}.#{usec}"
|
224
|
+
else
|
225
|
+
super
|
226
|
+
end
|
227
|
+
end if ::ActiveRecord::VERSION::MAJOR >= 3
|
228
|
+
|
229
|
+
# @private In Derby, these cannot specify a limit.
|
230
|
+
NO_LIMIT_TYPES = [ :integer, :boolean, :timestamp, :datetime, :date, :time ]
|
231
|
+
|
232
|
+
# Convert the specified column type to a SQL string.
|
233
|
+
# @override
|
234
|
+
def type_to_sql(type, limit = nil, precision = nil, scale = nil)
|
235
|
+
return super unless NO_LIMIT_TYPES.include?(t = type.to_s.downcase.to_sym)
|
236
|
+
|
237
|
+
native_type = NATIVE_DATABASE_TYPES[t]
|
238
|
+
native_type.is_a?(Hash) ? native_type[:name] : native_type
|
239
|
+
end
|
240
|
+
|
241
|
+
# @private
|
242
|
+
class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
|
243
|
+
|
244
|
+
def xml(*args)
|
245
|
+
options = args.extract_options!
|
246
|
+
column(args[0], 'xml', options)
|
247
|
+
end
|
248
|
+
|
249
|
+
end
|
250
|
+
|
251
|
+
def table_definition(*args)
|
252
|
+
new_table_definition(TableDefinition, *args)
|
253
|
+
end
|
254
|
+
|
255
|
+
# @override
|
256
|
+
def empty_insert_statement_value
|
257
|
+
::Arel::Visitors::Derby::VALUES_DEFAULT # Derby needs to know the columns
|
258
|
+
end
|
259
|
+
|
260
|
+
# Set the sequence to the max value of the table's column.
|
261
|
+
# @override
|
262
|
+
def reset_sequence!(table, column, sequence = nil)
|
263
|
+
mpk = select_value("SELECT MAX(#{quote_column_name(column)}) FROM #{quote_table_name(table)}")
|
264
|
+
execute("ALTER TABLE #{quote_table_name(table)} ALTER COLUMN #{quote_column_name(column)} RESTART WITH #{mpk.to_i + 1}")
|
265
|
+
end
|
266
|
+
|
267
|
+
def reset_pk_sequence!(table, pk = nil, sequence = nil)
|
268
|
+
klasses = classes_for_table_name(table)
|
269
|
+
klass = klasses.nil? ? nil : klasses.first
|
270
|
+
pk = klass.primary_key unless klass.nil?
|
271
|
+
if pk && klass.columns_hash[pk].type == :integer
|
272
|
+
reset_sequence!(klass.table_name, pk)
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
def classes_for_table_name(table)
|
277
|
+
ActiveRecord::Base.send(:subclasses).select { |klass| klass.table_name == table }
|
278
|
+
end
|
279
|
+
private :classes_for_table_name
|
280
|
+
|
281
|
+
# @override
|
282
|
+
def remove_index!(table_name, index_name)
|
283
|
+
execute "DROP INDEX #{quote_column_name(index_name)}"
|
284
|
+
end
|
285
|
+
|
286
|
+
# @override
|
287
|
+
def rename_table(name, new_name)
|
288
|
+
execute "RENAME TABLE #{quote_table_name(name)} TO #{quote_table_name(new_name)}"
|
289
|
+
end
|
290
|
+
|
291
|
+
def add_column(table_name, column_name, type, options = {})
|
292
|
+
add_column_sql = "ALTER TABLE #{quote_table_name(table_name)} ADD #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
|
293
|
+
add_column_options!(add_column_sql, options)
|
294
|
+
execute(add_column_sql)
|
295
|
+
end unless const_defined? :SchemaCreation
|
296
|
+
|
297
|
+
# @override fix case where AR passes `:default => nil, :null => true`
|
298
|
+
def add_column_options!(sql, options)
|
299
|
+
options.delete(:default) if options.has_key?(:default) && options[:default].nil?
|
300
|
+
sql << " DEFAULT #{quote(options.delete(:default))}" if options.has_key?(:default)
|
301
|
+
super
|
302
|
+
end unless const_defined? :SchemaCreation
|
303
|
+
|
304
|
+
if ActiveRecord::VERSION::MAJOR >= 4
|
305
|
+
|
306
|
+
# @override
|
307
|
+
def remove_column(table_name, column_name, type = nil, options = {})
|
308
|
+
do_remove_column(table_name, column_name)
|
309
|
+
end
|
310
|
+
|
311
|
+
else
|
312
|
+
|
313
|
+
# @override
|
314
|
+
def remove_column(table_name, *column_names)
|
315
|
+
for column_name in column_names.flatten
|
316
|
+
do_remove_column(table_name, column_name)
|
317
|
+
end
|
318
|
+
end
|
319
|
+
alias remove_columns remove_column
|
320
|
+
|
321
|
+
end
|
322
|
+
|
323
|
+
def do_remove_column(table_name, column_name)
|
324
|
+
execute "ALTER TABLE #{quote_table_name(table_name)} DROP COLUMN #{quote_column_name(column_name)} RESTRICT"
|
325
|
+
end
|
326
|
+
private :do_remove_column
|
327
|
+
|
328
|
+
# @override
|
329
|
+
def change_column(table_name, column_name, type, options = {})
|
330
|
+
# TODO this needs a review since now we're likely to be on >= 10.8
|
331
|
+
|
332
|
+
# Notes about changing in Derby:
|
333
|
+
# http://db.apache.org/derby/docs/10.2/ref/rrefsqlj81859.html#rrefsqlj81859__rrefsqlj37860)
|
334
|
+
#
|
335
|
+
# We support changing columns using the strategy outlined in:
|
336
|
+
# https://issues.apache.org/jira/browse/DERBY-1515
|
337
|
+
#
|
338
|
+
# This feature has not made it into a formal release and is not in Java 6.
|
339
|
+
# We will need to conditionally support this (supposed to arrive for 10.3.0.0).
|
340
|
+
|
341
|
+
# null/not nulling is easy, handle that separately
|
342
|
+
if options.include?(:null)
|
343
|
+
# This seems to only work with 10.2 of Derby
|
344
|
+
if options.delete(:null) == false
|
345
|
+
execute "ALTER TABLE #{quote_table_name(table_name)} ALTER COLUMN #{quote_column_name(column_name)} NOT NULL"
|
346
|
+
else
|
347
|
+
execute "ALTER TABLE #{quote_table_name(table_name)} ALTER COLUMN #{quote_column_name(column_name)} NULL"
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
# anything left to do?
|
352
|
+
unless options.empty?
|
353
|
+
begin
|
354
|
+
execute "ALTER TABLE #{quote_table_name(table_name)} ALTER COLUMN " <<
|
355
|
+
" #{quote_column_name(column_name)} SET DATA TYPE #{type_to_sql(type, options[:limit])}"
|
356
|
+
rescue
|
357
|
+
transaction do
|
358
|
+
temp_new_column_name = "#{column_name}_newtype"
|
359
|
+
# 1) ALTER TABLE t ADD COLUMN c1_newtype NEWTYPE;
|
360
|
+
add_column table_name, temp_new_column_name, type, options
|
361
|
+
# 2) UPDATE t SET c1_newtype = c1;
|
362
|
+
execute "UPDATE #{quote_table_name(table_name)} SET " <<
|
363
|
+
" #{quote_column_name(temp_new_column_name)} = " <<
|
364
|
+
" CAST(#{quote_column_name(column_name)} AS #{type_to_sql(type, options[:limit])})"
|
365
|
+
# 3) ALTER TABLE t DROP COLUMN c1;
|
366
|
+
remove_column table_name, column_name
|
367
|
+
# 4) ALTER TABLE t RENAME COLUMN c1_newtype to c1;
|
368
|
+
rename_column table_name, temp_new_column_name, column_name
|
369
|
+
end
|
370
|
+
end
|
371
|
+
end
|
372
|
+
end
|
373
|
+
|
374
|
+
# @override
|
375
|
+
def rename_column(table_name, column_name, new_column_name)
|
376
|
+
execute "RENAME COLUMN #{quote_table_name(table_name)}.#{quote_column_name(column_name)} " <<
|
377
|
+
" TO #{quote_column_name(new_column_name)}"
|
378
|
+
end
|
379
|
+
|
380
|
+
# SELECT DISTINCT clause for a given set of columns and a given ORDER BY clause.
|
381
|
+
#
|
382
|
+
# Derby requires the ORDER BY columns in the select list for distinct queries, and
|
383
|
+
# requires that the ORDER BY include the distinct column.
|
384
|
+
# ```
|
385
|
+
# distinct("posts.id", "posts.created_at desc")
|
386
|
+
# ```
|
387
|
+
# @note This is based on distinct method for the PostgreSQL Adapter.
|
388
|
+
# @override
|
389
|
+
def distinct(columns, order_by)
|
390
|
+
"DISTINCT #{columns_for_distinct(columns, order_by)}"
|
391
|
+
end
|
392
|
+
|
393
|
+
# @override Since AR 4.0 (on 4.1 {#distinct} is gone and won't be called).
|
394
|
+
def columns_for_distinct(columns, orders)
|
395
|
+
return columns if orders.blank?
|
396
|
+
|
397
|
+
# construct a clean list of column names from the ORDER BY clause,
|
398
|
+
# removing any ASC/DESC modifiers
|
399
|
+
order_columns = [ orders ]; order_columns.flatten! # AR 3.x vs 4.x
|
400
|
+
order_columns.map! do |column|
|
401
|
+
column = column.to_sql unless column.is_a?(String) # handle AREL node
|
402
|
+
column.split(',').collect! { |s| s.split.first }
|
403
|
+
end.flatten!
|
404
|
+
order_columns.reject!(&:blank?)
|
405
|
+
order_columns = order_columns.zip (0...order_columns.size).to_a
|
406
|
+
order_columns = order_columns.map { |s, i| "#{s} AS alias_#{i}" }
|
407
|
+
|
408
|
+
columns = [ columns ]; columns.flatten!
|
409
|
+
columns.push( *order_columns ).join(', ')
|
410
|
+
# return a DISTINCT clause that's distinct on the columns we want but
|
411
|
+
# includes all the required columns for the ORDER BY to work properly
|
412
|
+
end
|
413
|
+
|
414
|
+
# @override
|
415
|
+
def primary_keys(table_name)
|
416
|
+
@connection.primary_keys table_name.to_s.upcase
|
417
|
+
end
|
418
|
+
|
419
|
+
# @override
|
420
|
+
def tables(name = nil)
|
421
|
+
@connection.tables(nil, current_schema)
|
422
|
+
end
|
423
|
+
|
424
|
+
# @override
|
425
|
+
def supports_ddl_transactions?; true end
|
426
|
+
|
427
|
+
# @override
|
428
|
+
def supports_foreign_keys?; true end
|
429
|
+
|
430
|
+
def truncate(table_name, name = nil)
|
431
|
+
execute "TRUNCATE TABLE #{quote_table_name(table_name)}", name
|
432
|
+
end
|
433
|
+
|
434
|
+
# @return [String] the current schema name
|
435
|
+
def current_schema
|
436
|
+
@current_schema ||=
|
437
|
+
select_value "SELECT CURRENT SCHEMA FROM SYS.SYSSCHEMAS FETCH FIRST 1 ROWS ONLY", 'SCHEMA'
|
438
|
+
end
|
439
|
+
|
440
|
+
# Change the current (implicit) Derby schema to be used for this connection.
|
441
|
+
def set_schema(schema)
|
442
|
+
@current_schema = nil
|
443
|
+
execute "SET SCHEMA #{schema}", 'SCHEMA'
|
444
|
+
end
|
445
|
+
alias_method :current_schema=, :set_schema
|
446
|
+
|
447
|
+
# Creates a new Derby schema.
|
448
|
+
# @see #set_schema
|
449
|
+
def create_schema(schema)
|
450
|
+
execute "CREATE SCHEMA #{schema}", 'Create Schema'
|
451
|
+
end
|
452
|
+
|
453
|
+
# Drops an existing schema, needs to be empty (no DB objects).
|
454
|
+
def drop_schema(schema)
|
455
|
+
execute "DROP SCHEMA #{schema} RESTRICT", 'Drop Schema'
|
456
|
+
end
|
457
|
+
|
458
|
+
# @private
|
459
|
+
def recreate_database(name = nil, options = {})
|
460
|
+
drop_database(name)
|
461
|
+
create_database(name, options)
|
462
|
+
end
|
463
|
+
|
464
|
+
# @private
|
465
|
+
def create_database(name = nil, options = {}); end
|
466
|
+
|
467
|
+
# @private
|
468
|
+
def drop_database(name = nil)
|
469
|
+
tables.each { |table| drop_table(table) }
|
470
|
+
end
|
471
|
+
|
472
|
+
# @override
|
473
|
+
def quote_column_name(name)
|
474
|
+
%Q{"#{name.to_s.upcase.gsub('"', '""')}"}
|
475
|
+
end
|
476
|
+
|
477
|
+
# @override
|
478
|
+
def quote_table_name_for_assignment(table, attr)
|
479
|
+
quote_column_name(attr)
|
480
|
+
end if ::ActiveRecord::VERSION::MAJOR > 3
|
481
|
+
|
482
|
+
# @note Only used with (non-AREL) ActiveRecord **2.3**.
|
483
|
+
# @see Arel::Visitors::Derby
|
484
|
+
def add_limit_offset!(sql, options)
|
485
|
+
sql << " OFFSET #{options[:offset]} ROWS" if options[:offset]
|
486
|
+
# ROWS/ROW and FIRST/NEXT mean the same
|
487
|
+
sql << " FETCH FIRST #{options[:limit]} ROWS ONLY" if options[:limit]
|
488
|
+
end if ::ActiveRecord::VERSION::MAJOR < 3
|
489
|
+
|
490
|
+
# @override
|
491
|
+
def execute(sql, name = nil, binds = [])
|
492
|
+
sql = to_sql(sql, binds)
|
493
|
+
insert = self.class.insert?(sql)
|
494
|
+
update = ! insert && ! self.class.select?(sql)
|
495
|
+
sql = correct_is_null(sql, insert || update)
|
496
|
+
super(sql, name, binds)
|
497
|
+
end
|
498
|
+
|
499
|
+
# Returns the value of an identity column of the last *INSERT* statement
|
500
|
+
# made over this connection.
|
501
|
+
# @note Check the *IDENTITY_VAL_LOCAL* function for documentation.
|
502
|
+
# @return [Fixnum]
|
503
|
+
def last_insert_id
|
504
|
+
@connection.identity_val_local
|
505
|
+
end
|
506
|
+
|
507
|
+
private
|
508
|
+
|
509
|
+
def correct_is_null(sql, insert_or_update = false)
|
510
|
+
if insert_or_update
|
511
|
+
if ( i = sql =~ /\sWHERE\s/im )
|
512
|
+
where_part = sql[i..-1]; sql = sql.dup
|
513
|
+
where_part.gsub!(/!=\s*NULL/i, 'IS NOT NULL')
|
514
|
+
where_part.gsub!(/=\sNULL/i, 'IS NULL')
|
515
|
+
sql[i..-1] = where_part
|
516
|
+
end
|
517
|
+
sql
|
518
|
+
else
|
519
|
+
sql.gsub(/=\sNULL/i, 'IS NULL')
|
520
|
+
end
|
521
|
+
end
|
522
|
+
|
523
|
+
# NOTE: only setup query analysis on AR <= 3.0 since on 3.1 {#exec_query},
|
524
|
+
# {#exec_insert} will be used for AR generated queries/inserts etc.
|
525
|
+
# Also there's prepared statement support and {#execute} is meant to stay
|
526
|
+
# as a way of running non-prepared SQL statements (returning raw results).
|
527
|
+
if ActiveRecord::VERSION::MAJOR < 3 ||
|
528
|
+
( ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR < 1 )
|
529
|
+
|
530
|
+
def _execute(sql, name = nil)
|
531
|
+
if self.class.insert?(sql)
|
532
|
+
@connection.execute_insert(sql)
|
533
|
+
elsif self.class.select?(sql)
|
534
|
+
@connection.execute_query_raw(sql)
|
535
|
+
else
|
536
|
+
@connection.execute_update(sql)
|
537
|
+
end
|
538
|
+
end
|
539
|
+
|
540
|
+
end
|
541
|
+
|
542
|
+
def self.const_missing(name)
|
543
|
+
if name.to_sym == :Column
|
544
|
+
ArJdbc.deprecate("#{self.name}::Column will change to refer to the actual column class, please use ColumnMethods instead", :once)
|
545
|
+
return ColumnMethods
|
546
|
+
end
|
547
|
+
super
|
548
|
+
end
|
549
|
+
|
550
|
+
end
|
551
|
+
end
|
552
|
+
|
553
|
+
module ActiveRecord::ConnectionAdapters
|
554
|
+
class DerbyAdapter < JdbcAdapter
|
555
|
+
include ::ArJdbc::Derby
|
556
|
+
|
557
|
+
class Column < JdbcColumn
|
558
|
+
include ::ArJdbc::Derby::ColumnMethods
|
559
|
+
end
|
560
|
+
end
|
561
|
+
end
|
562
|
+
|
563
|
+
#module ArJdbc
|
564
|
+
# module Derby
|
565
|
+
# Column = ::ActiveRecord::ConnectionAdapters::DerbyAdapter::Column
|
566
|
+
# end
|
567
|
+
#end
|