activerecord-jdbc-adapter 1.3.0.beta2 → 1.3.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +14 -8
- data/.travis.yml +40 -31
- data/.yardopts +4 -0
- data/Appraisals +2 -5
- data/CONTRIBUTING.md +46 -0
- data/Gemfile +21 -4
- data/Gemfile.lock +42 -17
- data/{History.txt → History.md} +142 -75
- data/README.md +102 -104
- data/RUNNING_TESTS.md +76 -0
- data/Rakefile.jdbc +20 -0
- data/activerecord-jdbc-adapter.gemspec +35 -18
- data/gemfiles/rails23.gemfile +4 -3
- data/gemfiles/rails23.gemfile.lock +9 -6
- data/gemfiles/rails30.gemfile +4 -3
- data/gemfiles/rails30.gemfile.lock +9 -6
- data/gemfiles/rails31.gemfile +4 -3
- data/gemfiles/rails31.gemfile.lock +9 -6
- data/gemfiles/rails32.gemfile +4 -3
- data/gemfiles/rails32.gemfile.lock +17 -14
- data/gemfiles/rails40.gemfile +5 -5
- data/gemfiles/rails40.gemfile.lock +17 -69
- data/lib/active_record/connection_adapters/firebird_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +1 -0
- data/lib/arel/visitors/compat.rb +22 -3
- data/lib/arel/visitors/db2.rb +8 -4
- data/lib/arel/visitors/derby.rb +14 -13
- data/lib/arel/visitors/firebird.rb +5 -4
- data/lib/arel/visitors/hsqldb.rb +11 -9
- data/lib/arel/visitors/sql_server.rb +89 -61
- data/lib/arjdbc.rb +1 -1
- data/lib/arjdbc/db2/adapter.rb +181 -212
- data/lib/arjdbc/db2/as400.rb +31 -18
- data/lib/arjdbc/db2/column.rb +167 -0
- data/lib/arjdbc/db2/connection_methods.rb +2 -0
- data/lib/arjdbc/derby/adapter.rb +206 -107
- data/lib/arjdbc/derby/connection_methods.rb +4 -9
- data/lib/arjdbc/firebird.rb +1 -0
- data/lib/arjdbc/firebird/adapter.rb +202 -64
- data/lib/arjdbc/firebird/connection_methods.rb +20 -0
- data/lib/arjdbc/h2/adapter.rb +56 -36
- data/lib/arjdbc/hsqldb/adapter.rb +99 -68
- data/lib/arjdbc/jdbc/adapter.rb +474 -265
- data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
- data/lib/arjdbc/jdbc/adapter_require.rb +8 -7
- data/lib/arjdbc/jdbc/arel_support.rb +132 -0
- data/lib/arjdbc/jdbc/base_ext.rb +8 -7
- data/lib/arjdbc/jdbc/callbacks.rb +16 -10
- data/lib/arjdbc/jdbc/column.rb +25 -3
- data/lib/arjdbc/jdbc/connection.rb +28 -55
- data/lib/arjdbc/jdbc/extension.rb +14 -14
- data/lib/arjdbc/jdbc/java.rb +6 -3
- data/lib/arjdbc/jdbc/jdbc.rake +1 -1
- data/lib/arjdbc/jdbc/quoted_primary_key.rb +2 -2
- data/lib/arjdbc/jdbc/rake_tasks.rb +1 -1
- data/lib/arjdbc/jdbc/type_converter.rb +5 -2
- data/lib/arjdbc/mssql/adapter.rb +160 -280
- data/lib/arjdbc/mssql/column.rb +182 -0
- data/lib/arjdbc/mssql/connection_methods.rb +37 -4
- data/lib/arjdbc/mssql/explain_support.rb +13 -21
- data/lib/arjdbc/mssql/limit_helpers.rb +79 -42
- data/lib/arjdbc/mssql/lock_methods.rb +77 -0
- data/lib/arjdbc/mssql/utils.rb +11 -11
- data/lib/arjdbc/mysql/adapter.rb +165 -247
- data/lib/arjdbc/mysql/column.rb +123 -0
- data/lib/arjdbc/mysql/connection_methods.rb +3 -6
- data/lib/arjdbc/oracle/adapter.rb +282 -288
- data/lib/arjdbc/oracle/column.rb +122 -0
- data/lib/arjdbc/oracle/connection_methods.rb +3 -0
- data/lib/arjdbc/postgresql/adapter.rb +336 -574
- data/lib/arjdbc/postgresql/column.rb +458 -0
- data/lib/arjdbc/postgresql/connection_methods.rb +1 -2
- data/lib/arjdbc/postgresql/schema_creation.rb +38 -0
- data/lib/arjdbc/sqlite3/adapter.rb +189 -145
- data/lib/arjdbc/sqlite3/explain_support.rb +1 -1
- data/lib/arjdbc/tasks/oracle/enhanced_structure_dump.rb +8 -8
- data/lib/arjdbc/util/quoted_cache.rb +60 -0
- data/lib/arjdbc/util/table_copier.rb +110 -0
- data/lib/arjdbc/version.rb +6 -7
- data/pom.xml +56 -2
- data/rakelib/02-test.rake +72 -83
- data/rakelib/db.rake +29 -17
- data/src/java/arjdbc/ArJdbcModule.java +21 -18
- data/src/java/arjdbc/db2/DB2RubyJdbcConnection.java +84 -12
- data/src/java/arjdbc/derby/DerbyModule.java +140 -143
- data/src/java/arjdbc/derby/DerbyRubyJdbcConnection.java +58 -7
- data/src/java/arjdbc/h2/H2Module.java +43 -0
- data/src/java/arjdbc/informix/InformixRubyJdbcConnection.java +7 -6
- data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +1223 -648
- data/src/java/arjdbc/mssql/MSSQLRubyJdbcConnection.java +24 -23
- data/src/java/arjdbc/mysql/MySQLModule.java +33 -32
- data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +147 -30
- data/src/java/arjdbc/oracle/OracleModule.java +13 -13
- data/src/java/arjdbc/oracle/OracleRubyJdbcConnection.java +114 -6
- data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +166 -36
- data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +101 -19
- data/src/java/arjdbc/util/QuotingUtils.java +19 -19
- metadata +240 -394
- data/bench/bench_attributes.rb +0 -13
- data/bench/bench_attributes_new.rb +0 -14
- data/bench/bench_create.rb +0 -12
- data/bench/bench_find_all.rb +0 -12
- data/bench/bench_find_all_mt.rb +0 -25
- data/bench/bench_model.rb +0 -85
- data/bench/bench_new.rb +0 -12
- data/bench/bench_new_valid.rb +0 -12
- data/bench/bench_valid.rb +0 -13
- 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/arjdbc/jdbc/missing_functionality_helper.rb +0 -98
- data/lib/arjdbc/mssql/lock_helpers.rb +0 -76
- data/lib/arjdbc/mssql/tsql_methods.rb +0 -58
- data/lib/arjdbc/postgresql/column_cast.rb +0 -134
- data/test/activerecord/connections/native_jdbc_mysql/connection.rb +0 -25
- data/test/activerecord/jall.sh +0 -7
- data/test/activerecord/jtest.sh +0 -3
- data/test/assets/flowers.jpg +0 -0
- data/test/binary.rb +0 -67
- data/test/db/db2.rb +0 -43
- data/test/db/db2/binary_test.rb +0 -6
- data/test/db/db2/has_many_through_test.rb +0 -6
- data/test/db/db2/rake_test.rb +0 -82
- data/test/db/db2/rake_test_data.sql +0 -35
- data/test/db/db2/reset_column_information_test.rb +0 -5
- data/test/db/db2/serialize_test.rb +0 -6
- data/test/db/db2/simple_test.rb +0 -81
- data/test/db/db2/test_helper.rb +0 -6
- data/test/db/db2/unit_test.rb +0 -73
- data/test/db/derby.rb +0 -12
- data/test/db/derby/binary_test.rb +0 -6
- data/test/db/derby/migration_test.rb +0 -74
- data/test/db/derby/rake_test.rb +0 -96
- data/test/db/derby/reset_column_information_test.rb +0 -6
- data/test/db/derby/row_locking_test.rb +0 -20
- data/test/db/derby/schema_dump_test.rb +0 -5
- data/test/db/derby/serialize_test.rb +0 -6
- data/test/db/derby/simple_test.rb +0 -173
- data/test/db/derby/test_helper.rb +0 -6
- data/test/db/derby/unit_test.rb +0 -32
- data/test/db/derby/xml_column_test.rb +0 -17
- data/test/db/h2.rb +0 -11
- data/test/db/h2/binary_test.rb +0 -6
- data/test/db/h2/change_column_test.rb +0 -68
- data/test/db/h2/identity_column_test.rb +0 -35
- data/test/db/h2/offset_test.rb +0 -49
- data/test/db/h2/rake_test.rb +0 -98
- data/test/db/h2/schema_dump_test.rb +0 -29
- data/test/db/h2/serialize_test.rb +0 -6
- data/test/db/h2/simple_test.rb +0 -56
- data/test/db/hsqldb.rb +0 -11
- data/test/db/hsqldb/binary_test.rb +0 -6
- data/test/db/hsqldb/rake_test.rb +0 -101
- data/test/db/hsqldb/schema_dump_test.rb +0 -19
- data/test/db/hsqldb/serialize_test.rb +0 -6
- data/test/db/hsqldb/simple_test.rb +0 -17
- data/test/db/informix.rb +0 -13
- data/test/db/jdbc.rb +0 -16
- data/test/db/jdbc_derby.rb +0 -14
- data/test/db/jdbc_h2.rb +0 -17
- data/test/db/jdbc_mysql.rb +0 -13
- data/test/db/jdbc_postgres.rb +0 -23
- data/test/db/jndi_config.rb +0 -32
- data/test/db/jndi_pooled_config.rb +0 -32
- data/test/db/mssql.rb +0 -11
- data/test/db/mssql/binary_test.rb +0 -6
- data/test/db/mssql/exec_proc_test.rb +0 -46
- data/test/db/mssql/identity_insert_test.rb +0 -18
- data/test/db/mssql/ignore_system_views_test.rb +0 -40
- data/test/db/mssql/limit_offset_test.rb +0 -190
- data/test/db/mssql/multibyte_test.rb +0 -16
- data/test/db/mssql/multiple_connections_test.rb +0 -71
- data/test/db/mssql/rake_test.rb +0 -143
- data/test/db/mssql/reset_column_information_test.rb +0 -6
- data/test/db/mssql/row_locking_test.rb +0 -7
- data/test/db/mssql/serialize_test.rb +0 -6
- data/test/db/mssql/simple_test.rb +0 -140
- data/test/db/mssql/transaction_test.rb +0 -6
- data/test/db/mssql/types_test.rb +0 -205
- data/test/db/mssql/unit_test.rb +0 -249
- data/test/db/mysql.rb +0 -4
- data/test/db/mysql/_rails_test_mysql.32.out +0 -6585
- data/test/db/mysql/binary_test.rb +0 -6
- data/test/db/mysql/connection_test.rb +0 -51
- data/test/db/mysql/index_length_test.rb +0 -58
- data/test/db/mysql/multibyte_test.rb +0 -10
- data/test/db/mysql/nonstandard_primary_key_test.rb +0 -39
- data/test/db/mysql/rake_test.rb +0 -97
- data/test/db/mysql/reset_column_information_test.rb +0 -6
- data/test/db/mysql/schema_dump_test.rb +0 -228
- data/test/db/mysql/serialize_test.rb +0 -6
- data/test/db/mysql/simple_test.rb +0 -187
- data/test/db/mysql/statement_escaping_test.rb +0 -46
- data/test/db/mysql/transaction_test.rb +0 -6
- data/test/db/mysql/types_test.rb +0 -30
- data/test/db/mysql/unit_test.rb +0 -93
- data/test/db/mysql_config.rb +0 -7
- data/test/db/oracle.rb +0 -27
- data/test/db/oracle/binary_test.rb +0 -6
- data/test/db/oracle/limit_test.rb +0 -24
- data/test/db/oracle/multibyte_test.rb +0 -22
- data/test/db/oracle/rake_test.rb +0 -100
- data/test/db/oracle/reset_column_information_test.rb +0 -6
- data/test/db/oracle/serialize_test.rb +0 -6
- data/test/db/oracle/simple_test.rb +0 -140
- data/test/db/oracle/specific_test.rb +0 -180
- data/test/db/oracle/transaction_test.rb +0 -31
- data/test/db/oracle/unit_test.rb +0 -31
- data/test/db/postgres.rb +0 -11
- data/test/db/postgres/_rails_test_postgres.32.out +0 -6405
- data/test/db/postgres/a_custom_primary_key_test.rb +0 -50
- data/test/db/postgres/active_schema_unit_test.rb +0 -68
- data/test/db/postgres/array_type_test.rb +0 -101
- data/test/db/postgres/binary_test.rb +0 -6
- data/test/db/postgres/connection_test.rb +0 -63
- data/test/db/postgres/data_types_test.rb +0 -703
- data/test/db/postgres/hstore_test.rb +0 -200
- data/test/db/postgres/information_schema_leak_test.rb +0 -30
- data/test/db/postgres/json_test.rb +0 -86
- data/test/db/postgres/ltree_test.rb +0 -51
- data/test/db/postgres/mixed_case_test.rb +0 -29
- data/test/db/postgres/native_types_test.rb +0 -124
- data/test/db/postgres/rake_test.rb +0 -117
- data/test/db/postgres/reserved_test.rb +0 -22
- data/test/db/postgres/reset_column_information_test.rb +0 -6
- data/test/db/postgres/row_locking_test.rb +0 -21
- data/test/db/postgres/schema_dump_test.rb +0 -95
- data/test/db/postgres/schema_test.rb +0 -115
- data/test/db/postgres/simple_test.rb +0 -260
- data/test/db/postgres/table_alias_length_test.rb +0 -16
- data/test/db/postgres/transaction_test.rb +0 -6
- data/test/db/postgres/unit_test.rb +0 -31
- data/test/db/postgres_config.rb +0 -10
- data/test/db/sqlite3.rb +0 -6
- data/test/db/sqlite3/_rails_test_sqlite3.32.out +0 -6274
- data/test/db/sqlite3/has_many_though_test.rb +0 -6
- data/test/db/sqlite3/rake_test.rb +0 -71
- data/test/db/sqlite3/reset_column_information_test.rb +0 -6
- data/test/db/sqlite3/schema_dump_test.rb +0 -6
- data/test/db/sqlite3/serialize_test.rb +0 -6
- data/test/db/sqlite3/simple_test.rb +0 -268
- data/test/db/sqlite3/transaction_test.rb +0 -32
- data/test/db/sqlite3/type_conversion_test.rb +0 -104
- data/test/has_many_through.rb +0 -61
- data/test/informix_simple_test.rb +0 -48
- data/test/jdbc/db2.rb +0 -36
- data/test/jdbc/oracle.rb +0 -34
- data/test/jdbc_column_test.rb +0 -23
- data/test/jdbc_common.rb +0 -16
- data/test/jdbc_connection_test.rb +0 -196
- data/test/jndi_callbacks_test.rb +0 -33
- data/test/jndi_test.rb +0 -55
- data/test/manualTestDatabase.rb +0 -191
- data/test/models/add_not_null_column_to_table.rb +0 -9
- data/test/models/auto_id.rb +0 -15
- data/test/models/binary.rb +0 -18
- data/test/models/custom_pk_name.rb +0 -15
- data/test/models/data_types.rb +0 -40
- data/test/models/entry.rb +0 -41
- data/test/models/mixed_case.rb +0 -22
- data/test/models/reserved_word.rb +0 -15
- data/test/models/rights_and_roles.rb +0 -57
- data/test/models/string_id.rb +0 -17
- data/test/models/thing.rb +0 -17
- data/test/models/topic.rb +0 -32
- data/test/models/validates_uniqueness_of_string.rb +0 -19
- data/test/rails/mysql.rb +0 -13
- data/test/rails/sqlite3/version.rb +0 -6
- data/test/rails_stub.rb +0 -31
- data/test/rake_test_support.rb +0 -298
- data/test/row_locking.rb +0 -102
- data/test/schema_dump.rb +0 -182
- data/test/serialize.rb +0 -275
- data/test/shared_helper.rb +0 -35
- data/test/simple.rb +0 -1317
- data/test/sybase_jtds_simple_test.rb +0 -28
- data/test/sybase_reset_column_information_test.rb +0 -6
- data/test/test_helper.rb +0 -304
- data/test/transaction.rb +0 -109
@@ -1,17 +1,17 @@
|
|
1
1
|
module ArJdbc
|
2
|
-
|
3
|
-
# Defines an AR-JDBC extension. An extension consists of a declaration using
|
4
|
-
# this method and an ArJdbc::XYZ module that contains implementation and
|
5
|
-
# overrides for methods in ActiveRecord::ConnectionAdapters::AbstractAdapter.
|
2
|
+
|
3
|
+
# Defines an AR-JDBC extension. An extension consists of a declaration using
|
4
|
+
# this method and an ArJdbc::XYZ module that contains implementation and
|
5
|
+
# overrides for methods in ActiveRecord::ConnectionAdapters::AbstractAdapter.
|
6
6
|
# When you declare your extension, you provide a block that detects when a
|
7
|
-
# database configured to use the extension is present and loads the necessary
|
8
|
-
# code for it. AR-JDBC will patch the code into the base JdbcAdapter by
|
7
|
+
# database configured to use the extension is present and loads the necessary
|
8
|
+
# code for it. AR-JDBC will patch the code into the base JdbcAdapter by
|
9
9
|
# extending an instance of it with your extension module.
|
10
10
|
#
|
11
11
|
# +name+ the name of a module to be defined under the +ArJdbc+ module.
|
12
12
|
#
|
13
|
-
# +block+ should be a one- or two-arity block that receives the dialect name
|
14
|
-
# or driver class name as the first argument, and optionally the whole
|
13
|
+
# +block+ should be a one- or two-arity block that receives the dialect name
|
14
|
+
# or driver class name as the first argument, and optionally the whole
|
15
15
|
# database configuration hash as a second argument
|
16
16
|
#
|
17
17
|
# Example:
|
@@ -39,14 +39,14 @@ module ArJdbc
|
|
39
39
|
end
|
40
40
|
end unless mod.respond_to?(:adapter_matcher)
|
41
41
|
end
|
42
|
-
|
42
|
+
|
43
43
|
private
|
44
44
|
def self.discover_extensions
|
45
|
-
if defined?(
|
46
|
-
files =
|
45
|
+
if defined?(Gem) && Gem.respond_to?(:find_files)
|
46
|
+
files = Gem.find_files('arjdbc/discover')
|
47
47
|
else
|
48
|
-
files = $LOAD_PATH.map do |
|
49
|
-
discover = File.join(
|
48
|
+
files = $LOAD_PATH.map do |path|
|
49
|
+
discover = File.join(path, 'arjdbc', 'discover.rb')
|
50
50
|
File.exist?(discover) ? discover : nil
|
51
51
|
end.compact
|
52
52
|
end
|
@@ -55,5 +55,5 @@ module ArJdbc
|
|
55
55
|
require file
|
56
56
|
end
|
57
57
|
end
|
58
|
-
|
58
|
+
|
59
59
|
end
|
data/lib/arjdbc/jdbc/java.rb
CHANGED
@@ -4,9 +4,12 @@ require 'arjdbc/jdbc/adapter_java'
|
|
4
4
|
module ActiveRecord
|
5
5
|
module ConnectionAdapters
|
6
6
|
module Jdbc
|
7
|
-
|
8
|
-
|
7
|
+
# @private
|
8
|
+
DriverManager = ::Java::JavaSql::DriverManager
|
9
|
+
# @private
|
10
|
+
Types = ::Java::JavaSql::Types
|
9
11
|
end
|
12
|
+
# @private JdbcConnectionFactory
|
10
13
|
java_import "arjdbc.jdbc.JdbcConnectionFactory"
|
11
14
|
end
|
12
|
-
end
|
15
|
+
end
|
data/lib/arjdbc/jdbc/jdbc.rake
CHANGED
@@ -12,9 +12,9 @@ module ArJdbc
|
|
12
12
|
pk_hash_value = "Arel::SqlLiteral.new(#{pk_hash_value})"
|
13
13
|
end
|
14
14
|
if meth
|
15
|
-
base.module_eval <<-PK, __FILE__, __LINE__
|
15
|
+
base.module_eval <<-PK, __FILE__, __LINE__ + 1
|
16
16
|
alias :#{meth}_pre_pk :#{meth}
|
17
|
-
def #{meth}(include_primary_key = true, *args)
|
17
|
+
def #{meth}(include_primary_key = true, *args)
|
18
18
|
aq = #{meth}_pre_pk(include_primary_key, *args)
|
19
19
|
if connection.is_a?(ArJdbc::Oracle) || connection.is_a?(ArJdbc::Mimer)
|
20
20
|
aq[#{pk_hash_key}] = #{pk_hash_value} if include_primary_key && aq[#{pk_hash_key}].nil?
|
@@ -44,16 +44,19 @@ module ActiveRecord
|
|
44
44
|
:datetime => [ lambda {|r| Jdbc::Types::TIMESTAMP == r['data_type'].to_i},
|
45
45
|
lambda {|r| r['type_name'] =~ /^datetime$/i},
|
46
46
|
lambda {|r| r['type_name'] =~ /^timestamp$/i},
|
47
|
+
lambda {|r| r['type_name'] =~ /^datetime.+/i},
|
47
48
|
lambda {|r| r['type_name'] =~ /^date/i},
|
48
49
|
lambda {|r| r['type_name'] =~ /^integer/i}], #Num of milliseconds for SQLite3 JDBC Driver
|
49
50
|
:timestamp => [ lambda {|r| Jdbc::Types::TIMESTAMP == r['data_type'].to_i},
|
50
51
|
lambda {|r| r['type_name'] =~ /^timestamp$/i},
|
51
|
-
lambda {|r| r['type_name'] =~ /^datetime
|
52
|
+
lambda {|r| r['type_name'] =~ /^datetime$/i},
|
53
|
+
lambda {|r| r['type_name'] =~ /^datetime.+/i},
|
52
54
|
lambda {|r| r['type_name'] =~ /^date/i},
|
53
55
|
lambda {|r| r['type_name'] =~ /^integer/i}], #Num of milliseconds for SQLite3 JDBC Driver
|
54
56
|
:time => [ lambda {|r| Jdbc::Types::TIME == r['data_type'].to_i},
|
55
57
|
lambda {|r| r['type_name'] =~ /^time$/i},
|
56
|
-
lambda {|r| r['type_name'] =~ /^datetime
|
58
|
+
lambda {|r| r['type_name'] =~ /^datetime$/i},
|
59
|
+
lambda {|r| r['type_name'] =~ /^datetime.+/i}, # For Informix
|
57
60
|
lambda {|r| r['type_name'] =~ /^date/i},
|
58
61
|
lambda {|r| r['type_name'] =~ /^integer/i}], #Num of milliseconds for SQLite3 JDBC Driver
|
59
62
|
:date => [ lambda {|r| Jdbc::Types::DATE == r['data_type'].to_i},
|
data/lib/arjdbc/mssql/adapter.rb
CHANGED
@@ -2,34 +2,33 @@ ArJdbc.load_java_part :MSSQL
|
|
2
2
|
|
3
3
|
require 'strscan'
|
4
4
|
require 'arjdbc/mssql/utils'
|
5
|
-
require 'arjdbc/mssql/tsql_methods'
|
6
5
|
require 'arjdbc/mssql/limit_helpers'
|
7
|
-
require 'arjdbc/mssql/
|
6
|
+
require 'arjdbc/mssql/lock_methods'
|
7
|
+
require 'arjdbc/mssql/column'
|
8
8
|
require 'arjdbc/mssql/explain_support'
|
9
9
|
|
10
10
|
module ArJdbc
|
11
11
|
module MSSQL
|
12
|
+
include LimitHelpers
|
12
13
|
include Utils
|
13
|
-
|
14
|
-
|
14
|
+
|
15
15
|
include ExplainSupport
|
16
|
-
|
17
|
-
|
16
|
+
|
17
|
+
# @private
|
18
|
+
def self.extended(adapter)
|
18
19
|
initialize!
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
else
|
23
|
-
extend LimitHelpers::SqlServerAddLimitOffset
|
24
|
-
end
|
25
|
-
adapter.config[:sqlserver_version] ||= version
|
20
|
+
|
21
|
+
version = adapter.config[:sqlserver_version] ||= adapter.sqlserver_version
|
22
|
+
adapter.send(:setup_limit_offset!, version)
|
26
23
|
end
|
27
24
|
|
25
|
+
# @private
|
28
26
|
@@_initialized = nil
|
29
|
-
|
27
|
+
|
28
|
+
# @private
|
30
29
|
def self.initialize!
|
31
30
|
return if @@_initialized; @@_initialized = true
|
32
|
-
|
31
|
+
|
33
32
|
require 'arjdbc/jdbc/serialized_attributes_helper'
|
34
33
|
ActiveRecord::Base.class_eval do
|
35
34
|
def after_save_with_mssql_lob
|
@@ -37,38 +36,39 @@ module ArJdbc
|
|
37
36
|
value = ::ArJdbc::SerializedAttributesHelper.dump_column_value(self, column)
|
38
37
|
next if value.nil? || (value == '')
|
39
38
|
|
40
|
-
self.class.connection.
|
41
|
-
column.type == :binary, column.name,
|
42
|
-
self.class.table_name, self.class.primary_key,
|
43
|
-
self.class.connection.quote(id), value
|
44
|
-
)
|
39
|
+
self.class.connection.update_lob_value(self, column, value)
|
45
40
|
end
|
46
41
|
end
|
47
42
|
end
|
48
43
|
ActiveRecord::Base.after_save :after_save_with_mssql_lob
|
49
44
|
end
|
50
|
-
|
51
|
-
def configure_connection
|
52
|
-
use_database # config[:database]
|
53
|
-
end
|
54
|
-
|
55
|
-
def self.column_selector
|
56
|
-
[ /sqlserver|tds|Microsoft SQL/i, lambda { |cfg, column| column.extend(::ArJdbc::MSSQL::Column) } ]
|
57
|
-
end
|
58
45
|
|
46
|
+
# @see ActiveRecord::ConnectionAdapters::JdbcAdapter#jdbc_connection_class
|
59
47
|
def self.jdbc_connection_class
|
60
48
|
::ActiveRecord::ConnectionAdapters::MSSQLJdbcConnection
|
61
49
|
end
|
62
50
|
|
51
|
+
# @see ActiveRecord::ConnectionAdapters::JdbcAdapter#jdbc_column_class
|
63
52
|
def jdbc_column_class
|
64
53
|
::ActiveRecord::ConnectionAdapters::MSSQLColumn
|
65
54
|
end
|
66
|
-
|
67
|
-
|
55
|
+
|
56
|
+
# @see ActiveRecord::ConnectionAdapters::Jdbc::ArelSupport
|
57
|
+
def self.arel_visitor_type(config)
|
68
58
|
require 'arel/visitors/sql_server'
|
69
|
-
|
59
|
+
( config && config[:sqlserver_version].to_s == '2000' ) ?
|
70
60
|
::Arel::Visitors::SQLServer2000 : ::Arel::Visitors::SQLServer
|
71
|
-
|
61
|
+
end
|
62
|
+
|
63
|
+
# @deprecated no longer used
|
64
|
+
# @see ActiveRecord::ConnectionAdapters::JdbcAdapter#arel2_visitors
|
65
|
+
def self.arel2_visitors(config)
|
66
|
+
visitor = arel_visitor_type(config)
|
67
|
+
{ 'mssql' => visitor, 'jdbcmssql' => visitor, 'sqlserver' => visitor }
|
68
|
+
end
|
69
|
+
|
70
|
+
def configure_connection
|
71
|
+
use_database # config[:database]
|
72
72
|
end
|
73
73
|
|
74
74
|
def sqlserver_version
|
@@ -79,8 +79,7 @@ module ArJdbc
|
|
79
79
|
end
|
80
80
|
end
|
81
81
|
|
82
|
-
def modify_types(types)
|
83
|
-
super(types)
|
82
|
+
def modify_types(types)
|
84
83
|
types[:string] = { :name => "NVARCHAR", :limit => 255 }
|
85
84
|
if sqlserver_2000?
|
86
85
|
types[:text] = { :name => "NTEXT" }
|
@@ -94,7 +93,11 @@ module ArJdbc
|
|
94
93
|
types
|
95
94
|
end
|
96
95
|
|
97
|
-
|
96
|
+
# @private these cannot specify a limit
|
97
|
+
NO_LIMIT_TYPES = %w( text binary boolean date datetime )
|
98
|
+
|
99
|
+
def type_to_sql(type, limit = nil, precision = nil, scale = nil)
|
100
|
+
type_s = type.to_s
|
98
101
|
# MSSQL's NVARCHAR(n | max) column supports either a number between 1 and
|
99
102
|
# 4000, or the word "MAX", which corresponds to 2**30-1 UCS-2 characters.
|
100
103
|
#
|
@@ -104,126 +107,28 @@ module ArJdbc
|
|
104
107
|
# MSSQL Server 2000 is skipped here because I don't know how it will behave.
|
105
108
|
#
|
106
109
|
# See: http://msdn.microsoft.com/en-us/library/ms186939.aspx
|
107
|
-
if
|
110
|
+
if type_s == 'string' && limit == 1073741823 && ! sqlserver_2000?
|
108
111
|
'NVARCHAR(MAX)'
|
109
|
-
elsif
|
110
|
-
super(type)
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
attr_accessor :identity, :special
|
120
|
-
alias_method :is_special, :special # #deprecated
|
121
|
-
|
122
|
-
def simplified_type(field_type)
|
123
|
-
case field_type
|
124
|
-
when /int|bigint|smallint|tinyint/i then :integer
|
125
|
-
when /numeric/i then (@scale.nil? || @scale == 0) ? :integer : :decimal
|
126
|
-
when /float|double|money|real|smallmoney/i then :decimal
|
127
|
-
when /datetime|smalldatetime/i then :datetime
|
128
|
-
when /timestamp/i then :timestamp
|
129
|
-
when /time/i then :time
|
130
|
-
when /date/i then :date
|
131
|
-
when /text|ntext|xml/i then :text
|
132
|
-
when /binary|image|varbinary/i then :binary
|
133
|
-
when /char|nchar|nvarchar|string|varchar/i then (@limit == 1073741823 ? (@limit = nil; :text) : :string)
|
134
|
-
when /bit/i then :boolean
|
135
|
-
when /uniqueidentifier/i then :string
|
136
|
-
else
|
137
|
-
super
|
138
|
-
end
|
139
|
-
end
|
140
|
-
|
141
|
-
def default_value(value)
|
142
|
-
return $1 if value =~ /^\(N?'(.*)'\)$/
|
143
|
-
value
|
144
|
-
end
|
145
|
-
|
146
|
-
def type_cast(value)
|
147
|
-
return nil if value.nil?
|
148
|
-
case type
|
149
|
-
when :integer then value.delete('()').to_i rescue unquote(value).to_i rescue value ? 1 : 0
|
150
|
-
when :primary_key then value == true || value == false ? value == true ? 1 : 0 : value.to_i
|
151
|
-
when :decimal then self.class.value_to_decimal(unquote(value))
|
152
|
-
when :datetime then cast_to_datetime(value)
|
153
|
-
when :timestamp then cast_to_time(value)
|
154
|
-
when :time then cast_to_time(value)
|
155
|
-
when :date then cast_to_date(value)
|
156
|
-
when :boolean then value == true or (value =~ /^t(rue)?$/i) == 0 or unquote(value)=="1"
|
157
|
-
when :binary then unquote value
|
158
|
-
else value
|
159
|
-
end
|
160
|
-
end
|
161
|
-
|
162
|
-
def extract_limit(sql_type)
|
163
|
-
case sql_type
|
164
|
-
when /^smallint/i
|
165
|
-
2
|
166
|
-
when /^int/i
|
167
|
-
4
|
168
|
-
when /^bigint/i
|
169
|
-
8
|
170
|
-
when /\(max\)/, /decimal/, /numeric/
|
171
|
-
nil
|
172
|
-
when /text|ntext|xml|binary|image|varbinary|bit/
|
173
|
-
nil
|
112
|
+
elsif NO_LIMIT_TYPES.include?(type_s)
|
113
|
+
super(type)
|
114
|
+
elsif type_s == 'integer'
|
115
|
+
if limit.nil? || limit == 4
|
116
|
+
'int'
|
117
|
+
elsif limit == 2
|
118
|
+
'smallint'
|
119
|
+
elsif limit == 1
|
120
|
+
'tinyint'
|
174
121
|
else
|
175
|
-
|
176
|
-
end
|
177
|
-
end
|
178
|
-
|
179
|
-
def is_utf8?
|
180
|
-
!!( sql_type =~ /nvarchar|ntext|nchar/i )
|
181
|
-
end
|
182
|
-
|
183
|
-
def unquote(value)
|
184
|
-
value.to_s.sub(/\A\([\(\']?/, "").sub(/[\'\)]?\)\Z/, "")
|
185
|
-
end
|
186
|
-
|
187
|
-
def cast_to_time(value)
|
188
|
-
return value if value.is_a?(Time)
|
189
|
-
DateTime.parse(value).to_time rescue nil
|
190
|
-
end
|
191
|
-
|
192
|
-
def cast_to_date(value)
|
193
|
-
return value if value.is_a?(Date)
|
194
|
-
return Date.parse(value) rescue nil
|
195
|
-
end
|
196
|
-
|
197
|
-
def cast_to_datetime(value)
|
198
|
-
if value.is_a?(Time)
|
199
|
-
if value.year != 0 and value.month != 0 and value.day != 0
|
200
|
-
return value
|
201
|
-
else
|
202
|
-
return Time.mktime(2000, 1, 1, value.hour, value.min, value.sec) rescue nil
|
203
|
-
end
|
122
|
+
'bigint'
|
204
123
|
end
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
rescue ArgumentError
|
210
|
-
return value
|
211
|
-
end
|
212
|
-
end
|
213
|
-
|
214
|
-
return cast_to_time(value) if value.is_a?(Date) or value.is_a?(String) rescue nil
|
215
|
-
|
216
|
-
return value.is_a?(Date) ? value : nil
|
217
|
-
end
|
218
|
-
|
219
|
-
# These methods will only allow the adapter to insert binary data with a length of 7K or less
|
220
|
-
# because of a SQL Server statement length policy.
|
221
|
-
def self.string_to_binary(value)
|
222
|
-
''
|
124
|
+
elsif type_s == 'uniqueidentifier'
|
125
|
+
type_s
|
126
|
+
else
|
127
|
+
super
|
223
128
|
end
|
224
|
-
|
225
129
|
end
|
226
130
|
|
131
|
+
# @override
|
227
132
|
def quote(value, column = nil)
|
228
133
|
return value.quoted_id if value.respond_to?(:quoted_id)
|
229
134
|
|
@@ -234,7 +139,7 @@ module ArJdbc
|
|
234
139
|
value = value.to_s
|
235
140
|
column_type = column && column.type
|
236
141
|
if column_type == :binary
|
237
|
-
"'#{quote_string(
|
142
|
+
"'#{quote_string(column.class.string_to_binary(value))}'" # ' (for ruby-mode)
|
238
143
|
elsif column_type == :integer
|
239
144
|
value.to_i.to_s
|
240
145
|
elsif column_type == :float
|
@@ -247,19 +152,16 @@ module ArJdbc
|
|
247
152
|
when Date, Time
|
248
153
|
if column && column.type == :time
|
249
154
|
"'#{quoted_time(value)}'"
|
250
|
-
elsif column && column.sql_type.index('datetimeoffset')
|
251
|
-
"'#{quoted_full_iso8601(value)}'"
|
252
|
-
elsif column && column.sql_type.index('datetime')
|
253
|
-
"'#{quoted_datetime(value)}'"
|
254
155
|
else
|
255
|
-
|
156
|
+
"'#{quoted_date(value)}'"
|
256
157
|
end
|
257
158
|
when TrueClass then '1'
|
258
159
|
when FalseClass then '0'
|
259
160
|
else super
|
260
161
|
end
|
261
162
|
end
|
262
|
-
|
163
|
+
|
164
|
+
# @override
|
263
165
|
def quoted_date(value)
|
264
166
|
if value.respond_to?(:usec)
|
265
167
|
"#{super}.#{sprintf("%03d", value.usec / 1000)}"
|
@@ -268,55 +170,39 @@ module ArJdbc
|
|
268
170
|
end
|
269
171
|
end
|
270
172
|
|
271
|
-
|
272
|
-
if value.acts_like?(:time)
|
273
|
-
time_zone_qualified_value = quoted_value_acts_like_time_filter(value)
|
274
|
-
if value.is_a?(Date)
|
275
|
-
time_zone_qualified_value.to_time.xmlschema.to(18)
|
276
|
-
else
|
277
|
-
if value.is_a?(ActiveSupport::TimeWithZone) && RUBY_VERSION < '1.9'
|
278
|
-
time_zone_qualified_value = time_zone_qualified_value.to_time
|
279
|
-
end
|
280
|
-
time_zone_qualified_value.iso8601(3).to(22)
|
281
|
-
end
|
282
|
-
else
|
283
|
-
quoted_date(value)
|
284
|
-
end
|
285
|
-
end
|
286
|
-
|
173
|
+
# @private
|
287
174
|
def quoted_time(value)
|
288
175
|
if value.acts_like?(:time)
|
289
|
-
tz_value =
|
290
|
-
|
176
|
+
tz_value = get_time(value)
|
177
|
+
usec = value.respond_to?(:usec) ? ( value.usec / 1000 ) : 0
|
178
|
+
sprintf("%02d:%02d:%02d.%03d", tz_value.hour, tz_value.min, tz_value.sec, usec)
|
291
179
|
else
|
292
180
|
quoted_date(value)
|
293
181
|
end
|
294
182
|
end
|
295
|
-
|
183
|
+
|
184
|
+
# @deprecated no longer used
|
185
|
+
# @private
|
186
|
+
def quoted_datetime(value)
|
187
|
+
quoted_date(value)
|
188
|
+
end
|
189
|
+
|
190
|
+
# @deprecated no longer used
|
191
|
+
# @private
|
296
192
|
def quoted_full_iso8601(value)
|
297
193
|
if value.acts_like?(:time)
|
298
|
-
value.is_a?(Date) ?
|
299
|
-
|
300
|
-
|
194
|
+
value.is_a?(Date) ?
|
195
|
+
get_time(value).to_time.xmlschema.to(18) :
|
196
|
+
get_time(value).iso8601(7).to(22)
|
301
197
|
else
|
302
198
|
quoted_date(value)
|
303
199
|
end
|
304
200
|
end
|
305
|
-
|
306
|
-
def quoted_value_acts_like_time_filter(value)
|
307
|
-
method = ActiveRecord::Base.default_timezone == :utc ? :getutc : :getlocal
|
308
|
-
value.respond_to?(method) ? value.send(method) : value
|
309
|
-
end
|
310
|
-
protected :quoted_value_acts_like_time_filter
|
311
|
-
|
201
|
+
|
312
202
|
def quote_table_name(name)
|
313
203
|
quote_column_name(name)
|
314
204
|
end
|
315
|
-
|
316
|
-
# def quote_table_name_for_assignment(table, attr)
|
317
|
-
# quote_column_name(attr)
|
318
|
-
# end if ::ActiveRecord::VERSION::MAJOR > 3
|
319
|
-
|
205
|
+
|
320
206
|
def quote_column_name(name)
|
321
207
|
name.to_s.split('.').map do |n| # "[#{name}]"
|
322
208
|
n =~ /^\[.*\]$/ ? n : "[#{n.gsub(']', ']]')}]"
|
@@ -324,8 +210,8 @@ module ArJdbc
|
|
324
210
|
end
|
325
211
|
|
326
212
|
ADAPTER_NAME = 'MSSQL'.freeze
|
327
|
-
|
328
|
-
def adapter_name
|
213
|
+
|
214
|
+
def adapter_name
|
329
215
|
ADAPTER_NAME
|
330
216
|
end
|
331
217
|
|
@@ -344,24 +230,28 @@ module ArJdbc
|
|
344
230
|
true
|
345
231
|
end
|
346
232
|
|
233
|
+
def tables(schema = current_schema)
|
234
|
+
@connection.tables(nil, schema)
|
235
|
+
end
|
236
|
+
|
347
237
|
# NOTE: Dynamic Name Resolution - SQL Server 2000 vs. 2005
|
348
|
-
#
|
349
|
-
# A query such as "select * from table1" in SQL Server 2000 goes through
|
350
|
-
# a set of steps to resolve and validate the object references before
|
351
|
-
# execution.
|
352
|
-
# The search first looks at the identity of the connection executing
|
238
|
+
#
|
239
|
+
# A query such as "select * from table1" in SQL Server 2000 goes through
|
240
|
+
# a set of steps to resolve and validate the object references before
|
241
|
+
# execution.
|
242
|
+
# The search first looks at the identity of the connection executing
|
353
243
|
# the query.
|
354
|
-
#
|
244
|
+
#
|
355
245
|
# However SQL Server 2005 provides a mechanism to allow finer control over
|
356
|
-
# name resolution to the administrators. By manipulating the value of the
|
246
|
+
# name resolution to the administrators. By manipulating the value of the
|
357
247
|
# default_schema_name columns in the sys.database_principals.
|
358
|
-
#
|
248
|
+
#
|
359
249
|
# http://blogs.msdn.com/b/mssqlisv/archive/2007/03/23/upgrading-to-sql-server-2005-and-default-schema-setting.aspx
|
360
|
-
|
250
|
+
|
361
251
|
# Returns the default schema (to be used for table resolution) used for the {#current_user}.
|
362
252
|
def default_schema
|
363
253
|
return current_user if sqlserver_2000?
|
364
|
-
@default_schema ||=
|
254
|
+
@default_schema ||=
|
365
255
|
@connection.execute_query_raw(
|
366
256
|
"SELECT default_schema_name FROM sys.database_principals WHERE name = CURRENT_USER"
|
367
257
|
).first['default_schema_name']
|
@@ -377,12 +267,12 @@ module ArJdbc
|
|
377
267
|
@default_schema = nil if defined?(@default_schema)
|
378
268
|
end
|
379
269
|
alias_method :current_schema=, :default_schema=
|
380
|
-
|
270
|
+
|
381
271
|
# `SELECT CURRENT_USER`
|
382
272
|
def current_user
|
383
273
|
@current_user ||= @connection.execute_query_raw("SELECT CURRENT_USER").first['']
|
384
274
|
end
|
385
|
-
|
275
|
+
|
386
276
|
def charset
|
387
277
|
select_value "SELECT SERVERPROPERTY('SqlCharSetName')"
|
388
278
|
end
|
@@ -390,21 +280,23 @@ module ArJdbc
|
|
390
280
|
def collation
|
391
281
|
select_value "SELECT SERVERPROPERTY('Collation')"
|
392
282
|
end
|
393
|
-
|
283
|
+
|
394
284
|
def current_database
|
395
285
|
select_value 'SELECT DB_NAME()'
|
396
286
|
end
|
397
|
-
|
287
|
+
|
398
288
|
def use_database(database = nil)
|
399
289
|
database ||= config[:database]
|
400
290
|
execute "USE #{quote_table_name(database)}" unless database.blank?
|
401
291
|
end
|
402
|
-
|
292
|
+
|
293
|
+
# @private
|
403
294
|
def recreate_database(name, options = {})
|
404
295
|
drop_database(name)
|
405
296
|
create_database(name, options)
|
406
297
|
end
|
407
298
|
|
299
|
+
# @private
|
408
300
|
def recreate_database!(database = nil)
|
409
301
|
current_db = current_database
|
410
302
|
database ||= current_db
|
@@ -414,8 +306,10 @@ module ArJdbc
|
|
414
306
|
ensure
|
415
307
|
use_database(current_db) if this_db
|
416
308
|
end
|
417
|
-
|
309
|
+
|
418
310
|
def drop_database(name)
|
311
|
+
current_db = current_database
|
312
|
+
use_database('master') if current_db.to_s == name
|
419
313
|
execute "DROP DATABASE #{quote_table_name(name)}"
|
420
314
|
end
|
421
315
|
|
@@ -426,14 +320,15 @@ module ArJdbc
|
|
426
320
|
def database_exists?(name)
|
427
321
|
select_value "SELECT name FROM sys.databases WHERE name = '#{name}'"
|
428
322
|
end
|
429
|
-
|
323
|
+
|
324
|
+
# @override
|
430
325
|
def rename_table(table_name, new_table_name)
|
431
326
|
clear_cached_table(table_name)
|
432
327
|
execute "EXEC sp_rename '#{table_name}', '#{new_table_name}'"
|
433
328
|
end
|
434
329
|
|
435
330
|
# Adds a new column to the named table.
|
436
|
-
#
|
331
|
+
# @override
|
437
332
|
def add_column(table_name, column_name, type, options = {})
|
438
333
|
clear_cached_table(table_name)
|
439
334
|
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])}"
|
@@ -443,32 +338,34 @@ module ArJdbc
|
|
443
338
|
execute(add_column_sql)
|
444
339
|
end
|
445
340
|
|
341
|
+
# @override
|
446
342
|
def rename_column(table_name, column_name, new_column_name)
|
447
343
|
clear_cached_table(table_name)
|
448
344
|
execute "EXEC sp_rename '#{table_name}.#{column_name}', '#{new_column_name}', 'COLUMN'"
|
449
345
|
end
|
450
346
|
|
451
|
-
|
347
|
+
# @override
|
348
|
+
def change_column(table_name, column_name, type, options = {})
|
452
349
|
clear_cached_table(table_name)
|
453
350
|
change_column_type(table_name, column_name, type, options)
|
454
351
|
change_column_default(table_name, column_name, options[:default]) if options_include_default?(options)
|
455
352
|
end
|
456
353
|
|
457
|
-
def change_column_type(table_name, column_name, type, options = {})
|
354
|
+
def change_column_type(table_name, column_name, type, options = {})
|
458
355
|
clear_cached_table(table_name)
|
459
356
|
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])}"
|
460
357
|
sql += (options[:null] ? " NULL" : " NOT NULL") if options.has_key?(:null)
|
461
358
|
execute(sql)
|
462
359
|
end
|
463
360
|
|
464
|
-
def change_column_default(table_name, column_name, default)
|
361
|
+
def change_column_default(table_name, column_name, default)
|
465
362
|
clear_cached_table(table_name)
|
466
363
|
remove_default_constraint(table_name, column_name)
|
467
364
|
unless default.nil?
|
468
365
|
execute "ALTER TABLE #{quote_table_name(table_name)} ADD CONSTRAINT DF_#{table_name}_#{column_name} DEFAULT #{quote(default)} FOR #{quote_column_name(column_name)}"
|
469
366
|
end
|
470
367
|
end
|
471
|
-
|
368
|
+
|
472
369
|
def remove_column(table_name, *column_names)
|
473
370
|
raise ArgumentError.new("You must specify at least one column name. Example: remove_column(:people, :first_name)") if column_names.empty?
|
474
371
|
# remove_columns(:posts, :foo, :bar) old syntax : remove_columns(:posts, [:foo, :bar])
|
@@ -517,29 +414,34 @@ module ArJdbc
|
|
517
414
|
remove_index(table_name, { :name => index.name })
|
518
415
|
end
|
519
416
|
end
|
520
|
-
|
417
|
+
|
521
418
|
def remove_index(table_name, options = {})
|
522
419
|
execute "DROP INDEX #{quote_table_name(table_name)}.#{index_name(table_name, options)}"
|
523
420
|
end
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
#
|
421
|
+
|
422
|
+
# @private
|
423
|
+
SKIP_COLUMNS_TABLE_NAMES_RE = /^information_schema\./i
|
424
|
+
# @private
|
425
|
+
IDENTITY_COLUMN_TYPE_RE = /identity/i
|
426
|
+
# NOTE: these do not handle = equality as expected
|
427
|
+
# see {#repair_special_columns}
|
528
428
|
# (TEXT, NTEXT, and IMAGE data types are deprecated)
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
429
|
+
# @private
|
430
|
+
SPECIAL_COLUMN_TYPE_RE = /text|ntext|image|xml/i
|
431
|
+
|
432
|
+
# @private
|
433
|
+
EMPTY_ARRAY = [].freeze
|
434
|
+
|
533
435
|
def columns(table_name, name = nil, default = EMPTY_ARRAY)
|
534
|
-
# It's possible for table_name to be an empty string, or nil, if something
|
535
|
-
# attempts to issue SQL which doesn't involve a table.
|
436
|
+
# It's possible for table_name to be an empty string, or nil, if something
|
437
|
+
# attempts to issue SQL which doesn't involve a table.
|
536
438
|
# IE. "SELECT 1" or "SELECT * FROM someFunction()".
|
537
439
|
return default if table_name.blank?
|
538
|
-
|
440
|
+
|
539
441
|
table_name = unquote_table_name(table_name)
|
540
442
|
|
541
443
|
return default if table_name =~ SKIP_COLUMNS_TABLE_NAMES_RE
|
542
|
-
|
444
|
+
|
543
445
|
unless columns = ( @table_columns ||= {} )[table_name]
|
544
446
|
columns = super(table_name, name)
|
545
447
|
for column in columns
|
@@ -558,7 +460,7 @@ module ArJdbc
|
|
558
460
|
def reset_column_information
|
559
461
|
@table_columns = nil if defined? @table_columns
|
560
462
|
end
|
561
|
-
|
463
|
+
|
562
464
|
# Turns IDENTITY_INSERT ON for table during execution of the block
|
563
465
|
# N.B. This sets the state of IDENTITY_INSERT to OFF after the
|
564
466
|
# block has been executed without regard to its previous state
|
@@ -572,10 +474,11 @@ module ArJdbc
|
|
572
474
|
def set_identity_insert(table_name, enable = true)
|
573
475
|
execute "SET IDENTITY_INSERT #{table_name} #{enable ? 'ON' : 'OFF'}"
|
574
476
|
rescue Exception => e
|
575
|
-
raise ActiveRecord::ActiveRecordError, "IDENTITY_INSERT could not be turned" +
|
477
|
+
raise ActiveRecord::ActiveRecordError, "IDENTITY_INSERT could not be turned" +
|
576
478
|
" #{enable ? 'ON' : 'OFF'} for table #{table_name} due : #{e.inspect}"
|
577
479
|
end
|
578
|
-
|
480
|
+
|
481
|
+
# @private
|
579
482
|
# @see ArJdbc::MSSQL::LimitHelpers
|
580
483
|
def determine_order_clause(sql)
|
581
484
|
return $1 if sql =~ /ORDER BY (.*)$/i
|
@@ -591,9 +494,10 @@ module ArJdbc
|
|
591
494
|
# NOTE: if still no PK column simply get something for ORDER BY ...
|
592
495
|
"#{table_name}.#{(primary_column || columns.first).name}"
|
593
496
|
end
|
594
|
-
|
497
|
+
|
498
|
+
# Support for executing a stored procedure.
|
595
499
|
def exec_proc(proc_name, *variables)
|
596
|
-
vars =
|
500
|
+
vars =
|
597
501
|
if variables.any? && variables.first.is_a?(Hash)
|
598
502
|
variables.first.map { |k, v| "@#{k} = #{quote(v)}" }
|
599
503
|
else
|
@@ -602,7 +506,7 @@ module ArJdbc
|
|
602
506
|
sql = "EXEC #{proc_name} #{vars}".strip
|
603
507
|
log(sql, 'Execute Procedure') do
|
604
508
|
result = @connection.execute_query_raw(sql)
|
605
|
-
result.map! do |row|
|
509
|
+
result.map! do |row|
|
606
510
|
row = row.is_a?(Hash) ? row.with_indifferent_access : row
|
607
511
|
yield(row) if block_given?
|
608
512
|
row
|
@@ -611,9 +515,9 @@ module ArJdbc
|
|
611
515
|
end
|
612
516
|
end
|
613
517
|
alias_method :execute_procedure, :exec_proc # AR-SQLServer-Adapter naming
|
614
|
-
|
518
|
+
|
615
519
|
# @override
|
616
|
-
def exec_query(sql, name = 'SQL', binds = [])
|
520
|
+
def exec_query(sql, name = 'SQL', binds = [])
|
617
521
|
# NOTE: we allow to execute SQL as requested returning a results.
|
618
522
|
# e.g. this allows to use SQLServer's EXEC with a result set ...
|
619
523
|
sql = repair_special_columns to_sql(sql, binds)
|
@@ -624,9 +528,9 @@ module ArJdbc
|
|
624
528
|
log(sql, name) { @connection.execute_query(sql) }
|
625
529
|
end
|
626
530
|
end
|
627
|
-
|
531
|
+
|
628
532
|
# @override
|
629
|
-
def exec_query_raw(sql, name = 'SQL', binds = [], &block)
|
533
|
+
def exec_query_raw(sql, name = 'SQL', binds = [], &block)
|
630
534
|
sql = repair_special_columns to_sql(sql, binds)
|
631
535
|
if prepared_statements?
|
632
536
|
log(sql, name, binds) { @connection.execute_query_raw(sql, binds, &block) }
|
@@ -635,12 +539,12 @@ module ArJdbc
|
|
635
539
|
log(sql, name) { @connection.execute_query_raw(sql, &block) }
|
636
540
|
end
|
637
541
|
end
|
638
|
-
|
542
|
+
|
639
543
|
private
|
640
|
-
|
544
|
+
|
641
545
|
def _execute(sql, name = nil)
|
642
546
|
# Match the start of the SQL to determine appropriate behavior.
|
643
|
-
# Be aware of multi-line SQL which might begin with 'create stored_proc'
|
547
|
+
# Be aware of multi-line SQL which might begin with 'create stored_proc'
|
644
548
|
# and contain 'insert into ...' lines.
|
645
549
|
# NOTE: ignoring comment blocks prior to the first statement ?!
|
646
550
|
if self.class.insert?(sql)
|
@@ -657,7 +561,7 @@ module ArJdbc
|
|
657
561
|
@connection.execute_update(sql)
|
658
562
|
end
|
659
563
|
end
|
660
|
-
|
564
|
+
|
661
565
|
def identity_insert_table_name(sql)
|
662
566
|
table_name = get_table_name(sql)
|
663
567
|
id_column = identity_column_name(table_name)
|
@@ -666,14 +570,14 @@ module ArJdbc
|
|
666
570
|
return table_name if insert_columns.include?(id_column)
|
667
571
|
end
|
668
572
|
end
|
669
|
-
|
573
|
+
|
670
574
|
def identity_column_name(table_name)
|
671
575
|
for column in columns(table_name)
|
672
576
|
return column.name if column.identity
|
673
577
|
end
|
674
578
|
nil
|
675
579
|
end
|
676
|
-
|
580
|
+
|
677
581
|
def repair_special_columns(sql)
|
678
582
|
qualified_table_name = get_table_name(sql, true)
|
679
583
|
if special_columns = special_column_names(qualified_table_name)
|
@@ -681,7 +585,7 @@ module ArJdbc
|
|
681
585
|
special_columns = special_columns.sort { |n1, n2| n2.size <=> n1.size }
|
682
586
|
for column in special_columns
|
683
587
|
sql.gsub!(/\s?\[?#{column}\]?\s?=\s?/, " [#{column}] LIKE ")
|
684
|
-
sql.gsub!(/ORDER BY \[?#{column}\]?/i, '') # NOTE: a bit stupid
|
588
|
+
sql.gsub!(/ORDER BY \[?#{column}([^\.\w]|$)\]?/i, '') # NOTE: a bit stupid
|
685
589
|
end
|
686
590
|
end
|
687
591
|
sql
|
@@ -694,58 +598,34 @@ module ArJdbc
|
|
694
598
|
columns.each { |column| special << column.name if column.special }
|
695
599
|
special
|
696
600
|
end
|
697
|
-
|
601
|
+
|
698
602
|
def sqlserver_2000?
|
699
603
|
sqlserver_version <= '2000'
|
700
604
|
end
|
701
|
-
|
605
|
+
|
702
606
|
end
|
703
607
|
end
|
704
608
|
|
609
|
+
require 'arjdbc/util/quoted_cache'
|
610
|
+
|
705
611
|
module ActiveRecord::ConnectionAdapters
|
706
|
-
|
612
|
+
|
707
613
|
class MSSQLAdapter < JdbcAdapter
|
708
614
|
include ::ArJdbc::MSSQL
|
709
|
-
|
615
|
+
include ::ArJdbc::Util::QuotedCache
|
616
|
+
|
710
617
|
def initialize(*args)
|
711
618
|
::ArJdbc::MSSQL.initialize!
|
712
|
-
|
713
|
-
super # configure_connection happens in super
|
714
|
-
|
715
|
-
if ( version = self.sqlserver_version ) == '2000'
|
716
|
-
extend LimitHelpers::SqlServer2000AddLimitOffset
|
717
|
-
else
|
718
|
-
extend LimitHelpers::SqlServerAddLimitOffset
|
719
|
-
end
|
720
|
-
config[:sqlserver_version] ||= version
|
721
|
-
end
|
722
|
-
|
723
|
-
# some QUOTING caching :
|
724
619
|
|
725
|
-
|
620
|
+
super # configure_connection happens in super
|
726
621
|
|
727
|
-
|
728
|
-
unless quoted = @@quoted_table_names[name]
|
729
|
-
quoted = super
|
730
|
-
@@quoted_table_names[name] = quoted.freeze
|
731
|
-
end
|
732
|
-
quoted
|
622
|
+
setup_limit_offset!
|
733
623
|
end
|
734
624
|
|
735
|
-
@@quoted_column_names = {}
|
736
|
-
|
737
|
-
def quote_column_name(name)
|
738
|
-
unless quoted = @@quoted_column_names[name]
|
739
|
-
quoted = super
|
740
|
-
@@quoted_column_names[name] = quoted.freeze
|
741
|
-
end
|
742
|
-
quoted
|
743
|
-
end
|
744
|
-
|
745
625
|
end
|
746
|
-
|
626
|
+
|
747
627
|
class MSSQLColumn < JdbcColumn
|
748
|
-
include ArJdbc::MSSQL::Column
|
628
|
+
include ::ArJdbc::MSSQL::Column
|
749
629
|
end
|
750
|
-
|
630
|
+
|
751
631
|
end
|