diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb index bdd746a96ce6d927ca08a112bba6ab108bb22459..6bccc97690e37bbc3993dd3fda954448e682b907 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb @@ -416,6 +416,10 @@ def supports_optimizer_hints? false end + def supports_common_table_expressions? + false + end + def supports_lazy_transactions? false 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 f68df40a87f5fa9e9cd1c0e49d9dd53cdf11aa3a..d22fdf94b2719f865086a76f096cf1e98889e393 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb @@ -110,6 +110,14 @@ def supports_optimizer_hints? !mariadb? && database_version >= "5.7.7" end + def supports_common_table_expressions? + if mariadb? + database_version >= "10.2.1" + else + database_version >= "8.0.1" + end + end + def supports_advisory_locks? true end 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 acfedcf0e2767673a8d9d6826765a8fb680246ec..a1b27dd76ea8d9745b804a61e570634ed21e9bf4 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb @@ -67,7 +67,9 @@ def query(sql, name = nil) #:nodoc: end end - READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(:begin, :commit, :explain, :select, :set, :show, :release, :savepoint, :rollback, :with) # :nodoc: + READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp( + :begin, :commit, :explain, :select, :set, :show, :release, :savepoint, :rollback, :with + ) # :nodoc: private_constant :READ_QUERY def write_query?(sql) # :nodoc: diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 2a2ac52203a038aabb00d62abec42a6afcfd9351..dc8c25e02ca6df3af67232e39e5dec6822616605 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -361,6 +361,10 @@ def supports_optimizer_hints? @has_pg_hint_plan end + def supports_common_table_expressions? + true + end + def supports_lazy_transactions? true end diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3/database_statements.rb b/activerecord/lib/active_record/connection_adapters/sqlite3/database_statements.rb index 3ea95a43fecb5fa4b5e4113c6ccd47cdd65bcb8a..dfcf936e00df08af8f8344f835c8e80d18a06b7a 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite3/database_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite3/database_statements.rb @@ -4,7 +4,9 @@ module ActiveRecord module ConnectionAdapters module SQLite3 module DatabaseStatements - READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(:begin, :commit, :explain, :select, :pragma, :release, :savepoint, :rollback, :with) # :nodoc: + READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp( + :begin, :commit, :explain, :select, :pragma, :release, :savepoint, :rollback, :with + ) # :nodoc: private_constant :READ_QUERY def write_query?(sql) # :nodoc: diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb index 303a10fdcd960452ce36ab5d1f5529e4ab113987..9fac33d97b86c117922ec83ae9e4babf3be3dae8 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb @@ -144,6 +144,10 @@ def supports_json? true end + def supports_common_table_expressions? + database_version >= "3.8.3" + end + def supports_insert_on_conflict? database_version >= "3.24.0" end diff --git a/activerecord/test/cases/adapter_test.rb b/activerecord/test/cases/adapter_test.rb index e4e815c1969a61bb1d7bc5e97eb38f764ea8b624..5882bc8c8f7092c0a4538bb265fedc4b1b9353ee 100644 --- a/activerecord/test/cases/adapter_test.rb +++ b/activerecord/test/cases/adapter_test.rb @@ -223,6 +223,20 @@ def test_doesnt_error_when_a_select_query_is_called_while_preventing_writes end end + if ActiveRecord::Base.connection.supports_common_table_expressions? + def test_doesnt_error_when_a_read_query_with_a_cte_is_called_while_preventing_writes + @connection.insert("INSERT INTO subscribers(nick) VALUES ('138853948594')") + + @connection_handler.while_preventing_writes do + result = @connection.select_all(<<~SQL) + WITH matching_subscribers AS (SELECT subscribers.* FROM subscribers WHERE nick = '138853948594') + SELECT * FROM matching_subscribers + SQL + assert_equal 1, result.length + end + end + end + def test_uniqueness_violations_are_translated_to_specific_exception @connection.execute "INSERT INTO subscribers(nick) VALUES('me')" error = assert_raises(ActiveRecord::RecordNotUnique) do diff --git a/activerecord/test/cases/adapters/mysql2/mysql2_adapter_test.rb b/activerecord/test/cases/adapters/mysql2/mysql2_adapter_test.rb index 6ed6c8dd044fa29ee8255454b9a8d6b380f9fa2b..d546ca8190f74a251bd19177d3739eeab61b9a2a 100644 --- a/activerecord/test/cases/adapters/mysql2/mysql2_adapter_test.rb +++ b/activerecord/test/cases/adapters/mysql2/mysql2_adapter_test.rb @@ -232,15 +232,6 @@ def test_doesnt_error_when_a_read_query_with_leading_chars_is_called_while_preve end end - def test_doesnt_error_when_a_read_query_with_a_cte_is_called_while_preventing_writes - @conn.execute("INSERT INTO `engines` (`car_id`) VALUES ('138853948594')") - - @connection_handler.while_preventing_writes do - sql = "WITH matching_cars AS (SELECT `engines`.* FROM `engines` WHERE `engines`.`car_id` = '138853948594') SELECT * FROM matching_cars" - assert_equal 1, @conn.execute(sql).entries.count - end - end - def test_statement_timeout_error_codes raw_conn = @conn.raw_connection assert_raises(ActiveRecord::StatementTimeout) do diff --git a/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb b/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb index 6a302bed5ca123b271c0d0b6fd4f141d348144af..2a9dc1e328647fa3dc67b1eabf5ba97a2fcc8057 100644 --- a/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb +++ b/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb @@ -457,17 +457,6 @@ def test_doesnt_error_when_a_read_query_with_leading_chars_is_called_while_preve end end - def test_doesnt_error_when_a_read_query_with_a_cte_is_called_while_preventing_writes - with_example_table do - @connection.execute("INSERT INTO ex (data) VALUES ('138853948594')") - - @connection_handler.while_preventing_writes do - sql = "WITH matching_ex_values AS (SELECT * FROM ex WHERE data = '138853948594') SELECT * FROM matching_ex_values" - assert_equal 1, @connection.execute(sql).entries.count - end - end - end - private def with_example_table(definition = "id serial primary key, number integer, data character varying(255)", &block) diff --git a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb index 38f8fd15cf6caeb9433dcb17fdb0710e143223eb..3cd287b5812186f96842d3b1921619381c616572 100644 --- a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb +++ b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb @@ -653,17 +653,6 @@ def test_doesnt_error_when_a_read_query_with_leading_chars_is_called_while_preve end end - def test_doesnt_error_when_a_read_query_with_a_cte_is_called_while_preventing_writes - with_example_table "id int, data string" do - @conn.execute("INSERT INTO ex (data) VALUES ('138853948594')") - - @connection_handler.while_preventing_writes do - sql = "WITH matching_ex_values AS (SELECT * FROM ex WHERE data = '138853948594') SELECT * FROM matching_ex_values" - assert_equal 1, @conn.execute(sql).entries.count - end - end - end - private def assert_logged(logs)