From 92bfdd62bfd0d420029020e9b10b273718c962dc Mon Sep 17 00:00:00 2001 From: jian he Date: Thu, 6 Nov 2025 15:10:26 +0800 Subject: [PATCH v1 1/1] fix COPY WHERE clause with tableoid field discussion: https://postgr.es/m/30c39ee8-bb11-4b8f-9697-45f7e018a8d3@eisentraut.org --- src/backend/commands/copyfrom.c | 32 +++++++++++++++++++++++++++--- src/test/regress/expected/copy.out | 16 +++++++++++++++ src/test/regress/sql/copy.sql | 14 +++++++++++++ 3 files changed, 59 insertions(+), 3 deletions(-) diff --git a/src/backend/commands/copyfrom.c b/src/backend/commands/copyfrom.c index 12781963b4f..94aed15d379 100644 --- a/src/backend/commands/copyfrom.c +++ b/src/backend/commands/copyfrom.c @@ -1178,15 +1178,16 @@ CopyFrom(CopyFromState cstate) ExecStoreVirtualTuple(myslot); /* - * Constraints and where clause might reference the tableoid column, - * so (re-)initialize tts_tableOid before evaluating them. + * where clause might reference the tableoid column, so (re-)initialize + * tts_tableOid before evaluating them. It may change later if we are + * COPY INTO partitioned table. */ myslot->tts_tableOid = RelationGetRelid(target_resultRelInfo->ri_RelationDesc); /* Triggers and stuff need to be invoked in query context. */ MemoryContextSwitchTo(oldcontext); - if (cstate->whereClause) + if (proute == NULL && cstate->whereClause) { econtext->ecxt_scantuple = myslot; /* Skip items that don't match COPY's WHERE clause */ @@ -1215,6 +1216,24 @@ CopyFrom(CopyFromState cstate) resultRelInfo = ExecFindPartition(mtstate, target_resultRelInfo, proute, myslot, estate); + myslot->tts_tableOid = RelationGetRelid(resultRelInfo->ri_RelationDesc); + + if (cstate->whereClause) + { + econtext->ecxt_scantuple = myslot; + /* Skip items that don't match COPY's WHERE clause */ + if (!ExecQual(cstate->qualexpr, econtext)) + { + /* + * Report that this tuple was filtered out by the WHERE + * clause. + */ + pgstat_progress_update_param(PROGRESS_COPY_TUPLES_EXCLUDED, + ++excluded); + continue; + } + } + if (prevResultRelInfo != resultRelInfo) { /* Determine which triggers exist on this partition */ @@ -1343,6 +1362,13 @@ CopyFrom(CopyFromState cstate) } else { + /* + * Constraints and GENERATED expressions might reference the + * tableoid column, so (re-)initialize tts_tableOid before + * evaluating them. + */ + myslot->tts_tableOid = RelationGetRelid(resultRelInfo->ri_RelationDesc); + /* Compute stored generated columns */ if (resultRelInfo->ri_RelationDesc->rd_att->constr && resultRelInfo->ri_RelationDesc->rd_att->constr->has_generated_stored) diff --git a/src/test/regress/expected/copy.out b/src/test/regress/expected/copy.out index 24e0f472f14..0735160bc10 100644 --- a/src/test/regress/expected/copy.out +++ b/src/test/regress/expected/copy.out @@ -121,6 +121,22 @@ insert into parted_copytest select x,2,'Two' from generate_series(1001,1010) x; insert into parted_copytest select x,1,'One' from generate_series(1011,1020) x; \set filename :abs_builddir '/results/parted_copytest.csv' copy (select * from parted_copytest order by a) to :'filename'; +truncate parted_copytest; +COPY parted_copytest FROM STDIN WHERE (tableoid in ('parted_copytest'::regclass, 'parted_copytest_a1'::regclass)); +SELECT * FROM parted_copytest; --expect one row + a | b | c +---+---+--- + 1 | 1 | a +(1 row) + +COPY parted_copytest FROM STDIN WHERE (tableoid in ('parted_copytest_a2'::regclass)); +SELECT * FROM parted_copytest; --expect two row + a | b | c +---+---+--- + 1 | 1 | a + 2 | 2 | b +(2 rows) + truncate parted_copytest; copy parted_copytest from :'filename'; -- Ensure COPY FREEZE errors for partitioned tables. diff --git a/src/test/regress/sql/copy.sql b/src/test/regress/sql/copy.sql index 676a8b342b5..a2d3194635a 100644 --- a/src/test/regress/sql/copy.sql +++ b/src/test/regress/sql/copy.sql @@ -148,6 +148,20 @@ copy (select * from parted_copytest order by a) to :'filename'; truncate parted_copytest; +COPY parted_copytest FROM STDIN WHERE (tableoid in ('parted_copytest'::regclass, 'parted_copytest_a1'::regclass)); +1 1 a +2 2 b +\. + +SELECT * FROM parted_copytest; --expect one row +COPY parted_copytest FROM STDIN WHERE (tableoid in ('parted_copytest_a2'::regclass)); +2 2 b +1 1 a +\. +SELECT * FROM parted_copytest; --expect two row +truncate parted_copytest; + + copy parted_copytest from :'filename'; -- Ensure COPY FREEZE errors for partitioned tables. -- 2.34.1