123456789_123456789_123456789_123456789_123456789_

Class: Arel::Visitors::PostgreSQL

Do not use. This class is for internal use only.
Relationships & Source Files
Super Chains via Extension / Inclusion / Inheritance
Class Chain:
self, ToSql, Visitor
Instance Chain:
self, ToSql, Visitor
Inherits: Arel::Visitors::ToSql
Defined in: activerecord/lib/arel/visitors/postgresql.rb

Constant Summary

ToSql - Inherited

BIND_BLOCK

Class Method Summary

ToSql - Inherited

Visitor - Inherited

Instance Attribute Summary

Visitor - Inherited

Instance Method Summary

ToSql - Inherited

#compile, #aggregate, #bind_block,
#build_subselect

FIXME: we should probably have a 2-pass visitor for this.

#collect_ctes, #collect_nodes_for, #collect_optimizer_hints,
#grouping_parentheses

Used by some visitors to enclose select queries in parentheses.

#has_group_by_and_having?, #has_join_sources?, #has_limit_or_offset_or_orders?, #infix_value, #infix_value_with_paren, #inject_join, #is_distinct_from, #maybe_visit,
#prepare_delete_statement
#prepare_update_statement

The default strategy for an UPDATE with joins is to use a subquery.

#quote, #quote_column_name, #quote_table_name, #require_parentheses?, #sanitize_as_sql_comment, #unboundable?, #unsupported, #visit_ActiveModel_Attribute,
#visit_ActiveSupport_Multibyte_Chars
#visit_ActiveSupport_StringInquirer
#visit_Arel_Attributes_Attribute, #visit_Arel_Nodes_And, #visit_Arel_Nodes_As, #visit_Arel_Nodes_Ascending, #visit_Arel_Nodes_Assignment, #visit_Arel_Nodes_Avg, #visit_Arel_Nodes_Between, #visit_Arel_Nodes_Bin, #visit_Arel_Nodes_BindParam, #visit_Arel_Nodes_BoundSqlLiteral, #visit_Arel_Nodes_Case, #visit_Arel_Nodes_Casted, #visit_Arel_Nodes_Comment, #visit_Arel_Nodes_Count, #visit_Arel_Nodes_Cte, #visit_Arel_Nodes_CurrentRow, #visit_Arel_Nodes_DeleteStatement, #visit_Arel_Nodes_Descending, #visit_Arel_Nodes_Distinct, #visit_Arel_Nodes_DistinctOn, #visit_Arel_Nodes_DoesNotMatch, #visit_Arel_Nodes_Else, #visit_Arel_Nodes_Equality, #visit_Arel_Nodes_Except, #visit_Arel_Nodes_Exists, #visit_Arel_Nodes_Extract, #visit_Arel_Nodes_False, #visit_Arel_Nodes_Filter, #visit_Arel_Nodes_Following, #visit_Arel_Nodes_Fragments, #visit_Arel_Nodes_FullOuterJoin, #visit_Arel_Nodes_GreaterThan, #visit_Arel_Nodes_GreaterThanOrEqual, #visit_Arel_Nodes_Group, #visit_Arel_Nodes_Grouping, #visit_Arel_Nodes_HomogeneousIn, #visit_Arel_Nodes_In, #visit_Arel_Nodes_InfixOperation, #visit_Arel_Nodes_InnerJoin, #visit_Arel_Nodes_InsertStatement, #visit_Arel_Nodes_Intersect, #visit_Arel_Nodes_IsDistinctFrom, #visit_Arel_Nodes_IsNotDistinctFrom, #visit_Arel_Nodes_JoinSource, #visit_Arel_Nodes_LessThan, #visit_Arel_Nodes_LessThanOrEqual, #visit_Arel_Nodes_Limit, #visit_Arel_Nodes_Lock, #visit_Arel_Nodes_Matches, #visit_Arel_Nodes_Max, #visit_Arel_Nodes_Min, #visit_Arel_Nodes_NamedFunction, #visit_Arel_Nodes_NamedWindow, #visit_Arel_Nodes_Not, #visit_Arel_Nodes_NotEqual, #visit_Arel_Nodes_NotIn, #visit_Arel_Nodes_NotRegexp,
#visit_Arel_Nodes_NullsFirst

NullsFirst is available on all but MySQL, where it is redefined.

#visit_Arel_Nodes_NullsLast, #visit_Arel_Nodes_Offset, #visit_Arel_Nodes_On, #visit_Arel_Nodes_OptimizerHints, #visit_Arel_Nodes_Or, #visit_Arel_Nodes_OuterJoin, #visit_Arel_Nodes_Over, #visit_Arel_Nodes_Preceding,
#visit_Arel_Nodes_Quoted
#visit_Arel_Nodes_Range, #visit_Arel_Nodes_Regexp, #visit_Arel_Nodes_RightOuterJoin, #visit_Arel_Nodes_Rows, #visit_Arel_Nodes_SelectCore,
#visit_Arel_Nodes_SelectOptions

The Oracle enhanced adapter uses this private method, see github.com/rsim/oracle-enhanced/issues/2186.

#visit_Arel_Nodes_SelectStatement, #visit_Arel_Nodes_SqlLiteral, #visit_Arel_Nodes_StringJoin, #visit_Arel_Nodes_Sum, #visit_Arel_Nodes_TableAlias, #visit_Arel_Nodes_True, #visit_Arel_Nodes_UnaryOperation, #visit_Arel_Nodes_Union, #visit_Arel_Nodes_UnionAll, #visit_Arel_Nodes_UnqualifiedColumn, #visit_Arel_Nodes_UpdateStatement, #visit_Arel_Nodes_ValuesList, #visit_Arel_Nodes_When, #visit_Arel_Nodes_Window, #visit_Arel_Nodes_With, #visit_Arel_Nodes_WithRecursive, #visit_Arel_SelectManager, #visit_Arel_Table, #visit_Array,
#visit_BigDecimal
#visit_Class
#visit_Date
#visit_DateTime
#visit_FalseClass
#visit_Float
#visit_Hash
#visit_Integer,
#visit_NilClass
#visit_Set
#visit_String
#visit_Symbol
#visit_Time
#visit_TrueClass

Visitor - Inherited

Constructor Details

This class inherits a constructor from Arel::Visitors::ToSql

Instance Method Details

#bind_block (private)

[ GitHub ]

  
# File 'activerecord/lib/arel/visitors/postgresql.rb', line 151

def bind_block; BIND_BLOCK; end

#grouping_array_or_grouping_element(o, collector) (private)

Utilized by GroupingSet, Cube & RollUp visitors to handle grouping aggregation semantics

[ GitHub ]

  
# File 'activerecord/lib/arel/visitors/postgresql.rb', line 155

def grouping_array_or_grouping_element(o, collector)
  if o.expr.is_a? Array
    collector << "( "
    visit o.expr, collector
    collector << " )"
  else
    visit o.expr, collector
  end
end

#prepare_update_statement(o) (private)

In the simple case, PostgreSQL allows us to place FROM or JOINs directly into the UPDATE query. However, this does not allow for LIMIT, OFFSET and ORDER. To support these, we must use a subquery.

[ GitHub ]

  
# File 'activerecord/lib/arel/visitors/postgresql.rb', line 62

def prepare_update_statement(o)
  if has_join_sources?(o) && !has_limit_or_offset_or_orders?(o) && !has_group_by_and_having?(o) &&
    # The PostgreSQL dialect isn't flexible enough to allow anything other than a inner join
    # for the first join:
    #   UPDATE table SET .. FROM joined_table WHERE ...
    (o.relation.right.all? { |join| join.is_a?(Arel::Nodes::InnerJoin) || join.right.expr.right.relation != o.relation.left })
    o
  else
    super
  end
end

#visit_Arel_Nodes_Cube(o, collector) (private)

[ GitHub ]

  
# File 'activerecord/lib/arel/visitors/postgresql.rb', line 116

def visit_Arel_Nodes_Cube(o, collector)
  collector << "CUBE"
  grouping_array_or_grouping_element o, collector
end

#visit_Arel_Nodes_DistinctOn(o, collector) (private)

[ GitHub ]

  
# File 'activerecord/lib/arel/visitors/postgresql.rb', line 106

def visit_Arel_Nodes_DistinctOn(o, collector)
  collector << "DISTINCT ON ( "
  visit(o.expr, collector) << " )"
end

#visit_Arel_Nodes_DoesNotMatch(o, collector) (private)

[ GitHub ]

  
# File 'activerecord/lib/arel/visitors/postgresql.rb', line 85

def visit_Arel_Nodes_DoesNotMatch(o, collector)
  op = o.case_sensitive ? " NOT LIKE " : " NOT ILIKE "
  collector = infix_value o, collector, op
  if o.escape
    collector << " ESCAPE "
    visit o.escape, collector
  else
    collector
  end
end

#visit_Arel_Nodes_GroupingElement(o, collector) (private)

[ GitHub ]

  
# File 'activerecord/lib/arel/visitors/postgresql.rb', line 111

def visit_Arel_Nodes_GroupingElement(o, collector)
  collector << "( "
  visit(o.expr, collector) << " )"
