mirror of
https://git.postgresql.org/git/postgresql.git
synced 2025-02-23 19:39:53 +08:00
Speedup of PL/pgSQL by calling ExecEvalExpr() directly
instead of SPI_execp() for simple expressions. Jan
This commit is contained in:
parent
d611ccb874
commit
28d8b42ca5
@ -3,25 +3,16 @@
|
||||
* spi.c--
|
||||
* Server Programming Interface
|
||||
*
|
||||
* $Id: spi.c,v 1.31 1999/01/27 00:36:21 tgl Exp $
|
||||
* $Id: spi.c,v 1.32 1999/01/27 16:15:20 wieck Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#include "executor/spi.h"
|
||||
#include "executor/spi_priv.h"
|
||||
#include "catalog/pg_type.h"
|
||||
#include "access/printtup.h"
|
||||
#include "fmgr.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
QueryTreeList *qtlist; /* malloced */
|
||||
uint32 processed; /* by Executor */
|
||||
SPITupleTable *tuptable;
|
||||
Portal portal; /* portal per procedure */
|
||||
MemoryContext savedcxt;
|
||||
CommandId savedId;
|
||||
} _SPI_connection;
|
||||
|
||||
static Portal _SPI_portal = (Portal) NULL;
|
||||
static _SPI_connection *_SPI_stack = NULL;
|
||||
static _SPI_connection *_SPI_current = NULL;
|
||||
@ -32,24 +23,12 @@ uint32 SPI_processed = 0;
|
||||
SPITupleTable *SPI_tuptable;
|
||||
int SPI_result;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
QueryTreeList *qtlist;
|
||||
List *ptlist;
|
||||
int nargs;
|
||||
Oid *argtypes;
|
||||
} _SPI_plan;
|
||||
|
||||
static int _SPI_execute(char *src, int tcount, _SPI_plan *plan);
|
||||
static int _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount);
|
||||
|
||||
static int _SPI_execute_plan(_SPI_plan *plan,
|
||||
Datum *Values, char *Nulls, int tcount);
|
||||
|
||||
#define _SPI_CPLAN_CURCXT 0
|
||||
#define _SPI_CPLAN_PROCXT 1
|
||||
#define _SPI_CPLAN_TOPCXT 2
|
||||
|
||||
static _SPI_plan *_SPI_copy_plan(_SPI_plan *plan, int location);
|
||||
|
||||
static int _SPI_begin_call(bool execmem);
|
||||
@ -178,6 +157,18 @@ SPI_finish()
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
SPI_push(void)
|
||||
{
|
||||
_SPI_curid++;
|
||||
}
|
||||
|
||||
void
|
||||
SPI_pop(void)
|
||||
{
|
||||
_SPI_curid--;
|
||||
}
|
||||
|
||||
int
|
||||
SPI_exec(char *src, int tcount)
|
||||
{
|
||||
|
@ -72,6 +72,8 @@ extern int SPI_result;
|
||||
|
||||
extern int SPI_connect(void);
|
||||
extern int SPI_finish(void);
|
||||
extern void SPI_push(void);
|
||||
extern void SPI_pop(void);
|
||||
extern int SPI_exec(char *src, int tcount);
|
||||
extern int SPI_execp(void *plan, Datum *values, char *Nulls, int tcount);
|
||||
extern void *SPI_prepare(char *src, int nargs, Oid *argtypes);
|
||||
|
38
src/include/executor/spi_priv.h
Normal file
38
src/include/executor/spi_priv.h
Normal file
@ -0,0 +1,38 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* spi.c--
|
||||
* Server Programming Interface private declarations
|
||||
*
|
||||
* $Header: /cvsroot/pgsql/src/include/executor/spi_priv.h,v 1.1 1999/01/27 16:15:21 wieck Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef SPI_PRIV_H
|
||||
#define SPI_PRIV_H
|
||||
|
||||
#include "catalog/pg_type.h"
|
||||
#include "access/printtup.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
QueryTreeList *qtlist; /* malloced */
|
||||
uint32 processed; /* by Executor */
|
||||
SPITupleTable *tuptable;
|
||||
Portal portal; /* portal per procedure */
|
||||
MemoryContext savedcxt;
|
||||
CommandId savedId;
|
||||
} _SPI_connection;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
QueryTreeList *qtlist;
|
||||
List *ptlist;
|
||||
int nargs;
|
||||
Oid *argtypes;
|
||||
} _SPI_plan;
|
||||
|
||||
#define _SPI_CPLAN_CURCXT 0
|
||||
#define _SPI_CPLAN_PROCXT 1
|
||||
#define _SPI_CPLAN_TOPCXT 2
|
||||
|
||||
#endif /* SPI_PRIV_H */
|
@ -3,7 +3,7 @@
|
||||
* procedural language
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.5 1999/01/17 21:53:32 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.6 1999/01/27 16:15:22 wieck Exp $
|
||||
*
|
||||
* This software is copyrighted by Jan Wieck - Hamburg.
|
||||
*
|
||||
@ -48,6 +48,7 @@
|
||||
#include "pl.tab.h"
|
||||
|
||||
#include "executor/spi.h"
|
||||
#include "executor/spi_priv.h"
|
||||
#include "commands/trigger.h"
|
||||
#include "utils/elog.h"
|
||||
#include "utils/builtins.h"
|
||||
@ -116,6 +117,16 @@ static int exec_stmt_raise(PLpgSQL_execstate * estate,
|
||||
static int exec_stmt_execsql(PLpgSQL_execstate * estate,
|
||||
PLpgSQL_stmt_execsql * stmt);
|
||||
|
||||
static void exec_prepare_plan(PLpgSQL_execstate * estate,
|
||||
PLpgSQL_expr * expr);
|
||||
static bool exec_simple_check_node(Node * node);
|
||||
static void exec_simple_check_plan(PLpgSQL_expr * expr);
|
||||
static void exec_eval_clear_fcache(Node *node);
|
||||
static Datum exec_eval_simple_expr(PLpgSQL_execstate * estate,
|
||||
PLpgSQL_expr * expr,
|
||||
bool *isNull,
|
||||
Oid *rettype);
|
||||
|
||||
static void exec_assign_expr(PLpgSQL_execstate * estate,
|
||||
PLpgSQL_datum * target,
|
||||
PLpgSQL_expr * expr);
|
||||
@ -1656,37 +1667,25 @@ exec_stmt_raise(PLpgSQL_execstate * estate, PLpgSQL_stmt_raise * stmt)
|
||||
|
||||
|
||||
/* ----------
|
||||
* exec_stmt_execsql Execute an SQL statement not
|
||||
* returning any data.
|
||||
* Generate a prepared plan
|
||||
* ----------
|
||||
*/
|
||||
static int
|
||||
exec_stmt_execsql(PLpgSQL_execstate * estate,
|
||||
PLpgSQL_stmt_execsql * stmt)
|
||||
static void
|
||||
exec_prepare_plan(PLpgSQL_execstate * estate,
|
||||
PLpgSQL_expr * expr)
|
||||
{
|
||||
PLpgSQL_var *var;
|
||||
PLpgSQL_rec *rec;
|
||||
PLpgSQL_recfield *recfield;
|
||||
PLpgSQL_trigarg *trigarg;
|
||||
int tgargno;
|
||||
Oid tgargoid;
|
||||
int fno;
|
||||
int i;
|
||||
Datum *values;
|
||||
char *nulls;
|
||||
int rc;
|
||||
PLpgSQL_expr *expr = stmt->sqlstmt;
|
||||
bool isnull;
|
||||
|
||||
/* ----------
|
||||
* On the first call for this expression generate the plan
|
||||
* ----------
|
||||
*/
|
||||
if (expr->plan == NULL)
|
||||
{
|
||||
int fno;
|
||||
void *plan;
|
||||
Oid *argtypes;
|
||||
|
||||
/* ----------
|
||||
* Setup the argtypes array
|
||||
* ----------
|
||||
*/
|
||||
argtypes = malloc(sizeof(Oid *) * (expr->nparams + 1));
|
||||
|
||||
for (i = 0; i < expr->nparams; i++)
|
||||
@ -1715,17 +1714,54 @@ exec_stmt_execsql(PLpgSQL_execstate * estate,
|
||||
break;
|
||||
|
||||
default:
|
||||
elog(ERROR, "unknown parameter dtype %d in exec_stmt_execsql()", estate->datums[expr->params[i]]->dtype);
|
||||
elog(ERROR, "unknown parameter dtype %d in exec_run_select()", estate->datums[expr->params[i]]);
|
||||
}
|
||||
}
|
||||
|
||||
/* ----------
|
||||
* Generate and save the plan
|
||||
* ----------
|
||||
*/
|
||||
plan = SPI_prepare(expr->query, expr->nparams, argtypes);
|
||||
if (plan == NULL)
|
||||
elog(ERROR, "SPI_prepare() failed on \"%s\"", expr->query);
|
||||
expr->plan = SPI_saveplan(plan);
|
||||
expr->plan_argtypes = argtypes;
|
||||
expr->plan_simple_expr = NULL;
|
||||
exec_simple_check_plan(expr);
|
||||
}
|
||||
|
||||
|
||||
/* ----------
|
||||
* exec_stmt_execsql Execute an SQL statement not
|
||||
* returning any data.
|
||||
* ----------
|
||||
*/
|
||||
static int
|
||||
exec_stmt_execsql(PLpgSQL_execstate * estate,
|
||||
PLpgSQL_stmt_execsql * stmt)
|
||||
{
|
||||
PLpgSQL_var *var;
|
||||
PLpgSQL_rec *rec;
|
||||
PLpgSQL_recfield *recfield;
|
||||
PLpgSQL_trigarg *trigarg;
|
||||
int tgargno;
|
||||
Oid tgargoid;
|
||||
int fno;
|
||||
int i;
|
||||
Datum *values;
|
||||
char *nulls;
|
||||
int rc;
|
||||
PLpgSQL_expr *expr = stmt->sqlstmt;
|
||||
bool isnull;
|
||||
|
||||
/* ----------
|
||||
* On the first call for this expression generate the plan
|
||||
* ----------
|
||||
*/
|
||||
if (expr->plan == NULL)
|
||||
exec_prepare_plan(estate, expr);
|
||||
|
||||
/* ----------
|
||||
* Now build up the values and nulls arguments for SPI_execp()
|
||||
* ----------
|
||||
@ -1987,6 +2023,21 @@ exec_eval_expr(PLpgSQL_execstate * estate,
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* ----------
|
||||
* If not already done create a plan for this expression
|
||||
* ----------
|
||||
*/
|
||||
if (expr->plan == NULL)
|
||||
exec_prepare_plan(estate, expr);
|
||||
|
||||
/* ----------
|
||||
* If this is a simple expression, bypass SPI and use the
|
||||
* executor directly
|
||||
* ----------
|
||||
*/
|
||||
if (expr->plan_simple_expr != NULL)
|
||||
return exec_eval_simple_expr(estate, expr, isNull, rettype);
|
||||
|
||||
rc = exec_run_select(estate, expr, 2);
|
||||
if (rc != SPI_OK_SELECT)
|
||||
elog(ERROR, "query \"%s\" didn't return data", expr->query);
|
||||
@ -2045,56 +2096,7 @@ exec_run_select(PLpgSQL_execstate * estate,
|
||||
* ----------
|
||||
*/
|
||||
if (expr->plan == NULL)
|
||||
{
|
||||
void *plan;
|
||||
Oid *argtypes;
|
||||
|
||||
/* ----------
|
||||
* Setup the argtypes array
|
||||
* ----------
|
||||
*/
|
||||
argtypes = malloc(sizeof(Oid *) * (expr->nparams + 1));
|
||||
|
||||
for (i = 0; i < expr->nparams; i++)
|
||||
{
|
||||
switch (estate->datums[expr->params[i]]->dtype)
|
||||
{
|
||||
case PLPGSQL_DTYPE_VAR:
|
||||
var = (PLpgSQL_var *) (estate->datums[expr->params[i]]);
|
||||
argtypes[i] = var->datatype->typoid;
|
||||
break;
|
||||
|
||||
case PLPGSQL_DTYPE_RECFIELD:
|
||||
recfield = (PLpgSQL_recfield *) (estate->datums[expr->params[i]]);
|
||||
rec = (PLpgSQL_rec *) (estate->datums[recfield->recno]);
|
||||
|
||||
if (!HeapTupleIsValid(rec->tup))
|
||||
elog(ERROR, "record %s is unassigned yet", rec->refname);
|
||||
fno = SPI_fnumber(rec->tupdesc, recfield->fieldname);
|
||||
if (fno == SPI_ERROR_NOATTRIBUTE)
|
||||
elog(ERROR, "record %s has no field %s", rec->refname, recfield->fieldname);
|
||||
argtypes[i] = SPI_gettypeid(rec->tupdesc, fno);
|
||||
break;
|
||||
|
||||
case PLPGSQL_DTYPE_TRIGARG:
|
||||
argtypes[i] = (Oid) TEXTOID;
|
||||
break;
|
||||
|
||||
default:
|
||||
elog(ERROR, "unknown parameter dtype %d in exec_run_select()", estate->datums[expr->params[i]]);
|
||||
}
|
||||
}
|
||||
|
||||
/* ----------
|
||||
* Generate and save the plan
|
||||
* ----------
|
||||
*/
|
||||
plan = SPI_prepare(expr->query, expr->nparams, argtypes);
|
||||
if (plan == NULL)
|
||||
elog(ERROR, "SPI_prepare() failed on \"%s\"", expr->query);
|
||||
expr->plan = SPI_saveplan(plan);
|
||||
expr->plan_argtypes = argtypes;
|
||||
}
|
||||
exec_prepare_plan(estate, expr);
|
||||
|
||||
/* ----------
|
||||
* Now build up the values and nulls arguments for SPI_execp()
|
||||
@ -2172,6 +2174,130 @@ exec_run_select(PLpgSQL_execstate * estate,
|
||||
}
|
||||
|
||||
|
||||
/* ----------
|
||||
* exec_eval_simple_expr - Evaluate a simple expression returning
|
||||
* a Datum by directly calling ExecEvalExpr().
|
||||
* ----------
|
||||
*/
|
||||
static Datum
|
||||
exec_eval_simple_expr(PLpgSQL_execstate * estate,
|
||||
PLpgSQL_expr * expr,
|
||||
bool *isNull,
|
||||
Oid *rettype)
|
||||
{
|
||||
Datum retval;
|
||||
PLpgSQL_var *var;
|
||||
PLpgSQL_rec *rec;
|
||||
PLpgSQL_recfield *recfield;
|
||||
PLpgSQL_trigarg *trigarg;
|
||||
int tgargno;
|
||||
Oid tgargoid;
|
||||
int fno;
|
||||
int i;
|
||||
bool isnull;
|
||||
bool isdone;
|
||||
ExprContext *econtext;
|
||||
ParamListInfo paramLI;
|
||||
|
||||
/* ----------
|
||||
* Create a simple expression context to hold the arguments
|
||||
* ----------
|
||||
*/
|
||||
econtext = makeNode(ExprContext);
|
||||
paramLI = (ParamListInfo) palloc((expr->nparams + 1) *
|
||||
sizeof(ParamListInfoData));
|
||||
econtext->ecxt_param_list_info = paramLI;
|
||||
|
||||
/* ----------
|
||||
* Put the parameter values into the parameter list info of
|
||||
* the expression context.
|
||||
* ----------
|
||||
*/
|
||||
for (i = 0; i < expr->nparams; i++, paramLI++)
|
||||
{
|
||||
paramLI->kind = PARAM_NUM;
|
||||
paramLI->id = i + 1;
|
||||
|
||||
switch (estate->datums[expr->params[i]]->dtype)
|
||||
{
|
||||
case PLPGSQL_DTYPE_VAR:
|
||||
var = (PLpgSQL_var *) (estate->datums[expr->params[i]]);
|
||||
paramLI->isnull = var->isnull;
|
||||
paramLI->value = var->value;
|
||||
break;
|
||||
|
||||
case PLPGSQL_DTYPE_RECFIELD:
|
||||
recfield = (PLpgSQL_recfield *) (estate->datums[expr->params[i]]);
|
||||
rec = (PLpgSQL_rec *) (estate->datums[recfield->recno]);
|
||||
|
||||
if (!HeapTupleIsValid(rec->tup))
|
||||
elog(ERROR, "record %s is unassigned yet", rec->refname);
|
||||
fno = SPI_fnumber(rec->tupdesc, recfield->fieldname);
|
||||
if (fno == SPI_ERROR_NOATTRIBUTE)
|
||||
elog(ERROR, "record %s has no field %s", rec->refname, recfield->fieldname);
|
||||
|
||||
if (expr->plan_argtypes[i] != SPI_gettypeid(rec->tupdesc, fno))
|
||||
elog(ERROR, "type of %s.%s doesn't match that when preparing the plan", rec->refname, recfield->fieldname);
|
||||
|
||||
paramLI->value = SPI_getbinval(rec->tup, rec->tupdesc, fno, &isnull);
|
||||
paramLI->isnull = isnull;
|
||||
break;
|
||||
|
||||
case PLPGSQL_DTYPE_TRIGARG:
|
||||
trigarg = (PLpgSQL_trigarg *) (estate->datums[expr->params[i]]);
|
||||
tgargno = (int) exec_eval_expr(estate, trigarg->argnum,
|
||||
&isnull, &tgargoid);
|
||||
if (isnull || tgargno < 0 || tgargno >= estate->trig_nargs)
|
||||
{
|
||||
paramLI->value = 0;
|
||||
paramLI->isnull = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
paramLI->value = estate->trig_argv[tgargno];
|
||||
paramLI->isnull = FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
elog(ERROR, "unknown parameter dtype %d in exec_eval_simple_expr()", estate->datums[expr->params[i]]->dtype);
|
||||
}
|
||||
}
|
||||
paramLI->kind = PARAM_INVALID;
|
||||
|
||||
/* ----------
|
||||
* Initialize things
|
||||
* ----------
|
||||
*/
|
||||
*isNull = FALSE;
|
||||
*rettype = expr->plan_simple_type;
|
||||
isdone = FALSE;
|
||||
|
||||
/* ----------
|
||||
* Clear the function cache
|
||||
* ----------
|
||||
*/
|
||||
exec_eval_clear_fcache(expr->plan_simple_expr);
|
||||
|
||||
/* ----------
|
||||
* Now call the executor to evaluate the expression
|
||||
* ----------
|
||||
*/
|
||||
SPI_push();
|
||||
retval = ExecEvalExpr(expr->plan_simple_expr,
|
||||
econtext,
|
||||
isNull,
|
||||
&isdone);
|
||||
SPI_pop();
|
||||
|
||||
/* ----------
|
||||
* That's it.
|
||||
* ----------
|
||||
*/
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/* ----------
|
||||
* exec_move_row Move one tuples values into a
|
||||
* record or row
|
||||
@ -2296,6 +2422,169 @@ exec_cast_value(Datum value, Oid valtype,
|
||||
}
|
||||
|
||||
|
||||
/* ----------
|
||||
* exec_simple_check_node - Recursively check if an expression
|
||||
* is made only of simple things we can
|
||||
* hand out directly to ExecEvalExpr()
|
||||
* instead of calling SPI.
|
||||
* ----------
|
||||
*/
|
||||
static bool
|
||||
exec_simple_check_node(Node * node)
|
||||
{
|
||||
switch (nodeTag(node))
|
||||
{
|
||||
case T_Expr: {
|
||||
Expr *expr = (Expr *)node;
|
||||
List *l;
|
||||
|
||||
switch (expr->opType)
|
||||
{
|
||||
case OP_EXPR:
|
||||
case FUNC_EXPR:
|
||||
case OR_EXPR:
|
||||
case AND_EXPR:
|
||||
case NOT_EXPR: break;
|
||||
|
||||
default: return FALSE;
|
||||
}
|
||||
|
||||
foreach (l, expr->args)
|
||||
{
|
||||
if (!exec_simple_check_node(lfirst(l)))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
case T_Param: return TRUE;
|
||||
|
||||
case T_Const: return TRUE;
|
||||
|
||||
default: return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ----------
|
||||
* exec_simple_check_plan - Check if a plan is simple enough to
|
||||
* be evaluated by ExecEvalExpr() instead
|
||||
* of SPI.
|
||||
* ----------
|
||||
*/
|
||||
static void
|
||||
exec_simple_check_plan(PLpgSQL_expr * expr)
|
||||
{
|
||||
_SPI_plan *spi_plan = (_SPI_plan *)expr->plan;
|
||||
Plan *plan;
|
||||
TargetEntry *tle;
|
||||
|
||||
expr->plan_simple_expr = NULL;
|
||||
|
||||
/* ----------
|
||||
* 1. We can only evaluate queries that resulted in one single
|
||||
* execution plan
|
||||
* ----------
|
||||
*/
|
||||
if (spi_plan->ptlist == NULL || length(spi_plan->ptlist) != 1)
|
||||
return;
|
||||
|
||||
plan = (Plan *)lfirst(spi_plan->ptlist);
|
||||
|
||||
/* ----------
|
||||
* 2. It must be a RESULT plan --> no scan's required
|
||||
* ----------
|
||||
*/
|
||||
if (nodeTag(plan) != T_Result)
|
||||
return;
|
||||
|
||||
/* ----------
|
||||
* 3. The plan must have a single attribute as result
|
||||
* ----------
|
||||
*/
|
||||
if (length(plan->targetlist) != 1)
|
||||
return;
|
||||
|
||||
/* ----------
|
||||
* 4. Don't know if all these can break us, so let SPI handle
|
||||
* those plans
|
||||
* ----------
|
||||
*/
|
||||
if (plan->qual != NULL || plan->lefttree != NULL || plan->righttree != NULL)
|
||||
return;
|
||||
|
||||
/* ----------
|
||||
* 5. Check that all the nodes in the expression are one of
|
||||
* Expr, Param or Const.
|
||||
* ----------
|
||||
*/
|
||||
tle = (TargetEntry *)lfirst(plan->targetlist);
|
||||
if (!exec_simple_check_node(tle->expr))
|
||||
return;
|
||||
|
||||
/* ----------
|
||||
* Yes - this is a simple expression. Remember the expression
|
||||
* and the return type
|
||||
* ----------
|
||||
*/
|
||||
expr->plan_simple_expr = tle->expr;
|
||||
|
||||
switch (nodeTag(tle->expr))
|
||||
{
|
||||
case T_Expr: expr->plan_simple_type =
|
||||
((Expr *)(tle->expr))->typeOid;
|
||||
break;
|
||||
|
||||
case T_Param: expr->plan_simple_type =
|
||||
((Param *)(tle->expr))->paramtype;
|
||||
break;
|
||||
|
||||
case T_Const: expr->plan_simple_type =
|
||||
((Const *)(tle->expr))->consttype;
|
||||
break;
|
||||
|
||||
default: expr->plan_simple_type = InvalidOid;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* ----------
|
||||
* exec_eval_clear_fcache - The function cache is palloc()'d by
|
||||
* the executor, and contains call specific
|
||||
* data based on the arguments. This has
|
||||
* to be recalculated.
|
||||
* ----------
|
||||
*/
|
||||
static void
|
||||
exec_eval_clear_fcache(Node *node)
|
||||
{
|
||||
Expr *expr;
|
||||
List *l;
|
||||
|
||||
if (nodeTag(node) != T_Expr)
|
||||
return;
|
||||
|
||||
expr = (Expr *)node;
|
||||
|
||||
switch(expr->opType)
|
||||
{
|
||||
case OP_EXPR: ((Oper *)(expr->oper))->op_fcache = NULL;
|
||||
break;
|
||||
|
||||
case FUNC_EXPR: ((Func *)(expr->oper))->func_fcache = NULL;
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
foreach (l, expr->args)
|
||||
exec_eval_clear_fcache(lfirst(l));
|
||||
}
|
||||
|
||||
|
||||
/* ----------
|
||||
* exec_set_found Set the global found variable
|
||||
* to true/false
|
||||
|
@ -3,7 +3,7 @@
|
||||
* procedural language
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.2 1998/09/01 04:40:27 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.3 1999/01/27 16:15:22 wieck Exp $
|
||||
*
|
||||
* This software is copyrighted by Jan Wieck - Hamburg.
|
||||
*
|
||||
@ -143,6 +143,8 @@ typedef struct
|
||||
int exprno;
|
||||
char *query;
|
||||
void *plan;
|
||||
Node *plan_simple_expr;
|
||||
Oid plan_simple_type;
|
||||
Oid *plan_argtypes;
|
||||
int nparams;
|
||||
int params[1];
|
||||
|
Loading…
Reference in New Issue
Block a user