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

📄 pl_exec.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 5 页
字号:
	PLpgSQL_dstring ds;	ListCell   *current_param;	plpgsql_dstring_init(&ds);	current_param = list_head(stmt->params);	for (cp = stmt->message; *cp; cp++)	{		/*		 * Occurrences of a single % are replaced by the next parameter's		 * external representation. Double %'s are converted to one %.		 */		if (cp[0] == '%')		{			Oid			paramtypeid;			Datum		paramvalue;			bool		paramisnull;			char	   *extval;			if (cp[1] == '%')			{				plpgsql_dstring_append_char(&ds, cp[1]);				cp++;				continue;			}			if (current_param == NULL)				ereport(ERROR,						(errcode(ERRCODE_SYNTAX_ERROR),						 errmsg("too few parameters specified for RAISE")));			paramvalue = exec_eval_expr(estate,									  (PLpgSQL_expr *) lfirst(current_param),										&paramisnull,										&paramtypeid);			if (paramisnull)				extval = "<NULL>";			else				extval = convert_value_to_string(paramvalue, paramtypeid);			plpgsql_dstring_append(&ds, extval);			current_param = lnext(current_param);			exec_eval_cleanup(estate);			continue;		}		plpgsql_dstring_append_char(&ds, cp[0]);	}	/*	 * If more parameters were specified than were required to process the	 * format string, throw an error	 */	if (current_param != NULL)		ereport(ERROR,				(errcode(ERRCODE_SYNTAX_ERROR),				 errmsg("too many parameters specified for RAISE")));	/*	 * Throw the error (may or may not come back)	 */	estate->err_text = raise_skip_msg;	/* suppress traceback of raise */	ereport(stmt->elog_level,		 ((stmt->elog_level >= ERROR) ? errcode(ERRCODE_RAISE_EXCEPTION) : 0,		  errmsg_internal("%s", plpgsql_dstring_get(&ds))));	estate->err_text = NULL;	/* un-suppress... */	plpgsql_dstring_free(&ds);	return PLPGSQL_RC_OK;}/* ---------- * Initialize a mostly empty execution state * ---------- */static voidplpgsql_estate_setup(PLpgSQL_execstate *estate,					 PLpgSQL_function *func,					 ReturnSetInfo *rsi){	estate->retval = (Datum) 0;	estate->retisnull = true;	estate->rettype = InvalidOid;	estate->fn_rettype = func->fn_rettype;	estate->retistuple = func->fn_retistuple;	estate->retisset = func->fn_retset;	estate->readonly_func = func->fn_readonly;	estate->rettupdesc = NULL;	estate->exitlabel = NULL;	estate->tuple_store = NULL;	estate->tuple_store_cxt = NULL;	estate->rsi = rsi;	estate->trig_nargs = 0;	estate->trig_argv = NULL;	estate->found_varno = func->found_varno;	estate->ndatums = func->ndatums;	estate->datums = palloc(sizeof(PLpgSQL_datum *) * estate->ndatums);	/* caller is expected to fill the datums array */	estate->eval_tuptable = NULL;	estate->eval_processed = 0;	estate->eval_lastoid = InvalidOid;	estate->err_func = func;	estate->err_stmt = NULL;	estate->err_text = NULL;	/*	 * Create an EState for evaluation of simple expressions, if there's not	 * one already in the current transaction.	The EState is made a child of	 * TopTransactionContext so it will have the right lifespan.	 */	if (simple_eval_estate == NULL)	{		MemoryContext oldcontext;		oldcontext = MemoryContextSwitchTo(TopTransactionContext);		simple_eval_estate = CreateExecutorState();		MemoryContextSwitchTo(oldcontext);	}	/*	 * Create an expression context for simple expressions. This must be a	 * child of simple_eval_estate.	 */	estate->eval_econtext = CreateExprContext(simple_eval_estate);}/* ---------- * Release temporary memory used by expression/subselect evaluation * * NB: the result of the evaluation is no longer valid after this is done, * unless it is a pass-by-value datatype. * ---------- */static voidexec_eval_cleanup(PLpgSQL_execstate *estate){	/* Clear result of a full SPI_execute */	if (estate->eval_tuptable != NULL)		SPI_freetuptable(estate->eval_tuptable);	estate->eval_tuptable = NULL;	/* Clear result of exec_eval_simple_expr (but keep the econtext) */	if (estate->eval_econtext != NULL)		ResetExprContext(estate->eval_econtext);}/* ---------- * Generate a prepared plan * ---------- */static voidexec_prepare_plan(PLpgSQL_execstate *estate,				  PLpgSQL_expr *expr){	int			i;	_SPI_plan  *spi_plan;	void	   *plan;	Oid		   *argtypes;	/*	 * We need a temporary argtypes array to load with data. (The finished	 * plan structure will contain a copy of it.)	 */	argtypes = (Oid *) palloc(expr->nparams * sizeof(Oid));	for (i = 0; i < expr->nparams; i++)	{		Datum		paramval;		bool		paramisnull;		exec_eval_datum(estate, estate->datums[expr->params[i]],						InvalidOid,						&argtypes[i], &paramval, &paramisnull);	}	/*	 * Generate and save the plan	 */	plan = SPI_prepare(expr->query, expr->nparams, argtypes);	if (plan == NULL)	{		/* Some SPI errors deserve specific error messages */		switch (SPI_result)		{			case SPI_ERROR_COPY:				ereport(ERROR,						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),						 errmsg("cannot COPY to/from client in PL/pgSQL")));			case SPI_ERROR_CURSOR:				ereport(ERROR,						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),					errmsg("cannot manipulate cursors directly in PL/pgSQL"),						 errhint("Use PL/pgSQL's cursor features instead.")));			case SPI_ERROR_TRANSACTION:				ereport(ERROR,						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),						 errmsg("cannot begin/end transactions in PL/pgSQL"),						 errhint("Use a BEGIN block with an EXCEPTION clause instead.")));			default:				elog(ERROR, "SPI_prepare failed for \"%s\": %s",					 expr->query, SPI_result_code_string(SPI_result));		}	}	expr->plan = SPI_saveplan(plan);	spi_plan = (_SPI_plan *) expr->plan;	expr->plan_argtypes = spi_plan->argtypes;	expr->expr_simple_expr = NULL;	exec_simple_check_plan(expr);	SPI_freeplan(plan);	pfree(argtypes);}/* ---------- * exec_stmt_execsql			Execute an SQL statement not *					returning any data. * ---------- */static intexec_stmt_execsql(PLpgSQL_execstate *estate,				  PLpgSQL_stmt_execsql *stmt){	int			i;	Datum	   *values;	char	   *nulls;	int			rc;	PLpgSQL_expr *expr = stmt->sqlstmt;	/*	 * 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_execute_plan()	 */	values = (Datum *) palloc(expr->nparams * sizeof(Datum));	nulls = (char *) palloc(expr->nparams * sizeof(char));	for (i = 0; i < expr->nparams; i++)	{		PLpgSQL_datum *datum = estate->datums[expr->params[i]];		Oid			paramtypeid;		bool		paramisnull;		exec_eval_datum(estate, datum, expr->plan_argtypes[i],						&paramtypeid, &values[i], &paramisnull);		if (paramisnull)			nulls[i] = 'n';		else			nulls[i] = ' ';	}	/*	 * Execute the plan	 */	rc = SPI_execute_plan(expr->plan, values, nulls,						  estate->readonly_func, 0);	switch (rc)	{		case SPI_OK_UTILITY:		case SPI_OK_SELINTO:			break;		case SPI_OK_INSERT:		case SPI_OK_DELETE:		case SPI_OK_UPDATE:			/*			 * If the INSERT, DELETE, or UPDATE query affected at least one			 * tuple, set the magic 'FOUND' variable to true. This conforms			 * with the behavior of PL/SQL.			 */			exec_set_found(estate, (SPI_processed != 0));			break;		case SPI_OK_SELECT:			ereport(ERROR,					(errcode(ERRCODE_SYNTAX_ERROR),				   errmsg("SELECT query has no destination for result data"),					 errhint("If you want to discard the results, use PERFORM instead.")));		default:			elog(ERROR, "SPI_execute_plan failed executing query \"%s\": %s",				 expr->query, SPI_result_code_string(rc));	}	/*	 * Release any result tuples from SPI_execute_plan (probably shouldn't be	 * any)	 */	SPI_freetuptable(SPI_tuptable);	/* Save result info for GET DIAGNOSTICS */	estate->eval_processed = SPI_processed;	estate->eval_lastoid = SPI_lastoid;	pfree(values);	pfree(nulls);	return PLPGSQL_RC_OK;}/* ---------- * exec_stmt_dynexecute			Execute a dynamic SQL query not *					returning any data. * ---------- */static intexec_stmt_dynexecute(PLpgSQL_execstate *estate,					 PLpgSQL_stmt_dynexecute *stmt){	Datum		query;	bool		isnull = false;	Oid			restype;	char	   *querystr;	int			exec_res;	PLpgSQL_rec *rec = NULL;	PLpgSQL_row *row = NULL;	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]);	/*	 * First we evaluate the string expression after the EXECUTE keyword. It's	 * result is the querystring we have to execute.	 */	query = exec_eval_expr(estate, stmt->query, &isnull, &restype);	if (isnull)		ereport(ERROR,				(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),				 errmsg("cannot EXECUTE a null querystring")));	/* Get the C-String representation */	querystr = convert_value_to_string(query, restype);	exec_eval_cleanup(estate);	/*	 * Call SPI_execute() without preparing a saved plan. The returncode can	 * be any standard OK.	Note that while a SELECT is allowed, its results	 * will be discarded unless an INTO clause is specified.	 */	exec_res = SPI_execute(querystr, estate->readonly_func, 0);	/* Assign to INTO variable */	if (rec || row)	{		if (exec_res != SPI_OK_SELECT)			ereport(ERROR,					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),					 errmsg("EXECUTE ... INTO is only for SELECT")));		else		{			if (SPI_processed == 0)				exec_move_row(estate, rec, row, NULL, SPI_tuptable->tupdesc);			else				exec_move_row(estate, rec, row,							  SPI_tuptable->vals[0], SPI_tuptable->tupdesc);		}	}	switch (exec_res)	{		case SPI_OK_SELECT:		case SPI_OK_INSERT:		case SPI_OK_UPDATE:		case SPI_OK_DELETE:		case SPI_OK_UTILITY:			break;		case 0:			/*			 * Also allow a zero return, which implies the querystring			 * contained no commands.			 */			break;		case SPI_OK_SELINTO:			/*			 * We want to disallow SELECT INTO for now, because its behavior			 * is not consistent with SELECT INTO in a normal plpgsql context.			 * (We need to reimplement EXECUTE to parse the string as a			 * plpgsql command, not just feed it to SPI_execute.) However,			 * CREATE AS should be allowed ... and since it produces the same			 * parsetree as SELECT INTO, there's no way to tell the difference			 * except to look at the source text.  Wotta kluge!			 */			{				char	   *ptr;				for (ptr = querystr; *ptr; ptr++)					if (!isspace((unsigned char) *ptr))						break;				if (*ptr == 'S' || *ptr == 's')					ereport(ERROR,							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),							 errmsg("EXECUTE of SELECT ... INTO is not implemented yet")));				break;			}			/* Some SPI errors deserve specific error messages */		case SPI_ERROR_COPY:			ereport(ERROR,					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),					 errmsg("cannot COPY to/from client in PL/pgSQL")));		case SPI_ERROR_CURSOR:			ereport(ERROR,					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),					 errmsg("cannot manipulate cursors directly in PL/pgSQL"),					 errhint("Use PL/pgSQL's cursor features instead.")));		case SPI_ERROR_TRANSACTION:			ereport(ERROR,					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),					 errmsg("cannot begin/end transactions in PL/pgSQL"),			errhint("Use a BEGIN block with an EXCEPTION clause instead.")));		default:			elog(ERROR, "SPI_execute failed executing query \"%s\": %s",				 querystr, SPI_result_code_string(exec_res));			break;	}	/* Release any result from SPI_execute, as well as the querystring */	SPI_freetuptable(SPI_tuptable);	pfree(querystr);	/* Save result info for GET DIAGNOSTICS */	estate->eval_processed = SPI_processed;	estate->eval_lastoid = SPI_lastoid;	return PLPGSQL_RC_OK;}/* ---------- * exec_stmt_dynfors			Execute a dynamic query, assign each *					tuple to a record or row and *					execute a group of statements *					for it. * ---------- */static intexec_stmt_dynfors(PLpgSQL_execstate *estate, PLpgSQL_stmt_dynfors *stmt){	Datum		query;	bool		isnull;	Oid			restype;	char	   *querystr;	PLpgSQL_rec *rec = NULL;	PLpgSQL_row *row = NULL;	SPITupleTable *tuptab;	int			n;	void	   *plan;	Portal		portal;	bool		found = 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");	/*	 * Evaluate the string expression after the EXECUTE keyword. It's result	 * is the querystring we have to execute.	 */	query = exec_eval_expr(estate, stmt->query, &isnull, &restype);	if (isnull)		ereport(ERROR,				(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),				 errmsg("cannot EXECUTE a null querystring")));	/* Get the C-String representation */	querystr = convert_value_to_string(query, restype);	exec_eval_cleanup(estate);	/*	 * Prepare a plan and open an implicit cursor for the query	 */	plan = SPI_prepare(querystr, 0, NULL);	if

⌨️ 快捷键说明

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