|
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 | staticList*ExpandColumnRefStar(ParseState*pstate,ColumnRef*cref);
|
44 | 45 | staticList*ExpandAllTables(ParseState*pstate);
|
45 | 46 | staticList*ExpandIndirectionStar(ParseState*pstate,A_Indirection*ind);
|
| 47 | +staticTupleDescexpandRecordVariable(ParseState*pstate,Var*var, |
| 48 | +intlevelsup); |
46 | 49 | staticintFigureColnameInternal(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 | +elseif (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 | returnte_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 | +staticTupleDesc |
| 907 | +expandRecordVariable(ParseState*pstate,Var*var,intlevelsup) |
| 908 | +{ |
| 909 | +TupleDesctupleDesc; |
| 910 | +intnetlevelsup; |
| 911 | +RangeTblEntry*rte; |
| 912 | +AttrNumberattnum; |
| 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 | +caseRTE_RELATION: |
| 928 | +caseRTE_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 | +caseRTE_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 | +ParseStatemypstate; |
| 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 | +returnexpandRecordVariable(&mypstate, (Var*)expr,0); |
| 961 | +} |
| 962 | +/* else fall through to inspect the expression */ |
| 963 | +} |
| 964 | +break; |
| 965 | +caseRTE_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 | +inti; |
| 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 | +returntupleDesc; |
| 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 | +returnexpandRecordVariable(pstate, (Var*)expr,netlevelsup); |
| 1001 | +/* else fall through to inspect the expression */ |
| 1002 | +break; |
| 1003 | +caseRTE_FUNCTION: |
| 1004 | +expr=rte->funcexpr; |
| 1005 | +/* The func expr probably can't be a Var, but check */ |
| 1006 | +if (IsA(expr,Var)) |
| 1007 | +returnexpandRecordVariable(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 | +returntupleDesc; |
| 1022 | +} |
| 1023 | + |
| 1024 | + |
877 | 1025 | /*
|
878 | 1026 | * FigureColname -
|
879 | 1027 | * if the name of the resulting column is not specified in the target
|
|