diff options
13 files changed, 36 insertions, 18 deletions
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index c346b5d93d..691c684d76 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,9 @@ +* Fix inserts with prepared statements disabled. + + Fixes #12023. + + *Rafael Mendonça França* + * Setting a has_one association on a new record no longer causes an empty transaction. diff --git a/activerecord/lib/active_record/aggregations.rb b/activerecord/lib/active_record/aggregations.rb index d075edc159..0d5313956b 100644 --- a/activerecord/lib/active_record/aggregations.rb +++ b/activerecord/lib/active_record/aggregations.rb @@ -224,7 +224,7 @@ module ActiveRecord writer_method(name, class_name, mapping, allow_nil, converter) reflection = ActiveRecord::Reflection.create(:composed_of, part_id, nil, options, self) - Reflection.add_reflection self, part_id, reflection + Reflection.add_aggregate_reflection self, part_id, reflection end private 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 32244b1755..e1f29ea03a 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb @@ -377,7 +377,7 @@ module ActiveRecord def sql_for_insert(sql, pk, id_value, sequence_name, binds) [sql, binds] end - + def last_inserted_id(result) row = result.rows.first row && row.first diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb index ba1cb05d2c..4bb554f74d 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb @@ -97,6 +97,7 @@ module ActiveRecord @pool = pool @schema_cache = SchemaCache.new self @visitor = nil + @prepared_statements = false end def valid_type?(type) @@ -440,6 +441,10 @@ module ActiveRecord # override in derived class ActiveRecord::StatementInvalid.new(message, exception) end + + def without_prepared_statement?(binds) + !@prepared_statements || binds.empty? + end end end end diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb index 4b11ea795c..d502daf230 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb @@ -174,6 +174,7 @@ module ActiveRecord @quoted_column_names, @quoted_table_names = {}, {} if self.class.type_cast_config_to_boolean(config.fetch(:prepared_statements) { true }) + @prepared_statements = true @visitor = Arel::Visitors::MySQL.new self else @visitor = unprepared_visitor diff --git a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb index 92796c996e..e790f731ea 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb @@ -229,7 +229,7 @@ module ActiveRecord alias exec_without_stmt exec_query - # Returns an ActiveRecord::Result instance. + # Returns an ActiveRecord::Result instance. def select(sql, name = nil, binds = []) exec_query(sql, name) end diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb index 15b5452850..41a47183e0 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb @@ -279,11 +279,7 @@ module ActiveRecord end def exec_query(sql, name = 'SQL', binds = []) - # If the configuration sets prepared_statements:false, binds will - # always be empty, since the bind variables will have been already - # substituted and removed from binds by BindVisitor, so this will - # effectively disable prepared statement usage completely. - if binds.empty? + if without_prepared_statement?(binds) result_set, affected_rows = exec_without_stmt(sql, name) else result_set, affected_rows = exec_stmt(sql, name, binds) diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb b/activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb index 527d13b9b0..86b96a77fb 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb @@ -135,8 +135,8 @@ module ActiveRecord def exec_query(sql, name = 'SQL', binds = []) log(sql, name, binds) do - result = binds.empty? ? exec_no_cache(sql, binds) : - exec_cache(sql, binds) + result = without_prepared_statement?(binds) ? exec_no_cache(sql, binds) : + exec_cache(sql, binds) types = {} fields = result.fields diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 5b9453a579..13978fd113 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -531,6 +531,7 @@ module ActiveRecord super(connection, logger) if self.class.type_cast_config_to_boolean(config.fetch(:prepared_statements) { true }) + @prepared_statements = true @visitor = Arel::Visitors::PostgreSQL.new self else @visitor = unprepared_visitor diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb index df489a5b1f..136094dcc9 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb @@ -113,6 +113,7 @@ module ActiveRecord @config = config if self.class.type_cast_config_to_boolean(config.fetch(:prepared_statements) { true }) + @prepared_statements = true @visitor = Arel::Visitors::SQLite.new self else @visitor = unprepared_visitor @@ -293,8 +294,8 @@ module ActiveRecord def exec_query(sql, name = nil, binds = []) log(sql, name, binds) do - # Don't cache statements without bind values - if binds.empty? + # Don't cache statements if they are not prepared + if without_prepared_statement?(binds) stmt = @connection.prepare(sql) cols = stmt.columns records = stmt.to_a diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb index 150a90f5db..f47282b7fd 100644 --- a/activerecord/lib/active_record/reflection.rb +++ b/activerecord/lib/active_record/reflection.rb @@ -24,11 +24,11 @@ module ActiveRecord end def self.add_reflection(ar, name, reflection) - if reflection.class == AggregateReflection - ar.aggregate_reflections = ar.aggregate_reflections.merge(name => reflection) - else - ar.reflections = ar.reflections.merge(name => reflection) - end + ar.reflections = ar.reflections.merge(name => reflection) + end + + def self.add_aggregate_reflection(ar, name, reflection) + ar.aggregate_reflections = ar.aggregate_reflections.merge(name => reflection) end # \Reflection enables to interrogate Active Record classes and objects diff --git a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb index bb927841ab..f77066e6ab 100644 --- a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb @@ -651,7 +651,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase end def test_find_scoped_grouped_having - assert_equal 2, projects(:active_record).well_payed_salary_groups.size + assert_equal 2, projects(:active_record).well_payed_salary_groups.to_a.size assert projects(:active_record).well_payed_salary_groups.all? { |g| g.salary > 10000 } end diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index dc2de7b523..e3b441280b 100644 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -565,6 +565,14 @@ class BasicsTest < ActiveRecord::TestCase assert_equal [topic_2, topic_1].sort, [topic_1, topic_2] end + def test_create_without_prepared_statement + topic = Topic.connection.unprepared_statement do + Topic.create(:title => 'foo') + end + + assert_equal topic, Topic.find(topic.id) + end + def test_comparison_with_different_objects topic = Topic.create category = Category.create(:name => "comparison") |