aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actionview/lib/action_view/template.rb13
-rw-r--r--actionview/test/template/template_test.rb7
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb24
-rw-r--r--activerecord/lib/active_record/relation.rb5
-rw-r--r--activerecord/lib/active_record/statement_cache.rb28
-rw-r--r--activerecord/lib/arel/collectors/composite.rb3
-rw-r--r--activerecord/lib/arel/collectors/sql_string.rb4
-rw-r--r--activerecord/lib/arel/collectors/substitute_binds.rb3
-rw-r--r--activerecord/lib/arel/delete_manager.rb11
-rw-r--r--activerecord/lib/arel/nodes/delete_statement.rb13
-rw-r--r--activerecord/lib/arel/nodes/update_statement.rb3
-rw-r--r--activerecord/lib/arel/table.rb3
-rw-r--r--activerecord/lib/arel/tree_manager.rb29
-rw-r--r--activerecord/lib/arel/update_manager.rb29
-rw-r--r--activerecord/lib/arel/visitors/depth_first.rb2
-rw-r--r--activerecord/lib/arel/visitors/dot.rb1
-rw-r--r--activerecord/lib/arel/visitors/mysql.rb22
-rw-r--r--activerecord/lib/arel/visitors/to_sql.rb38
-rw-r--r--activerecord/test/cases/arel/collectors/sql_string_test.rb16
-rw-r--r--activerecord/test/cases/arel/delete_manager_test.rb1
-rw-r--r--activerecord/test/cases/arel/visitors/to_sql_test.rb2
-rw-r--r--activerecord/test/cases/base_test.rb10
-rw-r--r--activesupport/lib/active_support/hash_with_indifferent_access.rb1
23 files changed, 144 insertions, 124 deletions
diff --git a/actionview/lib/action_view/template.rb b/actionview/lib/action_view/template.rb
index f41bbf7fac..69a64948cc 100644
--- a/actionview/lib/action_view/template.rb
+++ b/actionview/lib/action_view/template.rb
@@ -235,6 +235,19 @@ module ActionView
end
end
+
+ # Exceptions are marshaled when using the parallel test runner with DRb, so we need
+ # to ensure that references to the template object can be marshaled as well. This means forgoing
+ # the marshalling of the compiler mutex and instantiating that again on unmarshaling.
+ def marshal_dump # :nodoc:
+ [ @source, @identifier, @handler, @compiled, @original_encoding, @locals, @virtual_path, @updated_at, @formats, @variants ]
+ end
+
+ def marshal_load(array) # :nodoc:
+ @source, @identifier, @handler, @compiled, @original_encoding, @locals, @virtual_path, @updated_at, @formats, @variants = *array
+ @compile_mutex = Mutex.new
+ end
+
private
# Compile a template. This method ensures a template is compiled
diff --git a/actionview/test/template/template_test.rb b/actionview/test/template/template_test.rb
index 3dc14e36e0..b348d1f17b 100644
--- a/actionview/test/template/template_test.rb
+++ b/actionview/test/template/template_test.rb
@@ -196,6 +196,13 @@ class TestERBTemplate < ActiveSupport::TestCase
assert_match(Regexp.new("\xFC"), e.message)
end
+ def test_template_is_marshalable
+ template = new_template
+ serialized = Marshal.load(Marshal.dump(template))
+ assert_equal template.identifier, serialized.identifier
+ assert_equal template.source, serialized.source
+ end
+
def with_external_encoding(encoding)
old = Encoding.default_external
Encoding::Converter.new old, encoding if old != encoding
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
index c10da813ec..feacdf6931 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
@@ -35,7 +35,7 @@ module ActiveRecord
sql, binds = visitor.compile(arel.ast, collector)
query = klass.query(sql)
else
- collector = PartialQueryCollector.new
+ collector = klass.partial_query_collector
parts, binds = visitor.compile(arel.ast, collector)
query = klass.partial_query(parts)
end
@@ -507,28 +507,6 @@ module ActiveRecord
value
end
end
-
- class PartialQueryCollector
- def initialize
- @parts = []
- @binds = []
- end
-
- def <<(str)
- @parts << str
- self
- end
-
- def add_bind(obj)
- @binds << obj
- @parts << Arel::Nodes::BindParam.new(1)
- self
- end
-
- def value
- [@parts, @binds]
- end
- end
end
end
end
diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb
index db06bd9e26..5bad5bfcc2 100644
--- a/activerecord/lib/active_record/relation.rb
+++ b/activerecord/lib/active_record/relation.rb
@@ -484,9 +484,12 @@ module ActiveRecord
stmt = Arel::DeleteManager.new
stmt.from(table)
- if has_join_values? || has_limit_or_offset?
+ if has_join_values? || offset_value
@klass.connection.join_to_delete(stmt, arel, arel_attribute(primary_key))
else
+ stmt.key = arel_attribute(primary_key)
+ stmt.take(arel.limit)
+ stmt.order(*arel.orders)
stmt.wheres = arel.constraints
end
diff --git a/activerecord/lib/active_record/statement_cache.rb b/activerecord/lib/active_record/statement_cache.rb
index b41d3504fd..1b1736dcab 100644
--- a/activerecord/lib/active_record/statement_cache.rb
+++ b/activerecord/lib/active_record/statement_cache.rb
@@ -44,7 +44,7 @@ module ActiveRecord
def initialize(values)
@values = values
@indexes = values.each_with_index.find_all { |thing, i|
- Arel::Nodes::BindParam === thing
+ Substitute === thing
}.map(&:last)
end
@@ -56,6 +56,28 @@ module ActiveRecord
end
end
+ class PartialQueryCollector
+ def initialize
+ @parts = []
+ @binds = []
+ end
+
+ def <<(str)
+ @parts << str
+ self
+ end
+
+ def add_bind(obj)
+ @binds << obj
+ @parts << Substitute.new
+ self
+ end
+
+ def value
+ [@parts, @binds]
+ end
+ end
+
def self.query(sql)
Query.new(sql)
end
@@ -64,6 +86,10 @@ module ActiveRecord
PartialQuery.new(values)
end
+ def self.partial_query_collector
+ PartialQueryCollector.new
+ end
+
class Params # :nodoc:
def bind; Substitute.new; end
end
diff --git a/activerecord/lib/arel/collectors/composite.rb b/activerecord/lib/arel/collectors/composite.rb
index d040d8598d..0533544993 100644
--- a/activerecord/lib/arel/collectors/composite.rb
+++ b/activerecord/lib/arel/collectors/composite.rb
@@ -24,8 +24,7 @@ module Arel # :nodoc: all
[left.value, right.value]
end
- protected
-
+ private
attr_reader :left, :right
end
end
diff --git a/activerecord/lib/arel/collectors/sql_string.rb b/activerecord/lib/arel/collectors/sql_string.rb
index c293a89a74..54e1e562c2 100644
--- a/activerecord/lib/arel/collectors/sql_string.rb
+++ b/activerecord/lib/arel/collectors/sql_string.rb
@@ -15,10 +15,6 @@ module Arel # :nodoc: all
@bind_index += 1
self
end
-
- def compile(bvs)
- value
- end
end
end
end
diff --git a/activerecord/lib/arel/collectors/substitute_binds.rb b/activerecord/lib/arel/collectors/substitute_binds.rb
index 3f40eec8a8..4b894bc4b1 100644
--- a/activerecord/lib/arel/collectors/substitute_binds.rb
+++ b/activerecord/lib/arel/collectors/substitute_binds.rb
@@ -21,8 +21,7 @@ module Arel # :nodoc: all
delegate.value
end
- protected
-
+ private
attr_reader :quoter, :delegate
end
end
diff --git a/activerecord/lib/arel/delete_manager.rb b/activerecord/lib/arel/delete_manager.rb
index 2def581009..fdba937d64 100644
--- a/activerecord/lib/arel/delete_manager.rb
+++ b/activerecord/lib/arel/delete_manager.rb
@@ -2,6 +2,8 @@
module Arel # :nodoc: all
class DeleteManager < Arel::TreeManager
+ include TreeManager::StatementMethods
+
def initialize
super
@ast = Nodes::DeleteStatement.new
@@ -12,14 +14,5 @@ module Arel # :nodoc: all
@ast.relation = relation
self
end
-
- def take(limit)
- @ast.limit = Nodes::Limit.new(Nodes.build_quoted(limit)) if limit
- self
- end
-
- def wheres=(list)
- @ast.wheres = list
- end
end
end
diff --git a/activerecord/lib/arel/nodes/delete_statement.rb b/activerecord/lib/arel/nodes/delete_statement.rb
index eaac05e2f6..5be42a084a 100644
--- a/activerecord/lib/arel/nodes/delete_statement.rb
+++ b/activerecord/lib/arel/nodes/delete_statement.rb
@@ -3,8 +3,7 @@
module Arel # :nodoc: all
module Nodes
class DeleteStatement < Arel::Nodes::Node
- attr_accessor :left, :right
- attr_accessor :limit
+ attr_accessor :left, :right, :orders, :limit, :key
alias :relation :left
alias :relation= :left=
@@ -15,6 +14,9 @@ module Arel # :nodoc: all
super()
@left = relation
@right = wheres
+ @orders = []
+ @limit = nil
+ @key = nil
end
def initialize_copy(other)
@@ -24,13 +26,16 @@ module Arel # :nodoc: all
end
def hash
- [self.class, @left, @right].hash
+ [self.class, @left, @right, @orders, @limit, @key].hash
end
def eql?(other)
self.class == other.class &&
self.left == other.left &&
- self.right == other.right
+ self.right == other.right &&
+ self.orders == other.orders &&
+ self.limit == other.limit &&
+ self.key == other.key
end
alias :== :eql?
end
diff --git a/activerecord/lib/arel/nodes/update_statement.rb b/activerecord/lib/arel/nodes/update_statement.rb
index 5184b1180f..017a553c4c 100644
--- a/activerecord/lib/arel/nodes/update_statement.rb
+++ b/activerecord/lib/arel/nodes/update_statement.rb
@@ -3,8 +3,7 @@
module Arel # :nodoc: all
module Nodes
class UpdateStatement < Arel::Nodes::Node
- attr_accessor :relation, :wheres, :values, :orders, :limit
- attr_accessor :key
+ attr_accessor :relation, :wheres, :values, :orders, :limit, :key
def initialize
@relation = nil
diff --git a/activerecord/lib/arel/table.rb b/activerecord/lib/arel/table.rb
index 686fcdf962..c40c68715a 100644
--- a/activerecord/lib/arel/table.rb
+++ b/activerecord/lib/arel/table.rb
@@ -104,8 +104,7 @@ module Arel # :nodoc: all
!type_caster.nil?
end
- protected
-
+ private
attr_reader :type_caster
end
end
diff --git a/activerecord/lib/arel/tree_manager.rb b/activerecord/lib/arel/tree_manager.rb
index ed47b09a37..149c69ce7a 100644
--- a/activerecord/lib/arel/tree_manager.rb
+++ b/activerecord/lib/arel/tree_manager.rb
@@ -4,6 +4,35 @@ module Arel # :nodoc: all
class TreeManager
include Arel::FactoryMethods
+ module StatementMethods
+ def take(limit)
+ @ast.limit = Nodes::Limit.new(Nodes.build_quoted(limit)) if limit
+ self
+ end
+
+ def order(*expr)
+ @ast.orders = expr
+ self
+ end
+
+ def key=(key)
+ @ast.key = Nodes.build_quoted(key)
+ end
+
+ def key
+ @ast.key
+ end
+
+ def wheres=(exprs)
+ @ast.wheres = exprs
+ end
+
+ def where(expr)
+ @ast.wheres << expr
+ self
+ end
+ end
+
attr_reader :ast
def initialize
diff --git a/activerecord/lib/arel/update_manager.rb b/activerecord/lib/arel/update_manager.rb
index fe444343ba..a809dbb307 100644
--- a/activerecord/lib/arel/update_manager.rb
+++ b/activerecord/lib/arel/update_manager.rb
@@ -2,30 +2,14 @@
module Arel # :nodoc: all
class UpdateManager < Arel::TreeManager
+ include TreeManager::StatementMethods
+
def initialize
super
@ast = Nodes::UpdateStatement.new
@ctx = @ast
end
- def take(limit)
- @ast.limit = Nodes::Limit.new(Nodes.build_quoted(limit)) if limit
- self
- end
-
- def key=(key)
- @ast.key = Nodes.build_quoted(key)
- end
-
- def key
- @ast.key
- end
-
- def order(*expr)
- @ast.orders = expr
- self
- end
-
###
# UPDATE +table+
def table(table)
@@ -33,15 +17,6 @@ module Arel # :nodoc: all
self
end
- def wheres=(exprs)
- @ast.wheres = exprs
- end
-
- def where(expr)
- @ast.wheres << expr
- self
- end
-
def set(values)
if String === values
@ast.values = [values]
diff --git a/activerecord/lib/arel/visitors/depth_first.rb b/activerecord/lib/arel/visitors/depth_first.rb
index 5948622aea..8f65d303ac 100644
--- a/activerecord/lib/arel/visitors/depth_first.rb
+++ b/activerecord/lib/arel/visitors/depth_first.rb
@@ -135,12 +135,10 @@ module Arel # :nodoc: all
alias :visit_Arel_Nodes_True :terminal
alias :visit_Arel_Nodes_False :terminal
alias :visit_BigDecimal :terminal
- alias :visit_Bignum :terminal
alias :visit_Class :terminal
alias :visit_Date :terminal
alias :visit_DateTime :terminal
alias :visit_FalseClass :terminal
- alias :visit_Fixnum :terminal
alias :visit_Float :terminal
alias :visit_Integer :terminal
alias :visit_NilClass :terminal
diff --git a/activerecord/lib/arel/visitors/dot.rb b/activerecord/lib/arel/visitors/dot.rb
index 76830412d4..9054f0159b 100644
--- a/activerecord/lib/arel/visitors/dot.rb
+++ b/activerecord/lib/arel/visitors/dot.rb
@@ -211,7 +211,6 @@ module Arel # :nodoc: all
alias :visit_TrueClass :visit_String
alias :visit_FalseClass :visit_String
alias :visit_Integer :visit_String
- alias :visit_Fixnum :visit_String
alias :visit_BigDecimal :visit_String
alias :visit_Float :visit_String
alias :visit_Symbol :visit_String
diff --git a/activerecord/lib/arel/visitors/mysql.rb b/activerecord/lib/arel/visitors/mysql.rb
index ee75b6bb25..0f7d5aa803 100644
--- a/activerecord/lib/arel/visitors/mysql.rb
+++ b/activerecord/lib/arel/visitors/mysql.rb
@@ -65,6 +65,19 @@ module Arel # :nodoc: all
collector = inject_join o.values, collector, ", "
end
+ collect_where_for(o, collector)
+ end
+
+ def visit_Arel_Nodes_Concat(o, collector)
+ collector << " CONCAT("
+ visit o.left, collector
+ collector << ", "
+ visit o.right, collector
+ collector << ") "
+ collector
+ end
+
+ def collect_where_for(o, collector)
unless o.wheres.empty?
collector << " WHERE "
collector = inject_join o.wheres, collector, " AND "
@@ -77,15 +90,6 @@ module Arel # :nodoc: all
maybe_visit o.limit, collector
end
-
- def visit_Arel_Nodes_Concat(o, collector)
- collector << " CONCAT("
- visit o.left, collector
- collector << ", "
- visit o.right, collector
- collector << ") "
- collector
- end
end
end
end
diff --git a/activerecord/lib/arel/visitors/to_sql.rb b/activerecord/lib/arel/visitors/to_sql.rb
index 1ed41ff577..575bfd6e36 100644
--- a/activerecord/lib/arel/visitors/to_sql.rb
+++ b/activerecord/lib/arel/visitors/to_sql.rb
@@ -67,8 +67,8 @@ module Arel # :nodoc: all
@connection = connection
end
- def compile(node, collector = Arel::Collectors::SQLString.new, &block)
- accept(node, collector, &block).value
+ def compile(node, collector = Arel::Collectors::SQLString.new)
+ accept(node, collector).value
end
private
@@ -76,12 +76,8 @@ module Arel # :nodoc: all
def visit_Arel_Nodes_DeleteStatement(o, collector)
collector << "DELETE FROM "
collector = visit o.relation, collector
- if o.wheres.any?
- collector << WHERE
- collector = inject_join o.wheres, collector, AND
- end
- maybe_visit o.limit, collector
+ collect_where_for(o, collector)
end
# FIXME: we should probably have a 2-pass visitor for this
@@ -97,12 +93,6 @@ module Arel # :nodoc: all
end
def visit_Arel_Nodes_UpdateStatement(o, collector)
- if o.orders.empty? && o.limit.nil?
- wheres = o.wheres
- else
- wheres = [Nodes::In.new(o.key, [build_subselect(o.key, o)])]
- end
-
collector << "UPDATE "
collector = visit o.relation, collector
unless o.values.empty?
@@ -110,12 +100,7 @@ module Arel # :nodoc: all
collector = inject_join o.values, collector, ", "
end
- unless wheres.empty?
- collector << " WHERE "
- collector = inject_join wheres, collector, " AND "
- end
-
- collector
+ collect_where_for(o, collector)
end
def visit_Arel_Nodes_InsertStatement(o, collector)
@@ -814,6 +799,21 @@ module Arel # :nodoc: all
}
end
+ def collect_where_for(o, collector)
+ if o.orders.empty? && o.limit.nil?
+ wheres = o.wheres
+ else
+ wheres = [Nodes::In.new(o.key, [build_subselect(o.key, o)])]
+ end
+
+ unless wheres.empty?
+ collector << " WHERE "
+ collector = inject_join wheres, collector, " AND "
+ end
+
+ collector
+ end
+
def infix_value(o, collector, value)
collector = visit o.left, collector
collector << value
diff --git a/activerecord/test/cases/arel/collectors/sql_string_test.rb b/activerecord/test/cases/arel/collectors/sql_string_test.rb
index 380573494d..443c7eb54b 100644
--- a/activerecord/test/cases/arel/collectors/sql_string_test.rb
+++ b/activerecord/test/cases/arel/collectors/sql_string_test.rb
@@ -19,27 +19,21 @@ module Arel
collect(node).value
end
- def ast_with_binds(bv)
+ def ast_with_binds
table = Table.new(:users)
manager = Arel::SelectManager.new table
- manager.where(table[:age].eq(bv))
- manager.where(table[:name].eq(bv))
+ manager.where(table[:age].eq(Nodes::BindParam.new("hello")))
+ manager.where(table[:name].eq(Nodes::BindParam.new("world")))
manager.ast
end
def test_compile
- bv = Nodes::BindParam.new(1)
- collector = collect ast_with_binds bv
-
- sql = collector.compile ["hello", "world"]
+ sql = compile(ast_with_binds)
assert_equal 'SELECT FROM "users" WHERE "users"."age" = ? AND "users"."name" = ?', sql
end
def test_returned_sql_uses_utf8_encoding
- bv = Nodes::BindParam.new(1)
- collector = collect ast_with_binds bv
-
- sql = collector.compile ["hello", "world"]
+ sql = compile(ast_with_binds)
assert_equal sql.encoding, Encoding::UTF_8
end
end
diff --git a/activerecord/test/cases/arel/delete_manager_test.rb b/activerecord/test/cases/arel/delete_manager_test.rb
index 17a5271039..0bad02f4d2 100644
--- a/activerecord/test/cases/arel/delete_manager_test.rb
+++ b/activerecord/test/cases/arel/delete_manager_test.rb
@@ -15,6 +15,7 @@ module Arel
dm = Arel::DeleteManager.new
dm.take 10
dm.from table
+ dm.key = table[:id]
assert_match(/LIMIT 10/, dm.to_sql)
end
diff --git a/activerecord/test/cases/arel/visitors/to_sql_test.rb b/activerecord/test/cases/arel/visitors/to_sql_test.rb
index e8ac50bfa3..b6426a211e 100644
--- a/activerecord/test/cases/arel/visitors/to_sql_test.rb
+++ b/activerecord/test/cases/arel/visitors/to_sql_test.rb
@@ -221,7 +221,7 @@ module Arel
sql.must_be_like "foo AS bar"
end
- it "should visit_Bignum" do
+ it "should visit_Integer" do
compile 8787878092
end
diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb
index f6311f9256..09e5517449 100644
--- a/activerecord/test/cases/base_test.rb
+++ b/activerecord/test/cases/base_test.rb
@@ -282,11 +282,13 @@ class BasicsTest < ActiveRecord::TestCase
end
def test_initialize_with_invalid_attribute
- Topic.new("title" => "test",
- "last_read(1i)" => "2005", "last_read(2i)" => "2", "last_read(3i)" => "31")
- rescue ActiveRecord::MultiparameterAssignmentErrors => ex
+ ex = assert_raise(ActiveRecord::MultiparameterAssignmentErrors) do
+ Topic.new("title" => "test",
+ "written_on(4i)" => "16", "written_on(5i)" => "24", "written_on(6i)" => "00")
+ end
+
assert_equal(1, ex.errors.size)
- assert_equal("last_read", ex.errors[0].attribute)
+ assert_equal("written_on", ex.errors[0].attribute)
end
def test_create_after_initialize_without_block
diff --git a/activesupport/lib/active_support/hash_with_indifferent_access.rb b/activesupport/lib/active_support/hash_with_indifferent_access.rb
index b9e64ed05d..2fac579469 100644
--- a/activesupport/lib/active_support/hash_with_indifferent_access.rb
+++ b/activesupport/lib/active_support/hash_with_indifferent_access.rb
@@ -2,6 +2,7 @@
require "active_support/core_ext/hash/keys"
require "active_support/core_ext/hash/reverse_merge"
+require "active_support/core_ext/hash/except"
module ActiveSupport
# Implements a hash where keys <tt>:foo</tt> and <tt>"foo"</tt> are considered