Class: ActiveRecord::ConnectionAdapters::MSSQLAdapter

Overview

MSSQL (SQLServer) adapter class definition

Constant Summary collapse

ADAPTER_NAME =
'MSSQL'.freeze
MSSQL_VERSION_YEAR =
{
  8 => '2000',
  9 => '2005',
  10 => '2008',
  11 => '2012',
  12 => '2014',
  13 => '2016',
  14 => '2017',
  15 => '2019'
}.freeze

Constants included from ArJdbc::MSSQL

ArJdbc::MSSQL::NATIVE_DATABASE_TYPES

Constants included from ActiveRecord::ConnectionAdapters::MSSQL::ExplainSupport

ActiveRecord::ConnectionAdapters::MSSQL::ExplainSupport::DISABLED

Constants included from ActiveRecord::ConnectionAdapters::MSSQL::SchemaStatements

ActiveRecord::ConnectionAdapters::MSSQL::SchemaStatements::NATIVE_DATABASE_TYPES

Constants included from ActiveRecord::ConnectionAdapters::MSSQL::Quoting

ActiveRecord::ConnectionAdapters::MSSQL::Quoting::QUOTED_FALSE, ActiveRecord::ConnectionAdapters::MSSQL::Quoting::QUOTED_TRUE

Constants included from ArJdbc::Abstract::DatabaseStatements

ArJdbc::Abstract::DatabaseStatements::NO_BINDS

Class Attribute Summary collapse

Attributes included from ArJdbc::Abstract::Core

#config

Attributes inherited from JdbcAdapter

#prepared_statements

Class Method Summary collapse

Instance Method Summary collapse

Methods included from ArJdbc::Util::QuotedCache

#quote_column_name, #quote_table_name

Methods included from ArJdbc::MSSQL

#adapter_name, #add_column, #change_column, #change_column_default, #change_column_type, #change_order_direction, #charset, #clear_cached_table, #collation, column_selector, #columns, #columns_for_distinct, #create_database, #current_database, #database_exists?, #distinct, #drop_database, #exec_proc, #exec_query, #exec_query_raw, jdbc_connection_class, #modify_types, #native_database_types, #quote, #quote_column_name, #quote_database_name, #quote_default_value, #quote_table_name, #quoted_date, #release_savepoint, #remove_check_constraints, #remove_column, #remove_columns, #remove_default_constraint, #remove_index, #remove_indexes, #rename_column, #rename_table, #reset_column_information, #set_identity_insert, #sqlserver_version, #tables, #truncate, #type_to_sql, #update_lob_value?, update_lob_values=, update_lob_values?, #use_database, #with_identity_insert_enabled

Methods included from ArJdbc::MSSQL::Utils

remove_identifier_delimiters, unqualify_db_name, unqualify_table_name, unqualify_table_schema, unquote_column_name, unquote_string, unquote_table_name

Methods included from ActiveRecord::ConnectionAdapters::MSSQL::DatabaseLimits

#in_clause_length

Methods included from ActiveRecord::ConnectionAdapters::MSSQL::ExplainSupport

#explain, #interpolate_sql_statement, #set_showplan_option, #supports_explain?, #with_showplan_on

Methods included from ActiveRecord::ConnectionAdapters::MSSQL::DatabaseStatements

#exec_insert, #exec_proc, #execute, #insert_fixtures_set, #supports_transaction_isolation_level?, #transaction_isolation, #transaction_isolation=, #truncate, #truncate_tables, #write_query?

Methods included from ActiveRecord::ConnectionAdapters::MSSQL::SchemaStatements

#add_timestamps, #change_column, #change_column_default, #change_column_null, #charset, #collation, #columns_for_distinct, #create_database, #create_schema_dumper, #current_database, #drop_database, #drop_table, #foreign_keys, #indexes, #native_database_types, #primary_keys, #quote_column_name, #quote_database_name, #quote_table_name, #recreate_database, #remove_column, #rename_column, #rename_table, #type_to_sql, #update_table_definition, #use_database

Methods included from ActiveRecord::ConnectionAdapters::MSSQL::Quoting

#column_name_matcher, #column_name_with_order_matcher, #quote_default_expression, #quote_string, #quoted_date, #quoted_false, #quoted_time, #quoted_true

Methods included from ArJdbc::Abstract::TransactionSupport

