diff options
-rw-r--r-- | History.txt | 12 | ||||
-rw-r--r-- | Manifest.txt | 1 | ||||
-rw-r--r-- | Rakefile | 1 | ||||
-rw-r--r-- | arel.gemspec | 31 | ||||
-rw-r--r-- | lib/arel.rb | 2 | ||||
-rw-r--r-- | lib/arel/table.rb | 5 | ||||
-rw-r--r-- | lib/arel/visitors/oracle.rb | 4 | ||||
-rw-r--r-- | lib/arel/visitors/to_sql.rb | 2 | ||||
-rw-r--r-- | lib/arel/visitors/visitor.rb | 9 | ||||
-rw-r--r-- | test/test_update_manager.rb | 1 | ||||
-rw-r--r-- | test/visitors/test_dispatch_contamination.rb | 22 | ||||
-rw-r--r-- | test/visitors/test_oracle.rb | 3 |
12 files changed, 69 insertions, 24 deletions
diff --git a/History.txt b/History.txt index 9f8e9c99f7..71c8a81514 100644 --- a/History.txt +++ b/History.txt @@ -1,3 +1,15 @@ +== 4.0.1 / 2013-10-22 + +* Enhancements + + * Cache visitor dispatch on a per-visitor basis + * Improve performance of #uniq across a large number of nodes + +* Bug Fixes + + * Make visitors threadsafe by removing @last_column + * Support `columns_for_distinct` with Oracle adapter + == 2.2.1 / 2011-09-15 * Enhancements diff --git a/Manifest.txt b/Manifest.txt index b70d706ba9..cd4af8c588 100644 --- a/Manifest.txt +++ b/Manifest.txt @@ -121,6 +121,7 @@ test/test_table.rb test/test_update_manager.rb test/visitors/test_bind_visitor.rb test/visitors/test_depth_first.rb +test/visitors/test_dispatch_contamination.rb test/visitors/test_dot.rb test/visitors/test_ibm_db.rb test/visitors/test_informix.rb @@ -14,6 +14,7 @@ Hoe.spec 'arel' do developer('Emilio Tagua', 'miloops@gmail.com') developer('Nick Kallen', 'nick@example.org') # FIXME: need Nick's email + self.licenses = ['MIT'] self.readme_file = 'README.markdown' self.extra_rdoc_files = FileList['README.markdown'] end diff --git a/arel.gemspec b/arel.gemspec index 1a9799e400..1e3f73acba 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -2,38 +2,39 @@ Gem::Specification.new do |s| s.name = "arel" - s.version = "4.0.0.20130418133826" + s.version = "4.0.1.20131022201058" - s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version= + s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = ["Aaron Patterson", "Bryan Halmkamp", "Emilio Tagua", "Nick Kallen"] - s.date = "2013-04-18" + s.date = "2013-10-22" s.description = "Arel is a SQL AST manager for Ruby. It\n\n1. Simplifies the generation of complex SQL queries\n2. Adapts to various RDBMS systems\n\nIt is intended to be a framework framework; that is, you can build your own ORM\nwith it, focusing on innovative object and collection modeling as opposed to\ndatabase compatibility and query generation." s.email = ["aaron@tenderlovemaking.com", "bryan@brynary.com", "miloops@gmail.com", "nick@example.org"] s.extra_rdoc_files = ["History.txt", "MIT-LICENSE.txt", "Manifest.txt", "README.markdown"] - s.files = [".autotest", ".gemtest", ".travis.yml", "Gemfile", "History.txt", "MIT-LICENSE.txt", "Manifest.txt", "README.markdown", "Rakefile", "arel.gemspec", "lib/arel.rb", "lib/arel/alias_predication.rb", "lib/arel/attributes.rb", "lib/arel/attributes/attribute.rb", "lib/arel/compatibility/wheres.rb", "lib/arel/crud.rb", "lib/arel/delete_manager.rb", "lib/arel/deprecated.rb", "lib/arel/expression.rb", "lib/arel/expressions.rb", "lib/arel/factory_methods.rb", "lib/arel/insert_manager.rb", "lib/arel/math.rb", "lib/arel/nodes.rb", "lib/arel/nodes/and.rb", "lib/arel/nodes/ascending.rb", "lib/arel/nodes/binary.rb", "lib/arel/nodes/count.rb", "lib/arel/nodes/delete_statement.rb", "lib/arel/nodes/descending.rb", "lib/arel/nodes/equality.rb", "lib/arel/nodes/extract.rb", "lib/arel/nodes/false.rb", "lib/arel/nodes/function.rb", "lib/arel/nodes/grouping.rb", "lib/arel/nodes/in.rb", "lib/arel/nodes/infix_operation.rb", "lib/arel/nodes/inner_join.rb", "lib/arel/nodes/insert_statement.rb", "lib/arel/nodes/join_source.rb", "lib/arel/nodes/named_function.rb", "lib/arel/nodes/node.rb", "lib/arel/nodes/outer_join.rb", "lib/arel/nodes/over.rb", "lib/arel/nodes/select_core.rb", "lib/arel/nodes/select_statement.rb", "lib/arel/nodes/sql_literal.rb", "lib/arel/nodes/string_join.rb", "lib/arel/nodes/table_alias.rb", "lib/arel/nodes/terminal.rb", "lib/arel/nodes/true.rb", "lib/arel/nodes/unary.rb", "lib/arel/nodes/unqualified_column.rb", "lib/arel/nodes/update_statement.rb", "lib/arel/nodes/values.rb", "lib/arel/nodes/window.rb", "lib/arel/nodes/with.rb", "lib/arel/order_predications.rb", "lib/arel/predications.rb", "lib/arel/select_manager.rb", "lib/arel/sql/engine.rb", "lib/arel/sql_literal.rb", "lib/arel/table.rb", "lib/arel/tree_manager.rb", "lib/arel/update_manager.rb", "lib/arel/visitors.rb", "lib/arel/visitors/bind_visitor.rb", "lib/arel/visitors/depth_first.rb", "lib/arel/visitors/dot.rb", "lib/arel/visitors/ibm_db.rb", "lib/arel/visitors/informix.rb", "lib/arel/visitors/join_sql.rb", "lib/arel/visitors/mssql.rb", "lib/arel/visitors/mysql.rb", "lib/arel/visitors/oracle.rb", "lib/arel/visitors/order_clauses.rb", "lib/arel/visitors/postgresql.rb", "lib/arel/visitors/sqlite.rb", "lib/arel/visitors/to_sql.rb", "lib/arel/visitors/visitor.rb", "lib/arel/visitors/where_sql.rb", "lib/arel/window_predications.rb", "test/attributes/test_attribute.rb", "test/helper.rb", "test/nodes/test_and.rb", "test/nodes/test_as.rb", "test/nodes/test_ascending.rb", "test/nodes/test_bin.rb", "test/nodes/test_count.rb", "test/nodes/test_delete_statement.rb", "test/nodes/test_descending.rb", "test/nodes/test_distinct.rb", "test/nodes/test_equality.rb", "test/nodes/test_extract.rb", "test/nodes/test_false.rb", "test/nodes/test_grouping.rb", "test/nodes/test_infix_operation.rb", "test/nodes/test_insert_statement.rb", "test/nodes/test_named_function.rb", "test/nodes/test_node.rb", "test/nodes/test_not.rb", "test/nodes/test_or.rb", "test/nodes/test_over.rb", "test/nodes/test_select_core.rb", "test/nodes/test_select_statement.rb", "test/nodes/test_sql_literal.rb", "test/nodes/test_sum.rb", "test/nodes/test_table_alias.rb", "test/nodes/test_true.rb", "test/nodes/test_update_statement.rb", "test/nodes/test_window.rb", "test/support/fake_record.rb", "test/test_activerecord_compat.rb", "test/test_attributes.rb", "test/test_crud.rb", "test/test_delete_manager.rb", "test/test_factory_methods.rb", "test/test_insert_manager.rb", "test/test_select_manager.rb", "test/test_table.rb", "test/test_update_manager.rb", "test/visitors/test_bind_visitor.rb", "test/visitors/test_depth_first.rb", "test/visitors/test_dot.rb", "test/visitors/test_ibm_db.rb", "test/visitors/test_informix.rb", "test/visitors/test_join_sql.rb", "test/visitors/test_mssql.rb", "test/visitors/test_mysql.rb", "test/visitors/test_oracle.rb", "test/visitors/test_postgres.rb", "test/visitors/test_sqlite.rb", "test/visitors/test_to_sql.rb"] + s.files = [".autotest", ".gemtest", ".travis.yml", "Gemfile", "History.txt", "MIT-LICENSE.txt", "Manifest.txt", "README.markdown", "Rakefile", "arel.gemspec", "lib/arel.rb", "lib/arel/alias_predication.rb", "lib/arel/attributes.rb", "lib/arel/attributes/attribute.rb", "lib/arel/compatibility/wheres.rb", "lib/arel/crud.rb", "lib/arel/delete_manager.rb", "lib/arel/deprecated.rb", "lib/arel/expression.rb", "lib/arel/expressions.rb", "lib/arel/factory_methods.rb", "lib/arel/insert_manager.rb", "lib/arel/math.rb", "lib/arel/nodes.rb", "lib/arel/nodes/and.rb", "lib/arel/nodes/ascending.rb", "lib/arel/nodes/binary.rb", "lib/arel/nodes/count.rb", "lib/arel/nodes/delete_statement.rb", "lib/arel/nodes/descending.rb", "lib/arel/nodes/equality.rb", "lib/arel/nodes/extract.rb", "lib/arel/nodes/false.rb", "lib/arel/nodes/function.rb", "lib/arel/nodes/grouping.rb", "lib/arel/nodes/in.rb", "lib/arel/nodes/infix_operation.rb", "lib/arel/nodes/inner_join.rb", "lib/arel/nodes/insert_statement.rb", "lib/arel/nodes/join_source.rb", "lib/arel/nodes/named_function.rb", "lib/arel/nodes/node.rb", "lib/arel/nodes/outer_join.rb", "lib/arel/nodes/over.rb", "lib/arel/nodes/select_core.rb", "lib/arel/nodes/select_statement.rb", "lib/arel/nodes/sql_literal.rb", "lib/arel/nodes/string_join.rb", "lib/arel/nodes/table_alias.rb", "lib/arel/nodes/terminal.rb", "lib/arel/nodes/true.rb", "lib/arel/nodes/unary.rb", "lib/arel/nodes/unqualified_column.rb", "lib/arel/nodes/update_statement.rb", "lib/arel/nodes/values.rb", "lib/arel/nodes/window.rb", "lib/arel/nodes/with.rb", "lib/arel/order_predications.rb", "lib/arel/predications.rb", "lib/arel/select_manager.rb", "lib/arel/sql/engine.rb", "lib/arel/sql_literal.rb", "lib/arel/table.rb", "lib/arel/tree_manager.rb", "lib/arel/update_manager.rb", "lib/arel/visitors.rb", "lib/arel/visitors/bind_visitor.rb", "lib/arel/visitors/depth_first.rb", "lib/arel/visitors/dot.rb", "lib/arel/visitors/ibm_db.rb", "lib/arel/visitors/informix.rb", "lib/arel/visitors/join_sql.rb", "lib/arel/visitors/mssql.rb", "lib/arel/visitors/mysql.rb", "lib/arel/visitors/oracle.rb", "lib/arel/visitors/order_clauses.rb", "lib/arel/visitors/postgresql.rb", "lib/arel/visitors/sqlite.rb", "lib/arel/visitors/to_sql.rb", "lib/arel/visitors/visitor.rb", "lib/arel/visitors/where_sql.rb", "lib/arel/window_predications.rb", "test/attributes/test_attribute.rb", "test/helper.rb", "test/nodes/test_and.rb", "test/nodes/test_as.rb", "test/nodes/test_ascending.rb", "test/nodes/test_bin.rb", "test/nodes/test_count.rb", "test/nodes/test_delete_statement.rb", "test/nodes/test_descending.rb", "test/nodes/test_distinct.rb", "test/nodes/test_equality.rb", "test/nodes/test_extract.rb", "test/nodes/test_false.rb", "test/nodes/test_grouping.rb", "test/nodes/test_infix_operation.rb", "test/nodes/test_insert_statement.rb", "test/nodes/test_named_function.rb", "test/nodes/test_node.rb", "test/nodes/test_not.rb", "test/nodes/test_or.rb", "test/nodes/test_over.rb", "test/nodes/test_select_core.rb", "test/nodes/test_select_statement.rb", "test/nodes/test_sql_literal.rb", "test/nodes/test_sum.rb", "test/nodes/test_table_alias.rb", "test/nodes/test_true.rb", "test/nodes/test_update_statement.rb", "test/nodes/test_window.rb", "test/support/fake_record.rb", "test/test_activerecord_compat.rb", "test/test_attributes.rb", "test/test_crud.rb", "test/test_delete_manager.rb", "test/test_factory_methods.rb", "test/test_insert_manager.rb", "test/test_select_manager.rb", "test/test_table.rb", "test/test_update_manager.rb", "test/visitors/test_bind_visitor.rb", "test/visitors/test_depth_first.rb", "test/visitors/test_dispatch_contamination.rb", "test/visitors/test_dot.rb", "test/visitors/test_ibm_db.rb", "test/visitors/test_informix.rb", "test/visitors/test_join_sql.rb", "test/visitors/test_mssql.rb", "test/visitors/test_mysql.rb", "test/visitors/test_oracle.rb", "test/visitors/test_postgres.rb", "test/visitors/test_sqlite.rb", "test/visitors/test_to_sql.rb"] s.homepage = "http://github.com/rails/arel" + s.licenses = ["MIT"] s.rdoc_options = ["--main", "README.markdown"] s.require_paths = ["lib"] s.rubyforge_project = "arel" - s.rubygems_version = "2.0.2" + s.rubygems_version = "2.0.6" s.summary = "Arel is a SQL AST manager for Ruby" - s.test_files = ["test/attributes/test_attribute.rb", "test/nodes/test_and.rb", "test/nodes/test_as.rb", "test/nodes/test_ascending.rb", "test/nodes/test_bin.rb", "test/nodes/test_count.rb", "test/nodes/test_delete_statement.rb", "test/nodes/test_descending.rb", "test/nodes/test_distinct.rb", "test/nodes/test_equality.rb", "test/nodes/test_extract.rb", "test/nodes/test_false.rb", "test/nodes/test_grouping.rb", "test/nodes/test_infix_operation.rb", "test/nodes/test_insert_statement.rb", "test/nodes/test_named_function.rb", "test/nodes/test_node.rb", "test/nodes/test_not.rb", "test/nodes/test_or.rb", "test/nodes/test_over.rb", "test/nodes/test_select_core.rb", "test/nodes/test_select_statement.rb", "test/nodes/test_sql_literal.rb", "test/nodes/test_sum.rb", "test/nodes/test_table_alias.rb", "test/nodes/test_true.rb", "test/nodes/test_update_statement.rb", "test/nodes/test_window.rb", "test/test_activerecord_compat.rb", "test/test_attributes.rb", "test/test_crud.rb", "test/test_delete_manager.rb", "test/test_factory_methods.rb", "test/test_insert_manager.rb", "test/test_select_manager.rb", "test/test_table.rb", "test/test_update_manager.rb", "test/visitors/test_bind_visitor.rb", "test/visitors/test_depth_first.rb", "test/visitors/test_dot.rb", "test/visitors/test_ibm_db.rb", "test/visitors/test_informix.rb", "test/visitors/test_join_sql.rb", "test/visitors/test_mssql.rb", "test/visitors/test_mysql.rb", "test/visitors/test_oracle.rb", "test/visitors/test_postgres.rb", "test/visitors/test_sqlite.rb", "test/visitors/test_to_sql.rb"] + s.test_files = ["test/attributes/test_attribute.rb", "test/nodes/test_and.rb", "test/nodes/test_as.rb", "test/nodes/test_ascending.rb", "test/nodes/test_bin.rb", "test/nodes/test_count.rb", "test/nodes/test_delete_statement.rb", "test/nodes/test_descending.rb", "test/nodes/test_distinct.rb", "test/nodes/test_equality.rb", "test/nodes/test_extract.rb", "test/nodes/test_false.rb", "test/nodes/test_grouping.rb", "test/nodes/test_infix_operation.rb", "test/nodes/test_insert_statement.rb", "test/nodes/test_named_function.rb", "test/nodes/test_node.rb", "test/nodes/test_not.rb", "test/nodes/test_or.rb", "test/nodes/test_over.rb", "test/nodes/test_select_core.rb", "test/nodes/test_select_statement.rb", "test/nodes/test_sql_literal.rb", "test/nodes/test_sum.rb", "test/nodes/test_table_alias.rb", "test/nodes/test_true.rb", "test/nodes/test_update_statement.rb", "test/nodes/test_window.rb", "test/test_activerecord_compat.rb", "test/test_attributes.rb", "test/test_crud.rb", "test/test_delete_manager.rb", "test/test_factory_methods.rb", "test/test_insert_manager.rb", "test/test_select_manager.rb", "test/test_table.rb", "test/test_update_manager.rb", "test/visitors/test_bind_visitor.rb", "test/visitors/test_depth_first.rb", "test/visitors/test_dispatch_contamination.rb", "test/visitors/test_dot.rb", "test/visitors/test_ibm_db.rb", "test/visitors/test_informix.rb", "test/visitors/test_join_sql.rb", "test/visitors/test_mssql.rb", "test/visitors/test_mysql.rb", "test/visitors/test_oracle.rb", "test/visitors/test_postgres.rb", "test/visitors/test_sqlite.rb", "test/visitors/test_to_sql.rb"] if s.respond_to? :specification_version then s.specification_version = 4 if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then - s.add_development_dependency(%q<minitest>, ["~> 4.6"]) - s.add_development_dependency(%q<rdoc>, ["~> 3.10"]) - s.add_development_dependency(%q<hoe>, ["~> 3.5"]) + s.add_development_dependency(%q<minitest>, ["~> 5.0"]) + s.add_development_dependency(%q<rdoc>, ["~> 4.0"]) + s.add_development_dependency(%q<hoe>, ["~> 3.7"]) else - s.add_dependency(%q<minitest>, ["~> 4.6"]) - s.add_dependency(%q<rdoc>, ["~> 3.10"]) - s.add_dependency(%q<hoe>, ["~> 3.5"]) + s.add_dependency(%q<minitest>, ["~> 5.0"]) + s.add_dependency(%q<rdoc>, ["~> 4.0"]) + s.add_dependency(%q<hoe>, ["~> 3.7"]) end else - s.add_dependency(%q<minitest>, ["~> 4.6"]) - s.add_dependency(%q<rdoc>, ["~> 3.10"]) - s.add_dependency(%q<hoe>, ["~> 3.5"]) + s.add_dependency(%q<minitest>, ["~> 5.0"]) + s.add_dependency(%q<rdoc>, ["~> 4.0"]) + s.add_dependency(%q<hoe>, ["~> 3.7"]) end end diff --git a/lib/arel.rb b/lib/arel.rb index f2f046f672..5d4982502c 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -32,7 +32,7 @@ require 'arel/sql_literal' #### module Arel - VERSION = '4.0.0' + VERSION = '4.0.1' def self.sql raw_sql Arel::Nodes::SqlLiteral.new raw_sql diff --git a/lib/arel/table.rb b/lib/arel/table.rb index 189fb8eb94..32e3d84099 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -113,7 +113,10 @@ primary_key (#{caller.first}) is deprecated and will be removed in Arel 4.0.0 end def hash - [@name, @engine, @aliases, @table_alias].hash + # Perf note: aliases, table alias and engine is excluded from the hash + # aliases can have a loop back to this table breaking hashes in parent + # relations, for the vast majority of cases @name is unique to a query + @name.hash end def eql? other diff --git a/lib/arel/visitors/oracle.rb b/lib/arel/visitors/oracle.rb index b58d7338ef..b6f7b4cc3c 100644 --- a/lib/arel/visitors/oracle.rb +++ b/lib/arel/visitors/oracle.rb @@ -8,7 +8,7 @@ module Arel # if need to select first records without ORDER BY and GROUP BY and without DISTINCT # then can use simple ROWNUM in WHERE clause - if o.limit && o.orders.empty? && !o.offset && o.cores.first.projections.first !~ /^DISTINCT / + if o.limit && o.orders.empty? && !o.offset && o.cores.first.set_quantifier.class.to_s !~ /Distinct/ o.cores.last.wheres.push Nodes::LessThanOrEqual.new( Nodes::SqlLiteral.new('ROWNUM'), o.limit.expr ) @@ -83,7 +83,7 @@ module Arel return o if o.orders.empty? return o unless o.cores.any? do |core| core.projections.any? do |projection| - /DISTINCT.*FIRST_VALUE/ === projection + /FIRST_VALUE/ === projection end end # Previous version with join and split broke ORDER BY clause diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 4e1f7ab466..b61d5f7acd 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -90,7 +90,7 @@ module Arel warn(<<-eowarn) if $VERBOSE (#{caller.first}) Using UpdateManager without setting UpdateManager#key is deprecated and support will be removed in Arel 4.0.0. Please set the primary -key on UpdateManager using UpdateManager#key= +key on UpdateManager using UpdateManager#key= '#{key.inspect}' eowarn key = o.relation.primary_key end diff --git a/lib/arel/visitors/visitor.rb b/lib/arel/visitors/visitor.rb index 204657883f..420549b2aa 100644 --- a/lib/arel/visitors/visitor.rb +++ b/lib/arel/visitors/visitor.rb @@ -7,12 +7,15 @@ module Arel private - DISPATCH = Hash.new do |hash, klass| - hash[klass] = "visit_#{(klass.name || '').gsub('::', '_')}" + DISPATCH = Hash.new do |hash, visitor_class| + hash[visitor_class] = + Hash.new do |method_hash, node_class| + method_hash[node_class] = "visit_#{(node_class.name || '').gsub('::', '_')}" + end end def dispatch - DISPATCH + DISPATCH[self.class] end def visit object, attribute = nil diff --git a/test/test_update_manager.rb b/test/test_update_manager.rb index 1dd881b259..f1a019970d 100644 --- a/test/test_update_manager.rb +++ b/test/test_update_manager.rb @@ -19,6 +19,7 @@ module Arel it 'handles limit properly' do table = Table.new(:users) um = Arel::UpdateManager.new Table.engine + um.key = 'id' um.take 10 um.table table um.set [[table[:name], nil]] diff --git a/test/visitors/test_dispatch_contamination.rb b/test/visitors/test_dispatch_contamination.rb new file mode 100644 index 0000000000..d3c9e8af2e --- /dev/null +++ b/test/visitors/test_dispatch_contamination.rb @@ -0,0 +1,22 @@ +require 'helper' + +module Arel + module Visitors + describe 'avoiding contamination between visitor dispatch tables' do + before do + @connection = Table.engine.connection + @table = Table.new(:users) + end + + it 'dispatches properly after failing upwards' do + node = Nodes::Union.new(Nodes::True.new, Nodes::False.new) + assert_equal "( TRUE UNION FALSE )", node.to_sql + + node.first # from Nodes::Node's Enumerable mixin + + assert_equal "( TRUE UNION FALSE )", node.to_sql + end + end + end +end + diff --git a/test/visitors/test_oracle.rb b/test/visitors/test_oracle.rb index 421e9951e6..bd22822bca 100644 --- a/test/visitors/test_oracle.rb +++ b/test/visitors/test_oracle.rb @@ -85,7 +85,8 @@ module Arel it 'creates a subquery when there is DISTINCT' do stmt = Nodes::SelectStatement.new - stmt.cores.first.projections << Nodes::SqlLiteral.new('DISTINCT id') + stmt.cores.first.set_quantifier = Arel::Nodes::Distinct.new + stmt.cores.first.projections << Nodes::SqlLiteral.new('id') stmt.limit = Arel::Nodes::Limit.new(10) sql = @visitor.accept stmt sql.must_be_like %{ |