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