|
| 1 | +require 'active_record/version' |
| 2 | + |
| 3 | +module ActiveRecord |
| 4 | + module ConnectionAdapters |
| 5 | + module SQLServerCoreExtensions |
| 6 | + |
| 7 | + |
| 8 | + module ActiveRecord |
| 9 | + |
| 10 | + def self.included(klass) |
| 11 | + klass.extend ClassMethods |
| 12 | + class << klass |
| 13 | + alias_method_chain :reset_column_information, :sqlserver_cache_support |
| 14 | + alias_method_chain :add_order!, :sqlserver_unique_checking |
| 15 | + alias_method_chain :add_limit!, :sqlserver_order_checking |
| 16 | + end |
| 17 | + end |
| 18 | + |
| 19 | + module ClassMethods |
| 20 | + |
| 21 | + def execute_procedure(proc_name, *variables) |
| 22 | + if connection.respond_to?(:execute_procedure) |
| 23 | + connection.execute_procedure(proc_name,*variables) |
| 24 | + else |
| 25 | + [] |
| 26 | + end |
| 27 | + end |
| 28 | + |
| 29 | + def coerce_sqlserver_date(*attributes) |
| 30 | + write_inheritable_attribute :coerced_sqlserver_date_columns, Set.new(attributes.map(&:to_s)) |
| 31 | + end |
| 32 | + |
| 33 | + def coerce_sqlserver_time(*attributes) |
| 34 | + write_inheritable_attribute :coerced_sqlserver_time_columns, Set.new(attributes.map(&:to_s)) |
| 35 | + end |
| 36 | + |
| 37 | + def coerced_sqlserver_date_columns |
| 38 | + read_inheritable_attribute(:coerced_sqlserver_date_columns) || [] |
| 39 | + end |
| 40 | + |
| 41 | + def coerced_sqlserver_time_columns |
| 42 | + read_inheritable_attribute(:coerced_sqlserver_time_columns) || [] |
| 43 | + end |
| 44 | + |
| 45 | + def reset_column_information_with_sqlserver_cache_support |
| 46 | + connection.send(:initialize_sqlserver_caches) if connection.respond_to?(:sqlserver?) |
| 47 | + reset_column_information_without_sqlserver_cache_support |
| 48 | + end |
| 49 | + |
| 50 | + private |
| 51 | + |
| 52 | + def add_limit_with_sqlserver_order_checking!(sql, options, scope = :auto) |
| 53 | + if connection.respond_to?(:sqlserver?) |
| 54 | + scope = scope(:find) if :auto == scope |
| 55 | + if scope |
| 56 | + options = options.dup |
| 57 | + scoped_order = scope[:order] |
| 58 | + order = options[:order] |
| 59 | + if order && scoped_order |
| 60 | + options[:order] = add_order_with_sqlserver_unique_checking!('', order, scope).gsub(/^ ORDER BY /,'') |
| 61 | + elsif scoped_order |
| 62 | + options[:order] = scoped_order |
| 63 | + end |
| 64 | + end |
| 65 | + end |
| 66 | + add_limit_without_sqlserver_order_checking!(sql, options, scope) |
| 67 | + end |
| 68 | + |
| 69 | + def add_order_with_sqlserver_unique_checking!(sql, order, scope = :auto) |
| 70 | + if connection.respond_to?(:sqlserver?) |
| 71 | + order_sql = '' |
| 72 | + add_order_without_sqlserver_unique_checking!(order_sql, order, scope) |
| 73 | + unless order_sql.blank? |
| 74 | + unique_order_hash = {} |
| 75 | + select_table_name = connection.send(:get_table_name,sql) |
| 76 | + select_table_name.tr!('[]','') if select_table_name |
| 77 | + orders_and_dirs_set = connection.send(:orders_and_dirs_set,order_sql) |
| 78 | + unique_order_sql = orders_and_dirs_set.inject([]) do |array,order_dir| |
| 79 | + ord, dir = order_dir |
| 80 | + ord_tn_and_cn = ord.to_s.split('.').map{|o|o.tr('[]','')} |
| 81 | + ord_table_name, ord_column_name = if ord_tn_and_cn.size > 1 |
| 82 | + ord_tn_and_cn |
| 83 | + else |
| 84 | + [nil, ord_tn_and_cn.first] |
| 85 | + end |
| 86 | + if (ord_table_name && ord_table_name == select_table_name && unique_order_hash[ord_column_name]) || unique_order_hash[ord_column_name] |
| 87 | + array |
| 88 | + else |
| 89 | + unique_order_hash[ord_column_name] = true |
| 90 | + array << "#{ord} #{dir}".strip |
| 91 | + end |
| 92 | + end.join(', ') |
| 93 | + sql << " ORDER BY #{unique_order_sql}" |
| 94 | + end |
| 95 | + else |
| 96 | + add_order_without_sqlserver_unique_checking!(sql, order, scope) |
| 97 | + end |
| 98 | + end |
| 99 | + |
| 100 | + end |
| 101 | + |
| 102 | + module JoinAssociationChanges |
| 103 | + |
| 104 | + def self.included(klass) |
| 105 | + klass.class_eval do |
| 106 | + include InstanceMethods |
| 107 | + alias_method_chain :aliased_table_name_for, :sqlserver_support |
| 108 | + end |
| 109 | + end |
| 110 | + |
| 111 | + module InstanceMethods |
| 112 | + |
| 113 | + protected |
| 114 | + |
| 115 | + # An exact copy, except this method has a Regexp escape on the quoted table name. |
| 116 | + def aliased_table_name_for_with_sqlserver_support(name,suffix=nil) |
| 117 | + if !parent.table_joins.blank? && parent.table_joins.to_s.downcase =~ %r{join(\s+\w+)?\s+#{Regexp.escape(active_record.connection.quote_table_name(name.downcase))}\son}i |
| 118 | + @join_dependency.table_aliases[name] += 1 |
| 119 | + end |
| 120 | + unless @join_dependency.table_aliases[name].zero? |
| 121 | + # if the table name has been used, then use an alias |
| 122 | + name = active_record.connection.table_alias_for "#{pluralize(reflection.name)}_#{parent_table_name}#{suffix}" |
| 123 | + table_index = @join_dependency.table_aliases[name] |
| 124 | + @join_dependency.table_aliases[name] += 1 |
| 125 | + name = name[0..active_record.connection.table_alias_length-3] + "_#{table_index+1}" if table_index > 0 |
| 126 | + else |
| 127 | + @join_dependency.table_aliases[name] += 1 |
| 128 | + end |
| 129 | + name |
| 130 | + end |
| 131 | + |
| 132 | + end |
| 133 | + |
| 134 | + end |
| 135 | + |
| 136 | + end |
| 137 | + |
| 138 | + |
| 139 | + end |
| 140 | + end |
| 141 | +end |
| 142 | + |
| 143 | + |
| 144 | +ActiveRecord::Base.send :include, ActiveRecord::ConnectionAdapters::SQLServerCoreExtensions::ActiveRecord |
| 145 | + |
| 146 | +if ActiveRecord::VERSION::MAJOR == 2 && ActiveRecord::VERSION::MINOR >= 3 |
| 147 | + require 'active_record/associations' |
| 148 | + ActiveRecord::Associations::ClassMethods::JoinDependency::JoinAssociation.send :include, ActiveRecord::ConnectionAdapters::SQLServerCoreExtensions::ActiveRecord::JoinAssociationChanges |
| 149 | +end |
| 150 | + |
0 commit comments