From 706249677fa3d84e44ce32bf58ae514ece7a1a5d Mon Sep 17 00:00:00 2001 From: Aidan Haran Date: Thu, 18 Apr 2024 18:30:32 +0100 Subject: [PATCH] Don't require an active connection for table and column quoting See https://github.com/rails/rails/pull/51174 --- .../sqlserver/database_statements.rb | 8 +- .../connection_adapters/sqlserver/quoting.rb | 90 +++++++++---------- 2 files changed, 48 insertions(+), 50 deletions(-) diff --git a/lib/active_record/connection_adapters/sqlserver/database_statements.rb b/lib/active_record/connection_adapters/sqlserver/database_statements.rb index f7abe9e2d..0b6f95ec2 100644 --- a/lib/active_record/connection_adapters/sqlserver/database_statements.rb +++ b/lib/active_record/connection_adapters/sqlserver/database_statements.rb @@ -153,10 +153,10 @@ def build_insert_sql(insert) # :nodoc: if returning = insert.send(:insert_all).returning returning_sql = if returning.is_a?(String) - returning - else - returning.map { |column| "INSERTED.#{quote_column_name(column)}" }.join(", ") - end + returning + else + returning.map { |column| "INSERTED.#{quote_column_name(column)}" }.join(", ") + end sql << " OUTPUT #{returning_sql}" end diff --git a/lib/active_record/connection_adapters/sqlserver/quoting.rb b/lib/active_record/connection_adapters/sqlserver/quoting.rb index 54f65ca54..3fe889bd5 100644 --- a/lib/active_record/connection_adapters/sqlserver/quoting.rb +++ b/lib/active_record/connection_adapters/sqlserver/quoting.rb @@ -4,9 +4,53 @@ module ActiveRecord module ConnectionAdapters module SQLServer module Quoting + extend ActiveSupport::Concern + QUOTED_COLUMN_NAMES = Concurrent::Map.new # :nodoc: QUOTED_TABLE_NAMES = Concurrent::Map.new # :nodoc: + module ClassMethods + def column_name_matcher + / + \A + ( + (?: + # [database_name].[database_owner].[table_name].[column_name] | function(one or no argument) + ((?:\w+\.|\[\w+\]\.)?(?:\w+\.|\[\w+\]\.)?(?:\w+\.|\[\w+\]\.)?(?:\w+|\[\w+\]) | \w+\((?:|\g<2>)\)) + ) + (?:\s+AS\s+(?:\w+|\[\w+\]))? + ) + (?:\s*,\s*\g<1>)* + \z + /ix + end + + def column_name_with_order_matcher + / + \A + ( + (?: + # [database_name].[database_owner].[table_name].[column_name] | function(one or no argument) + ((?:\w+\.|\[\w+\]\.)?(?:\w+\.|\[\w+\]\.)?(?:\w+\.|\[\w+\]\.)?(?:\w+|\[\w+\]) | \w+\((?:|\g<2>)\)) + ) + (?:\s+COLLATE\s+\w+)? + (?:\s+ASC|\s+DESC)? + (?:\s+NULLS\s+(?:FIRST|LAST))? + ) + (?:\s*,\s*\g<1>)* + \z + /ix + end + + def quote_column_name(name) + QUOTED_COLUMN_NAMES[name] ||= SQLServer::Utils.extract_identifiers(name).quoted + end + + def quote_table_name(name) + QUOTED_TABLE_NAMES[name] ||= SQLServer::Utils.extract_identifiers(name).quoted + end + end + def fetch_type_metadata(sql_type, sqlserver_options = {}) cast_type = lookup_cast_type(sql_type) @@ -33,14 +77,6 @@ def quote_string_single_national(s) SQLServer::Utils.quote_string_single_national(s) end - def quote_column_name(name) - QUOTED_COLUMN_NAMES[name] ||= SQLServer::Utils.extract_identifiers(name).quoted - end - - def quote_table_name(name) - QUOTED_TABLE_NAMES[name] ||= SQLServer::Utils.extract_identifiers(name).quoted - end - def quote_default_expression(value, column) cast_type = lookup_cast_type(column.sql_type) if cast_type.type == :uuid && value.is_a?(String) && value.include?('()') @@ -76,44 +112,6 @@ def quoted_date(value) end end - def column_name_matcher - COLUMN_NAME - end - - def column_name_with_order_matcher - COLUMN_NAME_WITH_ORDER - end - - COLUMN_NAME = / - \A - ( - (?: - # [database_name].[database_owner].[table_name].[column_name] | function(one or no argument) - ((?:\w+\.|\[\w+\]\.)?(?:\w+\.|\[\w+\]\.)?(?:\w+\.|\[\w+\]\.)?(?:\w+|\[\w+\]) | \w+\((?:|\g<2>)\)) - ) - (?:\s+AS\s+(?:\w+|\[\w+\]))? - ) - (?:\s*,\s*\g<1>)* - \z - /ix - - COLUMN_NAME_WITH_ORDER = / - \A - ( - (?: - # [database_name].[database_owner].[table_name].[column_name] | function(one or no argument) - ((?:\w+\.|\[\w+\]\.)?(?:\w+\.|\[\w+\]\.)?(?:\w+\.|\[\w+\]\.)?(?:\w+|\[\w+\]) | \w+\((?:|\g<2>)\)) - ) - (?:\s+COLLATE\s+\w+)? - (?:\s+ASC|\s+DESC)? - (?:\s+NULLS\s+(?:FIRST|LAST))? - ) - (?:\s*,\s*\g<1>)* - \z - /ix - - private_constant :COLUMN_NAME, :COLUMN_NAME_WITH_ORDER - def quote(value) case value when Type::Binary::Data