Skip to content

Commit 0f9e006

Browse files
peterejianhe-fun
andcommitted
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
1 parent 75ec47c commit 0f9e006

File tree

5 files changed

+59
-0
lines changed

5 files changed

+59
-0
lines changed

src/backend/commands/copy.c

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,9 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
133133

134134
if (stmt->whereClause)
135135
{
136+
Bitmapset *expr_attrs = NULL;
137+
int i;
138+
136139
/* add nsitem to query namespace */
137140
addNSItemToQuery(pstate, nsitem, false, true, true);
138141

@@ -145,6 +148,42 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
145148
/* we have to fix its collations too */
146149
assign_expr_collations(pstate, whereClause);
147150

151+
/*
152+
* Examine all the columns in the WHERE clause expression. When
153+
* the whole-row reference is present, examine all the columns of
154+
* the table.
155+
*/
156+
pull_varattnos(whereClause, 1, &expr_attrs);
157+
if (bms_is_member(0 - FirstLowInvalidHeapAttributeNumber, expr_attrs))
158+
{
159+
expr_attrs = bms_add_range(expr_attrs,
160+
1 - FirstLowInvalidHeapAttributeNumber,
161+
RelationGetNumberOfAttributes(rel) - FirstLowInvalidHeapAttributeNumber);
162+
expr_attrs = bms_del_member(expr_attrs, 0 - FirstLowInvalidHeapAttributeNumber);
163+
}
164+
165+
i = -1;
166+
while ((i = bms_next_member(expr_attrs, i)) >= 0)
167+
{
168+
AttrNumber attno = i + FirstLowInvalidHeapAttributeNumber;
169+
170+
Assert(attno != 0);
171+
172+
/*
173+
* Prohibit generated columns in the WHERE clause. Stored
174+
* generated columns are not yet computed when the filtering
175+
* happens. Virtual generated columns could probably work (we
176+
* would need to expand them somewhere around here), but for
177+
* now we keep them consistent with the stored variant.
178+
*/
179+
if (TupleDescAttr(RelationGetDescr(rel), attno - 1)->attgenerated)
180+
ereport(ERROR,
181+
errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
182+
errmsg("generated columns are not supported in COPY FROM WHERE conditions"),
183+
errdetail("Column \"%s\" is a generated column.",
184+
get_attname(RelationGetRelid(rel), attno, false)));
185+
}
186+
148187
whereClause = eval_const_expressions(NULL, whereClause);
149188

150189
whereClause = (Node *) canonicalize_qual((Expr *) whereClause, false);

src/test/regress/expected/generated_stored.out

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,12 @@ COPY gtest1 FROM stdin;
502502
COPY gtest1 (a, b) FROM stdin;
503503
ERROR: column "b" is a generated column
504504
DETAIL: Generated columns cannot be used in COPY.
505+
COPY gtest1 FROM stdin WHERE b <> 10;
506+
ERROR: generated columns are not supported in COPY FROM WHERE conditions
507+
DETAIL: Column "b" is a generated column.
508+
COPY gtest1 FROM stdin WHERE gtest1 IS NULL;
509+
ERROR: generated columns are not supported in COPY FROM WHERE conditions
510+
DETAIL: Column "b" is a generated column.
505511
SELECT * FROM gtest1 ORDER BY a;
506512
a | b
507513
---+---

src/test/regress/expected/generated_virtual.out

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,12 @@ COPY gtest1 FROM stdin;
496496
COPY gtest1 (a, b) FROM stdin;
497497
ERROR: column "b" is a generated column
498498
DETAIL: Generated columns cannot be used in COPY.
499+
COPY gtest1 FROM stdin WHERE b <> 10;
500+
ERROR: generated columns are not supported in COPY FROM WHERE conditions
501+
DETAIL: Column "b" is a generated column.
502+
COPY gtest1 FROM stdin WHERE gtest1 IS NULL;
503+
ERROR: generated columns are not supported in COPY FROM WHERE conditions
504+
DETAIL: Column "b" is a generated column.
499505
SELECT * FROM gtest1 ORDER BY a;
500506
a | b
501507
---+---

src/test/regress/sql/generated_stored.sql

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,10 @@ COPY gtest1 FROM stdin;
217217

218218
COPY gtest1 (a, b) FROM stdin;
219219

220+
COPY gtest1 FROM stdin WHERE b <> 10;
221+
222+
COPY gtest1 FROM stdin WHERE gtest1 IS NULL;
223+
220224
SELECT * FROM gtest1 ORDER BY a;
221225

222226
TRUNCATE gtest3;

src/test/regress/sql/generated_virtual.sql

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,10 @@ COPY gtest1 FROM stdin;
217217

218218
COPY gtest1 (a, b) FROM stdin;
219219

220+
COPY gtest1 FROM stdin WHERE b <> 10;
221+
222+
COPY gtest1 FROM stdin WHERE gtest1 IS NULL;
223+
220224
SELECT * FROM gtest1 ORDER BY a;
221225

222226
TRUNCATE gtest3;

0 commit comments

Comments
 (0)