diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c index 0e7400fe08..dd9d0883e4 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 (econtext->ecxt_estate && variable->varno <= list_length(econtext->ecxt_estate->es_range_table)) @@ -908,7 +910,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 035d843c39..5e3173774f 100644 --- a/src/test/regress/expected/copy2.out +++ b/src/test/regress/expected/copy2.out @@ -429,6 +429,40 @@ COPY forcetest (d, e) FROM STDIN WITH (FORMAT csv, FORCE_NULL(b)); ERROR: FORCE NULL column "b" not referenced by COPY ROLLBACK; \pset null '' +-- 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.*)) + +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 forcetest; DROP TABLE vistest; DROP FUNCTION truncate_in_subxact(); diff --git a/src/test/regress/sql/copy2.sql b/src/test/regress/sql/copy2.sql index 248055f506..39a9deb8f7 100644 --- a/src/test/regress/sql/copy2.sql +++ b/src/test/regress/sql/copy2.sql @@ -308,6 +308,25 @@ BEGIN; COPY forcetest (d, e) FROM STDIN WITH (FORMAT csv, FORCE_NULL(b)); ROLLBACK; \pset null '' + +-- 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 forcetest; DROP TABLE vistest; DROP FUNCTION truncate_in_subxact();