Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit02f8c9a

Browse files
committed
Fix ExecMakeTableFunctionResult() to work with generic expressions as
well as function calls. This is needed for cases where the planner hasconstant-folded or inlined the original function call. Possibly we shouldback-patch this change into 7.3 branch as well.
1 parent9ee7409 commit02f8c9a

File tree

3 files changed

+103
-62
lines changed

3 files changed

+103
-62
lines changed

‎src/backend/executor/execQual.c

Lines changed: 99 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* 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 $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -40,6 +40,7 @@
4040
#include"executor/functions.h"
4141
#include"executor/nodeSubplan.h"
4242
#include"miscadmin.h"
43+
#include"parser/parse_expr.h"
4344
#include"utils/array.h"
4445
#include"utils/builtins.h"
4546
#include"utils/fcache.h"
@@ -820,80 +821,109 @@ ExecMakeFunctionResult(FunctionCachePtr fcache,
820821
* object.(If function returns an empty set, we just return NULL instead.)
821822
*/
822823
Tuplestorestate*
823-
ExecMakeTableFunctionResult(Expr*funcexpr,
824+
ExecMakeTableFunctionResult(Node*funcexpr,
824825
ExprContext*econtext,
825826
TupleDescexpectedDesc,
826827
TupleDesc*returnDesc)
827828
{
828829
Tuplestorestate*tupstore=NULL;
829830
TupleDesctupdesc=NULL;
830-
Func*func;
831-
List*argList;
832-
FunctionCachePtrfcache;
831+
Oidfuncrettype;
833832
FunctionCallInfoDatafcinfo;
834833
ReturnSetInforsinfo;
835-
ExprDoneCondargDone;
836834
MemoryContextcallerContext;
837835
MemoryContextoldcontext;
838836
TupleTableSlot*slot;
837+
booldirect_function_call;
839838
boolfirst_time= true;
840839
boolreturnsTuple= false;
841840

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-
848841
/*
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.
851850
*/
852-
fcache=func->func_fcache;
853-
if (fcache==NULL)
851+
if (funcexpr&&
852+
IsA(funcexpr,Expr)&&
853+
((Expr*)funcexpr)->opType==FUNC_EXPR)
854854
{
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+
FunctionCachePtrfcache;
858+
ExprDoneCondargDone;
859859

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;
874864

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-
inti;
865+
funcrettype= ((Expr*)funcexpr)->typeOid;
866+
func= (Func*) ((Expr*)funcexpr)->oper;
867+
argList= ((Expr*)funcexpr)->args;
882868

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)
884875
{
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+
inti;
903+
904+
for (i=0;i<fcinfo.nargs;i++)
886905
{
887-
*returnDesc=NULL;
888-
returnNULL;
906+
if (fcinfo.argnull[i])
907+
{
908+
*returnDesc=NULL;
909+
returnNULL;
910+
}
889911
}
890912
}
891913
}
914+
else
915+
{
916+
/* Treat funcexpr as a generic expression */
917+
direct_function_call= false;
918+
funcrettype=exprType(funcexpr);
919+
}
892920

893921
/*
894922
* Prepare a resultinfo node for communication. We always do this
895923
* 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.
897927
*/
898928
fcinfo.resultinfo= (Node*)&rsinfo;
899929
rsinfo.type=T_ReturnSetInfo;
@@ -906,12 +936,13 @@ ExecMakeTableFunctionResult(Expr *funcexpr,
906936
rsinfo.setDesc=NULL;
907937

908938
/*
909-
* Switch to short-lived context for calling the function.
939+
* Switch to short-lived context for calling the function or expression.
910940
*/
911941
callerContext=MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
912942

913943
/*
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).
915946
*/
916947
for (;;)
917948
{
@@ -920,15 +951,23 @@ ExecMakeTableFunctionResult(Expr *funcexpr,
920951

921952
/*
922953
* 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 leakwhen called.
925956
*/
926957
ResetExprContext(econtext);
927958

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+
}
932971

933972
/* Which protocol does function want to use? */
934973
if (rsinfo.returnMode==SFRM_ValuePerCall)
@@ -949,8 +988,6 @@ ExecMakeTableFunctionResult(Expr *funcexpr,
949988
*/
950989
if (first_time)
951990
{
952-
Oidfuncrettype=funcexpr->typeOid;
953-
954991
oldcontext=MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
955992
if (funcrettype==RECORDOID||
956993
get_typtype(funcrettype)=='c')
@@ -960,7 +997,9 @@ ExecMakeTableFunctionResult(Expr *funcexpr,
960997
* TupleTableSlot; use its descriptor
961998
*/
962999
slot= (TupleTableSlot*)DatumGetPointer(result);
963-
if (fcinfo.isnull|| !slot|| !IsA(slot,TupleTableSlot)||
1000+
if (fcinfo.isnull||
1001+
!slot||
1002+
!IsA(slot,TupleTableSlot)||
9641003
!slot->ttc_tupleDescriptor)
9651004
elog(ERROR,"ExecMakeTableFunctionResult: Invalid result from function returning tuple");
9661005
tupdesc=CreateTupleDescCopy(slot->ttc_tupleDescriptor);
@@ -993,7 +1032,9 @@ ExecMakeTableFunctionResult(Expr *funcexpr,
9931032
if (returnsTuple)
9941033
{
9951034
slot= (TupleTableSlot*)DatumGetPointer(result);
996-
if (fcinfo.isnull|| !slot|| !IsA(slot,TupleTableSlot)||
1035+
if (fcinfo.isnull||
1036+
!slot||
1037+
!IsA(slot,TupleTableSlot)||
9971038
TupIsNull(slot))
9981039
elog(ERROR,"ExecMakeTableFunctionResult: Invalid result from function returning tuple");
9991040
tuple=slot->val;

‎src/backend/executor/nodeFunctionscan.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/executor/nodeFunctionscan.c,v 1.12 2002/09/04 20:31:18 momjian Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/executor/nodeFunctionscan.c,v 1.13 2002/12/01 20:27:32 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -78,7 +78,7 @@ FunctionNext(FunctionScan *node)
7878
TupleDescfuncTupdesc;
7979

8080
scanstate->tuplestorestate=tuplestorestate=
81-
ExecMakeTableFunctionResult((Expr*)scanstate->funcexpr,
81+
ExecMakeTableFunctionResult(scanstate->funcexpr,
8282
econtext,
8383
scanstate->tupdesc,
8484
&funcTupdesc);

‎src/include/executor/executor.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $Id: executor.h,v 1.79 2002/11/30 05:21:03 tgl Exp $
10+
* $Id: executor.h,v 1.80 2002/12/01 20:27:32 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -81,7 +81,7 @@ extern Datum ExecMakeFunctionResult(FunctionCachePtr fcache,
8181
ExprContext*econtext,
8282
bool*isNull,
8383
ExprDoneCond*isDone);
84-
externTuplestorestate*ExecMakeTableFunctionResult(Expr*funcexpr,
84+
externTuplestorestate*ExecMakeTableFunctionResult(Node*funcexpr,
8585
ExprContext*econtext,
8686
TupleDescexpectedDesc,
8787
TupleDesc*returnDesc);

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp