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

📄 pl_exec.c

📁 关系型数据库 Postgresql 6.5.2
💻 C
📖 第 1 页 / 共 4 页
字号:
/********************************************************************** * pl_exec.c		- Executor for the PL/pgSQL *			  procedural language * * IDENTIFICATION *	  $Header: /usr/local/cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.12 1999/07/04 01:03:01 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 <stdio.h>#include <stdlib.h>#include <stdarg.h>#include <unistd.h>#include <fcntl.h>#include <string.h>#include <ctype.h>#include <setjmp.h>#include "plpgsql.h"#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"#include "fmgr.h"#include "access/heapam.h"#include "tcop/tcopprot.h"#include "utils/syscache.h"#include "catalog/pg_proc.h"#include "catalog/pg_type.h"static PLpgSQL_function *error_info_func = NULL;static PLpgSQL_stmt *error_info_stmt = NULL;static char *error_info_text = NULL;/************************************************************ * Local function forward declarations ************************************************************/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_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_exit(PLpgSQL_execstate * estate,			   PLpgSQL_stmt_exit * stmt);static int exec_stmt_return(PLpgSQL_execstate * estate,				 PLpgSQL_stmt_return * 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 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);static void exec_assign_value(PLpgSQL_execstate * estate,				  PLpgSQL_datum * target,				  Datum value, Oid valtype, 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);static void exec_move_row(PLpgSQL_execstate * estate,			  PLpgSQL_rec * rec,			  PLpgSQL_row * row,			  HeapTuple tup, TupleDesc tupdesc);static Datum exec_cast_value(Datum value, Oid valtype,				Oid reqtype,				FmgrInfo *reqinput,				int16 reqtypmod,				bool *isnull);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,					  FmgrValues *args, bool *isNull){	PLpgSQL_execstate estate;	int			i;	sigjmp_buf	save_restart;	PLpgSQL_function *save_efunc;	PLpgSQL_stmt *save_estmt;	char	   *save_etext;	/* ----------	 * Setup debug error info and catch elog()	 * ----------	 */	save_efunc = error_info_func;	save_estmt = error_info_stmt;	save_etext = error_info_text;	error_info_func = func;	error_info_stmt = NULL;	error_info_text = "while initialization of execution state";	memcpy(&save_restart, &Warn_restart, sizeof(save_restart));	if (sigsetjmp(Warn_restart, 1) != 0)	{		memcpy(&Warn_restart, &save_restart, sizeof(Warn_restart));		/* ----------		 * If we are the first of cascaded error catchings,		 * print where this happened		 * ----------		 */		if (error_info_func != NULL)		{			elog(DEBUG, "Last error occured while executing PL/pgSQL function %s",				 error_info_func->fn_name);			if (error_info_stmt != NULL)			{				char	   *stmttype;				switch (error_info_stmt->cmd_type)				{					case PLPGSQL_STMT_BLOCK:						stmttype = "blocks variable initialization";						break;					case PLPGSQL_STMT_ASSIGN:						stmttype = "assignment";						break;					case PLPGSQL_STMT_IF:						stmttype = "if";						break;					case PLPGSQL_STMT_LOOP:						stmttype = "loop";						break;					case PLPGSQL_STMT_WHILE:						stmttype = "while";						break;					case PLPGSQL_STMT_FORI:						stmttype = "for with integer loopvar";						break;					case PLPGSQL_STMT_FORS:						stmttype = "for over select rows";						break;					case PLPGSQL_STMT_SELECT:						stmttype = "select into variables";						break;					case PLPGSQL_STMT_EXIT:						stmttype = "exit";						break;					case PLPGSQL_STMT_RETURN:						stmttype = "return";						break;					case PLPGSQL_STMT_RAISE:						stmttype = "raise";						break;					case PLPGSQL_STMT_EXECSQL:						stmttype = "SQL statement";						break;					default:						stmttype = "unknown";						break;				}				elog(DEBUG, "line %d at %s", error_info_stmt->lineno,					 stmttype);			}			else			{				if (error_info_text != NULL)					elog(DEBUG, "%s", error_info_text);				else					elog(DEBUG, "no more error information available");			}			error_info_func = NULL;			error_info_stmt = NULL;			error_info_text = NULL;		}		siglongjmp(Warn_restart, 1);	}	/* ----------	 * Setup the execution state	 * ----------	 */	estate.retval = 0;	estate.retisnull = false;	estate.rettype = InvalidOid;	estate.retistuple = func->fn_retistuple;	estate.retisset = func->fn_retset;	estate.exitlabel = NULL;	estate.found_varno = func->found_varno;	estate.ndatums = func->ndatums;	estate.datums = palloc(sizeof(PLpgSQL_datum *) * estate.ndatums);	/* ----------	 * Make local execution copies of all the datums	 * ----------	 */	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:				estate.datums[i] = func->datums[i];				break;			default:				elog(ERROR, "unknown dtype %d in plpgsql_exec_function()",					 func->datums[i]->dtype);		}	}	/* ----------	 * Put the actual call argument values into the variables	 * ----------	 */	error_info_text = "while putting call arguments to 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 = (Datum) (args->data[i]);					var->isnull = *isNull;					var->shouldfree = false;				}				break;			case PLPGSQL_DTYPE_ROW:				{					HeapTuple	tup;					TupleDesc	tupdesc;					PLpgSQL_row *row = (PLpgSQL_row *) estate.datums[n];					tup = ((TupleTableSlot *) (args->data[i]))->val;					tupdesc = ((TupleTableSlot *) (args->data[i]))->ttc_tupleDescriptor;					exec_move_row(&estate, NULL, row, tup, tupdesc);				}				break;			default:				elog(ERROR, "unknown dtype %d in plpgsql_exec_function()",					 func->datums[i]->dtype);		}	}	/* ----------	 * Initialize the other variables to NULL values for now.	 * The default values are set when the blocks are entered.	 * ----------	 */	error_info_text = "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->shouldfree = false;				}				break;			case PLPGSQL_DTYPE_ROW:			case PLPGSQL_DTYPE_REC:			case PLPGSQL_DTYPE_RECFIELD:				break;			default:				elog(ERROR, "unknown dtype %d in plpgsql_exec_function()",					 func->datums[i]->dtype);		}	}	/* ----------	 * Set the magic variable FOUND to false	 * ----------	 */	exec_set_found(&estate, false);	/* ----------	 * Now call the toplevel block of statements	 * ----------	 */	error_info_text = NULL;	error_info_stmt = (PLpgSQL_stmt *) (func->action);	if (exec_stmt_block(&estate, func->action) != PLPGSQL_RC_RETURN)	{		error_info_stmt = NULL;		error_info_text = "at END of toplevel PL block";		elog(ERROR, "control reaches end of function without RETURN");	}	/* ----------	 * We got a return value - process it	 * ----------	 */	error_info_stmt = NULL;	error_info_text = "while casting return value to functions return type";	*isNull = estate.retisnull;	if (!estate.retistuple)	{		estate.retval = exec_cast_value(estate.retval, estate.rettype,							  func->fn_rettype, &(func->fn_retinput), -1,										isNull);		/* ----------		 * If the functions return type isn't by value,		 * copy the value into upper executor memory context.		 * ----------		 */		if (!*isNull && !func->fn_retbyval)		{			int			len;			Datum		tmp;			if (func->fn_rettyplen < 0)				len = VARSIZE(estate.retval);			else				len = func->fn_rettyplen;			tmp = (Datum) SPI_palloc(len);			memcpy((void *) tmp, (void *) estate.retval, len);			estate.retval = tmp;		}	}	/* ----------	 * Restore the previous error info and elog() jump target	 * ----------	 */	error_info_func = save_efunc;	error_info_stmt = save_estmt;	error_info_text = save_etext;	memcpy(&Warn_restart, &save_restart, sizeof(Warn_restart));	/* ----------	 * 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;	int			i;	sigjmp_buf	save_restart;	PLpgSQL_function *save_efunc;	PLpgSQL_stmt *save_estmt;	char	   *save_etext;	PLpgSQL_rec *rec_new;	PLpgSQL_rec *rec_old;	PLpgSQL_var *var;	HeapTuple	rettup;	/* ----------	 * Setup debug error info and catch elog()	 * ----------	 */	save_efunc = error_info_func;	save_estmt = error_info_stmt;	save_etext = error_info_text;	error_info_func = func;	error_info_stmt = NULL;	error_info_text = "while initialization of execution state";	memcpy(&save_restart, &Warn_restart, sizeof(save_restart));	if (sigsetjmp(Warn_restart, 1) != 0)	{		memcpy(&Warn_restart, &save_restart, sizeof(Warn_restart));		/* ----------		 * If we are the first of cascaded error catchings,		 * print where this happened		 * ----------		 */		if (error_info_func != NULL)		{			elog(DEBUG, "Last error occured while executing PL/pgSQL function %s",				 error_info_func->fn_name);			if (error_info_stmt != NULL)			{				char	   *stmttype;				switch (error_info_stmt->cmd_type)				{					case PLPGSQL_STMT_BLOCK:						stmttype = "blocks variable initialization";						break;					case PLPGSQL_STMT_ASSIGN:						stmttype = "assignment";						break;					case PLPGSQL_STMT_IF:						stmttype = "if";						break;					case PLPGSQL_STMT_LOOP:						stmttype = "loop";						break;					case PLPGSQL_STMT_WHILE:						stmttype = "while";						break;					case PLPGSQL_STMT_FORI:						stmttype = "for with integer loopvar";						break;					case PLPGSQL_STMT_FORS:						stmttype = "for over select rows";						break;					case PLPGSQL_STMT_SELECT:						stmttype = "select into variables";						break;					case PLPGSQL_STMT_EXIT:						stmttype = "exit";						break;					case PLPGSQL_STMT_RETURN:						stmttype = "return";						break;					case PLPGSQL_STMT_RAISE:						stmttype = "raise";						break;					case PLPGSQL_STMT_EXECSQL:						stmttype = "SQL statement";						break;					default:						stmttype = "unknown";						break;				}				elog(DEBUG, "line %d at %s", error_info_stmt->lineno,					 stmttype);			}			else			{				if (error_info_text != NULL)					elog(DEBUG, "%s", error_info_text);				else					elog(DEBUG, "no more error information available");			}			error_info_func = NULL;			error_info_stmt = NULL;			error_info_text = NULL;		}		siglongjmp(Warn_restart, 1);	}	/* ----------	 * Setup the execution state	 * ----------	 */	estate.retval = 0;	estate.retisnull = false;	estate.rettype = InvalidOid;	estate.retistuple = func->fn_retistuple;	estate.retisset = func->fn_retset;	estate.exitlabel = NULL;	estate.found_varno = func->found_varno;	estate.ndatums = func->ndatums;	estate.datums = palloc(sizeof(PLpgSQL_datum *) * estate.ndatums);	/* ----------	 * Make local execution copies of all the datums	 * ----------	 */	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_TRIGARG:				estate.datums[i] = func->datums[i];				break;			default:				elog(ERROR, "unknown dtype %d in plpgsql_exec_function()",					 func->datums[i]->dtype);		}	}	/* ----------	 * Put the trig and new tuples into the records	 * and set the tg_op variable	 * ----------	 */	rec_new = (PLpgSQL_rec *) (estate.datums[func->new_varno]);	rec_old = (PLpgSQL_rec *) (estate.datums[func->old_varno]);	var = (PLpgSQL_var *) (estate.datums[func->tg_op_varno]);	var->isnull = false;	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;		var->value = (Datum) textin("INSERT");	}	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;		var->value = (Datum) textin("UPDATE");	}	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;		var->value = (Datum) textin("DELETE");	}	else	{		rec_new->tup = NULL;		rec_new->tupdesc = NULL;		var->value = (Datum) textin("UNKNOWN");	}	/* ----------	 * Fill all the other special tg_ variables	 * ----------	 */	var = (PLpgSQL_var *) (estate.datums[func->tg_name_varno]);	var->isnull = false;	var->value = (Datum) namein(trigdata->tg_trigger->tgname);	var = (PLpgSQL_var *) (estate.datums[func->tg_when_varno]);	var->isnull = false;	if (TRIGGER_FIRED_BEFORE(trigdata->tg_event))		var->value = (Datum) textin("BEFORE");	else if (TRIGGER_FIRED_AFTER(trigdata->tg_event))		var->value = (Datum) textin("AFTER");	else		var->value = (Datum) textin("UNKNOWN");	var = (PLpgSQL_var *) (estate.datums[func->tg_level_varno]);	var->isnull = false;	if (TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))		var->value = (Datum) textin("ROW");

⌨️ 快捷键说明

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