#begin_db_transaction, #begin_isolated_db_transaction, #commit_db_transaction, #create_savepoint, #exec_rollback_db_transaction, #exec_rollback_to_savepoint, #release_savepoint

Methods included from ArJdbc::Abstract::StatementCache

#delete_cached_statement, #fetch_cached_statement

Methods included from ArJdbc::Abstract::DatabaseStatements

#exec_insert, #exec_query, #exec_update, #execute, #select_all

Methods included from ArJdbc::Abstract::ConnectionManagement

#active?, #disconnect!, #really_valid?, #reconnect!

Methods included from ArJdbc::Abstract::Core

#extract_raw_bind_values, #jdbc_connection, #log, #translate_exception_class

Methods included from Jdbc::ConnectionPoolCallbacks

#on_checkin, #on_checkout

Methods inherited from JdbcAdapter

#adapter_name, #adapter_spec, arel2_visitors, #columns, configure_arel2_visitors, #data_source_exists?, #data_sources, #database_name, #exec_query_raw, #execute, #execute_quietly, #foreign_keys, #indexes, #is_a?, #last_inserted_id, #modify_types, #native_database_types, #pk_and_sequence_for, prepared_statements?, #prepared_statements?, #primary_keys, #structure_dump, #supports_migrations?, #table_definition, #table_exists?, #tables, #update_lob_value, #write_large_object

Constructor Details

#initialize(*args) ⇒ MSSQLAdapter

Returns a new instance of MSSQLAdapter.



67
68
69
70
71
72
73
74
# File 'lib/arjdbc/mssql/adapter.rb', line 67

def initialize(connection, logger, _connection_parameters, config = {})
  # configure_connection happens in super
  super(connection, logger, config)

  if database_version < '11'
    raise "Your #{mssql_product_name} #{mssql_version_year} is too old. This adapter supports #{mssql_product_name} >= 2012."
  end
end

Class Attribute Details

.cs_equality_operatorObject

Returns the value of attribute cs_equality_operator.



64
65
66
# File 'lib/arjdbc/mssql/adapter.rb', line 64

def cs_equality_operator
  @cs_equality_operator
end

Class Method Details

.database_exists?(config) ⇒ Boolean

Returns:

  • (Boolean)


76
77
78
79
80
81
82
83
84
85
# File 'lib/arjdbc/mssql/adapter.rb', line 76

def self.database_exists?(config)
  !!ActiveRecord::Base.sqlserver_connection(config)
rescue ActiveRecord::JDBCError => e
  case e.message
  when /Cannot open database .* requested by the login/
    false
  else
    raise
  end
end

Instance Method Details

#arel_visitorObject

:nodoc:



454
455
456
# File 'lib/arjdbc/mssql/adapter.rb', line 454

def arel_visitor # :nodoc:
  ::Arel::Visitors::SQLServer.new(self)
end

#build_insert_sql(insert) ⇒ Object

:nodoc:



150
151
152
153
# File 'lib/arjdbc/mssql/adapter.rb', line 150

def build_insert_sql(insert) # :nodoc:
  # TODO: hope we can implement an upsert like feature
  "INSERT #{insert.into} #{insert.values_list}"
end

#case_sensitive_comparison(attribute, value) ⇒ Object



239
240
241
242
243
244
245
246
247
# File 'lib/arjdbc/mssql/adapter.rb', line 239

def case_sensitive_comparison(attribute, value)
  column = column_for_attribute(attribute)

  if [:string, :text].include?(column.type) && collation && !collation.match(/_CS/) && !value.nil?
    attribute.eq(Arel::Nodes::Bin.new(value))
  else
    super
  end
end

#check_versionObject

:nodoc:



291
292
293
294
# File 'lib/arjdbc/mssql/adapter.rb', line 291

def check_version # :nodoc:
  # NOTE: hitting the database from here causes trouble when adapter
  # uses JNDI or Data Source setup.
end

#clear_cache!Object



160
161
162
163
# File 'lib/arjdbc/mssql/adapter.rb', line 160

def clear_cache!
  reload_type_map
  super
end

#combine_bind_parameters(from_clause: [], join_clause: [], where_clause: [], having_clause: [], limit: nil, offset: nil) ⇒ Object

Overrides the method in abstract adapter to set the limit and offset in the right order. (SQLServer specific) Called by bound_attributes



188
189
190
191
192
193
194
195
196
197
198
199
200
201
# File 'lib/arjdbc/mssql/adapter.rb', line 188

