Skip to content

Move AbstractAdapter#valid_type? to a class method #1326

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 25, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ See [Rubygems](https://rubygems.org/gems/activerecord-sqlserver-adapter/versions

#### Native Data Type Support

We support every data type supported by FreeTDS. All simplified Rails types in migrations will correspond to a matching SQL Server national (unicode) data type. Always check the `initialize_native_database_types` [(here)](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/blob/master/lib/active_record/connection_adapters/sqlserver/schema_statements.rb) for an updated list.
We support every data type supported by FreeTDS. All simplified Rails types in migrations will correspond to a matching SQL Server national (unicode) data type. Always check the `NATIVE_DATABASE_TYPES` [(here)](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/blob/master/lib/active_record/connection_adapters/sqlserver_adapter.rb) for an updated list.

The following types (`date`, `datetime2`, `datetimeoffset`, `time`) all require TDS version `7.3` with TinyTDS. We recommend using FreeTDS 1.0 or higher which default to using `TDSVER` to `7.3`. The adapter also sets TinyTDS's `tds_version` to this as well if non is specified.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,6 @@ module ActiveRecord
module ConnectionAdapters
module SQLServer
module SchemaStatements
def native_database_types
@native_database_types ||= initialize_native_database_types.freeze
end

def create_table(table_name, **options)
res = super
clear_cache!
Expand Down Expand Up @@ -488,42 +484,6 @@ def quoted_scope(name = nil, type: nil)

# === SQLServer Specific ======================================== #

def initialize_native_database_types
{
primary_key: "bigint NOT NULL IDENTITY(1,1) PRIMARY KEY",
primary_key_nonclustered: "bigint NOT NULL IDENTITY(1,1) PRIMARY KEY NONCLUSTERED",
integer: {name: "int", limit: 4},
bigint: {name: "bigint"},
boolean: {name: "bit"},
decimal: {name: "decimal"},
money: {name: "money"},
smallmoney: {name: "smallmoney"},
float: {name: "float"},
real: {name: "real"},
date: {name: "date"},
datetime: {name: "datetime"},
datetime2: {name: "datetime2"},
datetimeoffset: {name: "datetimeoffset"},
smalldatetime: {name: "smalldatetime"},
timestamp: {name: "datetime2(6)"},
time: {name: "time"},
char: {name: "char"},
varchar: {name: "varchar", limit: 8000},
varchar_max: {name: "varchar(max)"},
text_basic: {name: "text"},
nchar: {name: "nchar"},
string: {name: "nvarchar", limit: 4000},
text: {name: "nvarchar(max)"},
ntext: {name: "ntext"},
binary_basic: {name: "binary"},
varbinary: {name: "varbinary", limit: 8000},
binary: {name: "varbinary(max)"},
uuid: {name: "uniqueidentifier"},
ss_timestamp: {name: "timestamp"},
json: {name: "nvarchar(max)"}
}
end

def column_definitions(table_name)
identifier = database_prefix_identifier(table_name)
database = identifier.fully_qualified_database_quoted
Expand Down
38 changes: 38 additions & 0 deletions lib/active_record/connection_adapters/sqlserver_adapter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,40 @@ class SQLServerAdapter < AbstractAdapter
self.use_output_inserted = true
self.exclude_output_inserted_table_names = Concurrent::Map.new { false }

NATIVE_DATABASE_TYPES = {
primary_key: "bigint NOT NULL IDENTITY(1,1) PRIMARY KEY",
primary_key_nonclustered: "bigint NOT NULL IDENTITY(1,1) PRIMARY KEY NONCLUSTERED",
integer: {name: "int", limit: 4},
bigint: {name: "bigint"},
boolean: {name: "bit"},
decimal: {name: "decimal"},
money: {name: "money"},
smallmoney: {name: "smallmoney"},
float: {name: "float"},
real: {name: "real"},
date: {name: "date"},
datetime: {name: "datetime"},
datetime2: {name: "datetime2"},
datetimeoffset: {name: "datetimeoffset"},
smalldatetime: {name: "smalldatetime"},
timestamp: {name: "datetime2(6)"},
time: {name: "time"},
char: {name: "char"},
varchar: {name: "varchar", limit: 8000},
varchar_max: {name: "varchar(max)"},
text_basic: {name: "text"},
nchar: {name: "nchar"},
string: {name: "nvarchar", limit: 4000},
text: {name: "nvarchar(max)"},
ntext: {name: "ntext"},
binary_basic: {name: "binary"},
varbinary: {name: "varbinary", limit: 8000},
binary: {name: "varbinary(max)"},
uuid: {name: "uniqueidentifier"},
ss_timestamp: {name: "timestamp"},
json: {name: "nvarchar(max)"}
}

class << self
def dbconsole(config, options = {})
sqlserver_config = config.configuration_hash
Expand Down Expand Up @@ -95,6 +129,10 @@ def rails_application_name
rescue
nil # Might not be in a Rails context so we fallback to `nil`.
end

def native_database_types # :nodoc:
NATIVE_DATABASE_TYPES
end
end

def initialize(...)
Expand Down
4 changes: 2 additions & 2 deletions test/cases/coerced_tests.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1850,13 +1850,13 @@ class TransactionIsolationTest < ActiveRecord::TestCase
# can assert the number of expected isolation level events.
undef_method :assert_begin_isolation_level_event
def assert_begin_isolation_level_event(events, isolation: "READ COMMITTED")
isolation_events = events.select { _1.match(/SET TRANSACTION ISOLATION LEVEL/) }
isolation_events = events.select { |event| event.match(/SET TRANSACTION ISOLATION LEVEL/) }

index_of_reset_starting_isolation_level_event = isolation_events.index("SET TRANSACTION ISOLATION LEVEL READ COMMITTED")
assert index_of_reset_starting_isolation_level_event.present?
isolation_events.delete_at(index_of_reset_starting_isolation_level_event)

assert_equal 1, isolation_events.select { _1.match(/SET TRANSACTION ISOLATION LEVEL #{isolation}/) }.size
assert_equal 1, isolation_events.count { |event| event.match(/SET TRANSACTION ISOLATION LEVEL #{isolation}/) }
end
end

Expand Down