aboutsummaryrefslogtreecommitdiffstats
path: root/lib/arel/visitors
diff options
context:
space:
mode:
authorErnie Miller <ernie@erniemiller.org>2013-03-16 19:20:11 -0400
committerErnie Miller <ernie@erniemiller.org>2013-04-28 22:20:16 -0700
commit68a95542e1a7a79d9777223fbffd2b982fed0268 (patch)
tree7ae8829cefd20f214cfac9f8f1b141b4f9146739 /lib/arel/visitors
parent3ef63ac5366000b232ca5fe0848de9db9a3c1f9a (diff)
downloadrails-68a95542e1a7a79d9777223fbffd2b982fed0268.tar.gz
rails-68a95542e1a7a79d9777223fbffd2b982fed0268.tar.bz2
rails-68a95542e1a7a79d9777223fbffd2b982fed0268.zip
Make visitors threadsafe by removing @last_column
The last_column feature of the ToSql visitor and its descendants is what enabled quoting based on the column last visited -- in other words, if you have a standard condition like an equality with a string attribute on the left side and an integer on the right side, then when ARel visits the node, it'll first visit the left side attribute, setting the column of the string attribute as the last column, and resulting in the right side of the condition getting the appropriate quoting. The downside is that this means that visitors can't be shared between threads, because of the state mutation. It also makes for some really weird behavior in the event that the visitor visits a node that happens to contain an attribute you weren't expecting to be there, since it'll potentially quote something based on that attribute. So, it prevents reversing an equality condition. column = value will work, but not value = column, since the last column wouldn't be the column you're hoping for. This is a first pass at fixing this by changing the signature of the visit methods to accept the currently-relevant attribute, if any.
Diffstat (limited to 'lib/arel/visitors')
-rw-r--r--lib/arel/visitors/bind_visitor.rb8
-rw-r--r--lib/arel/visitors/depth_first.rb112
-rw-r--r--lib/arel/visitors/dot.rb150
-rw-r--r--lib/arel/visitors/ibm_db.rb4
-rw-r--r--lib/arel/visitors/informix.rb34
-rw-r--r--lib/arel/visitors/join_sql.rb4
-rw-r--r--lib/arel/visitors/mssql.rb24
-rw-r--r--lib/arel/visitors/mysql.rb30
-rw-r--r--lib/arel/visitors/oracle.rb34
-rw-r--r--lib/arel/visitors/order_clauses.rb4
-rw-r--r--lib/arel/visitors/postgresql.rb12
-rw-r--r--lib/arel/visitors/sqlite.rb4
-rw-r--r--lib/arel/visitors/to_sql.rb338
-rw-r--r--lib/arel/visitors/visitor.rb4
-rw-r--r--lib/arel/visitors/where_sql.rb4
15 files changed, 385 insertions, 381 deletions
diff --git a/lib/arel/visitors/bind_visitor.rb b/lib/arel/visitors/bind_visitor.rb
index 77f91d9451..77b3f8237b 100644
--- a/lib/arel/visitors/bind_visitor.rb
+++ b/lib/arel/visitors/bind_visitor.rb
@@ -13,22 +13,22 @@ module Arel
private
- def visit_Arel_Nodes_Assignment o
+ def visit_Arel_Nodes_Assignment o, a
if o.right.is_a? Arel::Nodes::BindParam
- "#{visit o.left} = #{visit o.right}"
+ "#{visit o.left, a} = #{visit o.right, a}"
else
super
end
end
- def visit_Arel_Nodes_BindParam o
+ def visit_Arel_Nodes_BindParam o, a
if @block
@block.call
else
super
end
end
-
+
end
end
end
diff --git a/lib/arel/visitors/depth_first.rb b/lib/arel/visitors/depth_first.rb
index 24c435ad1d..67cdecfa36 100644
--- a/lib/arel/visitors/depth_first.rb
+++ b/lib/arel/visitors/depth_first.rb
@@ -7,13 +7,13 @@ module Arel
private
- def visit o
+ def visit o, a = nil
super
@block.call o
end
- def unary o
- visit o.expr
+ def unary o, a
+ visit o.expr, a
end
alias :visit_Arel_Nodes_Group :unary
alias :visit_Arel_Nodes_Grouping :unary
@@ -28,10 +28,10 @@ module Arel
alias :visit_Arel_Nodes_Top :unary
alias :visit_Arel_Nodes_UnqualifiedColumn :unary
- def function o
- visit o.expressions
- visit o.alias
- visit o.distinct
+ def function o, a
+ visit o.expressions, a
+ visit o.alias, a
+ visit o.distinct, a
end
alias :visit_Arel_Nodes_Avg :function
alias :visit_Arel_Nodes_Exists :function
@@ -39,27 +39,27 @@ module Arel
alias :visit_Arel_Nodes_Min :function
alias :visit_Arel_Nodes_Sum :function
- def visit_Arel_Nodes_NamedFunction o
- visit o.name
- visit o.expressions
- visit o.distinct
- visit o.alias
+ def visit_Arel_Nodes_NamedFunction o, a
+ visit o.name, a
+ visit o.expressions, a
+ visit o.distinct, a
+ visit o.alias, a
end
- def visit_Arel_Nodes_Count o
- visit o.expressions
- visit o.alias
- visit o.distinct
+ def visit_Arel_Nodes_Count o, a
+ visit o.expressions, a
+ visit o.alias, a
+ visit o.distinct, a
end
- def nary o
- o.children.each { |child| visit child }
+ def nary o, a
+ o.children.each { |child| visit child, a }
end
alias :visit_Arel_Nodes_And :nary
- def binary o
- visit o.left
- visit o.right
+ def binary o, a
+ visit o.left, a
+ visit o.right, a
end
alias :visit_Arel_Nodes_As :binary
alias :visit_Arel_Nodes_Assignment :binary
@@ -83,13 +83,13 @@ module Arel
alias :visit_Arel_Nodes_TableAlias :binary
alias :visit_Arel_Nodes_Values :binary
- def visit_Arel_Nodes_StringJoin o
- visit o.left
+ def visit_Arel_Nodes_StringJoin o, a
+ visit o.left, a
end
- def visit_Arel_Attribute o
- visit o.relation
- visit o.name
+ def visit_Arel_Attribute o, a
+ visit o.relation, a
+ visit o.name, a
end
alias :visit_Arel_Attributes_Integer :visit_Arel_Attribute
alias :visit_Arel_Attributes_Float :visit_Arel_Attribute
@@ -99,11 +99,11 @@ module Arel
alias :visit_Arel_Attributes_Attribute :visit_Arel_Attribute
alias :visit_Arel_Attributes_Decimal :visit_Arel_Attribute
- def visit_Arel_Table o
- visit o.name
+ def visit_Arel_Table o, a
+ visit o.name, a
end
- def terminal o
+ def terminal o, a
end
alias :visit_ActiveSupport_Multibyte_Chars :terminal
alias :visit_ActiveSupport_StringInquirer :terminal
@@ -127,43 +127,43 @@ module Arel
alias :visit_Time :terminal
alias :visit_TrueClass :terminal
- def visit_Arel_Nodes_InsertStatement o
- visit o.relation
- visit o.columns
- visit o.values
+ def visit_Arel_Nodes_InsertStatement o, a
+ visit o.relation, a
+ visit o.columns, a
+ visit o.values, a
end
- def visit_Arel_Nodes_SelectCore o
- visit o.projections
- visit o.source
- visit o.wheres
- visit o.groups
- visit o.windows
- visit o.having
+ def visit_Arel_Nodes_SelectCore o, a
+ visit o.projections, a
+ visit o.source, a
+ visit o.wheres, a
+ visit o.groups, a
+ visit o.windows, a
+ visit o.having, a
end
- def visit_Arel_Nodes_SelectStatement o
- visit o.cores
- visit o.orders
- visit o.limit
- visit o.lock
- visit o.offset
+ def visit_Arel_Nodes_SelectStatement o, a
+ visit o.cores, a
+ visit o.orders, a
+ visit o.limit, a
+ visit o.lock, a
+ visit o.offset, a
end
- def visit_Arel_Nodes_UpdateStatement o
- visit o.relation
- visit o.values
- visit o.wheres
- visit o.orders
- visit o.limit
+ def visit_Arel_Nodes_UpdateStatement o, a
+ visit o.relation, a
+ visit o.values, a
+ visit o.wheres, a
+ visit o.orders, a
+ visit o.limit, a
end
- def visit_Array o
- o.each { |i| visit i }
+ def visit_Array o, a
+ o.each { |i| visit i, a }
end
- def visit_Hash o
- o.each { |k,v| visit(k); visit(v) }
+ def visit_Hash o, a
+ o.each { |k,v| visit(k, a); visit(v, a) }
end
end
end
diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb
index 843266f85a..82b8c771e4 100644
--- a/lib/arel/visitors/dot.rb
+++ b/lib/arel/visitors/dot.rb
@@ -28,41 +28,41 @@ module Arel
end
private
- def visit_Arel_Nodes_Ordering o
- visit_edge o, "expr"
+ def visit_Arel_Nodes_Ordering o, a
+ visit_edge o, a, "expr"
end
- def visit_Arel_Nodes_TableAlias o
- visit_edge o, "name"
- visit_edge o, "relation"
+ def visit_Arel_Nodes_TableAlias o, a
+ visit_edge o, a, "name"
+ visit_edge o, a, "relation"
end
- def visit_Arel_Nodes_Count o
- visit_edge o, "expressions"
- visit_edge o, "distinct"
+ def visit_Arel_Nodes_Count o, a
+ visit_edge o, a, "expressions"
+ visit_edge o, a, "distinct"
end
- def visit_Arel_Nodes_Values o
- visit_edge o, "expressions"
+ def visit_Arel_Nodes_Values o, a
+ visit_edge o, a, "expressions"
end
- def visit_Arel_Nodes_StringJoin o
- visit_edge o, "left"
+ def visit_Arel_Nodes_StringJoin o, a
+ visit_edge o, a, "left"
end
- def visit_Arel_Nodes_InnerJoin o
- visit_edge o, "left"
- visit_edge o, "right"
+ def visit_Arel_Nodes_InnerJoin o, a
+ visit_edge o, a, "left"
+ visit_edge o, a, "right"
end
alias :visit_Arel_Nodes_OuterJoin :visit_Arel_Nodes_InnerJoin
- def visit_Arel_Nodes_DeleteStatement o
- visit_edge o, "relation"
- visit_edge o, "wheres"
+ def visit_Arel_Nodes_DeleteStatement o, a
+ visit_edge o, a, "relation"
+ visit_edge o, a, "wheres"
end
- def unary o
- visit_edge o, "expr"
+ def unary o, a
+ visit_edge o, a, "expr"
end
alias :visit_Arel_Nodes_Group :unary
alias :visit_Arel_Nodes_Grouping :unary
@@ -78,23 +78,23 @@ module Arel
alias :visit_Arel_Nodes_Rows :unary
alias :visit_Arel_Nodes_Range :unary
- def window o
- visit_edge o, "orders"
- visit_edge o, "framing"
+ def window o, a
+ visit_edge o, a, "orders"
+ visit_edge o, a, "framing"
end
alias :visit_Arel_Nodes_Window :window
- def named_window o
- visit_edge o, "orders"
- visit_edge o, "framing"
- visit_edge o, "name"
+ def named_window o, a
+ visit_edge o, a, "orders"
+ visit_edge o, a, "framing"
+ visit_edge o, a, "name"
end
alias :visit_Arel_Nodes_NamedWindow :named_window
- def function o
- visit_edge o, "expressions"
- visit_edge o, "distinct"
- visit_edge o, "alias"
+ def function o, a
+ visit_edge o, a, "expressions"
+ visit_edge o, a, "distinct"
+ visit_edge o, a, "alias"
end
alias :visit_Arel_Nodes_Exists :function
alias :visit_Arel_Nodes_Min :function
@@ -102,52 +102,52 @@ module Arel
alias :visit_Arel_Nodes_Avg :function
alias :visit_Arel_Nodes_Sum :function
- def extract o
- visit_edge o, "expressions"
- visit_edge o, "alias"
+ def extract o, a
+ visit_edge o, a, "expressions"
+ visit_edge o, a, "alias"
end
alias :visit_Arel_Nodes_Extract :extract
- def visit_Arel_Nodes_NamedFunction o
- visit_edge o, "name"
- visit_edge o, "expressions"
- visit_edge o, "distinct"
- visit_edge o, "alias"
+ def visit_Arel_Nodes_NamedFunction o, a
+ visit_edge o, a, "name"
+ visit_edge o, a, "expressions"
+ visit_edge o, a, "distinct"
+ visit_edge o, a, "alias"
end
- def visit_Arel_Nodes_InsertStatement o
- visit_edge o, "relation"
- visit_edge o, "columns"
- visit_edge o, "values"
+ def visit_Arel_Nodes_InsertStatement o, a
+ visit_edge o, a, "relation"
+ visit_edge o, a, "columns"
+ visit_edge o, a, "values"
end
- def visit_Arel_Nodes_SelectCore o
- visit_edge o, "source"
- visit_edge o, "projections"
- visit_edge o, "wheres"
- visit_edge o, "windows"
+ def visit_Arel_Nodes_SelectCore o, a
+ visit_edge o, a, "source"
+ visit_edge o, a, "projections"
+ visit_edge o, a, "wheres"
+ visit_edge o, a, "windows"
end
- def visit_Arel_Nodes_SelectStatement o
- visit_edge o, "cores"
- visit_edge o, "limit"
- visit_edge o, "orders"
- visit_edge o, "offset"
+ def visit_Arel_Nodes_SelectStatement o, a
+ visit_edge o, a, "cores"
+ visit_edge o, a, "limit"
+ visit_edge o, a, "orders"
+ visit_edge o, a, "offset"
end
- def visit_Arel_Nodes_UpdateStatement o
- visit_edge o, "relation"
- visit_edge o, "wheres"
- visit_edge o, "values"
+ def visit_Arel_Nodes_UpdateStatement o, a
+ visit_edge o, a, "relation"
+ visit_edge o, a, "wheres"
+ visit_edge o, a, "values"
end
- def visit_Arel_Table o
- visit_edge o, "name"
+ def visit_Arel_Table o, a
+ visit_edge o, a, "name"
end
- def visit_Arel_Attribute o
- visit_edge o, "relation"
- visit_edge o, "name"
+ def visit_Arel_Attribute o, a
+ visit_edge o, a, "relation"
+ visit_edge o, a, "name"
end
alias :visit_Arel_Attributes_Integer :visit_Arel_Attribute
alias :visit_Arel_Attributes_Float :visit_Arel_Attribute
@@ -156,16 +156,16 @@ module Arel
alias :visit_Arel_Attributes_Boolean :visit_Arel_Attribute
alias :visit_Arel_Attributes_Attribute :visit_Arel_Attribute
- def nary o
+ def nary o, a
o.children.each_with_index do |x,i|
- edge(i) { visit x }
+ edge(i) { visit x, a }
end
end
alias :visit_Arel_Nodes_And :nary
- def binary o
- visit_edge o, "left"
- visit_edge o, "right"
+ def binary o, a
+ visit_edge o, a, "left"
+ visit_edge o, a, "right"
end
alias :visit_Arel_Nodes_As :binary
alias :visit_Arel_Nodes_Assignment :binary
@@ -184,7 +184,7 @@ module Arel
alias :visit_Arel_Nodes_Or :binary
alias :visit_Arel_Nodes_Over :binary
- def visit_String o
+ def visit_String o, a
@node_stack.last.fields << o
end
alias :visit_Time :visit_String
@@ -201,23 +201,23 @@ module Arel
alias :visit_Symbol :visit_String
alias :visit_Arel_Nodes_SqlLiteral :visit_String
- def visit_Hash o
+ def visit_Hash o, a
o.each_with_index do |pair, i|
- edge("pair_#{i}") { visit pair }
+ edge("pair_#{i}") { visit pair, a }
end
end
- def visit_Array o
+ def visit_Array o, a
o.each_with_index do |x,i|
- edge(i) { visit x }
+ edge(i) { visit x, a }
end
end
- def visit_edge o, method
- edge(method) { visit o.send(method) }
+ def visit_edge o, a, method
+ edge(method) { visit o.send(method), a }
end
- def visit o
+ def visit o, a = nil
if node = @seen[o.object_id]
@edge_stack.last.to = node
return
diff --git a/lib/arel/visitors/ibm_db.rb b/lib/arel/visitors/ibm_db.rb
index 0c26a3ae9e..13af27df71 100644
--- a/lib/arel/visitors/ibm_db.rb
+++ b/lib/arel/visitors/ibm_db.rb
@@ -3,8 +3,8 @@ module Arel
class IBM_DB < Arel::Visitors::ToSql
private
- def visit_Arel_Nodes_Limit o
- "FETCH FIRST #{visit o.expr} ROWS ONLY"
+ def visit_Arel_Nodes_Limit o, a
+ "FETCH FIRST #{visit o.expr, a} ROWS ONLY"
end
end
diff --git a/lib/arel/visitors/informix.rb b/lib/arel/visitors/informix.rb
index 984098cdf3..a578119d9b 100644
--- a/lib/arel/visitors/informix.rb
+++ b/lib/arel/visitors/informix.rb
@@ -2,32 +2,32 @@ module Arel
module Visitors
class Informix < Arel::Visitors::ToSql
private
- def visit_Arel_Nodes_SelectStatement o
+ def visit_Arel_Nodes_SelectStatement o, a
[
"SELECT",
- (visit(o.offset) if o.offset),
- (visit(o.limit) if o.limit),
- o.cores.map { |x| visit_Arel_Nodes_SelectCore x }.join,
- ("ORDER BY #{o.orders.map { |x| visit x }.join(', ')}" unless o.orders.empty?),
- (visit(o.lock) if o.lock),
+ (visit(o.offset, a) if o.offset),
+ (visit(o.limit, a) if o.limit),
+ o.cores.map { |x| visit_Arel_Nodes_SelectCore x, a }.join,
+ ("ORDER BY #{o.orders.map { |x| visit x, a }.join(', ')}" unless o.orders.empty?),
+ (visit(o.lock, a) if o.lock),
].compact.join ' '
end
- def visit_Arel_Nodes_SelectCore o
+ def visit_Arel_Nodes_SelectCore o, a
[
- "#{o.projections.map { |x| visit x }.join ', '}",
- ("FROM #{visit(o.source)}" if o.source && !o.source.empty?),
- ("WHERE #{o.wheres.map { |x| visit x }.join ' AND ' }" unless o.wheres.empty?),
- ("GROUP BY #{o.groups.map { |x| visit x }.join ', ' }" unless o.groups.empty?),
- (visit(o.having) if o.having),
+ "#{o.projections.map { |x| visit x, a }.join ', '}",
+ ("FROM #{visit(o.source, a)}" if o.source && !o.source.empty?),
+ ("WHERE #{o.wheres.map { |x| visit x, a }.join ' AND ' }" unless o.wheres.empty?),
+ ("GROUP BY #{o.groups.map { |x| visit x, a }.join ', ' }" unless o.groups.empty?),
+ (visit(o.having, a) if o.having),
].compact.join ' '
end
- def visit_Arel_Nodes_Offset o
- "SKIP #{visit o.expr}"
+ def visit_Arel_Nodes_Offset o, a
+ "SKIP #{visit o.expr, a}"
end
- def visit_Arel_Nodes_Limit o
- "LIMIT #{visit o.expr}"
+ def visit_Arel_Nodes_Limit o, a
+ "LIMIT #{visit o.expr, a}"
end
end
end
-end
+end
diff --git a/lib/arel/visitors/join_sql.rb b/lib/arel/visitors/join_sql.rb
index 1cdd7eb5ca..9708887075 100644
--- a/lib/arel/visitors/join_sql.rb
+++ b/lib/arel/visitors/join_sql.rb
@@ -11,8 +11,8 @@ module Arel
module JoinSql
private
- def visit_Arel_Nodes_SelectCore o
- o.source.right.map { |j| visit j }.join ' '
+ def visit_Arel_Nodes_SelectCore o, a
+ o.source.right.map { |j| visit j, a }.join ' '
end
end
end
diff --git a/lib/arel/visitors/mssql.rb b/lib/arel/visitors/mssql.rb
index 23dc06a936..9a88ee5b0f 100644
--- a/lib/arel/visitors/mssql.rb
+++ b/lib/arel/visitors/mssql.rb
@@ -6,20 +6,20 @@ module Arel
# `top` wouldn't really work here. I.e. User.select("distinct first_name").limit(10) would generate
# "select top 10 distinct first_name from users", which is invalid query! it should be
# "select distinct top 10 first_name from users"
- def visit_Arel_Nodes_Top o
+ def visit_Arel_Nodes_Top o, a
""
end
- def visit_Arel_Nodes_SelectStatement o
+ def visit_Arel_Nodes_SelectStatement o, a
if !o.limit && !o.offset
- return super o
+ return super o, a
end
- select_order_by = "ORDER BY #{o.orders.map { |x| visit x }.join(', ')}" unless o.orders.empty?
+ select_order_by = "ORDER BY #{o.orders.map { |x| visit x, a }.join(', ')}" unless o.orders.empty?
is_select_count = false
sql = o.cores.map { |x|
- core_order_by = select_order_by || determine_order_by(x)
+ core_order_by = select_order_by || determine_order_by(x, a)
if select_count? x
x.projections = [row_num_literal(core_order_by)]
is_select_count = true
@@ -27,7 +27,7 @@ module Arel
x.projections << row_num_literal(core_order_by)
end
- visit_Arel_Nodes_SelectCore x
+ visit_Arel_Nodes_SelectCore x, a
}.join
sql = "SELECT _t.* FROM (#{sql}) as _t WHERE #{get_offset_limit_clause(o)}"
@@ -46,11 +46,11 @@ module Arel
end
end
- def determine_order_by x
+ def determine_order_by x, a
unless x.groups.empty?
- "ORDER BY #{x.groups.map { |g| visit g }.join ', ' }"
+ "ORDER BY #{x.groups.map { |g| visit g, a }.join ', ' }"
else
- "ORDER BY #{find_left_table_pk(x.froms)}"
+ "ORDER BY #{find_left_table_pk(x.froms, a)}"
end
end
@@ -64,9 +64,9 @@ module Arel
# fixme raise exception of there is no pk?
# fixme!! Table.primary_key will be depricated. What is the replacement??
- def find_left_table_pk o
- return visit o.primary_key if o.instance_of? Arel::Table
- find_left_table_pk o.left if o.kind_of? Arel::Nodes::Join
+ def find_left_table_pk o, a
+ return visit o.primary_key, a if o.instance_of? Arel::Table
+ find_left_table_pk o.left, a if o.kind_of? Arel::Nodes::Join
end
end
end
diff --git a/lib/arel/visitors/mysql.rb b/lib/arel/visitors/mysql.rb
index ee8483372a..4db5a94019 100644
--- a/lib/arel/visitors/mysql.rb
+++ b/lib/arel/visitors/mysql.rb
@@ -2,19 +2,19 @@ module Arel
module Visitors
class MySQL < Arel::Visitors::ToSql
private
- def visit_Arel_Nodes_Union o, suppress_parens = false
+ def visit_Arel_Nodes_Union o, a, suppress_parens = false
left_result = case o.left
when Arel::Nodes::Union
- visit_Arel_Nodes_Union o.left, true
+ visit_Arel_Nodes_Union o.left, a, true
else
- visit o.left
+ visit o.left, a
end
right_result = case o.right
when Arel::Nodes::Union
- visit_Arel_Nodes_Union o.right, true
+ visit_Arel_Nodes_Union o.right, a, true
else
- visit o.right
+ visit o.right, a
end
if suppress_parens
@@ -24,30 +24,30 @@ module Arel
end
end
- def visit_Arel_Nodes_Bin o
- "BINARY #{visit o.expr}"
+ def visit_Arel_Nodes_Bin o, a
+ "BINARY #{visit o.expr, a}"
end
###
# :'(
# http://dev.mysql.com/doc/refman/5.0/en/select.html#id3482214
- def visit_Arel_Nodes_SelectStatement o
+ def visit_Arel_Nodes_SelectStatement o, a
o.limit = Arel::Nodes::Limit.new(18446744073709551615) if o.offset && !o.limit
super
end
- def visit_Arel_Nodes_SelectCore o
+ def visit_Arel_Nodes_SelectCore o, a
o.froms ||= Arel.sql('DUAL')
super
end
- def visit_Arel_Nodes_UpdateStatement o
+ def visit_Arel_Nodes_UpdateStatement o, a
[
- "UPDATE #{visit o.relation}",
- ("SET #{o.values.map { |value| visit value }.join ', '}" unless o.values.empty?),
- ("WHERE #{o.wheres.map { |x| visit x }.join ' AND '}" unless o.wheres.empty?),
- ("ORDER BY #{o.orders.map { |x| visit x }.join(', ')}" unless o.orders.empty?),
- (visit(o.limit) if o.limit),
+ "UPDATE #{visit o.relation, a}",
+ ("SET #{o.values.map { |value| visit value, a }.join ', '}" unless o.values.empty?),
+ ("WHERE #{o.wheres.map { |x| visit x, a }.join ' AND '}" unless o.wheres.empty?),
+ ("ORDER BY #{o.orders.map { |x| visit x, a }.join(', ')}" unless o.orders.empty?),
+ (visit(o.limit, a) if o.limit),
].compact.join ' '
end
diff --git a/lib/arel/visitors/oracle.rb b/lib/arel/visitors/oracle.rb
index 375f7dbfe9..b58d7338ef 100644
--- a/lib/arel/visitors/oracle.rb
+++ b/lib/arel/visitors/oracle.rb
@@ -3,8 +3,8 @@ module Arel
class Oracle < Arel::Visitors::ToSql
private
- def visit_Arel_Nodes_SelectStatement o
- o = order_hacks(o)
+ def visit_Arel_Nodes_SelectStatement o, a
+ o = order_hacks(o, a)
# if need to select first records without ORDER BY and GROUP BY and without DISTINCT
# then can use simple ROWNUM in WHERE clause
@@ -20,53 +20,53 @@ module Arel
limit = o.limit.expr.to_i
offset = o.offset
o.offset = nil
- sql = super(o)
+ sql = super(o, a)
return <<-eosql
SELECT * FROM (
SELECT raw_sql_.*, rownum raw_rnum_
FROM (#{sql}) raw_sql_
WHERE rownum <= #{offset.expr.to_i + limit}
)
- WHERE #{visit offset}
+ WHERE #{visit offset, a}
eosql
end
if o.limit
o = o.dup
limit = o.limit.expr
- return "SELECT * FROM (#{super(o)}) WHERE ROWNUM <= #{visit limit}"
+ return "SELECT * FROM (#{super(o, a)}) WHERE ROWNUM <= #{visit limit, a}"
end
if o.offset
o = o.dup
offset = o.offset
o.offset = nil
- sql = super(o)
+ sql = super(o, a)
return <<-eosql
SELECT * FROM (
SELECT raw_sql_.*, rownum raw_rnum_
FROM (#{sql}) raw_sql_
)
- WHERE #{visit offset}
+ WHERE #{visit offset, a}
eosql
end
super
end
- def visit_Arel_Nodes_Limit o
+ def visit_Arel_Nodes_Limit o, a
end
- def visit_Arel_Nodes_Offset o
- "raw_rnum_ > #{visit o.expr}"
+ def visit_Arel_Nodes_Offset o, a
+ "raw_rnum_ > #{visit o.expr, a}"
end
- def visit_Arel_Nodes_Except o
- "( #{visit o.left} MINUS #{visit o.right} )"
+ def visit_Arel_Nodes_Except o, a
+ "( #{visit o.left, a} MINUS #{visit o.right, a} )"
end
- def visit_Arel_Nodes_UpdateStatement o
- # Oracle does not allow ORDER BY/LIMIT in UPDATEs.
+ def visit_Arel_Nodes_UpdateStatement o, a
+ # Oracle does not allow ORDER BY/LIMIT in UPDATEs.
if o.orders.any? && o.limit.nil?
# However, there is no harm in silently eating the ORDER BY clause if no LIMIT has been provided,
# otherwise let the user deal with the error
@@ -79,7 +79,7 @@ module Arel
###
# Hacks for the order clauses specific to Oracle
- def order_hacks o
+ def order_hacks o, a
return o if o.orders.empty?
return o unless o.cores.any? do |core|
core.projections.any? do |projection|
@@ -89,9 +89,9 @@ module Arel
# Previous version with join and split broke ORDER BY clause
# if it contained functions with several arguments (separated by ',').
#
- # orders = o.orders.map { |x| visit x }.join(', ').split(',')
+ # orders = o.orders.map { |x| visit x, a }.join(', ').split(',')
orders = o.orders.map do |x|
- string = visit x
+ string = visit x, a
if string.include?(',')
split_order_string(string)
else
diff --git a/lib/arel/visitors/order_clauses.rb b/lib/arel/visitors/order_clauses.rb
index 11dbfdad2a..b470d3f084 100644
--- a/lib/arel/visitors/order_clauses.rb
+++ b/lib/arel/visitors/order_clauses.rb
@@ -3,8 +3,8 @@ module Arel
class OrderClauses < Arel::Visitors::ToSql
private
- def visit_Arel_Nodes_SelectStatement o
- o.orders.map { |x| visit x }
+ def visit_Arel_Nodes_SelectStatement o, a
+ o.orders.map { |x| visit x, a }
end
end
end
diff --git a/lib/arel/visitors/postgresql.rb b/lib/arel/visitors/postgresql.rb
index 812710181c..080e402e3b 100644
--- a/lib/arel/visitors/postgresql.rb
+++ b/lib/arel/visitors/postgresql.rb
@@ -3,16 +3,16 @@ module Arel
class PostgreSQL < Arel::Visitors::ToSql
private
- def visit_Arel_Nodes_Matches o
- "#{visit o.left} ILIKE #{visit o.right}"
+ def visit_Arel_Nodes_Matches o, a
+ "#{visit o.left, a} ILIKE #{visit o.right, a}"
end
- def visit_Arel_Nodes_DoesNotMatch o
- "#{visit o.left} NOT ILIKE #{visit o.right}"
+ def visit_Arel_Nodes_DoesNotMatch o, a
+ "#{visit o.left, a} NOT ILIKE #{visit o.right, a}"
end
- def visit_Arel_Nodes_DistinctOn o
- "DISTINCT ON ( #{visit o.expr} )"
+ def visit_Arel_Nodes_DistinctOn o, a
+ "DISTINCT ON ( #{visit o.expr, a} )"
end
end
end
diff --git a/lib/arel/visitors/sqlite.rb b/lib/arel/visitors/sqlite.rb
index 2a509e95b5..07a18fc2f5 100644
--- a/lib/arel/visitors/sqlite.rb
+++ b/lib/arel/visitors/sqlite.rb
@@ -4,10 +4,10 @@ module Arel
private
# Locks are not supported in SQLite
- def visit_Arel_Nodes_Lock o
+ def visit_Arel_Nodes_Lock o, a
end
- def visit_Arel_Nodes_SelectStatement o
+ def visit_Arel_Nodes_SelectStatement o, a
o.limit = Arel::Nodes::Limit.new(-1) if o.offset && !o.limit
super
end
diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb
index 1a4826bcd2..4e1f7ab466 100644
--- a/lib/arel/visitors/to_sql.rb
+++ b/lib/arel/visitors/to_sql.rb
@@ -53,23 +53,16 @@ module Arel
DISTINCT = 'DISTINCT' # :nodoc:
- attr_accessor :last_column
-
def initialize connection
@connection = connection
@schema_cache = connection.schema_cache
@quoted_tables = {}
@quoted_columns = {}
- @last_column = nil
- end
-
- def accept object
- self.last_column = nil
- super
end
private
- def visit_Arel_Nodes_DeleteStatement o
+
+ def visit_Arel_Nodes_DeleteStatement o, a
[
"DELETE FROM #{visit o.relation}",
("WHERE #{o.wheres.map { |x| visit x }.join AND}" unless o.wheres.empty?)
@@ -88,7 +81,7 @@ module Arel
stmt
end
- def visit_Arel_Nodes_UpdateStatement o
+ def visit_Arel_Nodes_UpdateStatement o, a
if o.orders.empty? && o.limit.nil?
wheres = o.wheres
else
@@ -106,34 +99,34 @@ key on UpdateManager using UpdateManager#key=
end
[
- "UPDATE #{visit o.relation}",
- ("SET #{o.values.map { |value| visit value }.join ', '}" unless o.values.empty?),
- ("WHERE #{wheres.map { |x| visit x }.join ' AND '}" unless wheres.empty?),
+ "UPDATE #{visit o.relation, a}",
+ ("SET #{o.values.map { |value| visit value, a }.join ', '}" unless o.values.empty?),
+ ("WHERE #{wheres.map { |x| visit x, a }.join ' AND '}" unless wheres.empty?),
].compact.join ' '
end
- def visit_Arel_Nodes_InsertStatement o
+ def visit_Arel_Nodes_InsertStatement o, a
[
- "INSERT INTO #{visit o.relation}",
+ "INSERT INTO #{visit o.relation, a}",
("(#{o.columns.map { |x|
quote_column_name x.name
}.join ', '})" unless o.columns.empty?),
- (visit o.values if o.values),
+ (visit o.values, a if o.values),
].compact.join ' '
end
- def visit_Arel_Nodes_Exists o
- "EXISTS (#{visit o.expressions})#{
- o.alias ? " AS #{visit o.alias}" : ''}"
+ def visit_Arel_Nodes_Exists o, a
+ "EXISTS (#{visit o.expressions, a})#{
+ o.alias ? " AS #{visit o.alias, a}" : ''}"
end
- def visit_Arel_Nodes_True o
+ def visit_Arel_Nodes_True o, a
"TRUE"
end
- def visit_Arel_Nodes_False o
+ def visit_Arel_Nodes_False o, a
"FALSE"
end
@@ -142,6 +135,7 @@ key on UpdateManager using UpdateManager#key=
end
def column_for attr
+ return unless attr
name = attr.name.to_s
table = attr.relation.table_name
@@ -154,66 +148,66 @@ key on UpdateManager using UpdateManager#key=
@schema_cache.columns_hash(table)
end
- def visit_Arel_Nodes_Values o
+ def visit_Arel_Nodes_Values o, a
"VALUES (#{o.expressions.zip(o.columns).map { |value, attr|
if Nodes::SqlLiteral === value
- visit value
+ visit value, a
else
quote(value, attr && column_for(attr))
end
}.join ', '})"
end
- def visit_Arel_Nodes_SelectStatement o
+ def visit_Arel_Nodes_SelectStatement o, a
str = ''
if o.with
- str << visit(o.with)
+ str << visit(o.with, a)
str << SPACE
end
- o.cores.each { |x| str << visit_Arel_Nodes_SelectCore(x) }
+ o.cores.each { |x| str << visit_Arel_Nodes_SelectCore(x, a) }
unless o.orders.empty?
str << SPACE
str << ORDER_BY
len = o.orders.length - 1
o.orders.each_with_index { |x, i|
- str << visit(x)
+ str << visit(x, a)
str << COMMA unless len == i
}
end
- str << " #{visit(o.limit)}" if o.limit
- str << " #{visit(o.offset)}" if o.offset
- str << " #{visit(o.lock)}" if o.lock
+ str << " #{visit(o.limit, a)}" if o.limit
+ str << " #{visit(o.offset, a)}" if o.offset
+ str << " #{visit(o.lock, a)}" if o.lock
str.strip!
str
end
- def visit_Arel_Nodes_SelectCore o
+ def visit_Arel_Nodes_SelectCore o, a
str = "SELECT"
- str << " #{visit(o.top)}" if o.top
- str << " #{visit(o.set_quantifier)}" if o.set_quantifier
+ str << " #{visit(o.top, a)}" if o.top
+ str << " #{visit(o.set_quantifier, a)}" if o.set_quantifier
unless o.projections.empty?
str << SPACE
len = o.projections.length - 1
o.projections.each_with_index do |x, i|
- str << visit(x)
+ str << visit(x, a)
str << COMMA unless len == i
end
end
- str << " FROM #{visit(o.source)}" if o.source && !o.source.empty?
+ str << " FROM #{visit(o.source, a)}" if o.source && !o.source.empty?
unless o.wheres.empty?
str << WHERE
len = o.wheres.length - 1
o.wheres.each_with_index do |x, i|
- str << visit(x)
+ str << visit(x, a)
str << AND unless len == i
end
end
@@ -222,18 +216,18 @@ key on UpdateManager using UpdateManager#key=
str << GROUP_BY
len = o.groups.length - 1
o.groups.each_with_index do |x, i|
- str << visit(x)
+ str << visit(x, a)
str << COMMA unless len == i
end
end
- str << " #{visit(o.having)}" if o.having
+ str << " #{visit(o.having, a)}" if o.having
unless o.windows.empty?
str << WINDOW
len = o.windows.length - 1
o.windows.each_with_index do |x, i|
- str << visit(x)
+ str << visit(x, a)
str << COMMA unless len == i
end
end
@@ -241,237 +235,244 @@ key on UpdateManager using UpdateManager#key=
str
end
- def visit_Arel_Nodes_Bin o
- visit o.expr
+ def visit_Arel_Nodes_Bin o, a
+ visit o.expr, a
end
- def visit_Arel_Nodes_Distinct o
+ def visit_Arel_Nodes_Distinct o, a
DISTINCT
end
- def visit_Arel_Nodes_DistinctOn o
+ def visit_Arel_Nodes_DistinctOn o, a
raise NotImplementedError, 'DISTINCT ON not implemented for this db'
end
- def visit_Arel_Nodes_With o
- "WITH #{o.children.map { |x| visit x }.join(', ')}"
+ def visit_Arel_Nodes_With o, a
+ "WITH #{o.children.map { |x| visit x, a }.join(', ')}"
end
- def visit_Arel_Nodes_WithRecursive o
- "WITH RECURSIVE #{o.children.map { |x| visit x }.join(', ')}"
+ def visit_Arel_Nodes_WithRecursive o, a
+ "WITH RECURSIVE #{o.children.map { |x| visit x, a }.join(', ')}"
end
- def visit_Arel_Nodes_Union o
- "( #{visit o.left} UNION #{visit o.right} )"
+ def visit_Arel_Nodes_Union o, a
+ "( #{visit o.left, a} UNION #{visit o.right, a} )"
end
- def visit_Arel_Nodes_UnionAll o
- "( #{visit o.left} UNION ALL #{visit o.right} )"
+ def visit_Arel_Nodes_UnionAll o, a
+ "( #{visit o.left, a} UNION ALL #{visit o.right, a} )"
end
- def visit_Arel_Nodes_Intersect o
- "( #{visit o.left} INTERSECT #{visit o.right} )"
+ def visit_Arel_Nodes_Intersect o, a
+ "( #{visit o.left, a} INTERSECT #{visit o.right, a} )"
end
- def visit_Arel_Nodes_Except o
- "( #{visit o.left} EXCEPT #{visit o.right} )"
+ def visit_Arel_Nodes_Except o, a
+ "( #{visit o.left, a} EXCEPT #{visit o.right, a} )"
end
- def visit_Arel_Nodes_NamedWindow o
- "#{quote_column_name o.name} AS #{visit_Arel_Nodes_Window o}"
+ def visit_Arel_Nodes_NamedWindow o, a
+ "#{quote_column_name o.name} AS #{visit_Arel_Nodes_Window o, a}"
end
- def visit_Arel_Nodes_Window o
+ def visit_Arel_Nodes_Window o, a
s = [
- ("ORDER BY #{o.orders.map { |x| visit(x) }.join(', ')}" unless o.orders.empty?),
- (visit o.framing if o.framing)
+ ("ORDER BY #{o.orders.map { |x| visit(x, a) }.join(', ')}" unless o.orders.empty?),
+ (visit o.framing, a if o.framing)
].compact.join ' '
"(#{s})"
end
- def visit_Arel_Nodes_Rows o
+ def visit_Arel_Nodes_Rows o, a
if o.expr
- "ROWS #{visit o.expr}"
+ "ROWS #{visit o.expr, a}"
else
"ROWS"
end
end
- def visit_Arel_Nodes_Range o
+ def visit_Arel_Nodes_Range o, a
if o.expr
- "RANGE #{visit o.expr}"
+ "RANGE #{visit o.expr, a}"
else
"RANGE"
end
end
- def visit_Arel_Nodes_Preceding o
- "#{o.expr ? visit(o.expr) : 'UNBOUNDED'} PRECEDING"
+ def visit_Arel_Nodes_Preceding o, a
+ "#{o.expr ? visit(o.expr, a) : 'UNBOUNDED'} PRECEDING"
end
- def visit_Arel_Nodes_Following o
- "#{o.expr ? visit(o.expr) : 'UNBOUNDED'} FOLLOWING"
+ def visit_Arel_Nodes_Following o, a
+ "#{o.expr ? visit(o.expr, a) : 'UNBOUNDED'} FOLLOWING"
end
- def visit_Arel_Nodes_CurrentRow o
+ def visit_Arel_Nodes_CurrentRow o, a
"CURRENT ROW"
end
- def visit_Arel_Nodes_Over o
+ def visit_Arel_Nodes_Over o, a
case o.right
when nil
- "#{visit o.left} OVER ()"
+ "#{visit o.left, a} OVER ()"
when Arel::Nodes::SqlLiteral
- "#{visit o.left} OVER #{visit o.right}"
+ "#{visit o.left, a} OVER #{visit o.right, a}"
when String, Symbol
- "#{visit o.left} OVER #{quote_column_name o.right.to_s}"
+ "#{visit o.left, a} OVER #{quote_column_name o.right.to_s}"
else
- "#{visit o.left} OVER #{visit o.right}"
+ "#{visit o.left, a} OVER #{visit o.right, a}"
end
end
- def visit_Arel_Nodes_Having o
- "HAVING #{visit o.expr}"
+ def visit_Arel_Nodes_Having o, a
+ "HAVING #{visit o.expr, a}"
end
- def visit_Arel_Nodes_Offset o
- "OFFSET #{visit o.expr}"
+ def visit_Arel_Nodes_Offset o, a
+ "OFFSET #{visit o.expr, a}"
end
- def visit_Arel_Nodes_Limit o
- "LIMIT #{visit o.expr}"
+ def visit_Arel_Nodes_Limit o, a
+ "LIMIT #{visit o.expr, a}"
end
# FIXME: this does nothing on most databases, but does on MSSQL
- def visit_Arel_Nodes_Top o
+ def visit_Arel_Nodes_Top o, a
""
end
- def visit_Arel_Nodes_Lock o
- visit o.expr
+ def visit_Arel_Nodes_Lock o, a
+ visit o.expr, a
end
- def visit_Arel_Nodes_Grouping o
- "(#{visit o.expr})"
+ def visit_Arel_Nodes_Grouping o, a
+ "(#{visit o.expr, a})"
end
- def visit_Arel_SelectManager o
+ def visit_Arel_SelectManager o, a
"(#{o.to_sql.rstrip})"
end
- def visit_Arel_Nodes_Ascending o
- "#{visit o.expr} ASC"
+ def visit_Arel_Nodes_Ascending o, a
+ "#{visit o.expr, a} ASC"
end
- def visit_Arel_Nodes_Descending o
- "#{visit o.expr} DESC"
+ def visit_Arel_Nodes_Descending o, a
+ "#{visit o.expr, a} DESC"
end
- def visit_Arel_Nodes_Group o
- visit o.expr
+ def visit_Arel_Nodes_Group o, a
+ visit o.expr, a
end
- def visit_Arel_Nodes_NamedFunction o
+ def visit_Arel_Nodes_NamedFunction o, a
"#{o.name}(#{o.distinct ? 'DISTINCT ' : ''}#{o.expressions.map { |x|
- visit x
- }.join(', ')})#{o.alias ? " AS #{visit o.alias}" : ''}"
+ visit x, a
+ }.join(', ')})#{o.alias ? " AS #{visit o.alias, a}" : ''}"
end
- def visit_Arel_Nodes_Extract o
- "EXTRACT(#{o.field.to_s.upcase} FROM #{visit o.expr})#{o.alias ? " AS #{visit o.alias}" : ''}"
+ def visit_Arel_Nodes_Extract o, a
+ "EXTRACT(#{o.field.to_s.upcase} FROM #{visit o.expr, a})#{o.alias ? " AS #{visit o.alias, a}" : ''}"
end
- def visit_Arel_Nodes_Count o
+ def visit_Arel_Nodes_Count o, a
"COUNT(#{o.distinct ? 'DISTINCT ' : ''}#{o.expressions.map { |x|
- visit x
- }.join(', ')})#{o.alias ? " AS #{visit o.alias}" : ''}"
+ visit x, a
+ }.join(', ')})#{o.alias ? " AS #{visit o.alias, a}" : ''}"
end
- def visit_Arel_Nodes_Sum o
+ def visit_Arel_Nodes_Sum o, a
"SUM(#{o.distinct ? 'DISTINCT ' : ''}#{o.expressions.map { |x|
- visit x }.join(', ')})#{o.alias ? " AS #{visit o.alias}" : ''}"
+ visit x, a }.join(', ')})#{o.alias ? " AS #{visit o.alias, a}" : ''}"
end
- def visit_Arel_Nodes_Max o
+ def visit_Arel_Nodes_Max o, a
"MAX(#{o.distinct ? 'DISTINCT ' : ''}#{o.expressions.map { |x|
- visit x }.join(', ')})#{o.alias ? " AS #{visit o.alias}" : ''}"
+ visit x, a }.join(', ')})#{o.alias ? " AS #{visit o.alias, a}" : ''}"
end
- def visit_Arel_Nodes_Min o
+ def visit_Arel_Nodes_Min o, a
"MIN(#{o.distinct ? 'DISTINCT ' : ''}#{o.expressions.map { |x|
- visit x }.join(', ')})#{o.alias ? " AS #{visit o.alias}" : ''}"
+ visit x, a }.join(', ')})#{o.alias ? " AS #{visit o.alias, a}" : ''}"
end
- def visit_Arel_Nodes_Avg o
+ def visit_Arel_Nodes_Avg o, a
"AVG(#{o.distinct ? 'DISTINCT ' : ''}#{o.expressions.map { |x|
- visit x }.join(', ')})#{o.alias ? " AS #{visit o.alias}" : ''}"
+ visit x, a }.join(', ')})#{o.alias ? " AS #{visit o.alias, a}" : ''}"
end
- def visit_Arel_Nodes_TableAlias o
- "#{visit o.relation} #{quote_table_name o.name}"
+ def visit_Arel_Nodes_TableAlias o, a
+ "#{visit o.relation, a} #{quote_table_name o.name}"
end
- def visit_Arel_Nodes_Between o
- "#{visit o.left} BETWEEN #{visit o.right}"
+ def visit_Arel_Nodes_Between o, a
+ a = o.left if Arel::Attributes::Attribute === o.left
+ "#{visit o.left, a} BETWEEN #{visit o.right, a}"
end
- def visit_Arel_Nodes_GreaterThanOrEqual o
- "#{visit o.left} >= #{visit o.right}"
+ def visit_Arel_Nodes_GreaterThanOrEqual o, a
+ a = o.left if Arel::Attributes::Attribute === o.left
+ "#{visit o.left, a} >= #{visit o.right, a}"
end
- def visit_Arel_Nodes_GreaterThan o
- "#{visit o.left} > #{visit o.right}"
+ def visit_Arel_Nodes_GreaterThan o, a
+ a = o.left if Arel::Attributes::Attribute === o.left
+ "#{visit o.left, a} > #{visit o.right, a}"
end
- def visit_Arel_Nodes_LessThanOrEqual o
- "#{visit o.left} <= #{visit o.right}"
+ def visit_Arel_Nodes_LessThanOrEqual o, a
+ a = o.left if Arel::Attributes::Attribute === o.left
+ "#{visit o.left, a} <= #{visit o.right, a}"
end
- def visit_Arel_Nodes_LessThan o
- "#{visit o.left} < #{visit o.right}"
+ def visit_Arel_Nodes_LessThan o, a
+ a = o.left if Arel::Attributes::Attribute === o.left
+ "#{visit o.left, a} < #{visit o.right, a}"
end
- def visit_Arel_Nodes_Matches o
- "#{visit o.left} LIKE #{visit o.right}"
+ def visit_Arel_Nodes_Matches o, a
+ a = o.left if Arel::Attributes::Attribute === o.left
+ "#{visit o.left, a} LIKE #{visit o.right, a}"
end
- def visit_Arel_Nodes_DoesNotMatch o
- "#{visit o.left} NOT LIKE #{visit o.right}"
+ def visit_Arel_Nodes_DoesNotMatch o, a
+ a = o.left if Arel::Attributes::Attribute === o.left
+ "#{visit o.left, a} NOT LIKE #{visit o.right, a}"
end
- def visit_Arel_Nodes_JoinSource o
+ def visit_Arel_Nodes_JoinSource o, a
[
- (visit(o.left) if o.left),
- o.right.map { |j| visit j }.join(' ')
+ (visit(o.left, a) if o.left),
+ o.right.map { |j| visit j, a }.join(' ')
].compact.join ' '
end
- def visit_Arel_Nodes_StringJoin o
- visit o.left
+ def visit_Arel_Nodes_StringJoin o, a
+ visit o.left, a
end
- def visit_Arel_Nodes_OuterJoin o
- "LEFT OUTER JOIN #{visit o.left} #{visit o.right}"
+ def visit_Arel_Nodes_OuterJoin o, a
+ "LEFT OUTER JOIN #{visit o.left, a} #{visit o.right, a}"
end
- def visit_Arel_Nodes_InnerJoin o
- s = "INNER JOIN #{visit o.left}"
+ def visit_Arel_Nodes_InnerJoin o, a
+ s = "INNER JOIN #{visit o.left, a}"
if o.right
s << SPACE
- s << visit(o.right)
+ s << visit(o.right, a)
end
s
end
- def visit_Arel_Nodes_On o
- "ON #{visit o.expr}"
+ def visit_Arel_Nodes_On o, a
+ "ON #{visit o.expr, a}"
end
- def visit_Arel_Nodes_Not o
- "NOT (#{visit o.expr})"
+ def visit_Arel_Nodes_Not o, a
+ "NOT (#{visit o.expr, a})"
end
- def visit_Arel_Table o
+ def visit_Arel_Table o, a
if o.table_alias
"#{quote_table_name o.name} #{quote_table_name o.table_alias}"
else
@@ -479,65 +480,68 @@ key on UpdateManager using UpdateManager#key=
end
end
- def visit_Arel_Nodes_In o
+ def visit_Arel_Nodes_In o, a
if Array === o.right && o.right.empty?
'1=0'
else
- "#{visit o.left} IN (#{visit o.right})"
+ a = o.left if Arel::Attributes::Attribute === o.left
+ "#{visit o.left, a} IN (#{visit o.right, a})"
end
end
- def visit_Arel_Nodes_NotIn o
+ def visit_Arel_Nodes_NotIn o, a
if Array === o.right && o.right.empty?
'1=1'
else
- "#{visit o.left} NOT IN (#{visit o.right})"
+ a = o.left if Arel::Attributes::Attribute === o.left
+ "#{visit o.left, a} NOT IN (#{visit o.right, a})"
end
end
- def visit_Arel_Nodes_And o
- o.children.map { |x| visit x }.join ' AND '
+ def visit_Arel_Nodes_And o, a
+ o.children.map { |x| visit x, a }.join ' AND '
end
- def visit_Arel_Nodes_Or o
- "#{visit o.left} OR #{visit o.right}"
+ def visit_Arel_Nodes_Or o, a
+ "#{visit o.left, a} OR #{visit o.right, a}"
end
- def visit_Arel_Nodes_Assignment o
+ def visit_Arel_Nodes_Assignment o, a
right = quote(o.right, column_for(o.left))
- "#{visit o.left} = #{right}"
+ "#{visit o.left, a} = #{right}"
end
- def visit_Arel_Nodes_Equality o
+ def visit_Arel_Nodes_Equality o, a
right = o.right
+ a = o.left if Arel::Attributes::Attribute === o.left
if right.nil?
- "#{visit o.left} IS NULL"
+ "#{visit o.left, a} IS NULL"
else
- "#{visit o.left} = #{visit right}"
+ "#{visit o.left, a} = #{visit right, a}"
end
end
- def visit_Arel_Nodes_NotEqual o
+ def visit_Arel_Nodes_NotEqual o, a
right = o.right
+ a = o.left if Arel::Attributes::Attribute === o.left
if right.nil?
- "#{visit o.left} IS NOT NULL"
+ "#{visit o.left, a} IS NOT NULL"
else
- "#{visit o.left} != #{visit right}"
+ "#{visit o.left, a} != #{visit right, a}"
end
end
- def visit_Arel_Nodes_As o
- "#{visit o.left} AS #{visit o.right}"
+ def visit_Arel_Nodes_As o, a
+ "#{visit o.left, a} AS #{visit o.right, a}"
end
- def visit_Arel_Nodes_UnqualifiedColumn o
+ def visit_Arel_Nodes_UnqualifiedColumn o, a
"#{quote_column_name o.name}"
end
- def visit_Arel_Attributes_Attribute o
- self.last_column = column_for o
+ def visit_Arel_Attributes_Attribute o, a
join_name = o.relation.table_alias || o.relation.name
"#{quote_table_name join_name}.#{quote_column_name o.name}"
end
@@ -548,7 +552,7 @@ key on UpdateManager using UpdateManager#key=
alias :visit_Arel_Attributes_Time :visit_Arel_Attributes_Attribute
alias :visit_Arel_Attributes_Boolean :visit_Arel_Attributes_Attribute
- def literal o; o end
+ def literal o, a; o end
alias :visit_Arel_Nodes_BindParam :literal
alias :visit_Arel_Nodes_SqlLiteral :literal
@@ -556,8 +560,8 @@ key on UpdateManager using UpdateManager#key=
alias :visit_Bignum :literal
alias :visit_Fixnum :literal
- def quoted o
- quote(o, last_column)
+ def quoted o, a
+ quote(o, column_for(a))
end
alias :visit_ActiveSupport_Multibyte_Chars :quoted
@@ -575,8 +579,8 @@ key on UpdateManager using UpdateManager#key=
alias :visit_Time :quoted
alias :visit_TrueClass :quoted
- def visit_Arel_Nodes_InfixOperation o
- "#{visit o.left} #{o.operator} #{visit o.right}"
+ def visit_Arel_Nodes_InfixOperation o, a
+ "#{visit o.left, a} #{o.operator} #{visit o.right, a}"
end
alias :visit_Arel_Nodes_Addition :visit_Arel_Nodes_InfixOperation
@@ -584,8 +588,8 @@ key on UpdateManager using UpdateManager#key=
alias :visit_Arel_Nodes_Multiplication :visit_Arel_Nodes_InfixOperation
alias :visit_Arel_Nodes_Division :visit_Arel_Nodes_InfixOperation
- def visit_Array o
- o.map { |x| visit x }.join(', ')
+ def visit_Array o, a
+ o.map { |x| visit x, a }.join(', ')
end
def quote value, column = nil
diff --git a/lib/arel/visitors/visitor.rb b/lib/arel/visitors/visitor.rb
index 8f9dd929e1..204657883f 100644
--- a/lib/arel/visitors/visitor.rb
+++ b/lib/arel/visitors/visitor.rb
@@ -15,8 +15,8 @@ module Arel
DISPATCH
end
- def visit object
- send dispatch[object.class], object
+ def visit object, attribute = nil
+ send dispatch[object.class], object, attribute
rescue NoMethodError => e
raise e if respond_to?(dispatch[object.class], true)
superklass = object.class.ancestors.find { |klass|
diff --git a/lib/arel/visitors/where_sql.rb b/lib/arel/visitors/where_sql.rb
index 9816fa7a70..d59bc26cb4 100644
--- a/lib/arel/visitors/where_sql.rb
+++ b/lib/arel/visitors/where_sql.rb
@@ -1,8 +1,8 @@
module Arel
module Visitors
class WhereSql < Arel::Visitors::ToSql
- def visit_Arel_Nodes_SelectCore o
- "WHERE #{o.wheres.map { |x| visit x }.join ' AND ' }"
+ def visit_Arel_Nodes_SelectCore o, a
+ "WHERE #{o.wheres.map { |x| visit x, a }.join ' AND ' }"
end
end
end