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

📄 pl_exec.c

📁 关系型数据库 Postgresql 6.5.2
💻 C
📖 第 1 页 / 共 4 页
字号:
	else if (TRIGGER_FIRED_FOR_STATEMENT(trigdata->tg_event))		var->value = (Datum) textin("STATEMENT");	else		var->value = (Datum) textin("UNKNOWN");	var = (PLpgSQL_var *) (estate.datums[func->tg_relid_varno]);	var->isnull = false;	var->value = (Datum) (trigdata->tg_relation->rd_id);	var = (PLpgSQL_var *) (estate.datums[func->tg_relname_varno]);	var->isnull = false;	var->value = (Datum) namein(nameout(&(trigdata->tg_relation->rd_rel->relname)));	var = (PLpgSQL_var *) (estate.datums[func->tg_nargs_varno]);	var->isnull = false;	var->value = (Datum) (trigdata->tg_trigger->tgnargs);	/* ----------	 * Put the actual call argument values into the special	 * execution state variables	 * ----------	 */	error_info_text = "while putting call arguments to 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] = (Datum) textin(trigdata->tg_trigger->tgargs[i]);	}	/* ----------	 * 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:			case PLPGSQL_DTYPE_TRIGARG:				break;			default:				elog(ERROR, "unknown dtype %d in plpgsql_exec_trigger()",					 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 trigger procedure without RETURN");	}	/* ----------	 * Check that the returned tuple structure has the same attributes,	 * the relation that fired the trigger has.	 *	 * 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)		rettup = NULL;	else	{		TupleDesc	td1 = trigdata->tg_relation->rd_att;		TupleDesc	td2 = estate.rettupdesc;		int			i;		if (td1->natts != td2->natts)			elog(ERROR, "returned tuple structure doesn't match table of trigger event");		for (i = 1; i <= td1->natts; i++)		{			if (SPI_gettypeid(td1, i) != SPI_gettypeid(td2, i))				elog(ERROR, "returned tuple structure doesn't match table of trigger event");		}		rettup = SPI_copytuple((HeapTuple) (estate.retval));	}	/* ----------	 * 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 triggers result	 * ----------	 */	return rettup;}/* ---------- * 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));	return new;}static PLpgSQL_rec *copy_rec(PLpgSQL_rec * rec){	PLpgSQL_rec *new = palloc(sizeof(PLpgSQL_rec));	memcpy(new, rec, sizeof(PLpgSQL_rec));	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->isconst || var->isnull)					{						if (var->default_val == NULL)						{							var->value = (Datum) 0;							var->isnull = true;							if (var->notnull)								elog(ERROR, "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]);					rec->tup = NULL;					rec->tupdesc = NULL;				}				break;			case PLPGSQL_DTYPE_RECFIELD:				break;			default:				elog(ERROR, "unknown dtype %d in exec_stmt_block()", 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, "unknown rc %d from exec_stmt()", 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 = error_info_stmt;	error_info_stmt = stmt;	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_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_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;		default:			error_info_stmt = save_estmt;			elog(ERROR, "unknown cmdtype %d in exec_stmt",				 stmt->cmd_type);	}	error_info_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){	if (stmt->varno < 0)		exec_assign_expr(estate, NULL, stmt->expr);	else		exec_assign_expr(estate, estate->datums[stmt->varno], stmt->expr);	return PLPGSQL_RC_OK;}/* ---------- * exec_stmt_if				Evaluate a bool expression and *					execute the true or false body *					conditionally. * ---------- */static intexec_stmt_if(PLpgSQL_execstate * estate, PLpgSQL_stmt_if * stmt){	Datum		value;	Oid			valtype;	bool		isnull = false;	value = exec_eval_expr(estate, stmt->cond, &isnull, &valtype);	if (value)	{		if (stmt->true_body != NULL)			return exec_stmts(estate, stmt->true_body);	}	else	{		if (stmt->false_body != NULL)			return exec_stmts(estate, stmt->false_body);	}	return PLPGSQL_RC_OK;}/* ---------- * exec_stmt_loop			Loop over statements until *					an exit occurs. * ---------- */static intexec_stmt_loop(PLpgSQL_execstate * estate, PLpgSQL_stmt_loop * stmt){	int			rc;	for (;;)	{		rc = exec_stmts(estate, stmt->body);		switch (rc)		{			case PLPGSQL_RC_OK:				break;			case PLPGSQL_RC_EXIT:				if (estate->exitlabel == NULL)					return PLPGSQL_RC_OK;				if (stmt->label == NULL)					return PLPGSQL_RC_EXIT;				if (strcmp(stmt->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, "unknown rc %d from exec_stmts()", rc);		}	}	return PLPGSQL_RC_OK;}/* ---------- * exec_stmt_while			Loop over statements as long *					as an expression evaluates to *					true or an exit occurs. * ---------- */static intexec_stmt_while(PLpgSQL_execstate * estate, PLpgSQL_stmt_while * stmt){	Datum		value;	Oid			valtype;	bool		isnull = false;	int			rc;	for (;;)	{		value = exec_eval_expr(estate, stmt->cond, &isnull, &valtype);		if (!value)			break;		rc = exec_stmts(estate, stmt->body);		switch (rc)		{			case PLPGSQL_RC_OK:				break;			case PLPGSQL_RC_EXIT:				if (estate->exitlabel == NULL)					return PLPGSQL_RC_OK;				if (stmt->label == NULL)					return PLPGSQL_RC_EXIT;				if (strcmp(stmt->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, "unknown rc %d from exec_stmts()", rc);		}	}	return PLPGSQL_RC_OK;}/* ---------- * exec_stmt_fori			Iterate an integer variable *					from a lower to an upper value. *					Loop can be left with exit. * ---------- */static intexec_stmt_fori(PLpgSQL_execstate * estate, PLpgSQL_stmt_fori * stmt){	PLpgSQL_var *var;	Datum		value;	Oid			valtype;	bool		isnull = false;	int			rc;	/* ----------	 * Get the value of the lower bound into the loop var	 * ----------	 */	value = exec_eval_expr(estate, stmt->lower, &isnull, &valtype);	var = (PLpgSQL_var *) (estate->datums[stmt->var->varno]);	value = exec_cast_value(value, valtype, var->datatype->typoid,							&(var->datatype->typinput),							var->datatype->atttypmod, &isnull);	if (isnull)		elog(ERROR, "lower bound of FOR loop cannot be NULL");	var->value = value;	var->isnull = false;	/* ----------	 * Get the value of the upper bound	 * ----------	 */	value = exec_eval_expr(estate, stmt->upper, &isnull, &valtype);	value = exec_cast_value(value, valtype, var->datatype->typoid,							&(var->datatype->typinput),							var->datatype->atttypmod, &isnull);	if (isnull)		elog(ERROR, "upper bound of FOR loop cannot be NULL");	/* ----------	 * Now do the loop	 * ----------	 */	exec_set_found(estate, false);	for (;;)	{		/* ----------		 * Check bounds		 * ----------		 */		if (stmt->reverse)		{			if ((int4) (var->value) < (int4) value)				break;		}		else		{			if ((int4) (var->value) > (int4) value)				break;		}		exec_set_found(estate, true);		/* ----------		 * Execute the statements		 * ----------		 */		rc = exec_stmts(estate, stmt->body);		/* ----------		 * Check returncode		 * ----------		 */		switch (rc)		{			case PLPGSQL_RC_OK:				break;			case PLPGSQL_RC_EXIT:				if (estate->exitlabel == NULL)					return PLPGSQL_RC_OK;				if (stmt->label == NULL)					return PLPGSQL_RC_EXIT;				if (strcmp(stmt->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, "unknown rc %d from exec_stmts()", rc);		}		/* ----------		 * Increase/decrease loop var		 * ----------		 */		if (stmt->reverse)			var->value--;		else			var->value++;	}	return PLPGSQL_RC_OK;}/* ---------- * exec_stmt_fors			Execute a query, assign each *					tuple to a record or row and *					execute a group of statements *					for it. * ---------- */static intexec_stmt_fors(PLpgSQL_execstate * estate, PLpgSQL_stmt_fors * stmt){	PLpgSQL_rec *rec = NULL;	PLpgSQL_row *row = NULL;	SPITupleTable *tuptab;	int			rc;	int			i;	int			n;	/* ----------	 * Initialize the global found variable to false	 * ----------	 */	exec_set_found(estate, false);	/* ----------	 * Determine if we assign to a record or a row	 * ----------	 */	if (stmt->rec != NULL)		rec = (PLpgSQL_rec *) (estate->datums[stmt->rec->recno]);	else	{		if (stmt->row != NULL)			row = (PLpgSQL_row *) (estate->datums[stmt->row->rowno]);		else			elog(ERROR, "unsupported target in exec_stmt_fors()");	}	/* ----------	 * Run the query	 * ----------	 */	exec_run_select(estate, stmt->query, 0);	n = SPI_processed;	/* ----------	 * If the query didn't return any row, set the target	 * to NULL and return.	 * ----------	 */	if (n == 0)	{		exec_move_row(estate, rec, row, NULL, NULL);		return PLPGSQL_RC_OK;

⌨️ 快捷键说明

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