def combine_bind_parameters(
  from_clause: [],
  join_clause: [],
  where_clause: [],
  having_clause: [],
  limit: nil,
  offset: nil
)

  result = from_clause + join_clause + where_clause + having_clause
  result << offset if offset
  result << limit if limit
  result
end

#configure_connectionObject



249
250
251
252
253
# File 'lib/arjdbc/mssql/adapter.rb', line 249

def configure_connection
  # Here goes initial settings per connection

  set_session_transaction_isolation
end

#current_userObject

Returns the name of the current security context



204
205
206
# File 'lib/arjdbc/mssql/adapter.rb', line 204

def current_user
  @current_user ||= select_value('SELECT CURRENT_USER')
end

#default_schemaObject Also known as: current_schema

Returns the default schema (to be used for table resolution) used for the #current_user.



210
211
212
# File 'lib/arjdbc/mssql/adapter.rb', line 210

def default_schema
  @default_schema ||= select_value('SELECT default_schema_name FROM sys.database_principals WHERE name = CURRENT_USER')
end

#default_schema=(default_schema) ⇒ Object Also known as: current_schema=

Allows for changing of the default schema. (to be used during unqualified table name resolution).



218
219
220
221
# File 'lib/arjdbc/mssql/adapter.rb', line 218

def default_schema=(default_schema)
  execute("ALTER #{current_user} WITH DEFAULT_SCHEMA=#{default_schema}")
  @default_schema = nil if defined?(@default_schema)
end

#default_uniqueness_comparison(attribute, value) ⇒ Object

FIXME: This needs to be fixed when we implement the collation per column basis. At the moment we only use the global database collation



227
228
229
230
231
232
233
234
235
236
237
# File 'lib/arjdbc/mssql/adapter.rb', line 227

def default_uniqueness_comparison(attribute, value) # :nodoc:
  column = column_for_attribute(attribute)

  if [:string, :text].include?(column.type) && collation && !collation.match(/_CS/) && !value.nil?
    # NOTE: there is a deprecation warning here in the mysql adapter
    # no sure if it's required.
    attribute.eq(Arel::Nodes::Bin.new(value))
  else
    super
  end
end

#disable_referential_integrityObject



172
173
174
175
176
177
178
179
180
181
182
183
# File 'lib/arjdbc/mssql/adapter.rb', line 172

def disable_referential_integrity
  tables = tables_with_referential_integrity

  tables.each do |table_name|
    execute "ALTER TABLE #{table_name} NOCHECK CONSTRAINT ALL"
  end
  yield
ensure
  tables.each do |table_name|
    execute "ALTER TABLE #{table_name} CHECK CONSTRAINT ALL"
  end
end

#get_database_versionObject

:nodoc:



287
288
289
# File 'lib/arjdbc/mssql/adapter.rb', line 287

def get_database_version # :nodoc:
  MSSQLAdapter::Version.new(mssql_product_version)
end

#jdbc_column_classObject

Returns the (JDBC) ActiveRecord column class for this adapter. Used in the java part.



95
96
97
# File 'lib/arjdbc/mssql/adapter.rb', line 95

def jdbc_column_class
  ::ActiveRecord::ConnectionAdapters::MSSQLColumn
end

#jdbc_connection_class(_spec) ⇒ Object

Returns the (JDBC) connection class to be used for this adapter. The class is defined in the java part



89
90
91
# File 'lib/arjdbc/mssql/adapter.rb', line 89

def jdbc_connection_class(_spec)
  ::ActiveRecord::ConnectionAdapters::MSSQLJdbcConnection
end

#mssql?Boolean

Returns:

  • (Boolean)


261
262
263
# File 'lib/arjdbc/mssql/adapter.rb', line 261

def mssql?
  true
end

#mssql_major_versionObject



265
266
267
268
269
# File 'lib/arjdbc/mssql/adapter.rb', line 265

def mssql_major_version
  return @mssql_major_version if defined? @mssql_major_version

  @mssql_major_version = @connection.database_major_version
end

#mssql_product_nameObject



281
282
283
284
285
# File 'lib/arjdbc/mssql/adapter.rb', line 281

def mssql_product_name
  return @mssql_product_name if defined? @mssql_product_name

  @mssql_product_name = @connection.database_product_name
end

#mssql_product_versionObject



275
276
277
278
279
# File 'lib/arjdbc/mssql/adapter.rb', line 275

