public inbox for [email protected]  
help / color / mirror / Atom feed
From: Amit Langote <[email protected]>
To: David Rowley <[email protected]>
Cc: Tom Lane <[email protected]>
Cc: Kirill Reshke <[email protected]>
Cc: Tender Wang <[email protected]>
Cc: jian he <[email protected]>
Cc: [email protected]
Cc: [email protected]
Subject: Re: BUG #19099: Conditional DELETE from partitioned table with non-updatable partition raises internal error
Date: Thu, 27 Nov 2025 10:25:36 +0900
Message-ID: <CA+HiwqFs-ycozH3XyTa404R2ZqF87UdeGZiCtrp4kaJP2hRF_g@mail.gmail.com> (raw)
In-Reply-To: <CA+HiwqGk1X-EiVL5kJjHD7V=a3JVDQodt2pwb9SK7q+cYQnpTg@mail.gmail.com>
References: <[email protected]>
	<CACJufxF9FcuYe8XOuWLgWK77HCUHpOc6+7+NkktFFNmzw15jKg@mail.gmail.com>
	<CAHewXN=vF5d9O4R3+iUwLqEaP7pb8iYAN_e3vEE_p5sJHofn7w@mail.gmail.com>
	<[email protected]>
	<CALdSSPi7udsgQg3PUG=Z4+-9pRg8wT3HkDvTgYvtg30xNWQ9OA@mail.gmail.com>
	<CALdSSPi9n2KGzKQn2Egqz3H8Nx0cgnZ8UeB5gk-KVdE3uBCj6Q@mail.gmail.com>
	<CA+HiwqFcejrmS_H8YB-AMB7sujB7wdJXFPdAVfDC6-19FXUjgg@mail.gmail.com>
	<CAHewXNmx+UXg46+WUrbPca91bmVipRTpe+SRm19GtxG6mArRhg@mail.gmail.com>
	<CALdSSPi6xR1tG2kLvpwNLnAjG9e0wmaY62r2_MF81ZYg5in+qQ@mail.gmail.com>
	<[email protected]>
	<CAApHDvpYEqJ6h-3NWi_4S19RY9NARpJ3h8CRmWYbz5MJFqE-sg@mail.gmail.com>
	<CA+HiwqEHHTG5_TKuNw1M0dCrgUd6SauJ5dcdicz7xozMJip0SA@mail.gmail.com>
	<CA+HiwqGk1X-EiVL5kJjHD7V=a3JVDQodt2pwb9SK7q+cYQnpTg@mail.gmail.com>

On Wed, Nov 26, 2025 at 8:27 PM Amit Langote <[email protected]> wrote:
> On Thu, Nov 6, 2025 at 7:00 PM Amit Langote <[email protected]> wrote:
> > Among those options, I considered the following block, which adds a
> > ctid for the partitioned root table when it’s the only target in the
> > query after partition pruning removes all child tables due to the
> > WHERE false condition in the problematic case:
> >
> >     /*
> >      * Ordinarily, we expect that leaf result relation(s) will have added some
> >      * ROWID_VAR Vars to the query.  However, it's possible that constraint
> >      * exclusion suppressed every leaf relation.  The executor will get upset
> >      * if the plan has no row identity columns at all, even though it will
> >      * certainly process no rows.  Handle this edge case by re-opening the top
> >      * result relation and adding the row identity columns it would have used,
> >      * as preprocess_targetlist() would have done if it weren't marked "inh".
> >      * Then re-run build_base_rel_tlists() to ensure that the added columns
> >      * get propagated to the relation's reltarget.  (This is a bit ugly, but
> >      * it seems better to confine the ugliness and extra cycles to this
> >      * unusual corner case.)
> >      */
> >     if (root->row_identity_vars == NIL)
> >     {
> >         Relation    target_relation;
> >
> >         target_relation = table_open(target_rte->relid, NoLock);
> >         add_row_identity_columns(root, result_relation,
> >                                  target_rte, target_relation);
> >         table_close(target_relation, NoLock);
> >         build_base_rel_tlists(root, root->processed_tlist);
> >         /* There are no ROWID_VAR Vars in this case, so we're done. */
> >         return;
> >     }
> >
> > If enable_partition_pruning is off, root->row_identity_vars already
> > contains a RowIdentityVarInfo entry for the tableoid Var that was
> > added while processing the foreign-table child partition. Because of
> > that, the if (root->row_identity_vars == NIL) block doesn’t run in
> > this case, so it won’t add any row identity columns such as ctid for
> > the partitioned root table.
> >
> > In theory, we could prevent the planner from adding tableoid in the
> > first place when the child table doesn’t support any row identity
> > column -- or worse, doesn’t support the UPDATE/DELETE/MERGE command at
> > all -- but doing so would require changing the order in which tableoid
> > appears in root->processed_tlist. That would be too invasive for a
> > back-patch.
>
> I’ve implemented this alternative as well -- the version that prevents
> adding tableoid when no other row-identity columns are added for the
> child. That allows to keep root->row_identity_vars empty so the
> dummy-root path can add ctid as intended by the above code block of
> distribute_row_identity_vars().
>
> This provides an alternative approach to compare against the other patch.

Forgot to mention that with this approach, unlike the other patch, the
targetlists are identical whether or not enable_partition_pruning is
on, since in both cases the if (root->row_identity_vars == NIL) block
of distribute_row_identity_vars() executes:

+SET enable_partition_pruning TO off;
+EXPLAIN (COSTS OFF, VERBOSE) DELETE FROM pt WHERE false;
+           QUERY PLAN
+--------------------------------
+ Delete on public.pt
+   ->  Result
+         Output: pt.ctid
+         Replaces: Scan on pt
+         One-Time Filter: false
+(5 rows)

+SET enable_partition_pruning TO on;
+EXPLAIN (COSTS OFF, VERBOSE) DELETE FROM pt WHERE false;
+           QUERY PLAN
+--------------------------------
+ Delete on public.pt
+   ->  Result
+         Output: ctid
+         Replaces: Scan on pt
+         One-Time Filter: false
+(5 rows)

pt.ctid in the off case vs only ctid in the on case has to do, I
think, with there being more than one entry in the rtable in the
pruning off case.

-- 
Thanks, Amit Langote






reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Reply to all the recipients using the --to and --cc options:
  reply via email

  To: [email protected]
  Cc: [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected]
  Subject: Re: BUG #19099: Conditional DELETE from partitioned table with non-updatable partition raises internal error
  In-Reply-To: <CA+HiwqFs-ycozH3XyTa404R2ZqF87UdeGZiCtrp4kaJP2hRF_g@mail.gmail.com>

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox