⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pl_exec.c

📁 PostgreSQL7.4.6 for Linux
💻 C
📖 第 1 页 / 共 5 页
字号:
/********************************************************************** * pl_exec.c		- Executor for the PL/pgSQL *			  procedural language * * IDENTIFICATION *	  $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.93.2.1 2004/02/24 01:44:47 tgl Exp $ * *	  This software is copyrighted by Jan Wieck - Hamburg. * *	  The author hereby grants permission  to  use,  copy,	modify, *	  distribute,  and	license this software and its documentation *	  for any purpose, provided that existing copyright notices are *	  retained	in	all  copies  and  that	this notice is included *	  verbatim in any distributions. No written agreement, license, *	  or  royalty  fee	is required for any of the authorized uses. *	  Modifications to this software may be  copyrighted  by  their *	  author  and  need  not  follow  the licensing terms described *	  here, provided that the new terms are  clearly  indicated  on *	  the first page of each file where they apply. * *	  IN NO EVENT SHALL THE AUTHOR OR DISTRIBUTORS BE LIABLE TO ANY *	  PARTY  FOR  DIRECT,	INDIRECT,	SPECIAL,   INCIDENTAL,	 OR *	  CONSEQUENTIAL   DAMAGES  ARISING	OUT  OF  THE  USE  OF  THIS *	  SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN *	  IF  THE  AUTHOR  HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH *	  DAMAGE. * *	  THE  AUTHOR  AND	DISTRIBUTORS  SPECIFICALLY	 DISCLAIM	ANY *	  WARRANTIES,  INCLUDING,  BUT	NOT  LIMITED  TO,  THE	IMPLIED *	  WARRANTIES  OF  MERCHANTABILITY,	FITNESS  FOR  A  PARTICULAR *	  PURPOSE,	AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON *	  AN "AS IS" BASIS, AND THE AUTHOR	AND  DISTRIBUTORS  HAVE  NO *	  OBLIGATION   TO	PROVIDE   MAINTENANCE,	 SUPPORT,  UPDATES, *	  ENHANCEMENTS, OR MODIFICATIONS. * **********************************************************************/#include "plpgsql.h"#include "pl.tab.h"#include <ctype.h>#include <setjmp.h>#include "access/heapam.h"#include "catalog/pg_proc.h"#include "catalog/pg_type.h"#include "executor/spi_priv.h"#include "funcapi.h"#include "optimizer/clauses.h"#include "parser/parse_expr.h"#include "tcop/tcopprot.h"#include "utils/array.h"#include "utils/builtins.h"#include "utils/lsyscache.h"static const char *const raise_skip_msg = "RAISE";/* * All plpgsql function executions within a single transaction share * the same executor EState for evaluating "simple" expressions.  Each * function call creates its own "eval_econtext" ExprContext within this * estate.  We destroy the estate at transaction shutdown to ensure there * is no permanent leakage of memory (especially for xact abort case). * * If a simple PLpgSQL_expr has been used in the current xact, it is * linked into the active_simple_exprs list. */static EState *simple_eval_estate = NULL;static PLpgSQL_expr *active_simple_exprs = NULL;/************************************************************ * Local function forward declarations ************************************************************/static void plpgsql_exec_error_callback(void *arg);static PLpgSQL_var *copy_var(PLpgSQL_var * var);static PLpgSQL_rec *copy_rec(PLpgSQL_rec * rec);static int exec_stmt_block(PLpgSQL_execstate * estate,				PLpgSQL_stmt_block * block);static int exec_stmts(PLpgSQL_execstate * estate,		   PLpgSQL_stmts * stmts);static int exec_stmt(PLpgSQL_execstate * estate,		  PLpgSQL_stmt * stmt);static int exec_stmt_assign(PLpgSQL_execstate * estate,				 PLpgSQL_stmt_assign * stmt);static int exec_stmt_perform(PLpgSQL_execstate * estate,				  PLpgSQL_stmt_perform * stmt);static int exec_stmt_getdiag(PLpgSQL_execstate * estate,				  PLpgSQL_stmt_getdiag * stmt);static int exec_stmt_if(PLpgSQL_execstate * estate,			 PLpgSQL_stmt_if * stmt);static int exec_stmt_loop(PLpgSQL_execstate * estate,			   PLpgSQL_stmt_loop * stmt);static int exec_stmt_while(PLpgSQL_execstate * estate,				PLpgSQL_stmt_while * stmt);static int exec_stmt_fori(PLpgSQL_execstate * estate,			   PLpgSQL_stmt_fori * stmt);static int exec_stmt_fors(PLpgSQL_execstate * estate,			   PLpgSQL_stmt_fors * stmt);static int exec_stmt_select(PLpgSQL_execstate * estate,				 PLpgSQL_stmt_select * stmt);static int exec_stmt_open(PLpgSQL_execstate * estate,			   PLpgSQL_stmt_open * stmt);static int exec_stmt_fetch(PLpgSQL_execstate * estate,				PLpgSQL_stmt_fetch * stmt);static int exec_stmt_close(PLpgSQL_execstate * estate,				PLpgSQL_stmt_close * stmt);static int exec_stmt_exit(PLpgSQL_execstate * estate,			   PLpgSQL_stmt_exit * stmt);static int exec_stmt_return(PLpgSQL_execstate * estate,				 PLpgSQL_stmt_return * stmt);static int exec_stmt_return_next(PLpgSQL_execstate * estate,					  PLpgSQL_stmt_return_next * stmt);static int exec_stmt_raise(PLpgSQL_execstate * estate,				PLpgSQL_stmt_raise * stmt);static int exec_stmt_execsql(PLpgSQL_execstate * estate,				  PLpgSQL_stmt_execsql * stmt);static int exec_stmt_dynexecute(PLpgSQL_execstate * estate,					 PLpgSQL_stmt_dynexecute * stmt);static int exec_stmt_dynfors(PLpgSQL_execstate * estate,				  PLpgSQL_stmt_dynfors * stmt);static void plpgsql_estate_setup(PLpgSQL_execstate * estate,					 PLpgSQL_function * func,					 ReturnSetInfo *rsi);static void exec_eval_cleanup(PLpgSQL_execstate * estate);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 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);static void exec_assign_value(PLpgSQL_execstate * estate,				  PLpgSQL_datum * target,				  Datum value, Oid valtype, bool *isNull);static void exec_eval_datum(PLpgSQL_execstate * estate,				PLpgSQL_datum * datum,				Oid expectedtypeid,				Oid *typeid,				Datum *value,				bool *isnull);static int exec_eval_integer(PLpgSQL_execstate * estate,					PLpgSQL_expr * expr,					bool *isNull);static bool exec_eval_boolean(PLpgSQL_execstate * estate,							  PLpgSQL_expr * expr,							  bool *isNull);static Datum exec_eval_expr(PLpgSQL_execstate * estate,			   PLpgSQL_expr * expr,			   bool *isNull,			   Oid *rettype);static int exec_run_select(PLpgSQL_execstate * estate,				PLpgSQL_expr * expr, int maxtuples, Portal *portalP);static void exec_move_row(PLpgSQL_execstate * estate,			  PLpgSQL_rec * rec,			  PLpgSQL_row * row,			  HeapTuple tup, TupleDesc tupdesc);static HeapTuple make_tuple_from_row(PLpgSQL_execstate * estate,									 PLpgSQL_row * row,									 TupleDesc tupdesc);static char *convert_value_to_string(Datum value, Oid valtype);static Datum exec_cast_value(Datum value, Oid valtype,				Oid reqtype,				FmgrInfo *reqinput,				Oid reqtypelem,				int32 reqtypmod,				bool *isnull);static Datum exec_simple_cast_value(Datum value, Oid valtype,					   Oid reqtype, int32 reqtypmod,					   bool *isnull);static void exec_init_tuple_store(PLpgSQL_execstate * estate);static bool compatible_tupdesc(TupleDesc td1, TupleDesc td2);static void exec_set_found(PLpgSQL_execstate * estate, bool state);/* ---------- * plpgsql_exec_function	Called by the call handler for *				function execution. * ---------- */Datumplpgsql_exec_function(PLpgSQL_function * func, FunctionCallInfo fcinfo){	PLpgSQL_execstate estate;	ErrorContextCallback plerrcontext;	int			i;	/*	 * Setup the execution state	 */	plpgsql_estate_setup(&estate, func, (ReturnSetInfo *) fcinfo->resultinfo);	/*	 * Setup error traceback support for ereport()	 */	plerrcontext.callback = plpgsql_exec_error_callback;	plerrcontext.arg = &estate;	plerrcontext.previous = error_context_stack;	error_context_stack = &plerrcontext;	/*	 * Make local execution copies of all the datums	 */	estate.err_text = gettext_noop("during initialization of execution state");	for (i = 0; i < func->ndatums; i++)	{		switch (func->datums[i]->dtype)		{			case PLPGSQL_DTYPE_VAR:				estate.datums[i] = (PLpgSQL_datum *)					copy_var((PLpgSQL_var *) (func->datums[i]));				break;			case PLPGSQL_DTYPE_REC:				estate.datums[i] = (PLpgSQL_datum *)					copy_rec((PLpgSQL_rec *) (func->datums[i]));				break;			case PLPGSQL_DTYPE_ROW:			case PLPGSQL_DTYPE_RECFIELD:			case PLPGSQL_DTYPE_ARRAYELEM:				estate.datums[i] = func->datums[i];				break;			default:				elog(ERROR, "unrecognized dtype: %d", func->datums[i]->dtype);		}	}	/*	 * Store the actual call argument values into the variables	 */	estate.err_text = gettext_noop("while storing call arguments into local variables");	for (i = 0; i < func->fn_nargs; i++)	{		int			n = func->fn_argvarnos[i];		switch (estate.datums[n]->dtype)		{			case PLPGSQL_DTYPE_VAR:				{					PLpgSQL_var *var = (PLpgSQL_var *) estate.datums[n];					var->value = fcinfo->arg[i];					var->isnull = fcinfo->argnull[i];					var->freeval = false;				}				break;			case PLPGSQL_DTYPE_ROW:				{					PLpgSQL_row *row = (PLpgSQL_row *) estate.datums[n];					TupleTableSlot *slot = (TupleTableSlot *) fcinfo->arg[i];					HeapTuple	tup;					TupleDesc	tupdesc;					if (!fcinfo->argnull[i])					{						Assert(slot != NULL);						tup = slot->val;						tupdesc = slot->ttc_tupleDescriptor;						exec_move_row(&estate, NULL, row, tup, tupdesc);					}					else					{						/* If arg is null, treat it as an empty row */						exec_move_row(&estate, NULL, row, NULL, NULL);					}				}				break;			default:				elog(ERROR, "unrecognized dtype: %d", func->datums[i]->dtype);		}	}	/*	 * Initialize the other variables to NULL values for now. The default	 * values are set when the blocks are entered.	 */	estate.err_text = gettext_noop("while initializing local variables to NULL");	for (i = estate.found_varno; i < estate.ndatums; i++)	{		switch (estate.datums[i]->dtype)		{			case PLPGSQL_DTYPE_VAR:				{					PLpgSQL_var *var = (PLpgSQL_var *) estate.datums[i];					var->value = 0;					var->isnull = true;					var->freeval = false;				}				break;			case PLPGSQL_DTYPE_ROW:			case PLPGSQL_DTYPE_REC:			case PLPGSQL_DTYPE_RECFIELD:			case PLPGSQL_DTYPE_ARRAYELEM:				break;			default:				elog(ERROR, "unrecognized dtype: %d", func->datums[i]->dtype);		}	}	/*	 * Set the magic variable FOUND to false	 */	exec_set_found(&estate, false);	/*	 * Now call the toplevel block of statements	 */	estate.err_text = NULL;	estate.err_stmt = (PLpgSQL_stmt *) (func->action);	if (exec_stmt_block(&estate, func->action) != PLPGSQL_RC_RETURN)	{		estate.err_stmt = NULL;		estate.err_text = NULL;		ereport(ERROR,		   (errcode(ERRCODE_S_R_E_FUNCTION_EXECUTED_NO_RETURN_STATEMENT),			errmsg("control reached end of function without RETURN")));	}	/*	 * We got a return value - process it	 */	estate.err_stmt = NULL;	estate.err_text = gettext_noop("while casting return value to function's return type");	fcinfo->isnull = estate.retisnull;	if (estate.retisset)	{		ReturnSetInfo *rsi = estate.rsi;		/* Check caller can handle a set result */		if (!rsi || !IsA(rsi, ReturnSetInfo) ||			(rsi->allowedModes & SFRM_Materialize) == 0)			ereport(ERROR,					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),					 errmsg("set-valued function called in context that cannot accept a set")));		rsi->returnMode = SFRM_Materialize;		/* If we produced any tuples, send back the result */		if (estate.tuple_store)		{			rsi->setResult = estate.tuple_store;			if (estate.rettupdesc)			{				MemoryContext oldcxt;				oldcxt = MemoryContextSwitchTo(estate.tuple_store_cxt);				rsi->setDesc = CreateTupleDescCopy(estate.rettupdesc);				MemoryContextSwitchTo(oldcxt);			}		}		estate.retval = (Datum) 0;		fcinfo->isnull = true;	}	else if (!estate.retisnull)	{		if (estate.retistuple)		{			/* Copy tuple to upper executor memory */			/* Here we need to return a TupleTableSlot not just a tuple */			estate.retval = (Datum)				SPI_copytupleintoslot((HeapTuple) (estate.retval),									  estate.rettupdesc);		}		else		{			/* Cast value to proper type */			estate.retval = exec_cast_value(estate.retval, estate.rettype,											func->fn_rettype,											&(func->fn_retinput),											func->fn_rettypelem,											-1,											&fcinfo->isnull);			/*			 * If the functions return type isn't by value, copy the value			 * into upper executor memory context.			 */			if (!fcinfo->isnull && !func->fn_retbyval)			{				Size		len;				void	   *tmp;				len = datumGetSize(estate.retval, false, func->fn_rettyplen);				tmp = (void *) SPI_palloc(len);				memcpy(tmp, DatumGetPointer(estate.retval), len);				estate.retval = PointerGetDatum(tmp);			}		}	}	/* Clean up any leftover temporary memory */	if (estate.eval_econtext != NULL)		FreeExprContext(estate.eval_econtext);	estate.eval_econtext = NULL;	exec_eval_cleanup(&estate);	/*	 * Pop the error context stack	 */	error_context_stack = plerrcontext.previous;	/*	 * Return the functions result	 */	return estate.retval;}/* ---------- * plpgsql_exec_trigger		Called by the call handler for *				trigger execution. * ---------- */HeapTupleplpgsql_exec_trigger(PLpgSQL_function * func,					 TriggerData *trigdata){	PLpgSQL_execstate estate;	ErrorContextCallback plerrcontext;	int			i;	PLpgSQL_var *var;	PLpgSQL_rec *rec_new,			   *rec_old;	HeapTuple	rettup;	/*	 * Setup the execution state	 */	plpgsql_estate_setup(&estate, func, NULL);	/*	 * Setup error traceback support for ereport()	 */	plerrcontext.callback = plpgsql_exec_error_callback;	plerrcontext.arg = &estate;	plerrcontext.previous = error_context_stack;	error_context_stack = &plerrcontext;	/*	 * Make local execution copies of all the datums	 */	estate.err_text = gettext_noop("during initialization of execution state");	for (i = 0; i < func->ndatums; i++)	{		switch (func->datums[i]->dtype)		{			case PLPGSQL_DTYPE_VAR:				estate.datums[i] = (PLpgSQL_datum *)					copy_var((PLpgSQL_var *) (func->datums[i]));				break;			case PLPGSQL_DTYPE_REC:				estate.datums[i] = (PLpgSQL_datum *)					copy_rec((PLpgSQL_rec *) (func->datums[i]));				break;			case PLPGSQL_DTYPE_ROW:			case PLPGSQL_DTYPE_RECFIELD:			case PLPGSQL_DTYPE_ARRAYELEM:			case PLPGSQL_DTYPE_TRIGARG:				estate.datums[i] = func->datums[i];				break;			default:				elog(ERROR, "unrecognized dtype: %d", func->datums[i]->dtype);		}	}	/*	 * Put the OLD and NEW tuples into record variables	 */	rec_new = (PLpgSQL_rec *) (estate.datums[func->new_varno]);	rec_new->freetup = false;	rec_new->freetupdesc = false;	rec_old = (PLpgSQL_rec *) (estate.datums[func->old_varno]);	rec_old->freetup = false;	rec_old->freetupdesc = false;	if (TRIGGER_FIRED_FOR_STATEMENT(trigdata->tg_event))	{		/*		 * Per-statement triggers don't use OLD/NEW variables		 */		rec_new->tup = NULL;		rec_new->tupdesc = NULL;		rec_old->tup = NULL;		rec_old->tupdesc = NULL;	}	else if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))	{		rec_new->tup = trigdata->tg_trigtuple;		rec_new->tupdesc = trigdata->tg_relation->rd_att;		rec_old->tup = NULL;		rec_old->tupdesc = NULL;	}	else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))	{		rec_new->tup = trigdata->tg_newtuple;		rec_new->tupdesc = trigdata->tg_relation->rd_att;		rec_old->tup = trigdata->tg_trigtuple;		rec_old->tupdesc = trigdata->tg_relation->rd_att;	}	else if (TRIGGER_FIRED_BY_DELETE(trigdata->tg_event))	{		rec_new->tup = NULL;		rec_new->tupdesc = NULL;		rec_old->tup = trigdata->tg_trigtuple;		rec_old->tupdesc = trigdata->tg_relation->rd_att;	}	else		elog(ERROR, "unrecognized trigger action: not INSERT, DELETE, or UPDATE");	/*	 * Assign the special tg_ variables

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -