Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1tvfDJ-006sdc-7Z for pgsql-general@arkaria.postgresql.org; Fri, 21 Mar 2025 16:27:17 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.94.2) (envelope-from ) id 1tvfDH-00B6pV-UD for pgsql-general@arkaria.postgresql.org; Fri, 21 Mar 2025 16:27:15 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from <01020195b987abd3-a008b77d-8c63-4931-80a4-be36a351c8b2-000000@eu-west-1.amazonses.com>) id 1tvfDH-00B6pN-JF for pgsql-general@lists.postgresql.org; Fri, 21 Mar 2025 16:27:15 +0000 Received: from a7-30.smtp-out.eu-west-1.amazonses.com ([54.240.7.30]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.96) (envelope-from <01020195b987abd3-a008b77d-8c63-4931-80a4-be36a351c8b2-000000@eu-west-1.amazonses.com>) id 1tvfDE-000LpS-1A for pgsql-general@postgresql.org; Fri, 21 Mar 2025 16:27:15 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/simple; s=wk7n4ms5lmg6b73k6q75nyqunfggnej7; d=realityexists.net; t=1742574431; h=From:Subject:To:Message-ID:Date:MIME-Version:Content-Type:Content-Transfer-Encoding; bh=TMr5w3kONgaryY9Xw2pHD3ECViZUR05SSOxiQ0Q+T74=; b=zTVW6/SjCavgiqrMbKCgJwOFy7BjeGPURdQDHhyxMSISqKDgc2v8FUKhiZJbVKyc Kqyn7Hafox2FXelRYHQZIOFVq9TsJv1qdNgrVF3sePeR9voFtzQiTFMukha75UJ/D4N F2iXIVKerZpQtzWF5krBOF3oaX1/p8twzyUE6HKA= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/simple; s=ihchhvubuqgjsxyuhssfvqohv7z3u4hn; d=amazonses.com; t=1742574431; h=From:Subject:To:Message-ID:Date:MIME-Version:Content-Type:Content-Transfer-Encoding:Feedback-ID; bh=TMr5w3kONgaryY9Xw2pHD3ECViZUR05SSOxiQ0Q+T74=; b=VCYVnqAioWnxojuueNhmMqYpWCEM+zZCmd/f2nICbee6hP9WrOxn4Na+aIwEQljj IaX9y5C+Xu0R+u2scWcKhQjdkw2/xQMUlou3E5mXy/g0NCXLVmB9XJ91DPXplaw+vL1 EnefGwCCchhSynCXhdC73D8QAY/p/CAbWKKJRTBw= From: Evgeny Morozov Subject: Querying one partition in a function takes locks on all partitions To: PostgreSQL General Message-ID: <01020195b987abd3-a008b77d-8c63-4931-80a4-be36a351c8b2-000000@eu-west-1.amazonses.com> Date: Fri, 21 Mar 2025 16:27:11 +0000 User-Agent: Microsoft Office/16.0 (Windows NT 10.0; Microsoft Outlook 16.0.6326; Pro) MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit Content-Language: en-GB Feedback-ID: ::1.eu-west-1.6myxQ/Nob+RNyv0fYur+XpsQ4yD8LrGlDW2OrOybOAI=:AmazonSES X-SES-Outgoing: 2025.03.21-54.240.7.30 List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk I have a list-partitioned table. When I query the base table but filter by the partition column in a regular SQL query this takes a lock only on the one partition being queried, as I expect. However, when the exact same SQL query is run fom a DB function, with the partition ID passed in as argument, it takes (shared) locks on ALL partitions - which blocks any other process that wants an exclusive lock on another partition (and vice-versa). Originally found on PG 15.12, but happens on 17.4 as well. Easily reproducible: -- One-time setup create table entity (     part_id integer not null ) partition by list (part_id); create table entity_1 partition of entity for values in (1); create table entity_2 partition of entity for values in (2); create function read_partition(which_part int) returns bigint as 'select count(*) from entity where part_id = which_part;' language sql stable; -- Then try this, keeping the connection open (so the transaction is pending): begin; select read_partition(1); -- This takes shared locks on entity_1 AND entity_2 -- select count(*) from entity where part_id = 1; -- but this would only take a shared lock only on entity_1 If another session tries something that takes an exclusive lock on another partition, like alter table entity_2 add column new_column text; I would expect that to be able to run concurrently, but it blocks due to the shared lock on entity_2. (The way I originally found the problem was the opposite: once one client took an exclusive lock on a partition many others were blocked from reading from ANY partition.) This seems like quite the "gotcha", especially when the query plan for the function call (logged via autoexplain) shows it only accessing one partition (entity_1). Is this expected behavior? If so, is it documented somewhere?