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

📄 pl_exec.c

📁 PostgreSQL7.4.6 for Linux
💻 C
📖 第 1 页 / 共 5 页
字号:
	 */	var = (PLpgSQL_var *) (estate.datums[func->tg_op_varno]);	var->isnull = false;	var->freeval = false;	if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))		var->value = DirectFunctionCall1(textin, CStringGetDatum("INSERT"));	else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))		var->value = DirectFunctionCall1(textin, CStringGetDatum("UPDATE"));	else if (TRIGGER_FIRED_BY_DELETE(trigdata->tg_event))		var->value = DirectFunctionCall1(textin, CStringGetDatum("DELETE"));	else		elog(ERROR, "unrecognized trigger action: not INSERT, DELETE, or UPDATE");	var = (PLpgSQL_var *) (estate.datums[func->tg_name_varno]);	var->isnull = false;	var->freeval = true;	var->value = DirectFunctionCall1(namein,						  CStringGetDatum(trigdata->tg_trigger->tgname));	var = (PLpgSQL_var *) (estate.datums[func->tg_when_varno]);	var->isnull = false;	var->freeval = true;	if (TRIGGER_FIRED_BEFORE(trigdata->tg_event))		var->value = DirectFunctionCall1(textin, CStringGetDatum("BEFORE"));	else if (TRIGGER_FIRED_AFTER(trigdata->tg_event))		var->value = DirectFunctionCall1(textin, CStringGetDatum("AFTER"));	else		elog(ERROR, "unrecognized trigger execution time: not BEFORE or AFTER");	var = (PLpgSQL_var *) (estate.datums[func->tg_level_varno]);	var->isnull = false;	var->freeval = true;	if (TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))		var->value = DirectFunctionCall1(textin, CStringGetDatum("ROW"));	else if (TRIGGER_FIRED_FOR_STATEMENT(trigdata->tg_event))		var->value = DirectFunctionCall1(textin, CStringGetDatum("STATEMENT"));	else		elog(ERROR, "unrecognized trigger event type: not ROW or STATEMENT");	var = (PLpgSQL_var *) (estate.datums[func->tg_relid_varno]);	var->isnull = false;	var->freeval = false;	var->value = ObjectIdGetDatum(trigdata->tg_relation->rd_id);	var = (PLpgSQL_var *) (estate.datums[func->tg_relname_varno]);	var->isnull = false;	var->freeval = true;	var->value = DirectFunctionCall1(namein,		CStringGetDatum(RelationGetRelationName(trigdata->tg_relation)));	var = (PLpgSQL_var *) (estate.datums[func->tg_nargs_varno]);	var->isnull = false;	var->freeval = false;	var->value = Int16GetDatum(trigdata->tg_trigger->tgnargs);	/*	 * Store the actual call argument values into the special execution	 * state variables	 */	estate.err_text = gettext_noop("while storing call arguments into local variables");	estate.trig_nargs = trigdata->tg_trigger->tgnargs;	if (estate.trig_nargs == 0)		estate.trig_argv = NULL;	else	{		estate.trig_argv = palloc(sizeof(Datum) * estate.trig_nargs);		for (i = 0; i < trigdata->tg_trigger->tgnargs; i++)			estate.trig_argv[i] = DirectFunctionCall1(textin,					   CStringGetDatum(trigdata->tg_trigger->tgargs[i]));	}	/*	 * 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:			case PLPGSQL_DTYPE_TRIGARG:				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 trigger procedure without RETURN")));	}	if (estate.retisset)		ereport(ERROR,				(errcode(ERRCODE_DATATYPE_MISMATCH),				 errmsg("trigger procedure cannot return a set")));	/*	 * Check that the returned tuple structure has the same attributes,	 * the relation that fired the trigger has. A per-statement trigger	 * always needs to return NULL, so we ignore any return value the	 * function itself produces (XXX: is this a good idea?)	 *	 * XXX This way it is possible, that the trigger returns a tuple where	 * attributes don't have the correct atttypmod's length. It's up to	 * the trigger's programmer to ensure that this doesn't happen. Jan	 */	if (estate.retisnull || TRIGGER_FIRED_FOR_STATEMENT(trigdata->tg_event))		rettup = NULL;	else	{		if (!compatible_tupdesc(estate.rettupdesc,								trigdata->tg_relation->rd_att))			ereport(ERROR,					(errcode(ERRCODE_DATATYPE_MISMATCH),					 errmsg("returned tuple structure does not match table of trigger event")));		/* Copy tuple to upper executor memory */		rettup = SPI_copytuple((HeapTuple) (estate.retval));	}	/* 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 triggers result	 */	return rettup;}/* * error context callback to let us supply a call-stack traceback */static voidplpgsql_exec_error_callback(void *arg){	PLpgSQL_execstate *estate = (PLpgSQL_execstate *) arg;	/* safety check, shouldn't happen */	if (estate->err_func == NULL)		return;	/* if we are doing RAISE, don't report its location */	if (estate->err_text == raise_skip_msg)		return;	if (estate->err_stmt != NULL)	{		/* translator: last %s is a plpgsql statement type name */		errcontext("PL/pgSQL function \"%s\" line %d at %s",				   estate->err_func->fn_name,				   estate->err_stmt->lineno,				   plpgsql_stmt_typename(estate->err_stmt));	}	else if (estate->err_text != NULL)	{		/*		 * We don't expend the cycles to run gettext() on err_text unless		 * we actually need it.  Therefore, places that set up err_text		 * should use gettext_noop() to ensure the strings get recorded in		 * the message dictionary.		 */		/*		 * translator: last %s is a phrase such as "while storing call		 * arguments into local variables"		 */		errcontext("PL/pgSQL function \"%s\" %s",				   estate->err_func->fn_name,				   gettext(estate->err_text));	}	else		errcontext("PL/pgSQL function \"%s\"",				   estate->err_func->fn_name);}/* ---------- * Support functions for copying local execution variables * ---------- */static PLpgSQL_var *copy_var(PLpgSQL_var * var){	PLpgSQL_var *new = palloc(sizeof(PLpgSQL_var));	memcpy(new, var, sizeof(PLpgSQL_var));	new->freeval = false;	return new;}static PLpgSQL_rec *copy_rec(PLpgSQL_rec * rec){	PLpgSQL_rec *new = palloc(sizeof(PLpgSQL_rec));	memcpy(new, rec, sizeof(PLpgSQL_rec));	new->tup = NULL;	new->tupdesc = NULL;	new->freetup = false;	new->freetupdesc = false;	return new;}/* ---------- * exec_stmt_block			Execute a block of statements * ---------- */static intexec_stmt_block(PLpgSQL_execstate * estate, PLpgSQL_stmt_block * block){	int			rc;	int			i;	int			n;	/*	 * First initialize all variables declared in this block	 */	for (i = 0; i < block->n_initvars; i++)	{		n = block->initvarnos[i];		switch (estate->datums[n]->dtype)		{			case PLPGSQL_DTYPE_VAR:				{					PLpgSQL_var *var = (PLpgSQL_var *) (estate->datums[n]);					if (var->freeval)					{						pfree((void *) (var->value));						var->freeval = false;					}					if (!var->isconst || var->isnull)					{						if (var->default_val == NULL)						{							var->value = (Datum) 0;							var->isnull = true;							if (var->notnull)								ereport(ERROR,								(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),								 errmsg("variable \"%s\" declared NOT NULL cannot default to NULL",										var->refname)));						}						else						{							exec_assign_expr(estate, (PLpgSQL_datum *) var,											 var->default_val);						}					}				}				break;			case PLPGSQL_DTYPE_REC:				{					PLpgSQL_rec *rec = (PLpgSQL_rec *) (estate->datums[n]);					if (rec->freetup)					{						heap_freetuple(rec->tup);						FreeTupleDesc(rec->tupdesc);						rec->freetup = false;					}					rec->tup = NULL;					rec->tupdesc = NULL;				}				break;			case PLPGSQL_DTYPE_RECFIELD:			case PLPGSQL_DTYPE_ARRAYELEM:				break;			default:				elog(ERROR, "unrecognized dtype: %d",					 estate->datums[n]->dtype);		}	}	/*	 * Execute the statements in the block's body	 */	rc = exec_stmts(estate, block->body);	/*	 * Handle the return code.	 */	switch (rc)	{		case PLPGSQL_RC_OK:			return PLPGSQL_RC_OK;		case PLPGSQL_RC_EXIT:			if (estate->exitlabel == NULL)				return PLPGSQL_RC_OK;			if (block->label == NULL)				return PLPGSQL_RC_EXIT;			if (strcmp(block->label, estate->exitlabel))				return PLPGSQL_RC_EXIT;			estate->exitlabel = NULL;			return PLPGSQL_RC_OK;		case PLPGSQL_RC_RETURN:			return PLPGSQL_RC_RETURN;		default:			elog(ERROR, "unrecognized rc: %d", rc);	}	return PLPGSQL_RC_OK;}/* ---------- * exec_stmts			Iterate over a list of statements *				as long as their return code is OK * ---------- */static intexec_stmts(PLpgSQL_execstate * estate, PLpgSQL_stmts * stmts){	int			rc;	int			i;	for (i = 0; i < stmts->stmts_used; i++)	{		rc = exec_stmt(estate, (PLpgSQL_stmt *) (stmts->stmts[i]));		if (rc != PLPGSQL_RC_OK)			return rc;	}	return PLPGSQL_RC_OK;}/* ---------- * exec_stmt			Distribute one statement to the statements *				type specific execution function. * ---------- */static intexec_stmt(PLpgSQL_execstate * estate, PLpgSQL_stmt * stmt){	PLpgSQL_stmt *save_estmt;	int			rc = -1;	save_estmt = estate->err_stmt;	estate->err_stmt = stmt;	CHECK_FOR_INTERRUPTS();	switch (stmt->cmd_type)	{		case PLPGSQL_STMT_BLOCK:			rc = exec_stmt_block(estate, (PLpgSQL_stmt_block *) stmt);			break;		case PLPGSQL_STMT_ASSIGN:			rc = exec_stmt_assign(estate, (PLpgSQL_stmt_assign *) stmt);			break;		case PLPGSQL_STMT_PERFORM:			rc = exec_stmt_perform(estate, (PLpgSQL_stmt_perform *) stmt);			break;		case PLPGSQL_STMT_GETDIAG:			rc = exec_stmt_getdiag(estate, (PLpgSQL_stmt_getdiag *) stmt);			break;		case PLPGSQL_STMT_IF:			rc = exec_stmt_if(estate, (PLpgSQL_stmt_if *) stmt);			break;		case PLPGSQL_STMT_LOOP:			rc = exec_stmt_loop(estate, (PLpgSQL_stmt_loop *) stmt);			break;		case PLPGSQL_STMT_WHILE:			rc = exec_stmt_while(estate, (PLpgSQL_stmt_while *) stmt);			break;		case PLPGSQL_STMT_FORI:			rc = exec_stmt_fori(estate, (PLpgSQL_stmt_fori *) stmt);			break;		case PLPGSQL_STMT_FORS:			rc = exec_stmt_fors(estate, (PLpgSQL_stmt_fors *) stmt);			break;		case PLPGSQL_STMT_SELECT:			rc = exec_stmt_select(estate, (PLpgSQL_stmt_select *) stmt);			break;		case PLPGSQL_STMT_EXIT:			rc = exec_stmt_exit(estate, (PLpgSQL_stmt_exit *) stmt);			break;		case PLPGSQL_STMT_RETURN:			rc = exec_stmt_return(estate, (PLpgSQL_stmt_return *) stmt);			break;		case PLPGSQL_STMT_RETURN_NEXT:			rc = exec_stmt_return_next(estate, (PLpgSQL_stmt_return_next *) stmt);			break;		case PLPGSQL_STMT_RAISE:			rc = exec_stmt_raise(estate, (PLpgSQL_stmt_raise *) stmt);			break;		case PLPGSQL_STMT_EXECSQL:			rc = exec_stmt_execsql(estate, (PLpgSQL_stmt_execsql *) stmt);			break;		case PLPGSQL_STMT_DYNEXECUTE:			rc = exec_stmt_dynexecute(estate, (PLpgSQL_stmt_dynexecute *) stmt);			break;		case PLPGSQL_STMT_DYNFORS:			rc = exec_stmt_dynfors(estate, (PLpgSQL_stmt_dynfors *) stmt);			break;		case PLPGSQL_STMT_OPEN:			rc = exec_stmt_open(estate, (PLpgSQL_stmt_open *) stmt);			break;		case PLPGSQL_STMT_FETCH:			rc = exec_stmt_fetch(estate, (PLpgSQL_stmt_fetch *) stmt);			break;		case PLPGSQL_STMT_CLOSE:			rc = exec_stmt_close(estate, (PLpgSQL_stmt_close *) stmt);			break;		default:			estate->err_stmt = save_estmt;			elog(ERROR, "unrecognized cmdtype: %d", stmt->cmd_type);	}	estate->err_stmt = save_estmt;	return rc;}/* ---------- * exec_stmt_assign			Evaluate an expression and *					put the result into a variable. * ---------- */static intexec_stmt_assign(PLpgSQL_execstate * estate, PLpgSQL_stmt_assign * stmt){	Assert(stmt->varno >= 0);	exec_assign_expr(estate, estate->datums[stmt->varno], stmt->expr);	return PLPGSQL_RC_OK;}/* ---------- * exec_stmt_perform		Evaluate query and discard result (but set *							FOUND depending on whether at least one row *							was returned). * ---------- */static intexec_stmt_perform(PLpgSQL_execstate * estate, PLpgSQL_stmt_perform * stmt){	PLpgSQL_expr *expr = stmt->expr;	int			rc;	/*	 * If not already done create a plan for this expression	 */	if (expr->plan == NULL)		exec_prepare_plan(estate, expr);	rc = exec_run_select(estate, expr, 0, NULL);	if (rc != SPI_OK_SELECT)		ereport(ERROR,				(errcode(ERRCODE_WRONG_OBJECT_TYPE),			   errmsg("query \"%s\" did not return data", expr->query)));	exec_set_found(estate, (estate->eval_processed != 0));

⌨️ 快捷键说明

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