Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit dfc5c72

Browse files
committed
Fix ExpandIndirectionStar to handle cases where the expression to be
expanded is of RECORD type, eg 'select (foo).* from (select foo(f1) from t1) ss' where foo() is a function declared with multiple OUT parameters.
1 parent ea19c87 commit dfc5c72

File tree

1 file changed

+151
-3
lines changed

1 file changed

+151
-3
lines changed

src/backend/parser/parse_target.c

Lines changed: 151 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,14 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/parser/parse_target.c,v 1.131 2005/04/06 16:34:06 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/parser/parse_target.c,v 1.132 2005/04/25 21:03:25 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
1515
#include "postgres.h"
1616

1717
#include "commands/dbcommands.h"
18+
#include "funcapi.h"
1819
#include "miscadmin.h"
1920
#include "nodes/bitmapset.h"
2021
#include "nodes/makefuncs.h"
@@ -43,6 +44,8 @@ static Node *transformAssignmentIndirection(ParseState *pstate,
4344
static List *ExpandColumnRefStar(ParseState *pstate, ColumnRef *cref);
4445
static List *ExpandAllTables(ParseState *pstate);
4546
static List *ExpandIndirectionStar(ParseState *pstate, A_Indirection *ind);
47+
static TupleDesc expandRecordVariable(ParseState *pstate, Var *var,
48+
int levelsup);
4649
static int FigureColnameInternal(Node *node, char **name);
4750

4851

@@ -822,8 +825,23 @@ ExpandIndirectionStar(ParseState *pstate, A_Indirection *ind)
822825
/* And transform that */
823826
expr = transformExpr(pstate, (Node *) ind);
824827

825-
/* Verify it's a composite type, and get the tupdesc */
826-
tupleDesc = lookup_rowtype_tupdesc(exprType(expr), exprTypmod(expr));
828+
/*
829+
* Verify it's a composite type, and get the tupdesc. We use
830+
* get_expr_result_type() because that can handle references to
831+
* functions returning anonymous record types. If that fails,
832+
* use lookup_rowtype_tupdesc(), which will almost certainly fail
833+
* as well, but it will give an appropriate error message.
834+
*
835+
* If it's a Var of type RECORD, we have to work even harder: we have
836+
* to find what the Var refers to, and pass that to get_expr_result_type.
837+
* That task is handled by expandRecordVariable().
838+
*/
839+
if (IsA(expr, Var) &&
840+
((Var *) expr)->vartype == RECORDOID)
841+
tupleDesc = expandRecordVariable(pstate, (Var *) expr, 0);
842+
else if (get_expr_result_type(expr, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE)
843+
tupleDesc = lookup_rowtype_tupdesc(exprType(expr), exprTypmod(expr));
844+
Assert(tupleDesc);
827845

828846
/* Generate a list of references to the individual fields */
829847
numAttrs = tupleDesc->natts;
@@ -874,6 +892,136 @@ ExpandIndirectionStar(ParseState *pstate, A_Indirection *ind)
874892
return te_list;
875893
}
876894

895+
/*
896+
* expandRecordVariable
897+
* Get the tuple descriptor for a Var of type RECORD, if possible.
898+
*
899+
* Since no actual table or view column is allowed to have type RECORD, such
900+
* a Var must refer to a JOIN or FUNCTION RTE or to a subquery output. We
901+
* drill down to find the ultimate defining expression and attempt to infer
902+
* the tupdesc from it. We ereport if we can't determine the tupdesc.
903+
*
904+
* levelsup is an extra offset to interpret the Var's varlevelsup correctly.
905+
*/
906+
static TupleDesc
907+
expandRecordVariable(ParseState *pstate, Var *var, int levelsup)
908+
{
909+
TupleDesc tupleDesc;
910+
int netlevelsup;
911+
RangeTblEntry *rte;
912+
AttrNumber attnum;
913+
Node *expr;
914+
915+
/* Check my caller didn't mess up */
916+
Assert(IsA(var, Var));
917+
Assert(var->vartype == RECORDOID);
918+
919+
netlevelsup = var->varlevelsup + levelsup;
920+
rte = GetRTEByRangeTablePosn(pstate, var->varno, netlevelsup);
921+
attnum = var->varattno;
922+
923+
expr = (Node *) var; /* default if we can't drill down */
924+
925+
switch (rte->rtekind)
926+
{
927+
case RTE_RELATION:
928+
case RTE_SPECIAL:
929+
/*
930+
* This case should not occur: a whole-row Var should have the
931+
* table's named rowtype, and a column of a table shouldn't have
932+
* type RECORD either. Fall through and fail (most likely)
933+
* at the bottom.
934+
*/
935+
break;
936+
case RTE_SUBQUERY:
937+
{
938+
/* Subselect-in-FROM: examine sub-select's output expr */
939+
TargetEntry *ste = get_tle_by_resno(rte->subquery->targetList,
940+
attnum);
941+
942+
if (ste == NULL || ste->resjunk)
943+
elog(ERROR, "subquery %s does not have attribute %d",
944+
rte->eref->aliasname, attnum);
945+
expr = (Node *) ste->expr;
946+
if (IsA(expr, Var))
947+
{
948+
/*
949+
* Recurse into the sub-select to see what its Var refers
950+
* to. We have to build an additional level of ParseState
951+
* to keep in step with varlevelsup in the subselect.
952+
*/
953+
ParseState mypstate;
954+
955+
MemSet(&mypstate, 0, sizeof(mypstate));
956+
mypstate.parentParseState = pstate;
957+
mypstate.p_rtable = rte->subquery->rtable;
958+
/* don't bother filling the rest of the fake pstate */
959+
960+
return expandRecordVariable(&mypstate, (Var *) expr, 0);
961+
}
962+
/* else fall through to inspect the expression */
963+
}
964+
break;
965+
case RTE_JOIN:
966+
/* Join RTE */
967+
if (attnum == InvalidAttrNumber)
968+
{
969+
/* Whole-row reference to join, so expand the fields */
970+
List *names,
971+
*vars;
972+
ListCell *lname,
973+
*lvar;
974+
int i;
975+
976+
expandRTE(GetLevelNRangeTable(pstate, netlevelsup),
977+
var->varno, 0, false, &names, &vars);
978+
979+
tupleDesc = CreateTemplateTupleDesc(list_length(vars), false);
980+
i = 1;
981+
forboth(lname, names, lvar, vars)
982+
{
983+
char *label = strVal(lfirst(lname));
984+
Node *varnode = (Node *) lfirst(lvar);
985+
986+
TupleDescInitEntry(tupleDesc, i,
987+
label,
988+
exprType(varnode),
989+
exprTypmod(varnode),
990+
0);
991+
i++;
992+
}
993+
Assert(lname == NULL && lvar == NULL); /* lists same len? */
994+
return tupleDesc;
995+
}
996+
/* Else recursively inspect the alias variable */
997+
Assert(attnum > 0 && attnum <= list_length(rte->joinaliasvars));
998+
expr = (Node *) list_nth(rte->joinaliasvars, attnum - 1);
999+
if (IsA(expr, Var))
1000+
return expandRecordVariable(pstate, (Var *) expr, netlevelsup);
1001+
/* else fall through to inspect the expression */
1002+
break;
1003+
case RTE_FUNCTION:
1004+
expr = rte->funcexpr;
1005+
/* The func expr probably can't be a Var, but check */
1006+
if (IsA(expr, Var))
1007+
return expandRecordVariable(pstate, (Var *) expr, netlevelsup);
1008+
/* else fall through to inspect the expression */
1009+
break;
1010+
}
1011+
1012+
/*
1013+
* We now have an expression we can't expand any more, so see if
1014+
* get_expr_result_type() can do anything with it. If not, pass
1015+
* to lookup_rowtype_tupdesc() which will probably fail, but will
1016+
* give an appropriate error message while failing.
1017+
*/
1018+
if (get_expr_result_type(expr, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE)
1019+
tupleDesc = lookup_rowtype_tupdesc(exprType(expr), exprTypmod(expr));
1020+
1021+
return tupleDesc;
1022+
}
1023+
1024+
8771025
/*
8781026
* FigureColname -
8791027
* if the name of the resulting column is not specified in the target

0 commit comments

Comments
 (0)