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 139

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 143

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 38

def prepare_update_statement(o)
  if o.key && has_join_sources?(o) && !has_group_by_and_having?(o) && !has_limit_or_offset_or_orders?(o)
    # Join clauses cannot reference the target table, so alias the
    # updated table, place the entire relation in the FROM clause, and
    # add a self-join (which requires the primary key)
    stmt = o.clone
    stmt.relation, stmt.wheres = o.relation.clone, o.wheres.clone
    stmt.relation.right = [stmt.relation.left, *stmt.relation.right]
    stmt.relation.left = stmt.relation.left.alias("__active_record_update_alias")
    Array.wrap(o.key).each do |key|
      stmt.wheres << key.eq(stmt.relation.left[key.name])
    end
    stmt
  else
    super
  end
end

#visit_Arel_Nodes_Cube(o, collector) (private)

[ GitHub ]

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

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 88

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 67

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 93

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 108

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

#visit_Arel_Nodes_InnerJoin(o, collector) (private)

[ GitHub ]

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

def visit_Arel_Nodes_InnerJoin(o, collector)
  return super if o.right
  collector << "CROSS JOIN "
  visit o.left, collector
end

#visit_Arel_Nodes_IsDistinctFrom(o, collector) (private)

[ GitHub ]

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

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 124

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 113

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 56

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 83

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 78

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 103

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 AS __active_record_update_alias
  #   SET ..
  #   FROM t1 JOIN t2 ON t2.join_id = t1.join_id ..
  #   WHERE t1.id = __active_record_update_alias.id AND ..
  if has_join_sources?(o)
    collector = visit o.relation.left, collector
    collect_nodes_for o.values, collector, " SET "
    collector << " FROM "
    collector = inject_join o.relation.right, collector, " "
  else
    collector = visit o.relation, collector
    collect_nodes_for o.values, collector, " SET "
  end

  collect_nodes_for o.wheres, collector, " WHERE ", " AND "
  collect_nodes_for o.orders, collector, " ORDER BY "
  maybe_visit o.limit, collector
  maybe_visit o.comment, collector
end