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
data/lib/arjdbc/mssql.rb
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
require 'arjdbc
|
|
2
|
-
jdbc_require_driver 'jdbc/jtds', 'jdbc-mssql'
|
|
3
|
-
require 'arjdbc/mssql/connection_methods'
|
|
1
|
+
require 'arjdbc'
|
|
4
2
|
require 'arjdbc/mssql/adapter'
|
|
3
|
+
require 'arjdbc/mssql/connection_methods'
|
|
4
|
+
module ArJdbc
|
|
5
|
+
MsSQL = MSSQL # compatibility with 1.2
|
|
6
|
+
end
|
|
7
|
+
ArJdbc.warn_unsupported_adapter 'mssql', [4, 2] # warns on AR >= 4.2
|
data/lib/arjdbc/mssql/adapter.rb
CHANGED
|
@@ -1,69 +1,175 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
# NOTE: file contains code adapted from **sqlserver** adapter, license follows
|
|
2
|
+
=begin
|
|
3
|
+
Copyright (c) 2008-2015
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
6
|
+
a copy of this software and associated documentation files (the
|
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
11
|
+
the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be
|
|
14
|
+
included in all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
23
|
+
=end
|
|
24
|
+
|
|
25
|
+
ArJdbc.load_java_part :MSSQL
|
|
26
|
+
|
|
27
|
+
require 'strscan'
|
|
28
|
+
|
|
29
|
+
module ArJdbc
|
|
30
|
+
module MSSQL
|
|
31
|
+
|
|
32
|
+
require 'arjdbc/mssql/utils'
|
|
33
|
+
require 'arjdbc/mssql/limit_helpers'
|
|
34
|
+
require 'arjdbc/mssql/lock_methods'
|
|
35
|
+
require 'arjdbc/mssql/column'
|
|
36
|
+
require 'arjdbc/mssql/explain_support'
|
|
37
|
+
require 'arjdbc/mssql/types' if AR42
|
|
38
|
+
require 'arel/visitors/sql_server'
|
|
3
39
|
|
|
4
|
-
module ::ArJdbc
|
|
5
|
-
module MsSQL
|
|
6
|
-
include TSqlMethods
|
|
7
40
|
include LimitHelpers
|
|
41
|
+
include Utils
|
|
42
|
+
include ExplainSupport
|
|
8
43
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
def after_save_with_mssql_lob
|
|
13
|
-
self.class.columns.select { |c| c.sql_type =~ /image/i }.each do |c|
|
|
14
|
-
value = self[c.name]
|
|
15
|
-
value = value.to_yaml if unserializable_attribute?(c.name, c)
|
|
16
|
-
next if value.nil? || (value == '')
|
|
17
|
-
|
|
18
|
-
connection.write_large_object(c.type == :binary, c.name, self.class.table_name, self.class.primary_key, quote_value(id), value)
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
end
|
|
44
|
+
# @private
|
|
45
|
+
def self.extended(adapter)
|
|
46
|
+
initialize!
|
|
22
47
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
end
|
|
26
|
-
mod.add_version_specific_add_limit_offset
|
|
48
|
+
version = adapter.config[:sqlserver_version] ||= adapter.sqlserver_version
|
|
49
|
+
adapter.send(:setup_limit_offset!, version)
|
|
27
50
|
end
|
|
28
51
|
|
|
29
|
-
|
|
30
|
-
|
|
52
|
+
# @private
|
|
53
|
+
@@_initialized = nil
|
|
54
|
+
|
|
55
|
+
# @private
|
|
56
|
+
def self.initialize!
|
|
57
|
+
return if @@_initialized; @@_initialized = true
|
|
58
|
+
|
|
59
|
+
require 'arjdbc/util/serialized_attributes'
|
|
60
|
+
Util::SerializedAttributes.setup /image/i, 'after_save_with_mssql_lob'
|
|
31
61
|
end
|
|
32
62
|
|
|
33
|
-
|
|
34
|
-
|
|
63
|
+
# @private
|
|
64
|
+
@@update_lob_values = true
|
|
65
|
+
|
|
66
|
+
# Updating records with LOB values (binary/text columns) in a separate
|
|
67
|
+
# statement can be disabled using :
|
|
68
|
+
#
|
|
69
|
+
# ArJdbc::MSSQL.update_lob_values = false
|
|
70
|
+
#
|
|
71
|
+
# @note This only applies when prepared statements are not used.
|
|
72
|
+
def self.update_lob_values?; @@update_lob_values; end
|
|
73
|
+
# @see #update_lob_values?
|
|
74
|
+
def self.update_lob_values=(update); @@update_lob_values = update; end
|
|
75
|
+
|
|
76
|
+
# @private
|
|
77
|
+
@@cs_equality_operator = 'COLLATE Latin1_General_CS_AS_WS'
|
|
78
|
+
|
|
79
|
+
# Operator for sorting strings in SQLServer, setup as :
|
|
80
|
+
#
|
|
81
|
+
# ArJdbc::MSSQL.cs_equality_operator = 'COLLATE Latin1_General_CS_AS_WS'
|
|
82
|
+
#
|
|
83
|
+
def self.cs_equality_operator; @@cs_equality_operator; end
|
|
84
|
+
# @see #cs_equality_operator
|
|
85
|
+
def self.cs_equality_operator=(operator); @@cs_equality_operator = operator; end
|
|
86
|
+
|
|
87
|
+
# @see #quote
|
|
88
|
+
# @private
|
|
89
|
+
BLOB_VALUE_MARKER = "''"
|
|
90
|
+
|
|
91
|
+
# @see #update_lob_values?
|
|
92
|
+
# @see ArJdbc::Util::SerializedAttributes#update_lob_columns
|
|
93
|
+
def update_lob_value?(value, column = nil)
|
|
94
|
+
MSSQL.update_lob_values? && ! prepared_statements? # && value
|
|
35
95
|
end
|
|
36
96
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
{ 'mssql' => visitor_class, 'jdbcmssql' => visitor_class}
|
|
97
|
+
# @see ActiveRecord::ConnectionAdapters::JdbcAdapter#jdbc_connection_class
|
|
98
|
+
def self.jdbc_connection_class
|
|
99
|
+
::ActiveRecord::ConnectionAdapters::MSSQLJdbcConnection
|
|
41
100
|
end
|
|
42
101
|
|
|
43
|
-
|
|
44
|
-
|
|
102
|
+
# @see ActiveRecord::ConnectionAdapters::JdbcAdapter#jdbc_column_class
|
|
103
|
+
def jdbc_column_class; ::ActiveRecord::ConnectionAdapters::MSSQLColumn end
|
|
104
|
+
|
|
105
|
+
def configure_connection
|
|
106
|
+
use_database # config[:database]
|
|
45
107
|
end
|
|
46
108
|
|
|
47
|
-
def
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
109
|
+
def sqlserver_version
|
|
110
|
+
@sqlserver_version ||= begin
|
|
111
|
+
config_version = config[:sqlserver_version]
|
|
112
|
+
config_version ? config_version.to_s :
|
|
113
|
+
select_value("SELECT @@version")[/(Microsoft SQL Server\s+|Microsoft SQL Azure.+\n.+)(\d{4})/, 2]
|
|
52
114
|
end
|
|
53
115
|
end
|
|
54
116
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
117
|
+
NATIVE_DATABASE_TYPES = {
|
|
118
|
+
:primary_key => 'int NOT NULL IDENTITY(1,1) PRIMARY KEY',
|
|
119
|
+
:integer => { :name => 'int', }, # :limit => 4
|
|
120
|
+
:boolean => { :name => 'bit' },
|
|
121
|
+
:decimal => { :name => 'decimal' },
|
|
122
|
+
:float => { :name => 'float' },
|
|
123
|
+
:bigint => { :name => 'bigint' },
|
|
124
|
+
:real => { :name => 'real' },
|
|
125
|
+
:date => { :name => 'date' },
|
|
126
|
+
:time => { :name => 'time' },
|
|
127
|
+
:datetime => { :name => 'datetime' },
|
|
128
|
+
:timestamp => { :name => 'datetime' },
|
|
129
|
+
|
|
130
|
+
:string => { :name => 'nvarchar', :limit => 4000 },
|
|
131
|
+
#:varchar => { :name => 'varchar' }, # limit: 8000
|
|
132
|
+
:text => { :name => 'nvarchar(max)' },
|
|
133
|
+
:text_basic => { :name => 'text' },
|
|
134
|
+
#:ntext => { :name => 'ntext' },
|
|
135
|
+
:char => { :name => 'char' },
|
|
136
|
+
#:nchar => { :name => 'nchar' },
|
|
137
|
+
:binary => { :name => 'image' }, # NOTE: :name => 'varbinary(max)'
|
|
138
|
+
:binary_basic => { :name => 'binary' },
|
|
139
|
+
:uuid => { :name => 'uniqueidentifier' },
|
|
140
|
+
:money => { :name => 'money' },
|
|
141
|
+
#:smallmoney => { :name => 'smallmoney' },
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
def native_database_types
|
|
145
|
+
# NOTE: due compatibility we're using the generic type resolution
|
|
146
|
+
# ... NATIVE_DATABASE_TYPES won't be used at all on SQLServer 2K
|
|
147
|
+
sqlserver_2000? ? super : super.merge(NATIVE_DATABASE_TYPES)
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def modify_types(types)
|
|
151
|
+
if sqlserver_2000?
|
|
152
|
+
types[:primary_key] = NATIVE_DATABASE_TYPES[:primary_key]
|
|
153
|
+
types[:string] = NATIVE_DATABASE_TYPES[:string]
|
|
154
|
+
types[:boolean] = NATIVE_DATABASE_TYPES[:boolean]
|
|
155
|
+
types[:text] = { :name => "ntext" }
|
|
156
|
+
types[:integer][:limit] = nil
|
|
157
|
+
types[:binary] = { :name => "image" }
|
|
60
158
|
else
|
|
61
|
-
|
|
159
|
+
# ~ private types for better "native" adapter compatibility
|
|
160
|
+
types[:varchar_max] = { :name => 'varchar(max)' }
|
|
161
|
+
types[:nvarchar_max] = { :name => 'nvarchar(max)' }
|
|
162
|
+
types[:varbinary_max] = { :name => 'varbinary(max)' }
|
|
62
163
|
end
|
|
63
|
-
|
|
164
|
+
types[:string][:limit] = 255 unless AR40 # backwards compatibility
|
|
165
|
+
types
|
|
64
166
|
end
|
|
65
167
|
|
|
66
|
-
|
|
168
|
+
# @private these cannot specify a limit
|
|
169
|
+
NO_LIMIT_TYPES = %w( text binary boolean date datetime )
|
|
170
|
+
|
|
171
|
+
def type_to_sql(type, limit = nil, precision = nil, scale = nil)
|
|
172
|
+
type_s = type.to_s
|
|
67
173
|
# MSSQL's NVARCHAR(n | max) column supports either a number between 1 and
|
|
68
174
|
# 4000, or the word "MAX", which corresponds to 2**30-1 UCS-2 characters.
|
|
69
175
|
#
|
|
@@ -73,329 +179,436 @@ module ::ArJdbc
|
|
|
73
179
|
# MSSQL Server 2000 is skipped here because I don't know how it will behave.
|
|
74
180
|
#
|
|
75
181
|
# See: http://msdn.microsoft.com/en-us/library/ms186939.aspx
|
|
76
|
-
if
|
|
182
|
+
if type_s == 'string' && limit == 1073741823 && ! sqlserver_2000?
|
|
77
183
|
'NVARCHAR(MAX)'
|
|
78
|
-
elsif
|
|
79
|
-
super(type)
|
|
184
|
+
elsif NO_LIMIT_TYPES.include?(type_s)
|
|
185
|
+
super(type)
|
|
186
|
+
elsif type_s == 'integer' || type_s == 'int'
|
|
187
|
+
if limit.nil? || limit == 4
|
|
188
|
+
'int'
|
|
189
|
+
elsif limit == 2
|
|
190
|
+
'smallint'
|
|
191
|
+
elsif limit == 1
|
|
192
|
+
'tinyint'
|
|
193
|
+
else
|
|
194
|
+
'bigint'
|
|
195
|
+
end
|
|
196
|
+
elsif type_s == 'uniqueidentifier'
|
|
197
|
+
type_s
|
|
80
198
|
else
|
|
81
199
|
super
|
|
82
200
|
end
|
|
83
201
|
end
|
|
84
202
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
case field_type
|
|
90
|
-
when /int|bigint|smallint|tinyint/i then :integer
|
|
91
|
-
when /numeric/i then (@scale.nil? || @scale == 0) ? :integer : :decimal
|
|
92
|
-
when /float|double|decimal|money|real|smallmoney/i then :decimal
|
|
93
|
-
when /datetime|smalldatetime/i then :datetime
|
|
94
|
-
when /timestamp/i then :timestamp
|
|
95
|
-
when /time/i then :time
|
|
96
|
-
when /date/i then :date
|
|
97
|
-
when /text|ntext|xml/i then :text
|
|
98
|
-
when /binary|image|varbinary/i then :binary
|
|
99
|
-
when /char|nchar|nvarchar|string|varchar/i then (@limit == 1073741823 ? (@limit = nil; :text) : :string)
|
|
100
|
-
when /bit/i then :boolean
|
|
101
|
-
when /uniqueidentifier/i then :string
|
|
102
|
-
end
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
def default_value(value)
|
|
106
|
-
return $1 if value =~ /^\(N?'(.*)'\)$/
|
|
107
|
-
value
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
def type_cast(value)
|
|
111
|
-
return nil if value.nil? || value == "(null)" || value == "(NULL)"
|
|
112
|
-
case type
|
|
113
|
-
when :integer then value.to_i rescue unquote(value).to_i rescue value ? 1 : 0
|
|
114
|
-
when :primary_key then value == true || value == false ? value == true ? 1 : 0 : value.to_i
|
|
115
|
-
when :decimal then self.class.value_to_decimal(unquote(value))
|
|
116
|
-
when :datetime then cast_to_datetime(value)
|
|
117
|
-
when :timestamp then cast_to_time(value)
|
|
118
|
-
when :time then cast_to_time(value)
|
|
119
|
-
when :date then cast_to_date(value)
|
|
120
|
-
when :boolean then value == true or (value =~ /^t(rue)?$/i) == 0 or unquote(value)=="1"
|
|
121
|
-
when :binary then unquote value
|
|
122
|
-
else value
|
|
123
|
-
end
|
|
124
|
-
end
|
|
203
|
+
# @override
|
|
204
|
+
def quote(value, column = nil)
|
|
205
|
+
return value.quoted_id if value.respond_to?(:quoted_id)
|
|
206
|
+
return value if sql_literal?(value)
|
|
125
207
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
208
|
+
case value
|
|
209
|
+
# SQL Server 2000 doesn't let you insert an integer into a NVARCHAR
|
|
210
|
+
when String, ActiveSupport::Multibyte::Chars, Integer
|
|
211
|
+
value = value.to_s
|
|
212
|
+
column_type = column && column.type
|
|
213
|
+
if column_type == :binary
|
|
214
|
+
if update_lob_value?(value, column)
|
|
215
|
+
BLOB_VALUE_MARKER
|
|
216
|
+
else
|
|
217
|
+
"'#{quote_string(column.class.string_to_binary(value))}'" # ' (for ruby-mode)
|
|
218
|
+
end
|
|
219
|
+
elsif column_type == :integer
|
|
220
|
+
value.to_i.to_s
|
|
221
|
+
elsif column_type == :float
|
|
222
|
+
value.to_f.to_s
|
|
223
|
+
elsif ! column.respond_to?(:is_utf8?) || column.is_utf8?
|
|
224
|
+
"N'#{quote_string(value)}'" # ' (for ruby-mode)
|
|
130
225
|
else
|
|
131
226
|
super
|
|
132
227
|
end
|
|
228
|
+
when Date, Time
|
|
229
|
+
if column && column.type == :time
|
|
230
|
+
"'#{quoted_time(value)}'"
|
|
231
|
+
else
|
|
232
|
+
"'#{quoted_date(value)}'"
|
|
233
|
+
end
|
|
234
|
+
when TrueClass then '1'
|
|
235
|
+
when FalseClass then '0'
|
|
236
|
+
else super
|
|
133
237
|
end
|
|
238
|
+
end
|
|
134
239
|
|
|
135
|
-
|
|
136
|
-
|
|
240
|
+
# @override
|
|
241
|
+
def quoted_date(value)
|
|
242
|
+
if value.respond_to?(:usec)
|
|
243
|
+
"#{super}.#{sprintf("%03d", value.usec / 1000)}"
|
|
244
|
+
else
|
|
245
|
+
super
|
|
137
246
|
end
|
|
247
|
+
end
|
|
138
248
|
|
|
139
|
-
|
|
140
|
-
|
|
249
|
+
# @private
|
|
250
|
+
def quoted_time(value)
|
|
251
|
+
if value.acts_like?(:time)
|
|
252
|
+
tz_value = get_time(value)
|
|
253
|
+
usec = value.respond_to?(:usec) ? ( value.usec / 1000 ) : 0
|
|
254
|
+
sprintf("%02d:%02d:%02d.%03d", tz_value.hour, tz_value.min, tz_value.sec, usec)
|
|
255
|
+
else
|
|
256
|
+
quoted_date(value)
|
|
141
257
|
end
|
|
258
|
+
end
|
|
142
259
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
time_array[1] ||= 1
|
|
149
|
-
time_array[2] ||= 1
|
|
150
|
-
return Time.send(ActiveRecord::Base.default_timezone, *time_array) rescue nil
|
|
151
|
-
|
|
152
|
-
# Try DateTime instead - the date may be outside the time period support by Time.
|
|
153
|
-
DateTime.new(*time_array[0..5]) rescue nil
|
|
154
|
-
end
|
|
260
|
+
# @deprecated no longer used
|
|
261
|
+
# @private
|
|
262
|
+
def quoted_datetime(value)
|
|
263
|
+
quoted_date(value)
|
|
264
|
+
end
|
|
155
265
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
266
|
+
# @deprecated no longer used
|
|
267
|
+
# @private
|
|
268
|
+
def quoted_full_iso8601(value)
|
|
269
|
+
if value.acts_like?(:time)
|
|
270
|
+
value.is_a?(Date) ?
|
|
271
|
+
get_time(value).to_time.xmlschema.to(18) :
|
|
272
|
+
get_time(value).iso8601(7).to(22)
|
|
273
|
+
else
|
|
274
|
+
quoted_date(value)
|
|
159
275
|
end
|
|
276
|
+
end
|
|
160
277
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
return value
|
|
165
|
-
else
|
|
166
|
-
return Time.mktime(2000, 1, 1, value.hour, value.min, value.sec) rescue nil
|
|
167
|
-
end
|
|
168
|
-
end
|
|
169
|
-
if value.is_a?(DateTime)
|
|
170
|
-
begin
|
|
171
|
-
# Attempt to convert back to a Time, but it could fail for dates significantly in the past/future.
|
|
172
|
-
return Time.mktime(value.year, value.mon, value.day, value.hour, value.min, value.sec)
|
|
173
|
-
rescue ArgumentError
|
|
174
|
-
return value
|
|
175
|
-
end
|
|
176
|
-
end
|
|
278
|
+
def quote_table_name(name)
|
|
279
|
+
quote_column_name(name)
|
|
280
|
+
end
|
|
177
281
|
|
|
178
|
-
|
|
282
|
+
def quote_column_name(name)
|
|
283
|
+
name = name.to_s.split('.')
|
|
284
|
+
name.map! { |n| quote_name_part(n) } # "[#{name}]"
|
|
285
|
+
name.join('.')
|
|
286
|
+
end
|
|
179
287
|
|
|
180
|
-
|
|
181
|
-
|
|
288
|
+
def quote_database_name(name)
|
|
289
|
+
quote_name_part(name.to_s)
|
|
290
|
+
end
|
|
182
291
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
292
|
+
# Does not quote function default values for UUID columns
|
|
293
|
+
def quote_default_value(value, column)
|
|
294
|
+
if column.type == :uuid && value =~ /\(\)/
|
|
295
|
+
value
|
|
296
|
+
else
|
|
297
|
+
quote(value)
|
|
187
298
|
end
|
|
188
|
-
|
|
189
299
|
end
|
|
190
300
|
|
|
191
|
-
|
|
192
|
-
return value.quoted_id if value.respond_to?(:quoted_id)
|
|
301
|
+
ADAPTER_NAME = 'MSSQL'.freeze
|
|
193
302
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
"N'#{quote_string(value)}'" # ' (for ruby-mode)
|
|
206
|
-
else
|
|
207
|
-
super
|
|
303
|
+
def adapter_name
|
|
304
|
+
ADAPTER_NAME
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
def change_order_direction(order)
|
|
308
|
+
asc, desc = /\bASC\b/i, /\bDESC\b/i
|
|
309
|
+
order.split(",").collect do |fragment|
|
|
310
|
+
case fragment
|
|
311
|
+
when desc then fragment.gsub(desc, "ASC")
|
|
312
|
+
when asc then fragment.gsub(asc, "DESC")
|
|
313
|
+
else "#{fragment.split(',').join(' DESC,')} DESC"
|
|
208
314
|
end
|
|
209
|
-
|
|
210
|
-
when FalseClass then '0'
|
|
211
|
-
else super
|
|
212
|
-
end
|
|
315
|
+
end.join(",")
|
|
213
316
|
end
|
|
214
317
|
|
|
215
|
-
|
|
216
|
-
|
|
318
|
+
# @override
|
|
319
|
+
def supports_ddl_transactions?; true end
|
|
320
|
+
|
|
321
|
+
# @override
|
|
322
|
+
def supports_views?; true end
|
|
323
|
+
|
|
324
|
+
def tables(schema = current_schema)
|
|
325
|
+
@connection.tables(nil, schema)
|
|
217
326
|
end
|
|
218
327
|
|
|
219
|
-
|
|
220
|
-
|
|
328
|
+
# NOTE: Dynamic Name Resolution - SQL Server 2000 vs. 2005
|
|
329
|
+
#
|
|
330
|
+
# A query such as "select * from table1" in SQL Server 2000 goes through
|
|
331
|
+
# a set of steps to resolve and validate the object references before
|
|
332
|
+
# execution.
|
|
333
|
+
# The search first looks at the identity of the connection executing
|
|
334
|
+
# the query.
|
|
335
|
+
#
|
|
336
|
+
# However SQL Server 2005 provides a mechanism to allow finer control over
|
|
337
|
+
# name resolution to the administrators. By manipulating the value of the
|
|
338
|
+
# default_schema_name columns in the sys.database_principals.
|
|
339
|
+
#
|
|
340
|
+
# http://blogs.msdn.com/b/mssqlisv/archive/2007/03/23/upgrading-to-sql-server-2005-and-default-schema-setting.aspx
|
|
341
|
+
|
|
342
|
+
# Returns the default schema (to be used for table resolution) used for the {#current_user}.
|
|
343
|
+
def default_schema
|
|
344
|
+
return current_user if sqlserver_2000?
|
|
345
|
+
@default_schema ||=
|
|
346
|
+
@connection.execute_query_raw(
|
|
347
|
+
"SELECT default_schema_name FROM sys.database_principals WHERE name = CURRENT_USER"
|
|
348
|
+
).first['default_schema_name']
|
|
221
349
|
end
|
|
350
|
+
alias_method :current_schema, :default_schema
|
|
222
351
|
|
|
223
|
-
|
|
224
|
-
|
|
352
|
+
# Allows for changing of the default schema (to be used during unqualified
|
|
353
|
+
# table name resolution).
|
|
354
|
+
# @note This is not supported on SQL Server 2000 !
|
|
355
|
+
def default_schema=(default_schema) # :nodoc:
|
|
356
|
+
raise "changing DEFAULT_SCHEMA only supported on SQLServer 2005+" if sqlserver_2000?
|
|
357
|
+
execute("ALTER #{current_user} WITH DEFAULT_SCHEMA=#{default_schema}")
|
|
358
|
+
@default_schema = nil if defined?(@default_schema)
|
|
225
359
|
end
|
|
360
|
+
alias_method :current_schema=, :default_schema=
|
|
226
361
|
|
|
227
|
-
|
|
228
|
-
|
|
362
|
+
# `SELECT CURRENT_USER`
|
|
363
|
+
def current_user
|
|
364
|
+
@current_user ||= @connection.execute_query_raw("SELECT CURRENT_USER").first['']
|
|
229
365
|
end
|
|
230
366
|
|
|
231
|
-
def
|
|
232
|
-
|
|
367
|
+
def charset
|
|
368
|
+
select_value "SELECT SERVERPROPERTY('SqlCharSetName')"
|
|
233
369
|
end
|
|
234
370
|
|
|
235
|
-
def
|
|
236
|
-
'
|
|
371
|
+
def collation
|
|
372
|
+
select_value "SELECT SERVERPROPERTY('Collation')"
|
|
237
373
|
end
|
|
238
374
|
|
|
239
|
-
def
|
|
240
|
-
|
|
241
|
-
case fragment
|
|
242
|
-
when /\bDESC\b/i then fragment.gsub(/\bDESC\b/i, "ASC")
|
|
243
|
-
when /\bASC\b/i then fragment.gsub(/\bASC\b/i, "DESC")
|
|
244
|
-
else String.new(fragment).split(',').join(' DESC,') + ' DESC'
|
|
245
|
-
end
|
|
246
|
-
end.join(",")
|
|
375
|
+
def current_database
|
|
376
|
+
select_value 'SELECT DB_NAME()'
|
|
247
377
|
end
|
|
248
378
|
|
|
249
|
-
def
|
|
250
|
-
|
|
379
|
+
def use_database(database = nil)
|
|
380
|
+
database ||= config[:database]
|
|
381
|
+
execute "USE #{quote_database_name(database)}" unless database.blank?
|
|
251
382
|
end
|
|
252
383
|
|
|
253
|
-
|
|
384
|
+
# @private
|
|
385
|
+
def recreate_database(name, options = {})
|
|
254
386
|
drop_database(name)
|
|
255
|
-
create_database(name)
|
|
387
|
+
create_database(name, options)
|
|
388
|
+
end
|
|
389
|
+
|
|
390
|
+
# @private
|
|
391
|
+
def recreate_database!(database = nil)
|
|
392
|
+
current_db = current_database
|
|
393
|
+
database ||= current_db
|
|
394
|
+
use_database('master') if this_db = ( database.to_s == current_db )
|
|
395
|
+
drop_database(database)
|
|
396
|
+
create_database(database)
|
|
397
|
+
ensure
|
|
398
|
+
use_database(current_db) if this_db
|
|
256
399
|
end
|
|
257
400
|
|
|
258
401
|
def drop_database(name)
|
|
259
|
-
|
|
260
|
-
|
|
402
|
+
current_db = current_database
|
|
403
|
+
use_database('master') if current_db.to_s == name
|
|
404
|
+
execute "DROP DATABASE #{quote_database_name(name)}"
|
|
405
|
+
end
|
|
406
|
+
|
|
407
|
+
def create_database(name, options = {})
|
|
408
|
+
execute "CREATE DATABASE #{quote_database_name(name)}"
|
|
261
409
|
end
|
|
262
410
|
|
|
263
|
-
def
|
|
264
|
-
|
|
265
|
-
execute "USE #{name}"
|
|
411
|
+
def database_exists?(name)
|
|
412
|
+
select_value "SELECT name FROM sys.databases WHERE name = '#{name}'"
|
|
266
413
|
end
|
|
267
414
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
415
|
+
# @override
|
|
416
|
+
def rename_table(table_name, new_table_name)
|
|
417
|
+
clear_cached_table(table_name)
|
|
418
|
+
execute "EXEC sp_rename '#{table_name}', '#{new_table_name}'"
|
|
271
419
|
end
|
|
272
420
|
|
|
273
421
|
# Adds a new column to the named table.
|
|
274
|
-
#
|
|
422
|
+
# @override
|
|
275
423
|
def add_column(table_name, column_name, type, options = {})
|
|
276
424
|
clear_cached_table(table_name)
|
|
277
|
-
add_column_sql = "ALTER TABLE #{table_name} ADD #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
|
|
425
|
+
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])}"
|
|
278
426
|
add_column_options!(add_column_sql, options)
|
|
279
427
|
# TODO: Add support to mimic date columns, using constraints to mark them as such in the database
|
|
280
428
|
# add_column_sql << " CONSTRAINT ck__#{table_name}__#{column_name}__date_only CHECK ( CONVERT(CHAR(12), #{quote_column_name(column_name)}, 14)='00:00:00:000' )" if type == :date
|
|
281
429
|
execute(add_column_sql)
|
|
282
430
|
end
|
|
283
431
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
432
|
+
# @override
|
|
433
|
+
def rename_column(table_name, column_name, new_column_name)
|
|
434
|
+
clear_cached_table(table_name)
|
|
435
|
+
execute "EXEC sp_rename '#{table_name}.#{column_name}', '#{new_column_name}', 'COLUMN'"
|
|
436
|
+
end
|
|
437
|
+
|
|
438
|
+
# SELECT DISTINCT clause for a given set of columns and a given ORDER BY clause.
|
|
439
|
+
# MSSQL requires the ORDER BY columns in the select list for distinct queries.
|
|
440
|
+
def distinct(columns, order_by)
|
|
441
|
+
"DISTINCT #{columns_for_distinct(columns, order_by)}"
|
|
287
442
|
end
|
|
288
443
|
|
|
289
|
-
def
|
|
290
|
-
|
|
444
|
+
def columns_for_distinct(columns, orders)
|
|
445
|
+
return columns if orders.blank?
|
|
446
|
+
|
|
447
|
+
# construct a clean list of column names from the ORDER BY clause,
|
|
448
|
+
# removing any ASC/DESC modifiers
|
|
449
|
+
order_columns = [ orders ]; order_columns.flatten! # AR 3.x vs 4.x
|
|
450
|
+
order_columns.map! do |column|
|
|
451
|
+
column = column.to_sql unless column.is_a?(String) # handle AREL node
|
|
452
|
+
column.split(',').collect!{ |s| s.split.first }
|
|
453
|
+
end.flatten!
|
|
454
|
+
order_columns.reject!(&:blank?)
|
|
455
|
+
order_columns = order_columns.zip(0...order_columns.size).to_a
|
|
456
|
+
order_columns = order_columns.map{ |s, i| "#{s}" }
|
|
457
|
+
|
|
458
|
+
columns = [ columns ]; columns.flatten!
|
|
459
|
+
columns.push( *order_columns ).join(', ')
|
|
460
|
+
# return a DISTINCT clause that's distinct on the columns we want but
|
|
461
|
+
# includes all the required columns for the ORDER BY to work properly
|
|
462
|
+
end
|
|
463
|
+
|
|
464
|
+
# @override
|
|
465
|
+
def change_column(table_name, column_name, type, options = {})
|
|
466
|
+
column = columns(table_name).find { |c| c.name.to_s == column_name.to_s }
|
|
467
|
+
|
|
468
|
+
indexes = EMPTY_ARRAY
|
|
469
|
+
if options_include_default?(options) || (column && column.type != type.to_sym)
|
|
470
|
+
remove_default_constraint(table_name, column_name)
|
|
471
|
+
indexes = indexes(table_name).select{ |index| index.columns.include?(column_name.to_s) }
|
|
472
|
+
remove_indexes(table_name, column_name)
|
|
473
|
+
end
|
|
474
|
+
|
|
475
|
+
if ! options[:null].nil? && options[:null] == false && ! options[:default].nil?
|
|
476
|
+
execute "UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote_default_value(options[:default], column)} WHERE #{quote_column_name(column_name)} IS NULL"
|
|
477
|
+
clear_cached_table(table_name)
|
|
478
|
+
end
|
|
291
479
|
change_column_type(table_name, column_name, type, options)
|
|
292
480
|
change_column_default(table_name, column_name, options[:default]) if options_include_default?(options)
|
|
293
|
-
end
|
|
294
481
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
if options.has_key?(:null)
|
|
299
|
-
sql += (options[:null] ? " NULL" : " NOT NULL")
|
|
482
|
+
indexes.each do |index| # add any removed indexes back
|
|
483
|
+
index_columns = index.columns.map { |c| quote_column_name(c) }.join(', ')
|
|
484
|
+
execute "CREATE INDEX #{quote_table_name(index.name)} ON #{quote_table_name(table_name)} (#{index_columns})"
|
|
300
485
|
end
|
|
301
|
-
execute(sql)
|
|
302
486
|
end
|
|
303
487
|
|
|
304
|
-
def
|
|
488
|
+
def change_column_type(table_name, column_name, type, options = {})
|
|
489
|
+
sql = "ALTER TABLE #{quote_table_name(table_name)} ALTER COLUMN #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
|
|
490
|
+
sql << (options[:null] ? " NULL" : " NOT NULL") if options.has_key?(:null)
|
|
491
|
+
result = execute(sql)
|
|
305
492
|
clear_cached_table(table_name)
|
|
493
|
+
result
|
|
494
|
+
end
|
|
495
|
+
|
|
496
|
+
def change_column_default(table_name, column_name, default)
|
|
306
497
|
remove_default_constraint(table_name, column_name)
|
|
307
498
|
unless default.nil?
|
|
308
|
-
|
|
499
|
+
column = columns(table_name).find { |c| c.name.to_s == column_name.to_s }
|
|
500
|
+
result = execute "ALTER TABLE #{quote_table_name(table_name)} ADD CONSTRAINT DF_#{table_name}_#{column_name} DEFAULT #{quote_default_value(default, column)} FOR #{quote_column_name(column_name)}"
|
|
501
|
+
clear_cached_table(table_name)
|
|
502
|
+
result
|
|
309
503
|
end
|
|
310
504
|
end
|
|
311
505
|
|
|
312
|
-
def
|
|
506
|
+
def remove_columns(table_name, *column_names)
|
|
507
|
+
raise ArgumentError.new("You must specify at least one column name. Example: remove_column(:people, :first_name)") if column_names.empty?
|
|
508
|
+
# remove_columns(:posts, :foo, :bar) old syntax : remove_columns(:posts, [:foo, :bar])
|
|
313
509
|
clear_cached_table(table_name)
|
|
510
|
+
|
|
511
|
+
column_names = column_names.flatten
|
|
512
|
+
return do_remove_column(table_name, column_names.first) if column_names.size == 1
|
|
513
|
+
column_names.each { |column_name| do_remove_column(table_name, column_name) }
|
|
514
|
+
end
|
|
515
|
+
|
|
516
|
+
def do_remove_column(table_name, column_name)
|
|
314
517
|
remove_check_constraints(table_name, column_name)
|
|
315
518
|
remove_default_constraint(table_name, column_name)
|
|
316
|
-
|
|
519
|
+
remove_indexes(table_name, column_name) unless sqlserver_2000?
|
|
520
|
+
execute "ALTER TABLE #{quote_table_name(table_name)} DROP COLUMN #{quote_column_name(column_name)}"
|
|
521
|
+
end
|
|
522
|
+
private :do_remove_column
|
|
523
|
+
|
|
524
|
+
if ActiveRecord::VERSION::MAJOR >= 4
|
|
525
|
+
|
|
526
|
+
# @override
|
|
527
|
+
def remove_column(table_name, column_name, type = nil, options = {})
|
|
528
|
+
remove_columns(table_name, column_name)
|
|
529
|
+
end
|
|
530
|
+
|
|
531
|
+
else
|
|
532
|
+
|
|
533
|
+
def remove_column(table_name, *column_names); remove_columns(table_name, *column_names) end
|
|
534
|
+
|
|
317
535
|
end
|
|
318
536
|
|
|
319
537
|
def remove_default_constraint(table_name, column_name)
|
|
320
538
|
clear_cached_table(table_name)
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
539
|
+
if sqlserver_2000?
|
|
540
|
+
# NOTE: since SQLServer 2005 these are provided as sys.sysobjects etc.
|
|
541
|
+
# but only due backwards-compatibility views and should be avoided ...
|
|
542
|
+
defaults = select_values "SELECT d.name" <<
|
|
543
|
+
" FROM sysobjects d, syscolumns c, sysobjects t" <<
|
|
544
|
+
" WHERE c.cdefault = d.id AND c.name = '#{column_name}'" <<
|
|
545
|
+
" AND t.name = '#{table_name}' AND c.id = t.id"
|
|
546
|
+
else
|
|
547
|
+
defaults = select_values "SELECT d.name FROM sys.tables t" <<
|
|
548
|
+
" JOIN sys.default_constraints d ON d.parent_object_id = t.object_id" <<
|
|
549
|
+
" JOIN sys.columns c ON c.object_id = t.object_id AND c.column_id = d.parent_column_id" <<
|
|
550
|
+
" WHERE t.name = '#{table_name}' AND c.name = '#{column_name}'"
|
|
551
|
+
end
|
|
552
|
+
defaults.each do |def_name|
|
|
553
|
+
execute "ALTER TABLE #{table_name} DROP CONSTRAINT #{def_name}"
|
|
554
|
+
end
|
|
325
555
|
end
|
|
326
556
|
|
|
327
557
|
def remove_check_constraints(table_name, column_name)
|
|
328
558
|
clear_cached_table(table_name)
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
559
|
+
constraints = select_values "SELECT constraint_name" <<
|
|
560
|
+
" FROM information_schema.constraint_column_usage" <<
|
|
561
|
+
" WHERE table_name = '#{table_name}' AND column_name = '#{column_name}'"
|
|
562
|
+
constraints.each do |constraint_name|
|
|
563
|
+
execute "ALTER TABLE #{table_name} DROP CONSTRAINT #{constraint_name}"
|
|
564
|
+
end
|
|
565
|
+
end
|
|
566
|
+
|
|
567
|
+
def remove_indexes(table_name, column_name)
|
|
568
|
+
indexes = self.indexes(table_name)
|
|
569
|
+
indexes.select{ |index| index.columns.include?(column_name.to_s) }.each do |index|
|
|
570
|
+
remove_index(table_name, { :name => index.name })
|
|
333
571
|
end
|
|
334
572
|
end
|
|
335
573
|
|
|
336
574
|
def remove_index(table_name, options = {})
|
|
337
|
-
execute "DROP INDEX #{table_name}.#{index_name(table_name, options)}"
|
|
575
|
+
execute "DROP INDEX #{quote_table_name(table_name)}.#{index_name(table_name, options)}"
|
|
338
576
|
end
|
|
339
577
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
# which doesn't involve a table. IE. "SELECT 1" or "SELECT * from someFunction()".
|
|
343
|
-
return [] if table_name.blank?
|
|
344
|
-
table_name = table_name.to_s if table_name.is_a?(Symbol)
|
|
578
|
+
# @private
|
|
579
|
+
SKIP_COLUMNS_TABLE_NAMES_RE = /^information_schema\./i
|
|
345
580
|
|
|
346
|
-
|
|
347
|
-
|
|
581
|
+
# @private
|
|
582
|
+
EMPTY_ARRAY = [].freeze
|
|
348
583
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
col.identity = true if col.sql_type =~ /identity/i
|
|
355
|
-
col.is_special = true if col.sql_type =~ /text|ntext|image|xml/i
|
|
356
|
-
end
|
|
357
|
-
end
|
|
358
|
-
@table_columns[table_name]
|
|
359
|
-
end
|
|
584
|
+
def columns(table_name, name = nil, default = EMPTY_ARRAY)
|
|
585
|
+
# It's possible for table_name to be an empty string, or nil, if something
|
|
586
|
+
# attempts to issue SQL which doesn't involve a table.
|
|
587
|
+
# IE. "SELECT 1" or "SELECT * FROM someFunction()".
|
|
588
|
+
return default if table_name.blank?
|
|
360
589
|
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
table_name = get_table_name(sql)
|
|
368
|
-
with_identity_insert_enabled(table_name) do
|
|
369
|
-
id = @connection.execute_insert(sql)
|
|
370
|
-
end
|
|
371
|
-
else
|
|
372
|
-
@connection.execute_insert(sql)
|
|
373
|
-
end
|
|
374
|
-
elsif sql.lstrip =~ /\A(create|exec)/i
|
|
375
|
-
@connection.execute_update(sql)
|
|
376
|
-
elsif sql.lstrip =~ /\A\(?\s*(select|show)/i
|
|
377
|
-
repair_special_columns(sql)
|
|
378
|
-
@connection.execute_query(sql)
|
|
379
|
-
else
|
|
380
|
-
@connection.execute_update(sql)
|
|
590
|
+
table_name = unquote_table_name(table_name)
|
|
591
|
+
|
|
592
|
+
return default if table_name =~ SKIP_COLUMNS_TABLE_NAMES_RE
|
|
593
|
+
|
|
594
|
+
unless columns = ( @table_columns ||= {} )[table_name]
|
|
595
|
+
@table_columns[table_name] = columns = super(table_name, name)
|
|
381
596
|
end
|
|
597
|
+
columns
|
|
382
598
|
end
|
|
383
599
|
|
|
384
|
-
def
|
|
385
|
-
|
|
386
|
-
@connection.execute_query(sql)
|
|
387
|
-
end
|
|
600
|
+
def clear_cached_table(table_name)
|
|
601
|
+
( @table_columns ||= {} ).delete(table_name.to_s)
|
|
388
602
|
end
|
|
389
603
|
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
sql
|
|
604
|
+
def reset_column_information
|
|
605
|
+
@table_columns = nil if defined? @table_columns
|
|
393
606
|
end
|
|
394
607
|
|
|
395
608
|
# Turns IDENTITY_INSERT ON for table during execution of the block
|
|
396
609
|
# N.B. This sets the state of IDENTITY_INSERT to OFF after the
|
|
397
610
|
# block has been executed without regard to its previous state
|
|
398
|
-
def with_identity_insert_enabled(table_name
|
|
611
|
+
def with_identity_insert_enabled(table_name)
|
|
399
612
|
set_identity_insert(table_name, true)
|
|
400
613
|
yield
|
|
401
614
|
ensure
|
|
@@ -405,68 +618,187 @@ module ::ArJdbc
|
|
|
405
618
|
def set_identity_insert(table_name, enable = true)
|
|
406
619
|
execute "SET IDENTITY_INSERT #{table_name} #{enable ? 'ON' : 'OFF'}"
|
|
407
620
|
rescue Exception => e
|
|
408
|
-
raise ActiveRecord::ActiveRecordError, "IDENTITY_INSERT could not be turned
|
|
621
|
+
raise ActiveRecord::ActiveRecordError, "IDENTITY_INSERT could not be turned" +
|
|
622
|
+
" #{enable ? 'ON' : 'OFF'} for table #{table_name} due : #{e.inspect}"
|
|
623
|
+
end
|
|
624
|
+
|
|
625
|
+
def disable_referential_integrity
|
|
626
|
+
execute "EXEC sp_MSforeachtable 'ALTER TABLE ? NOCHECK CONSTRAINT ALL'"
|
|
627
|
+
yield
|
|
628
|
+
ensure
|
|
629
|
+
execute "EXEC sp_MSforeachtable 'ALTER TABLE ? CHECK CONSTRAINT ALL'"
|
|
409
630
|
end
|
|
410
631
|
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
632
|
+
# @private
|
|
633
|
+
# @see ArJdbc::MSSQL::LimitHelpers
|
|
634
|
+
def determine_order_clause(sql)
|
|
635
|
+
return $1 if sql =~ /ORDER BY (.*)$/i
|
|
636
|
+
columns = self.columns(table_name = get_table_name(sql))
|
|
637
|
+
primary_column = columns.find { |column| column.primary? || column.identity? }
|
|
638
|
+
unless primary_column # look for an id column and return it,
|
|
639
|
+
# without changing case, to cover DBs with a case-sensitive collation :
|
|
640
|
+
primary_column = columns.find { |column| column.name =~ /^id$/i }
|
|
641
|
+
raise "no columns for table: #{table_name} (SQL query: ' #{sql} ')" if columns.empty?
|
|
414
642
|
end
|
|
415
|
-
|
|
643
|
+
# NOTE: if still no PK column simply get something for ORDER BY ...
|
|
644
|
+
"#{quote_table_name(table_name)}.#{quote_column_name((primary_column || columns.first).name)}"
|
|
416
645
|
end
|
|
417
646
|
|
|
418
|
-
def
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
647
|
+
def truncate(table_name, name = nil)
|
|
648
|
+
execute "TRUNCATE TABLE #{quote_table_name(table_name)}", name
|
|
649
|
+
end
|
|
650
|
+
|
|
651
|
+
# Support for executing a stored procedure.
|
|
652
|
+
def exec_proc(proc_name, *variables)
|
|
653
|
+
vars =
|
|
654
|
+
if variables.any? && variables.first.is_a?(Hash)
|
|
655
|
+
variables.first.map { |k, v| "@#{k} = #{quote(v)}" }
|
|
656
|
+
else
|
|
657
|
+
variables.map { |v| quote(v) }
|
|
658
|
+
end.join(', ')
|
|
659
|
+
sql = "EXEC #{proc_name} #{vars}".strip
|
|
660
|
+
log(sql, 'Execute Procedure') do
|
|
661
|
+
result = @connection.execute_query_raw(sql)
|
|
662
|
+
result.map! do |row|
|
|
663
|
+
row = row.is_a?(Hash) ? row.with_indifferent_access : row
|
|
664
|
+
yield(row) if block_given?
|
|
665
|
+
row
|
|
666
|
+
end
|
|
667
|
+
result
|
|
424
668
|
end
|
|
425
669
|
end
|
|
670
|
+
alias_method :execute_procedure, :exec_proc # AR-SQLServer-Adapter naming
|
|
426
671
|
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
672
|
+
# @override
|
|
673
|
+
def exec_query(sql, name = 'SQL', binds = [])
|
|
674
|
+
# NOTE: we allow to execute SQL as requested returning a results.
|
|
675
|
+
# e.g. this allows to use SQLServer's EXEC with a result set ...
|
|
676
|
+
sql = to_sql(sql, binds) if sql.respond_to?(:to_sql)
|
|
677
|
+
|
|
678
|
+
sql = repair_special_columns(sql)
|
|
679
|
+
if prepared_statements?
|
|
680
|
+
log(sql, name, binds) { @connection.execute_query(sql, binds) }
|
|
430
681
|
else
|
|
431
|
-
name
|
|
682
|
+
log(sql, name) { @connection.execute_query(sql) }
|
|
432
683
|
end
|
|
433
684
|
end
|
|
434
685
|
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
686
|
+
# @override
|
|
687
|
+
def exec_query_raw(sql, name = 'SQL', binds = [], &block)
|
|
688
|
+
sql = to_sql(sql, binds) if sql.respond_to?(:to_sql)
|
|
689
|
+
|
|
690
|
+
sql = repair_special_columns(sql)
|
|
691
|
+
if prepared_statements?
|
|
692
|
+
log(sql, name, binds) { @connection.execute_query_raw(sql, binds, &block) }
|
|
693
|
+
else
|
|
694
|
+
log(sql, name) { @connection.execute_query_raw(sql, &block) }
|
|
439
695
|
end
|
|
440
|
-
special
|
|
441
696
|
end
|
|
442
697
|
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
698
|
+
# @override
|
|
699
|
+
def release_savepoint(name = current_savepoint_name(false))
|
|
700
|
+
if @connection.jtds_driver?
|
|
701
|
+
@connection.release_savepoint(name)
|
|
702
|
+
else # MS invented it's "own" way
|
|
703
|
+
@connection.rollback_savepoint(name)
|
|
448
704
|
end
|
|
449
|
-
sql
|
|
450
705
|
end
|
|
451
706
|
|
|
452
|
-
|
|
453
|
-
|
|
707
|
+
private
|
|
708
|
+
|
|
709
|
+
def _execute(sql, name = nil)
|
|
710
|
+
# Match the start of the SQL to determine appropriate behavior.
|
|
711
|
+
# Be aware of multi-line SQL which might begin with 'create stored_proc'
|
|
712
|
+
# and contain 'insert into ...' lines.
|
|
713
|
+
# NOTE: ignoring comment blocks prior to the first statement ?!
|
|
714
|
+
if self.class.insert?(sql)
|
|
715
|
+
if id_insert_table_name = identity_insert_table_name(sql)
|
|
716
|
+
with_identity_insert_enabled(id_insert_table_name) do
|
|
717
|
+
@connection.execute_insert(sql)
|
|
718
|
+
end
|
|
719
|
+
else
|
|
720
|
+
@connection.execute_insert(sql)
|
|
721
|
+
end
|
|
722
|
+
elsif self.class.select?(sql)
|
|
723
|
+
@connection.execute_query_raw repair_special_columns(sql)
|
|
724
|
+
else # create | exec
|
|
725
|
+
@connection.execute_update(sql)
|
|
726
|
+
end
|
|
727
|
+
end
|
|
728
|
+
|
|
729
|
+
def identity_insert_table_name(sql)
|
|
454
730
|
table_name = get_table_name(sql)
|
|
455
|
-
|
|
731
|
+
id_column = identity_column_name(table_name)
|
|
732
|
+
if id_column && sql.strip =~ /INSERT INTO [^ ]+ ?\((.+?)\)/i
|
|
733
|
+
insert_columns = $1.split(/, */).map(&method(:unquote_column_name))
|
|
734
|
+
return table_name if insert_columns.include?(id_column)
|
|
735
|
+
end
|
|
736
|
+
end
|
|
737
|
+
|
|
738
|
+
def identity_column_name(table_name)
|
|
739
|
+
for column in columns(table_name)
|
|
740
|
+
return column.name if column.identity
|
|
741
|
+
end
|
|
742
|
+
nil
|
|
456
743
|
end
|
|
457
744
|
|
|
458
|
-
def
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
745
|
+
def repair_special_columns(sql)
|
|
746
|
+
qualified_table_name = get_table_name(sql, true)
|
|
747
|
+
if special_columns = special_column_names(qualified_table_name)
|
|
748
|
+
return sql if special_columns.empty?
|
|
749
|
+
special_columns = special_columns.sort { |n1, n2| n2.size <=> n1.size }
|
|
750
|
+
for column in special_columns
|
|
751
|
+
sql.gsub!(/\s?\[?#{column}\]?\s?=\s?/, " [#{column}] LIKE ")
|
|
752
|
+
sql.gsub!(/ORDER BY \[?#{column}([^\.\w]|$)\]?/i, '') # NOTE: a bit stupid
|
|
753
|
+
end
|
|
754
|
+
end
|
|
755
|
+
sql
|
|
465
756
|
end
|
|
466
757
|
|
|
467
|
-
def
|
|
468
|
-
|
|
758
|
+
def special_column_names(qualified_table_name)
|
|
759
|
+
columns = self.columns(qualified_table_name, nil, nil)
|
|
760
|
+
return columns if ! columns || columns.empty?
|
|
761
|
+
special = []
|
|
762
|
+
columns.each { |column| special << column.name if column.special? }
|
|
763
|
+
special
|
|
469
764
|
end
|
|
765
|
+
|
|
766
|
+
def sqlserver_2000?
|
|
767
|
+
sqlserver_version <= '2000'
|
|
768
|
+
end
|
|
769
|
+
|
|
470
770
|
end
|
|
471
771
|
end
|
|
472
772
|
|
|
773
|
+
require 'arjdbc/util/quoted_cache'
|
|
774
|
+
|
|
775
|
+
module ActiveRecord::ConnectionAdapters
|
|
776
|
+
|
|
777
|
+
class MSSQLAdapter < JdbcAdapter
|
|
778
|
+
include ::ArJdbc::MSSQL
|
|
779
|
+
include ::ArJdbc::Util::QuotedCache
|
|
780
|
+
|
|
781
|
+
def initialize(*args)
|
|
782
|
+
::ArJdbc::MSSQL.initialize!
|
|
783
|
+
|
|
784
|
+
super # configure_connection happens in super
|
|
785
|
+
|
|
786
|
+
setup_limit_offset!
|
|
787
|
+
end
|
|
788
|
+
|
|
789
|
+
def arel_visitor # :nodoc:
|
|
790
|
+
( config && config[:sqlserver_version].to_s == '2000' ) ?
|
|
791
|
+
::Arel::Visitors::SQLServer2000.new(self) :
|
|
792
|
+
::Arel::Visitors::SQLServer.new(self)
|
|
793
|
+
end
|
|
794
|
+
|
|
795
|
+
def self.cs_equality_operator; ::ArJdbc::MSSQL.cs_equality_operator end
|
|
796
|
+
def self.cs_equality_operator=(operator); ::ArJdbc::MSSQL.cs_equality_operator = operator end
|
|
797
|
+
|
|
798
|
+
end
|
|
799
|
+
|
|
800
|
+
class MSSQLColumn < JdbcColumn
|
|
801
|
+
include ::ArJdbc::MSSQL::Column
|
|
802
|
+
end
|
|
803
|
+
|
|
804
|
+
end
|