aboutsummaryrefslogtreecommitdiffstats
path: root/lib/arel/visitors
diff options
context:
space:
mode:
Diffstat (limited to 'lib/arel/visitors')
-rw-r--r--lib/arel/visitors/depth_first.rb22
-rw-r--r--lib/arel/visitors/dot.rb44
-rw-r--r--lib/arel/visitors/join_sql.rb25
-rw-r--r--lib/arel/visitors/oracle.rb4
-rw-r--r--lib/arel/visitors/to_sql.rb138
5 files changed, 146 insertions, 87 deletions
diff --git a/lib/arel/visitors/depth_first.rb b/lib/arel/visitors/depth_first.rb
index 00f18727f0..ed95cad472 100644
--- a/lib/arel/visitors/depth_first.rb
+++ b/lib/arel/visitors/depth_first.rb
@@ -18,9 +18,11 @@ module Arel
alias :visit_Arel_Nodes_Group :unary
alias :visit_Arel_Nodes_Grouping :unary
alias :visit_Arel_Nodes_Having :unary
+ alias :visit_Arel_Nodes_Limit :unary
alias :visit_Arel_Nodes_Not :unary
alias :visit_Arel_Nodes_Offset :unary
alias :visit_Arel_Nodes_On :unary
+ alias :visit_Arel_Nodes_Top :unary
alias :visit_Arel_Nodes_UnqualifiedColumn :unary
def function o
@@ -39,19 +41,15 @@ module Arel
visit o.distinct
end
- def join o
- visit o.left
- visit o.right
- visit o.constraint
+ def nary o
+ o.children.each { |child| visit child }
end
- alias :visit_Arel_Nodes_InnerJoin :join
- alias :visit_Arel_Nodes_OuterJoin :join
+ alias :visit_Arel_Nodes_And :nary
def binary o
visit o.left
visit o.right
end
- alias :visit_Arel_Nodes_And :binary
alias :visit_Arel_Nodes_As :binary
alias :visit_Arel_Nodes_Assignment :binary
alias :visit_Arel_Nodes_Between :binary
@@ -61,6 +59,8 @@ module Arel
alias :visit_Arel_Nodes_GreaterThan :binary
alias :visit_Arel_Nodes_GreaterThanOrEqual :binary
alias :visit_Arel_Nodes_In :binary
+ alias :visit_Arel_Nodes_JoinSource :binary
+ alias :visit_Arel_Nodes_InnerJoin :binary
alias :visit_Arel_Nodes_LessThan :binary
alias :visit_Arel_Nodes_LessThanOrEqual :binary
alias :visit_Arel_Nodes_Matches :binary
@@ -68,10 +68,14 @@ module Arel
alias :visit_Arel_Nodes_NotIn :binary
alias :visit_Arel_Nodes_Or :binary
alias :visit_Arel_Nodes_Ordering :binary
- alias :visit_Arel_Nodes_StringJoin :binary
+ alias :visit_Arel_Nodes_OuterJoin :binary
alias :visit_Arel_Nodes_TableAlias :binary
alias :visit_Arel_Nodes_Values :binary
+ def visit_Arel_Nodes_StringJoin o
+ visit o.left
+ end
+
def visit_Arel_Attribute o
visit o.relation
visit o.name
@@ -118,7 +122,7 @@ module Arel
def visit_Arel_Nodes_SelectCore o
visit o.projections
- visit o.froms
+ visit o.source
visit o.wheres
visit o.groups
visit o.having
diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb
index eab5e4afdc..3c4fe12d1f 100644
--- a/lib/arel/visitors/dot.rb
+++ b/lib/arel/visitors/dot.rb
@@ -36,7 +36,6 @@ module Arel
def visit_Arel_Nodes_TableAlias o
visit_edge o, "name"
visit_edge o, "relation"
- visit_edge o, "columns"
end
def visit_Arel_Nodes_Sum o
@@ -57,13 +56,11 @@ module Arel
def visit_Arel_Nodes_StringJoin o
visit_edge o, "left"
- visit_edge o, "right"
end
def visit_Arel_Nodes_InnerJoin o
visit_edge o, "left"
visit_edge o, "right"
- visit_edge o, "constraint"
end
alias :visit_Arel_Nodes_OuterJoin :visit_Arel_Nodes_InnerJoin
@@ -78,9 +75,11 @@ module Arel
alias :visit_Arel_Nodes_Group :unary
alias :visit_Arel_Nodes_Grouping :unary
alias :visit_Arel_Nodes_Having :unary
+ alias :visit_Arel_Nodes_Limit :unary
alias :visit_Arel_Nodes_Not :unary
alias :visit_Arel_Nodes_Offset :unary
alias :visit_Arel_Nodes_On :unary
+ alias :visit_Arel_Nodes_Top :unary
alias :visit_Arel_Nodes_UnqualifiedColumn :unary
def visit_Arel_Nodes_InsertStatement o
@@ -90,7 +89,7 @@ module Arel
end
def visit_Arel_Nodes_SelectCore o
- visit_edge o, "froms"
+ visit_edge o, "source"
visit_edge o, "projections"
visit_edge o, "wheres"
end
@@ -123,23 +122,32 @@ module Arel
alias :visit_Arel_Attributes_Boolean :visit_Arel_Attribute
alias :visit_Arel_Attributes_Attribute :visit_Arel_Attribute
- def visit_Arel_Nodes_Equality o
+ def nary o
+ o.children.each_with_index do |x,i|
+ edge(i) { visit x }
+ end
+ end
+ alias :visit_Arel_Nodes_And :nary
+
+ def binary o
visit_edge o, "left"
visit_edge o, "right"
end
- alias :visit_Arel_Nodes_And :visit_Arel_Nodes_Equality
- alias :visit_Arel_Nodes_Or :visit_Arel_Nodes_Equality
- alias :visit_Arel_Nodes_NotEqual :visit_Arel_Nodes_Equality
- alias :visit_Arel_Nodes_GreaterThan :visit_Arel_Nodes_Equality
- alias :visit_Arel_Nodes_GreaterThanOrEqual :visit_Arel_Nodes_Equality
- alias :visit_Arel_Nodes_Assignment :visit_Arel_Nodes_Equality
- alias :visit_Arel_Nodes_In :visit_Arel_Nodes_Equality
- alias :visit_Arel_Nodes_LessThan :visit_Arel_Nodes_Equality
- alias :visit_Arel_Nodes_LessThanOrEqual :visit_Arel_Nodes_Equality
- alias :visit_Arel_Nodes_Between :visit_Arel_Nodes_Equality
- alias :visit_Arel_Nodes_NotIn :visit_Arel_Nodes_Equality
- alias :visit_Arel_Nodes_DoesNotMatch :visit_Arel_Nodes_Equality
- alias :visit_Arel_Nodes_Matches :visit_Arel_Nodes_Equality
+ alias :visit_Arel_Nodes_As :binary
+ alias :visit_Arel_Nodes_Assignment :binary
+ alias :visit_Arel_Nodes_Between :binary
+ alias :visit_Arel_Nodes_DoesNotMatch :binary
+ alias :visit_Arel_Nodes_Equality :binary
+ alias :visit_Arel_Nodes_GreaterThan :binary
+ alias :visit_Arel_Nodes_GreaterThanOrEqual :binary
+ alias :visit_Arel_Nodes_In :binary
+ alias :visit_Arel_Nodes_JoinSource :binary
+ alias :visit_Arel_Nodes_LessThan :binary
+ alias :visit_Arel_Nodes_LessThanOrEqual :binary
+ alias :visit_Arel_Nodes_Matches :binary
+ alias :visit_Arel_Nodes_NotEqual :binary
+ alias :visit_Arel_Nodes_NotIn :binary
+ alias :visit_Arel_Nodes_Or :binary
def visit_String o
@node_stack.last.fields << o
diff --git a/lib/arel/visitors/join_sql.rb b/lib/arel/visitors/join_sql.rb
index d3fb18d3c6..1cdd7eb5ca 100644
--- a/lib/arel/visitors/join_sql.rb
+++ b/lib/arel/visitors/join_sql.rb
@@ -8,32 +8,11 @@ module Arel
#
# This visitor is used in SelectManager#join_sql and is for backwards
# compatibility with Arel V1.0
- class JoinSql < Arel::Visitors::ToSql
+ module JoinSql
private
def visit_Arel_Nodes_SelectCore o
- [o.froms].grep(Nodes::Join).map { |x| visit x }.join ', '
- end
-
- def visit_Arel_Nodes_StringJoin o
- [
- (visit o.left if Nodes::Join === o.left),
- visit(o.right)
- ].compact.join ' '
- end
-
- def visit_Arel_Nodes_OuterJoin o
- [
- (visit o.left if Nodes::Join === o.left),
- "LEFT OUTER JOIN #{visit o.right} #{visit o.constraint if o.constraint}"
- ].compact.join ' '
- end
-
- def visit_Arel_Nodes_InnerJoin o
- [
- (visit o.left if Nodes::Join === o.left),
- "INNER JOIN #{visit o.right} #{visit o.constraint if o.constraint}"
- ].compact.join ' '
+ o.source.right.map { |j| visit j }.join ' '
end
end
end
diff --git a/lib/arel/visitors/oracle.rb b/lib/arel/visitors/oracle.rb
index 87b8f10ef4..7d62531afb 100644
--- a/lib/arel/visitors/oracle.rb
+++ b/lib/arel/visitors/oracle.rb
@@ -25,7 +25,7 @@ module Arel
SELECT * FROM (
SELECT raw_sql_.*, rownum raw_rnum_
FROM (#{sql}) raw_sql_
- WHERE rownum <= #{offset.value.to_i + limit}
+ WHERE rownum <= #{offset.expr.to_i + limit}
)
WHERE #{visit offset}
eosql
@@ -59,7 +59,7 @@ module Arel
end
def visit_Arel_Nodes_Offset o
- "raw_rnum_ > #{visit o.value}"
+ "raw_rnum_ > #{visit o.expr}"
end
###
diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb
index 7435e41561..4eae5a9ae5 100644
--- a/lib/arel/visitors/to_sql.rb
+++ b/lib/arel/visitors/to_sql.rb
@@ -7,14 +7,24 @@ module Arel
def initialize engine
@engine = engine
@connection = nil
+ @pool = nil
@last_column = nil
@quoted_tables = {}
@quoted_columns = {}
+ @column_cache = Hash.new { |h,pool|
+ h[pool] = Hash.new { |conn_h,column|
+ conn_h[column] = {}
+ }
+ }
+ @table_exists = Hash.new { |h,pool|
+ h[pool] = {}
+ }
end
def accept object
@last_column = nil
- @engine.connection_pool.with_connection do |conn|
+ @pool = @engine.connection_pool
+ @pool.with_connection do |conn|
@connection = conn
super
end
@@ -32,20 +42,31 @@ module Arel
if o.orders.empty? && o.limit.nil?
wheres = o.wheres
else
+ key = o.key
+ unless key
+ warn(<<-eowarn) if $VERBOSE
+(#{caller.first}) Using UpdateManager without setting UpdateManager#key is
+deprecated and support will be removed in ARel 3.0.0. Please set the primary
+key on UpdateManager using UpdateManager#key=
+eowarn
+ key = o.relation.primary_key
+ end
+
+ wheres = o.wheres
stmt = Nodes::SelectStatement.new
core = stmt.cores.first
core.froms = o.relation
- core.projections = [o.relation.primary_key]
+ core.projections = [key]
stmt.limit = o.limit
stmt.orders = o.orders
- wheres = [Nodes::In.new(o.relation.primary_key, [stmt])]
+ wheres = [Nodes::In.new(key, [stmt])]
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?)
+ ("WHERE #{wheres.map { |x| visit x }.join ' AND '}" unless wheres.empty?),
].compact.join ' '
end
@@ -62,13 +83,47 @@ module Arel
end
def visit_Arel_Nodes_Exists o
- "EXISTS (#{visit o.select_stmt})#{
+ "EXISTS (#{visit o.expressions})#{
o.alias ? " AS #{visit o.alias}" : ''}"
end
+ def table_exists? name
+ return true if table_exists.key? name
+
+ @connection.tables.each do |table|
+ table_exists[table] = true
+ end
+
+ table_exists.key? name
+ end
+
+ def table_exists
+ @table_exists[@pool]
+ end
+
+ def column_for attr
+ name = attr.name.to_sym
+ table = attr.relation.name
+
+ return nil unless table_exists? table
+
+ # If we don't have this column cached, get a list of columns and
+ # cache them for this table
+ unless column_cache.key? table
+ columns = @connection.columns(table, "#{table}(#{name}) Columns")
+ column_cache[table] = Hash[columns.map { |c| [c.name.to_sym, c] }]
+ end
+
+ column_cache[table][name]
+ end
+
+ def column_cache
+ @column_cache[@pool]
+ end
+
def visit_Arel_Nodes_Values o
- "VALUES (#{o.expressions.zip(o.columns).map { |value, column|
- quote(value, column && column.column)
+ "VALUES (#{o.expressions.zip(o.columns).map { |value, attr|
+ quote(value, attr && column_for(attr))
}.join ', '})"
end
@@ -87,7 +142,7 @@ module Arel
"SELECT",
(visit(o.top) if o.top),
"#{o.projections.map { |x| visit x }.join ', '}",
- ("FROM #{visit o.froms}" if o.froms),
+ visit(o.source),
("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),
@@ -186,16 +241,26 @@ module Arel
"#{visit o.left} NOT LIKE #{visit o.right}"
end
+ def visit_Arel_Nodes_JoinSource o
+ return unless o.left || !o.right.empty?
+
+ [
+ "FROM",
+ (visit(o.left) if o.left),
+ o.right.map { |j| visit j }.join(' ')
+ ].compact.join ' '
+ end
+
def visit_Arel_Nodes_StringJoin o
- "#{visit o.left} #{visit o.right}"
+ visit o.left
end
def visit_Arel_Nodes_OuterJoin o
- "#{visit o.left} LEFT OUTER JOIN #{visit o.right} #{visit o.constraint}"
+ "LEFT OUTER JOIN #{visit o.left} #{visit o.right}"
end
def visit_Arel_Nodes_InnerJoin o
- "#{visit o.left} INNER JOIN #{visit o.right} #{visit o.constraint if o.constraint}"
+ "INNER JOIN #{visit o.left} #{visit o.right if o.right}"
end
def visit_Arel_Nodes_On o
@@ -223,7 +288,7 @@ module Arel
end
def visit_Arel_Nodes_And o
- "#{visit o.left} AND #{visit o.right}"
+ o.children.map { |x| visit x }.join ' AND '
end
def visit_Arel_Nodes_Or o
@@ -231,7 +296,7 @@ module Arel
end
def visit_Arel_Nodes_Assignment o
- right = quote(o.right, o.left.column)
+ right = quote(o.right, column_for(o.left))
"#{visit o.left} = #{right}"
end
@@ -264,7 +329,7 @@ module Arel
end
def visit_Arel_Attributes_Attribute o
- @last_column = o.column
+ @last_column = column_for o
join_name = o.relation.table_alias || o.relation.name
"#{quote_table_name join_name}.#{quote_column_name o.name}"
end
@@ -275,26 +340,29 @@ module Arel
alias :visit_Arel_Attributes_Time :visit_Arel_Attributes_Attribute
alias :visit_Arel_Attributes_Boolean :visit_Arel_Attributes_Attribute
- def visit_Fixnum o; o end
- alias :visit_Arel_Nodes_SqlLiteral :visit_Fixnum
- alias :visit_Arel_SqlLiteral :visit_Fixnum # This is deprecated
- alias :visit_Bignum :visit_Fixnum
-
- def visit_String o; quote(o, @last_column) end
-
- alias :visit_ActiveSupport_Multibyte_Chars :visit_String
- alias :visit_BigDecimal :visit_String
- alias :visit_Date :visit_String
- alias :visit_DateTime :visit_String
- alias :visit_FalseClass :visit_String
- alias :visit_Float :visit_String
- alias :visit_Hash :visit_String
- alias :visit_Symbol :visit_String
- alias :visit_Time :visit_String
- alias :visit_TrueClass :visit_String
- alias :visit_NilClass :visit_String
- alias :visit_ActiveSupport_StringInquirer :visit_String
- alias :visit_Class :visit_String
+ def literal o; o end
+
+ alias :visit_Arel_Nodes_SqlLiteral :literal
+ alias :visit_Arel_SqlLiteral :literal # This is deprecated
+ alias :visit_Bignum :literal
+ alias :visit_Fixnum :literal
+
+ def quoted o; quote(o, @last_column) end
+
+ alias :visit_ActiveSupport_Multibyte_Chars :quoted
+ alias :visit_ActiveSupport_StringInquirer :quoted
+ alias :visit_BigDecimal :quoted
+ alias :visit_Class :quoted
+ alias :visit_Date :quoted
+ alias :visit_DateTime :quoted
+ alias :visit_FalseClass :quoted
+ alias :visit_Float :quoted
+ alias :visit_Hash :quoted
+ alias :visit_NilClass :quoted
+ alias :visit_String :quoted
+ alias :visit_Symbol :quoted
+ alias :visit_Time :quoted
+ alias :visit_TrueClass :quoted
def visit_Array o
o.empty? ? 'NULL' : o.map { |x| visit x }.join(', ')
@@ -309,7 +377,7 @@ module Arel
end
def quote_column_name name
- @quoted_columns[name] ||= @connection.quote_column_name(name)
+ @quoted_columns[name] ||= Arel::Nodes::SqlLiteral === name ? name : @connection.quote_column_name(name)
end
end
end