end

#visit_Arel_Nodes_GroupingSet(o, collector) (private)

[ GitHub ]

  
# File 'activerecord/lib/arel/visitors/postgresql.rb', line 126

def visit_Arel_Nodes_GroupingSet(o, collector)
  collector << "GROUPING SETS"
  grouping_array_or_grouping_element o, collector
end

#visit_Arel_Nodes_IsDistinctFrom(o, collector) (private)

[ GitHub ]

  
# File 'activerecord/lib/arel/visitors/postgresql.rb', line 142

def visit_Arel_Nodes_IsDistinctFrom(o, collector)
  collector = visit o.left, collector
  collector << " IS DISTINCT FROM "
  visit o.right, collector
end

#visit_Arel_Nodes_IsNotDistinctFrom(o, collector) (private)

[ GitHub ]

  
# File 'activerecord/lib/arel/visitors/postgresql.rb', line 136

def visit_Arel_Nodes_IsNotDistinctFrom(o, collector)
  collector = visit o.left, collector
  collector << " IS NOT DISTINCT FROM "
  visit o.right, collector
end

#visit_Arel_Nodes_Lateral(o, collector) (private)

[ GitHub ]

  
# File 'activerecord/lib/arel/visitors/postgresql.rb', line 131

def visit_Arel_Nodes_Lateral(o, collector)
  collector << "LATERAL "
  grouping_parentheses o.expr, collector
end

#visit_Arel_Nodes_Matches(o, collector) (private)

[ GitHub ]

  
# File 'activerecord/lib/arel/visitors/postgresql.rb', line 74

def visit_Arel_Nodes_Matches(o, collector)
  op = o.case_sensitive ? " LIKE " : " ILIKE "
  collector = infix_value o, collector, op
  if o.escape
    collector << " ESCAPE "
    visit o.escape, collector
  else
    collector
  end
end

#visit_Arel_Nodes_NotRegexp(o, collector) (private)

[ GitHub ]

  
# File 'activerecord/lib/arel/visitors/postgresql.rb', line 101

def visit_Arel_Nodes_NotRegexp(o, collector)
  op = o.case_sensitive ? " !~ " : " !~* "
  infix_value o, collector, op
end

#visit_Arel_Nodes_Regexp(o, collector) (private)

[ GitHub ]

  
# File 'activerecord/lib/arel/visitors/postgresql.rb', line 96

def visit_Arel_Nodes_Regexp(o, collector)
  op = o.case_sensitive ? " ~ " : " ~* "
  infix_value o, collector, op
end

#visit_Arel_Nodes_RollUp(o, collector) (private)

[ GitHub ]

  
# File 'activerecord/lib/arel/visitors/postgresql.rb', line 121

def visit_Arel_Nodes_RollUp(o, collector)
  collector << "ROLLUP"
  grouping_array_or_grouping_element o, collector
end

#visit_Arel_Nodes_UpdateStatement(o, collector) (private)

[ GitHub ]

  
# File 'activerecord/lib/arel/visitors/postgresql.rb', line 7

def visit_Arel_Nodes_UpdateStatement(o, collector)
  collector.retryable = false
  o = prepare_update_statement(o)

  collector << "UPDATE "

  # UPDATE with JOIN is in the form of:
  #
  #   UPDATE t1
  #   SET ..
  #   FROM t2
  #   WHERE t1.join_id = t2.join_id
  #
  # Or if more than one join is present:
  #
  #   UPDATE t1
  #   SET ..
  #   FROM t2
  #   JOIN t3 ON t2.join_id = t3.join_id
  #   WHERE t1.join_id = t2.join_id
  if has_join_sources?(o)
    visit o.relation.left, collector
    collect_nodes_for o.values, collector, " SET "
    collector << " FROM "
    first_join, *remaining_joins = o.relation.right
    from_items = remaining_joins.extract! do |join|
      join.right.expr.right.relation == o.relation.left
    end

    from_where = [first_join.left] + from_items.map(&:left)
    collect_nodes_for from_where, collector, " ", ", "

    if remaining_joins && !remaining_joins.empty?
      collector << " "
      remaining_joins.each do |join|
        visit join, collector
        collector << " "
      end
    end

    from_where = [first_join.right.expr] + from_items.map { |i| i.right.expr }
    collect_nodes_for from_where + o.wheres, collector, " WHERE ", " AND "
  else
    collector = visit o.relation, collector
    collect_nodes_for o.values, collector, " SET "
    collect_nodes_for o.wheres, collector, " WHERE ", " AND "
  end

  collect_nodes_for o.orders, collector, " ORDER BY "
  maybe_visit o.limit, collector
end