ParseComplexProjection should make use of expandRecordVariable so that
authorTom Lane <[email protected]>
Tue, 31 May 2005 01:03:23 +0000 (01:03 +0000)
committerTom Lane <[email protected]>
Tue, 31 May 2005 01:03:23 +0000 (01:03 +0000)
it can handle cases like (foo.x).y where foo is a subquery and x is
a function-returning-RECORD RTE in that subquery.

src/backend/parser/parse_func.c
src/backend/parser/parse_target.c
src/include/parser/parse_target.h

index 22ecd1d2ebc524b504ba66f3446881b5e788c2c2..18584763fbc7f76151a4e593c7f1ee531792ceac 100644 (file)
@@ -25,6 +25,7 @@
 #include "parser/parse_expr.h"
 #include "parser/parse_func.h"
 #include "parser/parse_relation.h"
+#include "parser/parse_target.h"
 #include "parser/parse_type.h"
 #include "utils/builtins.h"
 #include "utils/fmgroids.h"
@@ -957,6 +958,9 @@ ParseComplexProjection(ParseState *pstate, char *funcname, Node *first_arg)
         * function. A bonus is that we avoid generating an unnecessary
         * FieldSelect; our result can omit the whole-row Var and just be a
         * Var for the selected field.
+        *
+        * This case could be handled by expandRecordVariable, but it's
+        * more efficient to do it this way when possible.
         */
        if (IsA(first_arg, Var) &&
                ((Var *) first_arg)->varattno == InvalidAttrNumber)
@@ -971,12 +975,18 @@ ParseComplexProjection(ParseState *pstate, char *funcname, Node *first_arg)
        }
 
        /*
-        * Else do it the hard way.  Note that if the arg is of RECORD type,
-        * and isn't resolvable as a function with OUT params, we will never
-        * be able to recognize a column name here.
+        * Else do it the hard way with get_expr_result_type().
+        *
+        * If it's a Var of type RECORD, we have to work even harder: we have
+        * to find what the Var refers to, and pass that to get_expr_result_type.
+        * That task is handled by expandRecordVariable().
         */
-       if (get_expr_result_type(first_arg, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+       if (IsA(first_arg, Var) &&
+               ((Var *) first_arg)->vartype == RECORDOID)
+               tupdesc = expandRecordVariable(pstate, (Var *) first_arg, 0);
+       else if (get_expr_result_type(first_arg, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
                return NULL;                    /* unresolvable RECORD type */
+       Assert(tupdesc);
 
        for (i = 0; i < tupdesc->natts; i++)
        {
index 5ff7c6f1764512fc2e936e9f778eef46c14c96ca..c2966c503c35263e586739ca0ab6d603b8368be4 100644 (file)
@@ -44,8 +44,6 @@ static Node *transformAssignmentIndirection(ParseState *pstate,
 static List *ExpandColumnRefStar(ParseState *pstate, ColumnRef *cref);
 static List *ExpandAllTables(ParseState *pstate);
 static List *ExpandIndirectionStar(ParseState *pstate, A_Indirection *ind);
-static TupleDesc expandRecordVariable(ParseState *pstate, Var *var,
-                                                                         int levelsup);
 static int     FigureColnameInternal(Node *node, char **name);
 
 
@@ -905,7 +903,7 @@ ExpandIndirectionStar(ParseState *pstate, A_Indirection *ind)
  *
  * levelsup is an extra offset to interpret the Var's varlevelsup correctly.
  */
-static TupleDesc
+TupleDesc
 expandRecordVariable(ParseState *pstate, Var *var, int levelsup)
 {
        TupleDesc       tupleDesc;
index 0577e6ac90379ad291ea4138d82aae83c099d8da..4d16ed3c2551242a0d2633e45756bedfc8e85b55 100644 (file)
@@ -27,6 +27,8 @@ extern void updateTargetListEntry(ParseState *pstate, TargetEntry *tle,
                                          List *indirection);
 extern List *checkInsertTargets(ParseState *pstate, List *cols,
                                   List **attrnos);
+extern TupleDesc expandRecordVariable(ParseState *pstate, Var *var,
+                                                                         int levelsup);
 extern char *FigureColname(Node *node);
 
 #endif   /* PARSE_TARGET_H */