1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-07 19:06:32 +03:00

Disallow generated columns in COPY WHERE clause

Stored generated columns are not yet computed when the filtering
happens, so we need to prohibit them to avoid incorrect behavior.

Virtual generated columns currently error out ("unexpected virtual
generated column reference").  They could probably work if we expand
them in the right place, but for now let's keep them consistent with
the stored variant.  This doesn't change the behavior, it only gives a
nicer error message.

Co-authored-by: jian he <jian.universality@gmail.com>
Reviewed-by: Kirill Reshke <reshkekirill@gmail.com>
Reviewed-by: Masahiko Sawada <sawada.mshk@gmail.com>
Discussion: https://www.postgresql.org/message-id/flat/CACJufxHb8YPQ095R_pYDr77W9XKNaXg5Rzy-WP525mkq+hRM3g@mail.gmail.com
This commit is contained in:
Peter Eisentraut
2025-11-06 11:52:47 +01:00
parent aa9c5fd3e3
commit aa606b9316
5 changed files with 59 additions and 0 deletions

View File

@@ -133,6 +133,9 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
if (stmt->whereClause)
{
Bitmapset *expr_attrs = NULL;
int i;
/* add nsitem to query namespace */
addNSItemToQuery(pstate, nsitem, false, true, true);
@@ -145,6 +148,42 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
/* we have to fix its collations too */
assign_expr_collations(pstate, whereClause);
/*
* Examine all the columns in the WHERE clause expression. When
* the whole-row reference is present, examine all the columns of
* the table.
*/
pull_varattnos(whereClause, 1, &expr_attrs);
if (bms_is_member(0 - FirstLowInvalidHeapAttributeNumber, expr_attrs))
{
expr_attrs = bms_add_range(expr_attrs,
1 - FirstLowInvalidHeapAttributeNumber,
RelationGetNumberOfAttributes(rel) - FirstLowInvalidHeapAttributeNumber);
expr_attrs = bms_del_member(expr_attrs, 0 - FirstLowInvalidHeapAttributeNumber);
}
i = -1;
while ((i = bms_next_member(expr_attrs, i)) >= 0)
{
AttrNumber attno = i + FirstLowInvalidHeapAttributeNumber;
Assert(attno != 0);
/*
* Prohibit generated columns in the WHERE clause. Stored
* generated columns are not yet computed when the filtering
* happens. Virtual generated columns could probably work (we
* would need to expand them somewhere around here), but for
* now we keep them consistent with the stored variant.
*/
if (TupleDescAttr(RelationGetDescr(rel), attno - 1)->attgenerated)
ereport(ERROR,
errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
errmsg("generated columns are not supported in COPY FROM WHERE conditions"),
errdetail("Column \"%s\" is a generated column.",
get_attname(RelationGetRelid(rel), attno, false)));
}
whereClause = eval_const_expressions(NULL, whereClause);
whereClause = (Node *) canonicalize_qual((Expr *) whereClause, false);

View File

@@ -502,6 +502,12 @@ COPY gtest1 FROM stdin;
COPY gtest1 (a, b) FROM stdin;
ERROR: column "b" is a generated column
DETAIL: Generated columns cannot be used in COPY.
COPY gtest1 FROM stdin WHERE b <> 10;
ERROR: generated columns are not supported in COPY FROM WHERE conditions
DETAIL: Column "b" is a generated column.
COPY gtest1 FROM stdin WHERE gtest1 IS NULL;
ERROR: generated columns are not supported in COPY FROM WHERE conditions
DETAIL: Column "b" is a generated column.
SELECT * FROM gtest1 ORDER BY a;
a | b
---+---

View File

@@ -496,6 +496,12 @@ COPY gtest1 FROM stdin;
COPY gtest1 (a, b) FROM stdin;
ERROR: column "b" is a generated column
DETAIL: Generated columns cannot be used in COPY.
COPY gtest1 FROM stdin WHERE b <> 10;
ERROR: generated columns are not supported in COPY FROM WHERE conditions
DETAIL: Column "b" is a generated column.
COPY gtest1 FROM stdin WHERE gtest1 IS NULL;
ERROR: generated columns are not supported in COPY FROM WHERE conditions
DETAIL: Column "b" is a generated column.
SELECT * FROM gtest1 ORDER BY a;
a | b
---+---

View File

@@ -217,6 +217,10 @@ COPY gtest1 FROM stdin;
COPY gtest1 (a, b) FROM stdin;
COPY gtest1 FROM stdin WHERE b <> 10;
COPY gtest1 FROM stdin WHERE gtest1 IS NULL;
SELECT * FROM gtest1 ORDER BY a;
TRUNCATE gtest3;

View File

@@ -217,6 +217,10 @@ COPY gtest1 FROM stdin;
COPY gtest1 (a, b) FROM stdin;
COPY gtest1 FROM stdin WHERE b <> 10;
COPY gtest1 FROM stdin WHERE gtest1 IS NULL;
SELECT * FROM gtest1 ORDER BY a;
TRUNCATE gtest3;