class Arel::Visitors::SQLServer

@note AREL set's up `Arel::Visitors::MSSQL` but its not usable as is … @private

Constants

MAX_LIMIT_VALUE

@private

Private Class Methods

possibly_private_method_defined?(name) click to toggle source
# File lib/arel/visitors/sql_server.rb, line 104
def self.possibly_private_method_defined?(name)
  private_method_defined?(name) || method_defined?(name)
end

Private Instance Methods

determine_order_by(x, a) click to toggle source
# File lib/arel/visitors/sql_server.rb, line 112
def determine_order_by x, a
  unless x.groups.empty?
    do_visit_columns x.groups, a, 'ORDER BY '
  else
    table_pk = find_left_table_pk(x)
    table_pk && "ORDER BY #{table_pk}"
  end
end
do_visit_columns(colls, a, sql) click to toggle source
# File lib/arel/visitors/sql_server.rb, line 125
def do_visit_columns(colls, a, sql)
  last = colls.size - 1
  colls.each_with_index do |x, i|
    sql << do_visit(x, a); sql << ', ' unless i == last
  end
  sql
end
find_left_table_pk(o) click to toggle source
# File lib/arel/visitors/sql_server.rb, line 121
def find_left_table_pk o
  primary_key_from_table table_from_select_core(o)
end
over_row_num(order_by) click to toggle source
# File lib/arel/visitors/sql_server.rb, line 163
def over_row_num order_by
  "ROW_NUMBER() OVER (#{order_by}) as _row_num"
end
primary_key_from_table(t) click to toggle source
# File lib/arel/visitors/sql_server.rb, line 191
def primary_key_from_table t
  return unless t
  return t.primary_key if t.primary_key

  engine = t.engine
  if engine_pk = engine.primary_key
    pk = engine.arel_table[engine_pk]
    return pk if pk
  end

  pk = (@primary_keys ||= {}).fetch(table_name = engine.table_name) do
    pk_name = @connection.primary_key(table_name)
    # some tables might be without primary key
    @primary_keys[table_name] = pk_name && t[pk_name]
  end
  return pk if pk

  column_name = engine.columns.first.try(:name)
  column_name && t[column_name]
end
select_count?(x) click to toggle source
# File lib/arel/visitors/sql_server.rb, line 108
def select_count? x
  x.projections.length == 1 && Arel::Nodes::Count === x.projections.first
end
table_from_select_core(core) click to toggle source
# File lib/arel/visitors/sql_server.rb, line 167
def table_from_select_core core
  if Arel::Table === core.from
    core.from
  elsif Arel::Nodes::SqlLiteral === core.from
    Arel::Table.new(core.from, @engine)
  elsif Arel::Nodes::JoinSource === core.source
    Arel::Nodes::SqlLiteral === core.source.left ? Arel::Table.new(core.source.left, @engine) : core.source.left
  end
end
visit_Arel_Nodes_Bin(o, a = nil) click to toggle source
# File lib/arel/visitors/sql_server.rb, line 92
def visit_Arel_Nodes_Bin o, a = nil
  expr = o.expr; sql = do_visit expr, a
  if expr.respond_to?(:val) && expr.val.is_a?(Numeric)
    sql
  else
    sql << " #{::ArJdbc::MSSQL.cs_equality_operator} "
    sql
  end
end
visit_Arel_Nodes_Limit(o, a = nil) click to toggle source
# File lib/arel/visitors/sql_server.rb, line 79
def visit_Arel_Nodes_Limit o, a = nil
  "TOP (#{do_visit o.expr, a})"
end
visit_Arel_Nodes_Lock(o, a = nil) click to toggle source
# File lib/arel/visitors/sql_server.rb, line 63
def visit_Arel_Nodes_Lock o, a = nil
  # MS-SQL doesn't support "SELECT...FOR UPDATE".  Instead, it needs
  # WITH(ROWLOCK,UPDLOCK) specified after each table in the FROM clause.
  #
  # we return nothing here and add the appropriate stuff with #add_lock!
  #do_visit o.expr, a
end
visit_Arel_Nodes_Ordering(o, a = nil) click to toggle source
# File lib/arel/visitors/sql_server.rb, line 83
def visit_Arel_Nodes_Ordering o, a = nil
  expr = do_visit o.expr, a
  if o.respond_to?(:direction)
    "#{expr} #{o.ascending? ? 'ASC' : 'DESC'}"
  else
    expr
  end
end
visit_Arel_Nodes_SelectStatement(*args) click to toggle source
# File lib/arel/visitors/sql_server.rb, line 14
def visit_Arel_Nodes_SelectStatement(*args) # [o] AR <= 4.0 [o, a] on 4.1
  o, a = args.first, args.last

  return _visit_Arel_Nodes_SelectStatement(*args) if ! o.limit && ! o.offset

  unless o.orders.empty?
    select_order_by = do_visit_columns o.orders, a, 'ORDER BY '
  end

  select_count = false; sql = ''
  o.cores.each do |x|
    x = x.dup
    core_order_by = select_order_by || determine_order_by(x, a)
    if select_count? x
      x.projections = [
        Arel::Nodes::SqlLiteral.new(core_order_by ? over_row_num(core_order_by) : '*')
      ]
      select_count = true
    else
      # NOTE: this should really be added here and we should built the
      # wrapping SQL but than #replace_limit_offset! assumes it does that
      # ... MS-SQL adapter code seems to be 'hacked' by a lot of people
      #x.projections << Arel::Nodes::SqlLiteral.new over_row_num(order_by)
    end
    sql << do_visit_select_core(x, a)
  end

  #sql = "SELECT _t.* FROM (#{sql}) as _t WHERE #{get_offset_limit_clause(o)}"
  select_order_by ||= "ORDER BY #{@connection.determine_order_clause(sql)}"
  replace_limit_offset!(sql, limit_for(o.limit), o.offset && o.offset.value.to_i, select_order_by)

  sql = "SELECT COUNT(*) AS count_id FROM (#{sql}) AS subquery" if select_count

  add_lock!(sql, :lock => o.lock && true)

  sql
end
visit_Arel_Nodes_Top(o, a = nil) click to toggle source
# File lib/arel/visitors/sql_server.rb, line 71
def visit_Arel_Nodes_Top o, a = nil
  # `top` wouldn't really work here:
  #   User.select("distinct first_name").limit(10)
  # would generate "select top 10 distinct first_name from users",
  # which is invalid should be "select distinct top 10 first_name ..."
  a || ''
end
visit_Arel_Nodes_UpdateStatement(*args) click to toggle source
Calls superclass method
# File lib/arel/visitors/sql_server.rb, line 55
def visit_Arel_Nodes_UpdateStatement(*args) # [o] AR <= 4.0 [o, a] on 4.1
  o = args.first
  if o.orders.any? && o.limit.nil?
    o.limit = Nodes::Limit.new(MAX_LIMIT_VALUE)
  end
  super
end