Skip to content

Commit 3f590fd

Browse files
yahondaclaude
andcommitted
Replace slow UNION ALL query with optimized all_objects query in describe
Replace the 4-way UNION ALL query across all_tables, all_views, and all_synonyms with a single all_objects query for the common TABLE/VIEW path. Synonym targets are resolved via a second all_synonyms query only when needed. - Add ORDER BY to preserve lookup priority (table, view, owner synonym, public synonym) - Add regression test covering table, view, private synonym and public synonym resolution for the same underlying table - Grant CREATE/DROP PUBLIC SYNONYM to test users Refs #2429 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent f3440f8 commit 3f590fd

3 files changed

Lines changed: 38 additions & 23 deletions

File tree

lib/active_record/connection_adapters/oracle_enhanced/connection.rb

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -34,30 +34,26 @@ def describe(name)
3434
table_owner, table_name = default_owner, real_name
3535
end
3636
sql = <<~SQL.squish
37-
SELECT owner, table_name, 'TABLE' name_type
38-
FROM all_tables
39-
WHERE owner = :table_owner
40-
AND table_name = :table_name
41-
UNION ALL
42-
SELECT owner, view_name table_name, 'VIEW' name_type
43-
FROM all_views
44-
WHERE owner = :table_owner
45-
AND view_name = :table_name
46-
UNION ALL
47-
SELECT table_owner, table_name, 'SYNONYM' name_type
48-
FROM all_synonyms
49-
WHERE owner = :table_owner
50-
AND synonym_name = :table_name
51-
UNION ALL
52-
SELECT table_owner, table_name, 'SYNONYM' name_type
53-
FROM all_synonyms
54-
WHERE owner = 'PUBLIC'
55-
AND synonym_name = :real_name
37+
SELECT owner, object_name table_name, object_type name_type
38+
FROM all_objects
39+
WHERE ((owner = :table_owner AND object_name = :table_name)
40+
OR (owner = 'PUBLIC' AND object_name = :real_name))
41+
AND object_type IN ('TABLE', 'VIEW', 'SYNONYM')
42+
ORDER BY DECODE(owner, 'PUBLIC', 2, 1),
43+
DECODE(object_type, 'TABLE', 1, 'VIEW', 2, 'SYNONYM', 3)
5644
SQL
57-
if result = _select_one(sql, "CONNECTION", [table_owner, table_name, table_owner, table_name, table_owner, table_name, real_name])
45+
if result = _select_one(sql, "CONNECTION", [table_owner, table_name, real_name])
5846
case result["name_type"]
5947
when "SYNONYM"
60-
describe("#{result['owner'] && "#{result['owner']}."}#{result['table_name']}")
48+
synonym_sql = <<~SQL.squish
49+
SELECT table_owner, table_name
50+
FROM all_synonyms
51+
WHERE owner = :owner
52+
AND synonym_name = :synonym_name
53+
SQL
54+
if syn = _select_one(synonym_sql, "CONNECTION", [result["owner"], result["table_name"]])
55+
describe("#{syn['table_owner'] && "#{syn['table_owner']}."}#{syn['table_name']}")
56+
end
6157
else
6258
[result["owner"], result["table_name"]]
6359
end

spec/active_record/connection_adapters/oracle_enhanced/connection_spec.rb

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -577,6 +577,23 @@ def kill_current_session
577577
expect(@conn.describe("all_tables")).to eq(["SYS", "ALL_TABLES"])
578578
end
579579

580+
it "should describe table, view, private synonym and public synonym for the same underlying table" do
581+
@conn.exec "CREATE TABLE test_describe_all (id NUMBER)" rescue nil
582+
@conn.exec "CREATE VIEW test_describe_all_v AS SELECT * FROM test_describe_all" rescue nil
583+
@conn.exec "CREATE SYNONYM test_describe_all_syn FOR test_describe_all" rescue nil
584+
@conn.exec "CREATE PUBLIC SYNONYM test_describe_all_pub FOR #{@owner}.test_describe_all" rescue nil
585+
586+
expect(@conn.describe("test_describe_all")).to eq([@owner, "TEST_DESCRIBE_ALL"])
587+
expect(@conn.describe("test_describe_all_v")).to eq([@owner, "TEST_DESCRIBE_ALL_V"])
588+
expect(@conn.describe("test_describe_all_syn")).to eq([@owner, "TEST_DESCRIBE_ALL"])
589+
expect(@conn.describe("test_describe_all_pub")).to eq([@owner, "TEST_DESCRIBE_ALL"])
590+
ensure
591+
@conn.exec "DROP PUBLIC SYNONYM test_describe_all_pub" rescue nil
592+
@conn.exec "DROP SYNONYM test_describe_all_syn" rescue nil
593+
@conn.exec "DROP VIEW test_describe_all_v" rescue nil
594+
@conn.exec "DROP TABLE test_describe_all" rescue nil
595+
end
596+
580597
if defined?(OCI8)
581598
context "OCI8 adapter" do
582599
it "should not fallback to SELECT-based logic when querying non-existent table information" do

spec/support/create_oracle_enhanced_users.sql

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@ CREATE USER oracle_enhanced IDENTIFIED BY oracle_enhanced;
44

55
GRANT unlimited tablespace, create session, create table, create sequence,
66
create procedure, create trigger, create view, create materialized view,
7-
create database link, create synonym, create type, ctxapp TO oracle_enhanced;
7+
create database link, create synonym, create public synonym, create type, ctxapp TO oracle_enhanced;
8+
GRANT drop public synonym TO oracle_enhanced;
89

910
CREATE USER oracle_enhanced_schema IDENTIFIED BY oracle_enhanced_schema;
1011

1112
GRANT unlimited tablespace, create session, create table, create sequence,
1213
create procedure, create trigger, create view, create materialized view,
13-
create database link, create synonym, create type, ctxapp TO oracle_enhanced_schema;
14+
create database link, create synonym, create public synonym, create type, ctxapp TO oracle_enhanced_schema;
15+
GRANT drop public synonym TO oracle_enhanced_schema;

0 commit comments

Comments
 (0)