|
8 | 8 | *
|
9 | 9 | *
|
10 | 10 | * 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 $ |
12 | 12 | *
|
13 | 13 | *-------------------------------------------------------------------------
|
14 | 14 | */
|
15 | 15 | #include "postgres.h"
|
16 | 16 |
|
17 | 17 | #include "commands/dbcommands.h"
|
| 18 | +#include "funcapi.h" |
18 | 19 | #include "miscadmin.h"
|
19 | 20 | #include "nodes/bitmapset.h"
|
20 | 21 | #include "nodes/makefuncs.h"
|
@@ -43,6 +44,8 @@ static Node *transformAssignmentIndirection(ParseState *pstate,
|
43 | 44 | static List *ExpandColumnRefStar(ParseState *pstate, ColumnRef *cref);
|
44 | 45 | static List *ExpandAllTables(ParseState *pstate);
|
45 | 46 | static List *ExpandIndirectionStar(ParseState *pstate, A_Indirection *ind);
|
| 47 | +static TupleDesc expandRecordVariable(ParseState *pstate, Var *var, |
| 48 | + int levelsup); |
46 | 49 | static int FigureColnameInternal(Node *node, char **name);
|
47 | 50 |
|
48 | 51 |
|
@@ -822,8 +825,23 @@ ExpandIndirectionStar(ParseState *pstate, A_Indirection *ind)
|
822 | 825 | /* And transform that */
|
823 | 826 | expr = transformExpr(pstate, (Node *) ind);
|
824 | 827 |
|
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); |
827 | 845 |
|
828 | 846 | /* Generate a list of references to the individual fields */
|
829 | 847 | numAttrs = tupleDesc->natts;
|
@@ -874,6 +892,136 @@ ExpandIndirectionStar(ParseState *pstate, A_Indirection *ind)
|
874 | 892 | return te_list;
|
875 | 893 | }
|
876 | 894 |
|
| 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 | + |
877 | 1025 | /*
|
878 | 1026 | * FigureColname -
|
879 | 1027 | * if the name of the resulting column is not specified in the target
|
|
0 commit comments