Thanks to visit codestin.com
Credit goes to github.com

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)