Skip to content

Commit fcaad7e

Browse files
committed
Standardize on the assumption that the arguments of a RowExpr correspond
to the physical layout of the rowtype, ie, there are dummy arguments corresponding to any dropped columns in the rowtype. We formerly had a couple of places that did it this way and several others that did not. Fixes Gaetano Mendola's "cache lookup failed for type 0" bug of 5-Aug.
1 parent 388ffad commit fcaad7e

File tree

8 files changed

+237
-61
lines changed

8 files changed

+237
-61
lines changed

src/backend/executor/execQual.c

Lines changed: 50 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.165 2004/08/02 01:30:41 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.166 2004/08/17 18:47:08 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -44,6 +44,7 @@
4444
#include "executor/nodeSubplan.h"
4545
#include "funcapi.h"
4646
#include "miscadmin.h"
47+
#include "nodes/makefuncs.h"
4748
#include "optimizer/planmain.h"
4849
#include "parser/parse_expr.h"
4950
#include "utils/acl.h"
@@ -2096,7 +2097,7 @@ ExecEvalRow(RowExprState *rstate,
20962097
HeapTuple tuple;
20972098
Datum *values;
20982099
char *nulls;
2099-
int nargs;
2100+
int natts;
21002101
ListCell *arg;
21012102
int i;
21022103

@@ -2106,9 +2107,12 @@ ExecEvalRow(RowExprState *rstate,
21062107
*isDone = ExprSingleResult;
21072108

21082109
/* Allocate workspace */
2109-
nargs = list_length(rstate->args);
2110-
values = (Datum *) palloc(nargs * sizeof(Datum));
2111-
nulls = (char *) palloc(nargs * sizeof(char));
2110+
natts = rstate->tupdesc->natts;
2111+
values = (Datum *) palloc0(natts * sizeof(Datum));
2112+
nulls = (char *) palloc(natts * sizeof(char));
2113+
2114+
/* preset to nulls in case rowtype has some later-added columns */
2115+
memset(nulls, 'n', natts * sizeof(char));
21122116

21132117
/* Evaluate field values */
21142118
i = 0;
@@ -2979,19 +2983,12 @@ ExecInitExpr(Expr *node, PlanState *parent)
29792983
{
29802984
RowExpr *rowexpr = (RowExpr *) node;
29812985
RowExprState *rstate = makeNode(RowExprState);
2986+
Form_pg_attribute *attrs;
29822987
List *outlist = NIL;
29832988
ListCell *l;
2989+
int i;
29842990

29852991
rstate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalRow;
2986-
foreach(l, rowexpr->args)
2987-
{
2988-
Expr *e = (Expr *) lfirst(l);
2989-
ExprState *estate;
2990-
2991-
estate = ExecInitExpr(e, parent);
2992-
outlist = lappend(outlist, estate);
2993-
}
2994-
rstate->args = outlist;
29952992
/* Build tupdesc to describe result tuples */
29962993
if (rowexpr->row_typeid == RECORDOID)
29972994
{
@@ -3003,7 +3000,46 @@ ExecInitExpr(Expr *node, PlanState *parent)
30033000
{
30043001
/* it's been cast to a named type, use that */
30053002
rstate->tupdesc = lookup_rowtype_tupdesc(rowexpr->row_typeid, -1);
3003+
rstate->tupdesc = CreateTupleDescCopy(rstate->tupdesc);
30063004
}
3005+
/* Set up evaluation, skipping any deleted columns */
3006+
Assert(list_length(rowexpr->args) <= rstate->tupdesc->natts);
3007+
attrs = rstate->tupdesc->attrs;
3008+
i = 0;
3009+
foreach(l, rowexpr->args)
3010+
{
3011+
Expr *e = (Expr *) lfirst(l);
3012+
ExprState *estate;
3013+
3014+
if (!attrs[i]->attisdropped)
3015+
{
3016+
/*
3017+
* Guard against ALTER COLUMN TYPE on rowtype
3018+
* since the RowExpr was created. XXX should we
3019+
* check typmod too? Not sure we can be sure it'll
3020+
* be the same.
3021+
*/
3022+
if (exprType((Node *) e) != attrs[i]->atttypid)
3023+
ereport(ERROR,
3024+
(errcode(ERRCODE_DATATYPE_MISMATCH),
3025+
errmsg("ROW() column has type %s instead of type %s",
3026+
format_type_be(exprType((Node *) e)),
3027+
format_type_be(attrs[i]->atttypid))));
3028+
}
3029+
else
3030+
{
3031+
/*
3032+
* Ignore original expression and insert a NULL.
3033+
* We don't really care what type of NULL it is,
3034+
* so always make an int4 NULL.
3035+
*/
3036+
e = (Expr *) makeNullConst(INT4OID);
3037+
}
3038+
estate = ExecInitExpr(e, parent);
3039+
outlist = lappend(outlist, estate);
3040+
i++;
3041+
}
3042+
rstate->args = outlist;
30073043
state = (ExprState *) rstate;
30083044
}
30093045
break;

src/backend/optimizer/util/clauses.c

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.177 2004/08/02 01:30:43 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.178 2004/08/17 18:47:08 tgl Exp $
1212
*
1313
* HISTORY
1414
* AUTHOR DATE MAJOR EVENT
@@ -40,6 +40,7 @@
4040
#include "utils/lsyscache.h"
4141
#include "utils/memutils.h"
4242
#include "utils/syscache.h"
43+
#include "utils/typcache.h"
4344

4445

4546
typedef struct
@@ -1054,6 +1055,33 @@ set_coercionform_dontcare_walker(Node *node, void *context)
10541055
context);
10551056
}
10561057

1058+
/*
1059+
* Helper for eval_const_expressions: check that datatype of an attribute
1060+
* is still what it was when the expression was parsed. This is needed to
1061+
* guard against improper simplification after ALTER COLUMN TYPE. (XXX we
1062+
* may well need to make similar checks elsewhere?)
1063+
*/
1064+
static bool
1065+
rowtype_field_matches(Oid rowtypeid, int fieldnum,
1066+
Oid expectedtype, int32 expectedtypmod)
1067+
{
1068+
TupleDesc tupdesc;
1069+
Form_pg_attribute attr;
1070+
1071+
/* No issue for RECORD, since there is no way to ALTER such a type */
1072+
if (rowtypeid == RECORDOID)
1073+
return true;
1074+
tupdesc = lookup_rowtype_tupdesc(rowtypeid, -1);
1075+
if (fieldnum <= 0 || fieldnum > tupdesc->natts)
1076+
return false;
1077+
attr = tupdesc->attrs[fieldnum - 1];
1078+
if (attr->attisdropped ||
1079+
attr->atttypid != expectedtype ||
1080+
attr->atttypmod != expectedtypmod)
1081+
return false;
1082+
return true;
1083+
}
1084+
10571085

10581086
/*--------------------
10591087
* eval_const_expressions
@@ -1630,6 +1658,10 @@ eval_const_expressions_mutator(Node *node,
16301658
* parser, because ParseComplexProjection short-circuits it. But
16311659
* it can arise while simplifying functions.) Also, we can
16321660
* optimize field selection from a RowExpr construct.
1661+
*
1662+
* We must however check that the declared type of the field is
1663+
* still the same as when the FieldSelect was created --- this
1664+
* can change if someone did ALTER COLUMN TYPE on the rowtype.
16331665
*/
16341666
FieldSelect *fselect = (FieldSelect *) node;
16351667
FieldSelect *newfselect;
@@ -1640,19 +1672,34 @@ eval_const_expressions_mutator(Node *node,
16401672
if (arg && IsA(arg, Var) &&
16411673
((Var *) arg)->varattno == InvalidAttrNumber)
16421674
{
1643-
return (Node *) makeVar(((Var *) arg)->varno,
1644-
fselect->fieldnum,
1645-
fselect->resulttype,
1646-
fselect->resulttypmod,
1647-
((Var *) arg)->varlevelsup);
1675+
if (rowtype_field_matches(((Var *) arg)->vartype,
1676+
fselect->fieldnum,
1677+
fselect->resulttype,
1678+
fselect->resulttypmod))
1679+
return (Node *) makeVar(((Var *) arg)->varno,
1680+
fselect->fieldnum,
1681+
fselect->resulttype,
1682+
fselect->resulttypmod,
1683+
((Var *) arg)->varlevelsup);
16481684
}
16491685
if (arg && IsA(arg, RowExpr))
16501686
{
16511687
RowExpr *rowexpr = (RowExpr *) arg;
16521688

16531689
if (fselect->fieldnum > 0 &&
16541690
fselect->fieldnum <= list_length(rowexpr->args))
1655-
return (Node *) list_nth(rowexpr->args, fselect->fieldnum - 1);
1691+
{
1692+
Node *fld = (Node *) list_nth(rowexpr->args,
1693+
fselect->fieldnum - 1);
1694+
1695+
if (rowtype_field_matches(rowexpr->row_typeid,
1696+
fselect->fieldnum,
1697+
fselect->resulttype,
1698+
fselect->resulttypmod) &&
1699+
fselect->resulttype == exprType(fld) &&
1700+
fselect->resulttypmod == exprTypmod(fld))
1701+
return fld;
1702+
}
16561703
}
16571704
newfselect = makeNode(FieldSelect);
16581705
newfselect->arg = (Expr *) arg;

src/backend/parser/parse_coerce.c

Lines changed: 44 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.119 2004/06/16 01:26:44 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.120 2004/08/17 18:47:08 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -648,10 +648,15 @@ coerce_record_to_complex(ParseState *pstate, Node *node,
648648
List *args = NIL;
649649
List *newargs;
650650
int i;
651+
int ucolno;
651652
ListCell *arg;
652653

653654
if (node && IsA(node, RowExpr))
654655
{
656+
/*
657+
* Since the RowExpr must be of type RECORD, we needn't worry
658+
* about it containing any dropped columns.
659+
*/
655660
args = ((RowExpr *) node)->args;
656661
}
657662
else if (node && IsA(node, Var) &&
@@ -670,6 +675,8 @@ coerce_record_to_complex(ParseState *pstate, Node *node,
670675
Oid vartype;
671676
int32 vartypmod;
672677

678+
if (get_rte_attribute_is_dropped(rte, nf))
679+
continue;
673680
get_rte_attribute_type(rte, nf, &vartype, &vartypmod);
674681
args = lappend(args,
675682
makeVar(((Var *) node)->varno,
@@ -687,19 +694,34 @@ coerce_record_to_complex(ParseState *pstate, Node *node,
687694
format_type_be(targetTypeId))));
688695

689696
tupdesc = lookup_rowtype_tupdesc(targetTypeId, -1);
690-
if (list_length(args) != tupdesc->natts)
691-
ereport(ERROR,
692-
(errcode(ERRCODE_CANNOT_COERCE),
693-
errmsg("cannot cast type %s to %s",
694-
format_type_be(RECORDOID),
695-
format_type_be(targetTypeId)),
696-
errdetail("Input has wrong number of columns.")));
697697
newargs = NIL;
698-
i = 0;
699-
foreach(arg, args)
698+
ucolno = 1;
699+
arg = list_head(args);
700+
for (i = 0; i < tupdesc->natts; i++)
700701
{
701-
Node *expr = (Node *) lfirst(arg);
702-
Oid exprtype = exprType(expr);
702+
Node *expr;
703+
Oid exprtype;
704+
705+
/* Fill in NULLs for dropped columns in rowtype */
706+
if (tupdesc->attrs[i]->attisdropped)
707+
{
708+
/*
709+
* can't use atttypid here, but it doesn't really matter
710+
* what type the Const claims to be.
711+
*/
712+
newargs = lappend(newargs, makeNullConst(INT4OID));
713+
continue;
714+
}
715+
716+
if (arg == NULL)
717+
ereport(ERROR,
718+
(errcode(ERRCODE_CANNOT_COERCE),
719+
errmsg("cannot cast type %s to %s",
720+
format_type_be(RECORDOID),
721+
format_type_be(targetTypeId)),
722+
errdetail("Input has too few columns.")));
723+
expr = (Node *) lfirst(arg);
724+
exprtype = exprType(expr);
703725

704726
expr = coerce_to_target_type(pstate,
705727
expr, exprtype,
@@ -716,10 +738,18 @@ coerce_record_to_complex(ParseState *pstate, Node *node,
716738
errdetail("Cannot cast type %s to %s in column %d.",
717739
format_type_be(exprtype),
718740
format_type_be(tupdesc->attrs[i]->atttypid),
719-
i + 1)));
741+
ucolno)));
720742
newargs = lappend(newargs, expr);
721-
i++;
743+
ucolno++;
744+
arg = lnext(arg);
722745
}
746+
if (arg != NULL)
747+
ereport(ERROR,
748+
(errcode(ERRCODE_CANNOT_COERCE),
749+
errmsg("cannot cast type %s to %s",
750+
format_type_be(RECORDOID),
751+
format_type_be(targetTypeId)),
752+
errdetail("Input has too many columns.")));
723753

724754
rowexpr = makeNode(RowExpr);
725755
rowexpr->args = newargs;

src/backend/parser/parse_relation.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.96 2004/05/30 23:40:35 neilc Exp $
11+
* $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.97 2004/08/17 18:47:08 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -42,8 +42,6 @@ static Node *scanNameSpaceForRelid(ParseState *pstate, Node *nsnode,
4242
static void scanNameSpaceForConflict(ParseState *pstate, Node *nsnode,
4343
RangeTblEntry *rte1, const char *aliasname1);
4444
static bool isForUpdate(ParseState *pstate, char *refname);
45-
static bool get_rte_attribute_is_dropped(RangeTblEntry *rte,
46-
AttrNumber attnum);
4745
static int specialAttNum(const char *attname);
4846
static void warnAutoRange(ParseState *pstate, RangeVar *relation);
4947

@@ -1699,7 +1697,7 @@ get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum,
16991697
* get_rte_attribute_is_dropped
17001698
* Check whether attempted attribute ref is to a dropped column
17011699
*/
1702-
static bool
1700+
bool
17031701
get_rte_attribute_is_dropped(RangeTblEntry *rte, AttrNumber attnum)
17041702
{
17051703
bool result;

src/backend/rewrite/rewriteManip.c

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,13 @@
77
*
88
*
99
* IDENTIFICATION
10-
* $PostgreSQL: pgsql/src/backend/rewrite/rewriteManip.c,v 1.84 2004/05/30 23:40:35 neilc Exp $
10+
* $PostgreSQL: pgsql/src/backend/rewrite/rewriteManip.c,v 1.85 2004/08/17 18:47:09 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
1414
#include "postgres.h"
1515

16+
#include "catalog/pg_type.h"
1617
#include "nodes/makefuncs.h"
1718
#include "optimizer/clauses.h"
1819
#include "optimizer/tlist.h"
@@ -938,18 +939,30 @@ ResolveNew_mutator(Node *node, ResolveNew_context *context)
938939

939940
for (nf = 1; nf <= nfields; nf++)
940941
{
941-
Oid vartype;
942-
int32 vartypmod;
943-
Var *newvar;
944-
945-
get_rte_attribute_type(rte, nf, &vartype, &vartypmod);
946-
newvar = makeVar(this_varno,
947-
nf,
948-
vartype,
949-
vartypmod,
950-
this_varlevelsup);
951-
fields = lappend(fields,
952-
resolve_one_var(newvar, context));
942+
if (get_rte_attribute_is_dropped(rte, nf))
943+
{
944+
/*
945+
* can't determine att type here, but it doesn't
946+
* really matter what type the Const claims to be.
947+
*/
948+
fields = lappend(fields,
949+
makeNullConst(INT4OID));
950+
}
951+
else
952+
{
953+
Oid vartype;
954+
int32 vartypmod;
955+
Var *newvar;
956+
957+
get_rte_attribute_type(rte, nf, &vartype, &vartypmod);
958+
newvar = makeVar(this_varno,
959+
nf,
960+
vartype,
961+
vartypmod,
962+
this_varlevelsup);
963+
fields = lappend(fields,
964+
resolve_one_var(newvar, context));
965+
}
953966
}
954967

955968
rowexpr = makeNode(RowExpr);

0 commit comments

Comments
 (0)