diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c index dae8bf0f2c1..c6386e46f2f 100644 --- a/src/backend/executor/execQual.c +++ b/src/backend/executor/execQual.c @@ -900,7 +900,9 @@ ExecEvalWholeRowVar(WholeRowVarExprState *wrvstate, ExprContext *econtext, * If we can't locate the RTE, assume the column names we've got are OK. * (As of this writing, the only cases where we can't locate the RTE are * in execution of trigger WHEN clauses, and then the Var will have the - * trigger's relation's rowtype, so its names are fine.) + * trigger's relation's rowtype, so its names are fine.) Also, if the + * creator of the RTE didn't bother to fill in an eref field, assume our + * column names are OK. (This happens in COPY, and perhaps other places.) */ if (variable->vartype == RECORDOID && econtext->ecxt_estate && @@ -909,7 +911,8 @@ ExecEvalWholeRowVar(WholeRowVarExprState *wrvstate, ExprContext *econtext, RangeTblEntry *rte = rt_fetch(variable->varno, econtext->ecxt_estate->es_range_table); - ExecTypeSetColNames(output_tupdesc, rte->eref->colnames); + if (rte->eref) + ExecTypeSetColNames(output_tupdesc, rte->eref->colnames); } /* Bless the tupdesc if needed, and save it in the execution state */ diff --git a/src/test/regress/expected/copy2.out b/src/test/regress/expected/copy2.out index 34fa131c52b..33ee8832dbe 100644 --- a/src/test/regress/expected/copy2.out +++ b/src/test/regress/expected/copy2.out @@ -382,6 +382,41 @@ SELECT * FROM vistest; e (2 rows) +-- test case with whole-row Var in a check constraint +create table check_con_tbl (f1 int); +create function check_con_function(check_con_tbl) returns bool as $$ +begin + raise notice 'input = %', row_to_json($1); + return $1.f1 > 0; +end $$ language plpgsql immutable; +alter table check_con_tbl add check (check_con_function(check_con_tbl.*)); +\d+ check_con_tbl + Table "public.check_con_tbl" + Column | Type | Modifiers | Storage | Stats target | Description +--------+---------+-----------+---------+--------------+------------- + f1 | integer | | plain | | +Check constraints: + "check_con_tbl_check" CHECK (check_con_function(check_con_tbl.*)) +Has OIDs: no + +copy check_con_tbl from stdin; +NOTICE: input = {"f1":1} +CONTEXT: COPY check_con_tbl, line 1: "1" +NOTICE: input = {"f1":null} +CONTEXT: COPY check_con_tbl, line 2: "\N" +copy check_con_tbl from stdin; +NOTICE: input = {"f1":0} +CONTEXT: COPY check_con_tbl, line 1: "0" +ERROR: new row for relation "check_con_tbl" violates check constraint "check_con_tbl_check" +DETAIL: Failing row contains (0). +CONTEXT: COPY check_con_tbl, line 1: "0" +select * from check_con_tbl; + f1 +---- + 1 + +(2 rows) + DROP TABLE vistest; DROP FUNCTION truncate_in_subxact(); DROP TABLE x, y; diff --git a/src/test/regress/sql/copy2.sql b/src/test/regress/sql/copy2.sql index c46128b38a1..bd27a25c026 100644 --- a/src/test/regress/sql/copy2.sql +++ b/src/test/regress/sql/copy2.sql @@ -270,6 +270,25 @@ e SELECT * FROM vistest; COMMIT; SELECT * FROM vistest; + +-- test case with whole-row Var in a check constraint +create table check_con_tbl (f1 int); +create function check_con_function(check_con_tbl) returns bool as $$ +begin + raise notice 'input = %', row_to_json($1); + return $1.f1 > 0; +end $$ language plpgsql immutable; +alter table check_con_tbl add check (check_con_function(check_con_tbl.*)); +\d+ check_con_tbl +copy check_con_tbl from stdin; +1 +\N +\. +copy check_con_tbl from stdin; +0 +\. +select * from check_con_tbl; + DROP TABLE vistest; DROP FUNCTION truncate_in_subxact(); DROP TABLE x, y;