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 138

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 142

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 37

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 97

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 87

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 66

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 92

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 107

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 117

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 129

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 123

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 112

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 55

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 82

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 77

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 102

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
end