def mssql_product_version
  return @mssql_product_version if defined? @mssql_product_version

  @mssql_product_version = @connection.database_product_version
end

#mssql_version_yearObject



271
272
273
# File 'lib/arjdbc/mssql/adapter.rb', line 271

def mssql_version_year
  MSSQL_VERSION_YEAR[mssql_major_version.to_i]
end

#reset!Object



165
166
167
168
169
170
# File 'lib/arjdbc/mssql/adapter.rb', line 165

def reset!
  # execute 'IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION'
  # NOTE: it seems the above line interferes with the jdbc driver
  # and ending up in connection closed, issue seen in rails 5.2 and 6.0
  reconnect!
end

#set_session_transaction_isolationObject



255
256
257
258
259
# File 'lib/arjdbc/mssql/adapter.rb', line 255

def set_session_transaction_isolation
  isolation_level = config[:transaction_isolation]

  self.transaction_isolation = isolation_level if isolation_level
end

#supports_datetime_with_precision?Boolean

The MSSQL datetime type doe have precision.

Returns:

  • (Boolean)


124
125
126
# File 'lib/arjdbc/mssql/adapter.rb', line 124

def supports_datetime_with_precision?
  true
end

#supports_ddl_transactions?Boolean

Does this adapter support DDL rollbacks in transactions? That is, would CREATE TABLE or ALTER TABLE get rolled back by a transaction?

Returns:

  • (Boolean)


101
102
103
# File 'lib/arjdbc/mssql/adapter.rb', line 101

def supports_ddl_transactions?
  true
end

#supports_foreign_keys?Boolean

Does this adapter support creating foreign key constraints?

Returns:

  • (Boolean)


106
107
108
# File 'lib/arjdbc/mssql/adapter.rb', line 106

def supports_foreign_keys?
  true
end

#supports_index_sort_order?Boolean

Does this adapter support index sort order?

Returns:

  • (Boolean)


129
130
131
# File 'lib/arjdbc/mssql/adapter.rb', line 129

def supports_index_sort_order?
  true
end

#supports_insert_on_conflict?Boolean Also known as: supports_insert_on_duplicate_skip?, supports_insert_on_duplicate_update?, supports_insert_conflict_target?

Returns:

  • (Boolean)


143
144
145
# File 'lib/arjdbc/mssql/adapter.rb', line 143

def supports_insert_on_conflict?
  false
end

#supports_lazy_transactions?Boolean

Returns:

  • (Boolean)


119
120
121
# File 'lib/arjdbc/mssql/adapter.rb', line 119

def supports_lazy_transactions?
  true
end

#supports_partial_index?Boolean

Also known as filtered index

Returns:

  • (Boolean)


134
135
136
# File 'lib/arjdbc/mssql/adapter.rb', line 134

def supports_partial_index?
  true
end

#supports_savepoints?Boolean

Returns:

  • (Boolean)


115
116
117
# File 'lib/arjdbc/mssql/adapter.rb', line 115

def supports_savepoints?
  true
end

#supports_transaction_isolation?Boolean

Does this adapter support setting the isolation level for a transaction?

Returns:

  • (Boolean)


111
112
113
# File 'lib/arjdbc/mssql/adapter.rb', line 111

def supports_transaction_isolation?
  true
end

#supports_views?Boolean

Does this adapter support views?

Returns:

  • (Boolean)


139
140
141
# File 'lib/arjdbc/mssql/adapter.rb', line 139

def supports_views?
  true
end

#tables_with_referential_integrityObject



296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
# File 'lib/arjdbc/mssql/adapter.rb', line 296

def tables_with_referential_integrity
  schema_and_tables_sql = %(
    SELECT s.name, o.name
    FROM sys.foreign_keys i
    INNER JOIN sys.objects o ON i.parent_object_id = o.OBJECT_ID
    INNER JOIN sys.schemas s ON o.schema_id = s.schema_id
  ).squish

  schemas_and_tables = select_rows(schema_and_tables_sql)

  schemas_and_tables.map do |schema_table|
    schema, table = schema_table
    "#{quote_name_part(schema)}.#{quote_name_part(table)}"
  end
end

#valid_type?(type) ⇒ Boolean

Overrides abstract method which always returns false

Returns:

  • (Boolean)


156
157
158
# File 'lib/arjdbc/mssql/adapter.rb', line 156

def valid_type?(type)
  !native_database_types[type].nil?
end