@@ -805,3 +805,78 @@ statement ok
805805SET ROLE root
806806
807807subtest end
808+
809+ # Regression test for #168992. Unqualified function calls should not leak
810+ # descriptors across database boundaries via the query cache. When two databases
811+ # have identically-named functions in custom schemas, the memo cached from one
812+ # database context must be treated as stale when accessed from another, rather
813+ # than producing a privilege error referencing schemas from the wrong database.
814+ subtest cross_database_function_resolution
815+
816+ statement ok
817+ CREATE DATABASE db_a;
818+ CREATE DATABASE db_b;
819+ CREATE ROLE role_a;
820+ CREATE ROLE role_b;
821+ GRANT role_a TO testuser;
822+ GRANT role_b TO testuser;
823+ GRANT CONNECT ON DATABASE db_a TO role_a;
824+ GRANT CONNECT ON DATABASE db_b TO role_b;
825+
826+ statement ok
827+ USE db_a;
828+ CREATE SCHEMA sch_a;
829+ GRANT USAGE ON SCHEMA sch_a TO role_a;
830+ CREATE TABLE sch_a.records (id INT PRIMARY KEY, label TEXT NOT NULL);
831+ GRANT SELECT ON TABLE sch_a.records TO role_a;
832+ CREATE FUNCTION sch_a.get_records(p_id INT) RETURNS TABLE(id INT, label TEXT) LANGUAGE SQL AS $$
833+ SELECT id, label FROM db_a.sch_a.records WHERE id >= p_id ORDER BY id
834+ $$;
835+ GRANT EXECUTE ON FUNCTION sch_a.get_records TO role_a;
836+ INSERT INTO sch_a.records VALUES (1, 'alpha');
837+
838+ statement ok
839+ USE db_b;
840+ CREATE SCHEMA sch_b;
841+ GRANT USAGE ON SCHEMA sch_b TO role_b;
842+ CREATE TABLE sch_b.records (id INT PRIMARY KEY, label TEXT NOT NULL);
843+ GRANT SELECT ON TABLE sch_b.records TO role_b;
844+ CREATE FUNCTION sch_b.get_records(p_id INT) RETURNS TABLE(id INT, label TEXT) LANGUAGE SQL AS $$
845+ SELECT id, label FROM db_b.sch_b.records WHERE id >= p_id ORDER BY id
846+ $$;
847+ GRANT EXECUTE ON FUNCTION sch_b.get_records TO role_b;
848+ INSERT INTO sch_b.records VALUES (1, 'beta');
849+
850+ # Populate the query cache for get_records via role_a in db_a.
851+ statement ok
852+ USE db_a;
853+ SET ROLE role_a;
854+ SET search_path = sch_a;
855+
856+ query I
857+ SELECT count(*) FROM get_records(1)
858+ ----
859+ 1
860+
861+ # Switch to role_b in db_b. The cached memo references db_a.sch_a, but that
862+ # should be detected as stale rather than producing a privilege error.
863+ statement ok
864+ SET ROLE role_b;
865+ USE db_b;
866+ SET search_path = sch_b;
867+
868+ query I
869+ SELECT count(*) FROM get_records(1)
870+ ----
871+ 1
872+
873+ statement ok
874+ SET ROLE root;
875+ USE test;
876+ SET search_path = public;
877+ DROP DATABASE db_a CASCADE;
878+ DROP DATABASE db_b CASCADE;
879+ DROP ROLE role_a;
880+ DROP ROLE role_b;
881+
882+ subtest end
0 commit comments