1
0
mirror of https://github.com/postgres/postgres.git synced 2026-10-23 13:29:09 +03:00

Fix COPY FROM ... WHERE for negated operators.

COPY FROM runs its WHERE clause through eval_const_expressions(),
which among other things replaces NOT above an operator with the
operator's negator, if it has one (e.g., NOT (a > 0) becomes
a <= 0).  The node it builds for the negator has no opfuncid, and
since COPY FROM never calls fix_opfuncids() on the clause, nothing
fills it in before the executor needs it.  So

	COPY tab FROM stdin WHERE NOT (a > 0)

fails with "cache lookup failed for function 0".

To fix, call fix_opfuncids() on the clause, as the relcache does
for index predicates.

Oversight in commit 31f3817402.

Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/asPZRTci4oBvxR9A%40nathan
Backpatch-through: 14
This commit is contained in:
Nathan Bossart
2026-10-06 09:04:32 -05:00
parent 3efbf3e1b4
commit 6b428e47b0
3 changed files with 14 additions and 1 deletions

View File

@@ -28,6 +28,7 @@
#include "mb/pg_wchar.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/optimizer.h"
#include "parser/parse_coerce.h"
#include "parser/parse_collate.h"
@@ -187,6 +188,7 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
whereClause = (Node *) canonicalize_qual((Expr *) whereClause, false);
whereClause = (Node *) make_ands_implicit((Expr *) whereClause);
fix_opfuncids(whereClause);
}
tupDesc = RelationGetDescr(rel);

View File

@@ -155,6 +155,7 @@ LINE 1: COPY x TO stdout WHERE a = 1;
^
COPY x from stdin WHERE a = 50004;
COPY x from stdin WHERE a > 60003;
COPY x from stdin WHERE NOT (a < 70003);
COPY x from stdin WHERE f > 60003;
ERROR: column "f" does not exist
LINE 1: COPY x from stdin WHERE f > 60003;
@@ -202,12 +203,13 @@ SELECT * FROM x;
50004 | 25 | 35 | 45 | before trigger fired
60004 | 25 | 35 | 45 | before trigger fired
60005 | 26 | 36 | 46 | before trigger fired
70003 | 24 | 34 | 44 | before trigger fired
1 | 1 | stuff | test_1 | after trigger fired
2 | 2 | stuff | test_2 | after trigger fired
3 | 3 | stuff | test_3 | after trigger fired
4 | 4 | stuff | test_4 | after trigger fired
5 | 5 | stuff | test_5 | after trigger fired
(28 rows)
(29 rows)
-- check copy out
COPY x TO stdout;
@@ -234,6 +236,7 @@ COPY x TO stdout;
50004 25 35 45 before trigger fired
60004 25 35 45 before trigger fired
60005 26 36 46 before trigger fired
70003 24 34 44 before trigger fired
1 1 stuff test_1 after trigger fired
2 2 stuff test_2 after trigger fired
3 3 stuff test_3 after trigger fired
@@ -263,6 +266,7 @@ Delimiter before trigger fired
35 before trigger fired
35 before trigger fired
36 before trigger fired
34 before trigger fired
stuff after trigger fired
stuff after trigger fired
stuff after trigger fired
@@ -292,6 +296,7 @@ I'm null before trigger fired
25 before trigger fired
25 before trigger fired
26 before trigger fired
24 before trigger fired
1 after trigger fired
2 after trigger fired
3 after trigger fired

View File

@@ -175,6 +175,12 @@ COPY x from stdin WHERE a > 60003;
60005 26 36 46 56
\.
COPY x from stdin WHERE NOT (a < 70003);
70001 22 32 42 52
70002 23 33 43 53
70003 24 34 44 54
\.
COPY x from stdin WHERE f > 60003;
\.