8
8
*
9
9
*
10
10
* IDENTIFICATION
11
- * $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.111 2002/11/30 21:25:04 tgl Exp $
11
+ * $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.112 2002/12/01 20:27:32 tgl Exp $
12
12
*
13
13
*-------------------------------------------------------------------------
14
14
*/
40
40
#include "executor/functions.h"
41
41
#include "executor/nodeSubplan.h"
42
42
#include "miscadmin.h"
43
+ #include "parser/parse_expr.h"
43
44
#include "utils/array.h"
44
45
#include "utils/builtins.h"
45
46
#include "utils/fcache.h"
@@ -820,80 +821,109 @@ ExecMakeFunctionResult(FunctionCachePtr fcache,
820
821
* object. (If function returns an empty set, we just return NULL instead.)
821
822
*/
822
823
Tuplestorestate *
823
- ExecMakeTableFunctionResult (Expr * funcexpr ,
824
+ ExecMakeTableFunctionResult (Node * funcexpr ,
824
825
ExprContext * econtext ,
825
826
TupleDesc expectedDesc ,
826
827
TupleDesc * returnDesc )
827
828
{
828
829
Tuplestorestate * tupstore = NULL ;
829
830
TupleDesc tupdesc = NULL ;
830
- Func * func ;
831
- List * argList ;
832
- FunctionCachePtr fcache ;
831
+ Oid funcrettype ;
833
832
FunctionCallInfoData fcinfo ;
834
833
ReturnSetInfo rsinfo ;
835
- ExprDoneCond argDone ;
836
834
MemoryContext callerContext ;
837
835
MemoryContext oldcontext ;
838
836
TupleTableSlot * slot ;
837
+ bool direct_function_call ;
839
838
bool first_time = true;
840
839
bool returnsTuple = false;
841
840
842
- /* Extract data from function-call expression node */
843
- if (!funcexpr || !IsA (funcexpr , Expr ) || funcexpr -> opType != FUNC_EXPR )
844
- elog (ERROR , "ExecMakeTableFunctionResult: expression is not a function call" );
845
- func = (Func * ) funcexpr -> oper ;
846
- argList = funcexpr -> args ;
847
-
848
841
/*
849
- * get the fcache from the Func node. If it is NULL, then initialize
850
- * it
842
+ * Normally the passed expression tree will be a FUNC_EXPR, since the
843
+ * grammar only allows a function call at the top level of a table
844
+ * function reference. However, if the function doesn't return set then
845
+ * the planner might have replaced the function call via constant-folding
846
+ * or inlining. So if we see any other kind of expression node, execute
847
+ * it via the general ExecEvalExpr() code; the only difference is that
848
+ * we don't get a chance to pass a special ReturnSetInfo to any functions
849
+ * buried in the expression.
851
850
*/
852
- fcache = func -> func_fcache ;
853
- if (fcache == NULL )
851
+ if (funcexpr &&
852
+ IsA (funcexpr , Expr ) &&
853
+ ((Expr * ) funcexpr )-> opType == FUNC_EXPR )
854
854
{
855
- fcache = init_fcache ( func -> funcid , length ( argList ),
856
- econtext -> ecxt_per_query_memory ) ;
857
- func -> func_fcache = fcache ;
858
- }
855
+ Func * func ;
856
+ List * argList ;
857
+ FunctionCachePtr fcache ;
858
+ ExprDoneCond argDone ;
859
859
860
- /*
861
- * Evaluate the function's argument list.
862
- *
863
- * Note: ideally, we'd do this in the per-tuple context, but then the
864
- * argument values would disappear when we reset the context in the
865
- * inner loop. So do it in caller context. Perhaps we should make a
866
- * separate context just to hold the evaluated arguments?
867
- */
868
- MemSet (& fcinfo , 0 , sizeof (fcinfo ));
869
- fcinfo .flinfo = & (fcache -> func );
870
- argDone = ExecEvalFuncArgs (& fcinfo , argList , econtext );
871
- /* We don't allow sets in the arguments of the table function */
872
- if (argDone != ExprSingleResult )
873
- elog (ERROR , "Set-valued function called in context that cannot accept a set" );
860
+ /*
861
+ * This path is similar to ExecMakeFunctionResult.
862
+ */
863
+ direct_function_call = true;
874
864
875
- /*
876
- * If function is strict, and there are any NULL arguments, skip
877
- * calling the function and return NULL (actually an empty set).
878
- */
879
- if (fcache -> func .fn_strict )
880
- {
881
- int i ;
865
+ funcrettype = ((Expr * ) funcexpr )-> typeOid ;
866
+ func = (Func * ) ((Expr * ) funcexpr )-> oper ;
867
+ argList = ((Expr * ) funcexpr )-> args ;
882
868
883
- for (i = 0 ; i < fcinfo .nargs ; i ++ )
869
+ /*
870
+ * get the fcache from the Func node. If it is NULL, then initialize
871
+ * it
872
+ */
873
+ fcache = func -> func_fcache ;
874
+ if (fcache == NULL )
884
875
{
885
- if (fcinfo .argnull [i ])
876
+ fcache = init_fcache (func -> funcid , length (argList ),
877
+ econtext -> ecxt_per_query_memory );
878
+ func -> func_fcache = fcache ;
879
+ }
880
+
881
+ /*
882
+ * Evaluate the function's argument list.
883
+ *
884
+ * Note: ideally, we'd do this in the per-tuple context, but then the
885
+ * argument values would disappear when we reset the context in the
886
+ * inner loop. So do it in caller context. Perhaps we should make a
887
+ * separate context just to hold the evaluated arguments?
888
+ */
889
+ MemSet (& fcinfo , 0 , sizeof (fcinfo ));
890
+ fcinfo .flinfo = & (fcache -> func );
891
+ argDone = ExecEvalFuncArgs (& fcinfo , argList , econtext );
892
+ /* We don't allow sets in the arguments of the table function */
893
+ if (argDone != ExprSingleResult )
894
+ elog (ERROR , "Set-valued function called in context that cannot accept a set" );
895
+
896
+ /*
897
+ * If function is strict, and there are any NULL arguments, skip
898
+ * calling the function and return NULL (actually an empty set).
899
+ */
900
+ if (fcache -> func .fn_strict )
901
+ {
902
+ int i ;
903
+
904
+ for (i = 0 ; i < fcinfo .nargs ; i ++ )
886
905
{
887
- * returnDesc = NULL ;
888
- return NULL ;
906
+ if (fcinfo .argnull [i ])
907
+ {
908
+ * returnDesc = NULL ;
909
+ return NULL ;
910
+ }
889
911
}
890
912
}
891
913
}
914
+ else
915
+ {
916
+ /* Treat funcexpr as a generic expression */
917
+ direct_function_call = false;
918
+ funcrettype = exprType (funcexpr );
919
+ }
892
920
893
921
/*
894
922
* Prepare a resultinfo node for communication. We always do this
895
923
* even if not expecting a set result, so that we can pass
896
- * expectedDesc.
924
+ * expectedDesc. In the generic-expression case, the expression
925
+ * doesn't actually get to see the resultinfo, but set it up anyway
926
+ * because we use some of the fields as our own state variables.
897
927
*/
898
928
fcinfo .resultinfo = (Node * ) & rsinfo ;
899
929
rsinfo .type = T_ReturnSetInfo ;
@@ -906,12 +936,13 @@ ExecMakeTableFunctionResult(Expr *funcexpr,
906
936
rsinfo .setDesc = NULL ;
907
937
908
938
/*
909
- * Switch to short-lived context for calling the function.
939
+ * Switch to short-lived context for calling the function or expression .
910
940
*/
911
941
callerContext = MemoryContextSwitchTo (econtext -> ecxt_per_tuple_memory );
912
942
913
943
/*
914
- * Loop to handle the ValuePerCall protocol.
944
+ * Loop to handle the ValuePerCall protocol (which is also the same
945
+ * behavior needed in the generic ExecEvalExpr path).
915
946
*/
916
947
for (;;)
917
948
{
@@ -920,15 +951,23 @@ ExecMakeTableFunctionResult(Expr *funcexpr,
920
951
921
952
/*
922
953
* reset per-tuple memory context before each call of the
923
- * function. This cleans up any local memory the function may leak
924
- * when called.
954
+ * function or expression . This cleans up any local memory the
955
+ * function may leak when called.
925
956
*/
926
957
ResetExprContext (econtext );
927
958
928
- /* Call the function one time */
929
- fcinfo .isnull = false;
930
- rsinfo .isDone = ExprSingleResult ;
931
- result = FunctionCallInvoke (& fcinfo );
959
+ /* Call the function or expression one time */
960
+ if (direct_function_call )
961
+ {
962
+ fcinfo .isnull = false;
963
+ rsinfo .isDone = ExprSingleResult ;
964
+ result = FunctionCallInvoke (& fcinfo );
965
+ }
966
+ else
967
+ {
968
+ result = ExecEvalExpr (funcexpr , econtext ,
969
+ & fcinfo .isnull , & rsinfo .isDone );
970
+ }
932
971
933
972
/* Which protocol does function want to use? */
934
973
if (rsinfo .returnMode == SFRM_ValuePerCall )
@@ -949,8 +988,6 @@ ExecMakeTableFunctionResult(Expr *funcexpr,
949
988
*/
950
989
if (first_time )
951
990
{
952
- Oid funcrettype = funcexpr -> typeOid ;
953
-
954
991
oldcontext = MemoryContextSwitchTo (econtext -> ecxt_per_query_memory );
955
992
if (funcrettype == RECORDOID ||
956
993
get_typtype (funcrettype ) == 'c' )
@@ -960,7 +997,9 @@ ExecMakeTableFunctionResult(Expr *funcexpr,
960
997
* TupleTableSlot; use its descriptor
961
998
*/
962
999
slot = (TupleTableSlot * ) DatumGetPointer (result );
963
- if (fcinfo .isnull || !slot || !IsA (slot , TupleTableSlot ) ||
1000
+ if (fcinfo .isnull ||
1001
+ !slot ||
1002
+ !IsA (slot , TupleTableSlot ) ||
964
1003
!slot -> ttc_tupleDescriptor )
965
1004
elog (ERROR , "ExecMakeTableFunctionResult: Invalid result from function returning tuple" );
966
1005
tupdesc = CreateTupleDescCopy (slot -> ttc_tupleDescriptor );
@@ -993,7 +1032,9 @@ ExecMakeTableFunctionResult(Expr *funcexpr,
993
1032
if (returnsTuple )
994
1033
{
995
1034
slot = (TupleTableSlot * ) DatumGetPointer (result );
996
- if (fcinfo .isnull || !slot || !IsA (slot , TupleTableSlot ) ||
1035
+ if (fcinfo .isnull ||
1036
+ !slot ||
1037
+ !IsA (slot , TupleTableSlot ) ||
997
1038
TupIsNull (slot ))
998
1039
elog (ERROR , "ExecMakeTableFunctionResult: Invalid result from function returning tuple" );
999
1040
tuple = slot -> val ;
0 commit comments