* ParseComplexProjection - * handles function calls with a single argument that is of complex type. * If the function call is actually a column projection, return a suitably * transformed expression tree. If not, return NULL. */
| 1964 | * transformed expression tree. If not, return NULL. |
| 1965 | */ |
| 1966 | static Node * |
| 1967 | ParseComplexProjection(ParseState *pstate, const char *funcname, Node *first_arg, |
| 1968 | int location) |
| 1969 | { |
| 1970 | TupleDesc tupdesc; |
| 1971 | int i; |
| 1972 | |
| 1973 | /* |
| 1974 | * Special case for whole-row Vars so that we can resolve (foo.*).bar even |
| 1975 | * when foo is a reference to a subselect, join, or RECORD function. A |
| 1976 | * bonus is that we avoid generating an unnecessary FieldSelect; our |
| 1977 | * result can omit the whole-row Var and just be a Var for the selected |
| 1978 | * field. |
| 1979 | * |
| 1980 | * This case could be handled by expandRecordVariable, but it's more |
| 1981 | * efficient to do it this way when possible. |
| 1982 | */ |
| 1983 | if (IsA(first_arg, Var) && |
| 1984 | ((Var *) first_arg)->varattno == InvalidAttrNumber) |
| 1985 | { |
| 1986 | ParseNamespaceItem *nsitem; |
| 1987 | |
| 1988 | nsitem = GetNSItemByRangeTablePosn(pstate, |
| 1989 | ((Var *) first_arg)->varno, |
| 1990 | ((Var *) first_arg)->varlevelsup); |
| 1991 | /* Return a Var if funcname matches a column, else NULL */ |
| 1992 | return scanNSItemForColumn(pstate, nsitem, |
| 1993 | ((Var *) first_arg)->varlevelsup, |
| 1994 | funcname, location); |
| 1995 | } |
| 1996 | |
| 1997 | /* |
| 1998 | * Else do it the hard way with get_expr_result_tupdesc(). |
| 1999 | * |
| 2000 | * If it's a Var of type RECORD, we have to work even harder: we have to |
| 2001 | * find what the Var refers to, and pass that to get_expr_result_tupdesc. |
| 2002 | * That task is handled by expandRecordVariable(). |
| 2003 | */ |
| 2004 | if (IsA(first_arg, Var) && |
| 2005 | ((Var *) first_arg)->vartype == RECORDOID) |
| 2006 | tupdesc = expandRecordVariable(pstate, (Var *) first_arg, 0); |
| 2007 | else |
| 2008 | tupdesc = get_expr_result_tupdesc(first_arg, true); |
| 2009 | if (!tupdesc) |
| 2010 | return NULL; /* unresolvable RECORD type */ |
| 2011 | |
| 2012 | for (i = 0; i < tupdesc->natts; i++) |
| 2013 | { |
| 2014 | Form_pg_attribute att = TupleDescAttr(tupdesc, i); |
| 2015 | |
| 2016 | if (strcmp(funcname, NameStr(att->attname)) == 0 && |
| 2017 | !att->attisdropped) |
| 2018 | { |
| 2019 | /* Success, so generate a FieldSelect expression */ |
| 2020 | FieldSelect *fselect = makeNode(FieldSelect); |
| 2021 | |
| 2022 | fselect->arg = (Expr *) first_arg; |
| 2023 | fselect->fieldnum = i + 1; |
no test coverage detected