diff options
Diffstat (limited to 'lib/arel/visitors')
-rw-r--r-- | lib/arel/visitors/depth_first.rb | 22 | ||||
-rw-r--r-- | lib/arel/visitors/dot.rb | 44 | ||||
-rw-r--r-- | lib/arel/visitors/join_sql.rb | 25 | ||||
-rw-r--r-- | lib/arel/visitors/oracle.rb | 4 | ||||
-rw-r--r-- | lib/arel/visitors/to_sql.rb | 138 |
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 |