mirror of
https://github.com/postgres/postgres.git
synced 2025-04-24 10:47:04 +03: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--
|
* spi.c--
|
||||||
* Server Programming Interface
|
* 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.h"
|
||||||
|
#include "executor/spi_priv.h"
|
||||||
#include "catalog/pg_type.h"
|
#include "catalog/pg_type.h"
|
||||||
#include "access/printtup.h"
|
#include "access/printtup.h"
|
||||||
#include "fmgr.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 Portal _SPI_portal = (Portal) NULL;
|
||||||
static _SPI_connection *_SPI_stack = NULL;
|
static _SPI_connection *_SPI_stack = NULL;
|
||||||
static _SPI_connection *_SPI_current = NULL;
|
static _SPI_connection *_SPI_current = NULL;
|
||||||
@ -32,24 +23,12 @@ uint32 SPI_processed = 0;
|
|||||||
SPITupleTable *SPI_tuptable;
|
SPITupleTable *SPI_tuptable;
|
||||||
int SPI_result;
|
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_execute(char *src, int tcount, _SPI_plan *plan);
|
||||||
static int _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount);
|
static int _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount);
|
||||||
|
|
||||||
static int _SPI_execute_plan(_SPI_plan *plan,
|
static int _SPI_execute_plan(_SPI_plan *plan,
|
||||||
Datum *Values, char *Nulls, int tcount);
|
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 _SPI_plan *_SPI_copy_plan(_SPI_plan *plan, int location);
|
||||||
|
|
||||||
static int _SPI_begin_call(bool execmem);
|
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
|
int
|
||||||
SPI_exec(char *src, int tcount)
|
SPI_exec(char *src, int tcount)
|
||||||
{
|
{
|
||||||
|
@ -72,6 +72,8 @@ extern int SPI_result;
|
|||||||
|
|
||||||
extern int SPI_connect(void);
|
extern int SPI_connect(void);
|
||||||
extern int SPI_finish(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_exec(char *src, int tcount);
|
||||||
extern int SPI_execp(void *plan, Datum *values, char *Nulls, int tcount);
|
extern int SPI_execp(void *plan, Datum *values, char *Nulls, int tcount);
|
||||||
extern void *SPI_prepare(char *src, int nargs, Oid *argtypes);
|
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
|
* procedural language
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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.
|
* This software is copyrighted by Jan Wieck - Hamburg.
|
||||||
*
|
*
|
||||||
@ -48,6 +48,7 @@
|
|||||||
#include "pl.tab.h"
|
#include "pl.tab.h"
|
||||||
|
|
||||||
#include "executor/spi.h"
|
#include "executor/spi.h"
|
||||||
|
#include "executor/spi_priv.h"
|
||||||
#include "commands/trigger.h"
|
#include "commands/trigger.h"
|
||||||
#include "utils/elog.h"
|
#include "utils/elog.h"
|
||||||
#include "utils/builtins.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,
|
static int exec_stmt_execsql(PLpgSQL_execstate * estate,
|
||||||
PLpgSQL_stmt_execsql * stmt);
|
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,
|
static void exec_assign_expr(PLpgSQL_execstate * estate,
|
||||||
PLpgSQL_datum * target,
|
PLpgSQL_datum * target,
|
||||||
PLpgSQL_expr * expr);
|
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
|
* Generate a prepared plan
|
||||||
* returning any data.
|
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
static int
|
static void
|
||||||
exec_stmt_execsql(PLpgSQL_execstate * estate,
|
exec_prepare_plan(PLpgSQL_execstate * estate,
|
||||||
PLpgSQL_stmt_execsql * stmt)
|
PLpgSQL_expr * expr)
|
||||||
{
|
{
|
||||||
PLpgSQL_var *var;
|
PLpgSQL_var *var;
|
||||||
PLpgSQL_rec *rec;
|
PLpgSQL_rec *rec;
|
||||||
PLpgSQL_recfield *recfield;
|
PLpgSQL_recfield *recfield;
|
||||||
PLpgSQL_trigarg *trigarg;
|
|
||||||
int tgargno;
|
|
||||||
Oid tgargoid;
|
|
||||||
int fno;
|
|
||||||
int i;
|
int i;
|
||||||
Datum *values;
|
int fno;
|
||||||
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)
|
|
||||||
{
|
|
||||||
void *plan;
|
void *plan;
|
||||||
Oid *argtypes;
|
Oid *argtypes;
|
||||||
|
|
||||||
|
/* ----------
|
||||||
|
* Setup the argtypes array
|
||||||
|
* ----------
|
||||||
|
*/
|
||||||
argtypes = malloc(sizeof(Oid *) * (expr->nparams + 1));
|
argtypes = malloc(sizeof(Oid *) * (expr->nparams + 1));
|
||||||
|
|
||||||
for (i = 0; i < expr->nparams; i++)
|
for (i = 0; i < expr->nparams; i++)
|
||||||
@ -1715,17 +1714,54 @@ exec_stmt_execsql(PLpgSQL_execstate * estate,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
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);
|
plan = SPI_prepare(expr->query, expr->nparams, argtypes);
|
||||||
if (plan == NULL)
|
if (plan == NULL)
|
||||||
elog(ERROR, "SPI_prepare() failed on \"%s\"", expr->query);
|
elog(ERROR, "SPI_prepare() failed on \"%s\"", expr->query);
|
||||||
expr->plan = SPI_saveplan(plan);
|
expr->plan = SPI_saveplan(plan);
|
||||||
expr->plan_argtypes = argtypes;
|
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()
|
* Now build up the values and nulls arguments for SPI_execp()
|
||||||
* ----------
|
* ----------
|
||||||
@ -1987,6 +2023,21 @@ exec_eval_expr(PLpgSQL_execstate * estate,
|
|||||||
{
|
{
|
||||||
int rc;
|
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);
|
rc = exec_run_select(estate, expr, 2);
|
||||||
if (rc != SPI_OK_SELECT)
|
if (rc != SPI_OK_SELECT)
|
||||||
elog(ERROR, "query \"%s\" didn't return data", expr->query);
|
elog(ERROR, "query \"%s\" didn't return data", expr->query);
|
||||||
@ -2045,56 +2096,7 @@ exec_run_select(PLpgSQL_execstate * estate,
|
|||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
if (expr->plan == NULL)
|
if (expr->plan == NULL)
|
||||||
{
|
exec_prepare_plan(estate, expr);
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* Now build up the values and nulls arguments for SPI_execp()
|
* 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
|
* exec_move_row Move one tuples values into a
|
||||||
* record or row
|
* 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
|
* exec_set_found Set the global found variable
|
||||||
* to true/false
|
* to true/false
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
* procedural language
|
* procedural language
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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.
|
* This software is copyrighted by Jan Wieck - Hamburg.
|
||||||
*
|
*
|
||||||
@ -143,6 +143,8 @@ typedef struct
|
|||||||
int exprno;
|
int exprno;
|
||||||
char *query;
|
char *query;
|
||||||
void *plan;
|
void *plan;
|
||||||
|
Node *plan_simple_expr;
|
||||||
|
Oid plan_simple_type;
|
||||||
Oid *plan_argtypes;
|
Oid *plan_argtypes;
|
||||||
int nparams;
|
int nparams;
|
||||||
int params[1];
|
int params[1];
|
||||||
|
Loading…
x
Reference in New Issue
Block a user