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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy