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

📄 pl_exec.c

📁 关系型数据库 Postgresql 6.5.2
💻 C
📖 第 1 页 / 共 4 页
字号:
	}	/* ----------	 * There are tuples, so set found to true	 * ----------	 */	exec_set_found(estate, true);	/* ----------	 * Now do the loop	 * ----------	 */	tuptab = SPI_tuptable;	SPI_tuptable = NULL;	for (i = 0; i < n; i++)	{		/* ----------		 * Assign the tuple to the target		 * ----------		 */		exec_move_row(estate, rec, row, tuptab->vals[i], tuptab->tupdesc);		/* ----------		 * 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);		}	}	return PLPGSQL_RC_OK;}/* ---------- * exec_stmt_select			Run a query and assign the first *					row to a record or rowtype. *					 ---------- */static intexec_stmt_select(PLpgSQL_execstate * estate, PLpgSQL_stmt_select * stmt){	PLpgSQL_rec *rec = NULL;	PLpgSQL_row *row = NULL;	SPITupleTable *tuptab;	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_select()");	}	/* ----------	 * Run the query	 * ----------	 */	exec_run_select(estate, stmt->query, 1);	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;	}	/* ----------	 * Put the result into the target and set found to true	 * ----------	 */	tuptab = SPI_tuptable;	SPI_tuptable = NULL;	exec_move_row(estate, rec, row, tuptab->vals[0], tuptab->tupdesc);	exec_set_found(estate, true);	return PLPGSQL_RC_OK;}/* ---------- * exec_stmt_exit			Start exiting loop(s) or blocks * ---------- */static intexec_stmt_exit(PLpgSQL_execstate * estate, PLpgSQL_stmt_exit * stmt){	Datum		value;	Oid			valtype;	bool		isnull = false;	/* ----------	 * If the exit has a condition, check that it's true	 * ----------	 */	if (stmt->cond != NULL)	{		value = exec_eval_expr(estate, stmt->cond, &isnull, &valtype);		if (!value)			return PLPGSQL_RC_OK;	}	estate->exitlabel = stmt->label;	return PLPGSQL_RC_EXIT;}/* ---------- * exec_stmt_return			Evaluate an expression and start *					returning from the function. * ---------- */static intexec_stmt_return(PLpgSQL_execstate * estate, PLpgSQL_stmt_return * stmt){	if (estate->retistuple)	{		if (stmt->retrecno >= 0)		{			PLpgSQL_rec *rec = (PLpgSQL_rec *) (estate->datums[stmt->retrecno]);			estate->retval = (Datum) (rec->tup);			estate->rettupdesc = rec->tupdesc;			estate->retisnull = !HeapTupleIsValid(rec->tup);			return PLPGSQL_RC_RETURN;		}		if (stmt->expr == NULL)		{			estate->retval = (Datum) 0;			estate->rettupdesc = NULL;			estate->retisnull = true;		}		else		{			exec_run_select(estate, stmt->expr, 1);			estate->retval = (Datum) SPI_copytuple(SPI_tuptable->vals[0]);			estate->rettupdesc = SPI_tuptable->tupdesc;			estate->retisnull = false;		}		return PLPGSQL_RC_RETURN;	}	estate->retval = exec_eval_expr(estate, stmt->expr,									&(estate->retisnull),									&(estate->rettype));	return PLPGSQL_RC_RETURN;}/* ---------- * exec_stmt_raise			Build a message and throw it with *					elog() * ---------- */static intexec_stmt_raise(PLpgSQL_execstate * estate, PLpgSQL_stmt_raise * stmt){	HeapTuple	typetup;	Form_pg_type typeStruct;	FmgrInfo	finfo_output;	char	   *extval;	int			pidx = 0;	char		c[2] = {0, 0};	char	   *cp;	PLpgSQL_dstring ds;	PLpgSQL_var *var;	PLpgSQL_rec *rec;	PLpgSQL_recfield *recfield;	int			fno;	plpgsql_dstring_init(&ds);	for (cp = stmt->message; *cp; cp++)	{		/* ----------		 * Occurences of a single % are replaced by the next		 * arguments external representation. Double %'s are		 * left as is so elog() will also don't touch them.		 * ----------		 */		if ((c[0] = *cp) == '%')		{			cp++;			if (*cp == '%')			{				plpgsql_dstring_append(&ds, c);				plpgsql_dstring_append(&ds, c);				continue;			}			cp--;			if (pidx >= stmt->nparams)			{				plpgsql_dstring_append(&ds, c);				plpgsql_dstring_append(&ds, c);				continue;			}			switch (estate->datums[stmt->params[pidx]]->dtype)			{				case PLPGSQL_DTYPE_VAR:					var = (PLpgSQL_var *)						(estate->datums[stmt->params[pidx]]);					if (var->isnull)						extval = "<NULL>";					else					{						typetup = SearchSysCacheTuple(TYPOID,						ObjectIdGetDatum(var->datatype->typoid), 0, 0, 0);						if (!HeapTupleIsValid(typetup))							elog(ERROR, "cache lookup for type %u failed (1)", var->datatype->typoid);						typeStruct = (Form_pg_type) GETSTRUCT(typetup);						fmgr_info(typeStruct->typoutput, &finfo_output);						extval = (char *) (*fmgr_faddr(&finfo_output)) (var->value, &(var->isnull), var->datatype->atttypmod);					}					plpgsql_dstring_append(&ds, extval);					break;				case PLPGSQL_DTYPE_RECFIELD:					recfield = (PLpgSQL_recfield *)						(estate->datums[stmt->params[pidx]]);					rec = (PLpgSQL_rec *)						(estate->datums[recfield->recno]);					if (!HeapTupleIsValid(rec->tup))						extval = "<NULL>";					else					{						fno = SPI_fnumber(rec->tupdesc, recfield->fieldname);						if (fno == SPI_ERROR_NOATTRIBUTE)							elog(ERROR, "record %s has no field %s", rec->refname, recfield->fieldname);						extval = SPI_getvalue(rec->tup, rec->tupdesc, fno);					}					plpgsql_dstring_append(&ds, extval);					break;				case PLPGSQL_DTYPE_TRIGARG:					{						PLpgSQL_trigarg *trigarg;						int			value;						Oid			valtype;						bool		valisnull = false;						trigarg = (PLpgSQL_trigarg *)							(estate->datums[stmt->params[pidx]]);						value = (int) exec_eval_expr(estate, trigarg->argnum,												   &valisnull, &valtype);						if (valisnull)							extval = "<INDEX_IS_NULL>";						else						{							if (value < 0 || value >= estate->trig_nargs)								extval = "<OUT_OF_RANGE>";							else								extval = textout((text *) (estate->trig_argv[value]));						}						plpgsql_dstring_append(&ds, extval);					}					break;				default:					c[0] = '?';					plpgsql_dstring_append(&ds, c);					break;			}			pidx++;			continue;		}		/* ----------		 * Occurences of single ' are removed. double ' are reduced		 * to single ones.		 * ----------		 */		if (*cp == '\'')		{			cp++;			if (*cp == '\'')				plpgsql_dstring_append(&ds, c);			else				cp--;			continue;		}		plpgsql_dstring_append(&ds, c);	}	/* ----------	 * Now suppress debug info and throw the elog()	 * ----------	 */	if (stmt->elog_level == ERROR)	{		error_info_func = NULL;		error_info_stmt = NULL;		error_info_text = NULL;	}	elog(stmt->elog_level, "%s", plpgsql_dstring_get(&ds));	plpgsql_dstring_free(&ds);	return PLPGSQL_RC_OK;}/* ---------- * Generate a prepared plan * ---------- */static voidexec_prepare_plan(PLpgSQL_execstate * estate,				  PLpgSQL_expr * expr){	PLpgSQL_var *var;	PLpgSQL_rec *rec;	PLpgSQL_recfield *recfield;	int			i;	int			fno;	void	   *plan;	Oid		   *argtypes;	/* ----------	 * Setup the argtypes array	 * ----------	 */	argtypes = malloc(sizeof(Oid *) * (expr->nparams + 1));	for (i = 0; i < expr->nparams; i++)	{		switch (estate->datums[expr->params[i]]->dtype)		{			case PLPGSQL_DTYPE_VAR:				var = (PLpgSQL_var *) (estate->datums[expr->params[i]]);				argtypes[i] = var->datatype->typoid;				break;			case PLPGSQL_DTYPE_RECFIELD:				recfield = (PLpgSQL_recfield *) (estate->datums[expr->params[i]]);				rec = (PLpgSQL_rec *) (estate->datums[recfield->recno]);				if (!HeapTupleIsValid(rec->tup))					elog(ERROR, "record %s is unassigned yet", rec->refname);				fno = SPI_fnumber(rec->tupdesc, recfield->fieldname);				if (fno == SPI_ERROR_NOATTRIBUTE)					elog(ERROR, "record %s has no field %s", rec->refname, recfield->fieldname);				argtypes[i] = SPI_gettypeid(rec->tupdesc, fno);				break;			case PLPGSQL_DTYPE_TRIGARG:				argtypes[i] = (Oid) TEXTOID;				break;			default:				elog(ERROR, "unknown parameter dtype %d in exec_run_select()", estate->datums[expr->params[i]]);		}	}	/* ----------	 * Generate and save the plan	 * ----------	 */	plan = SPI_prepare(expr->query, expr->nparams, argtypes);	if (plan == NULL)		elog(ERROR, "SPI_prepare() failed on \"%s\"", expr->query);	expr->plan = SPI_saveplan(plan);	expr->plan_argtypes = argtypes;	expr->plan_simple_expr = NULL;	exec_simple_check_plan(expr);}/* ---------- * exec_stmt_execsql			Execute an SQL statement not *					returning any data. * ---------- */static intexec_stmt_execsql(PLpgSQL_execstate * estate,				  PLpgSQL_stmt_execsql * stmt){	PLpgSQL_var *var;	PLpgSQL_rec *rec;	PLpgSQL_recfield *recfield;	PLpgSQL_trigarg *trigarg;	int			tgargno;	Oid			tgargoid;	int			fno;	int			i;	Datum	   *values;	char	   *nulls;	int			rc;	PLpgSQL_expr *expr = stmt->sqlstmt;	bool		isnull;	/* ----------	 * 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_execp()	 * ----------	 */	values = palloc(sizeof(Datum) * (expr->nparams + 1));	nulls = palloc(expr->nparams + 1);	for (i = 0; i < expr->nparams; i++)	{		switch (estate->datums[expr->params[i]]->dtype)		{			case PLPGSQL_DTYPE_VAR:				var = (PLpgSQL_var *) (estate->datums[expr->params[i]]);				values[i] = var->value;				if (var->isnull)					nulls[i] = 'n';				else					nulls[i] = ' ';				break;			case PLPGSQL_DTYPE_RECFIELD:				recfield = (PLpgSQL_recfield *) (estate->datums[expr->params[i]]);				rec = (PLpgSQL_rec *) (estate->datums[recfield->recno]);				if (!HeapTupleIsValid(rec->tup))					elog(ERROR, "record %s is unassigned yet", rec->refname);				fno = SPI_fnumber(rec->tupdesc, recfield->fieldname);				if (fno == SPI_ERROR_NOATTRIBUTE)					elog(ERROR, "record %s has no field %s", rec->refname, recfield->fieldname);				if (expr->plan_argtypes[i] != SPI_gettypeid(rec->tupdesc, fno))					elog(ERROR, "type of %s.%s doesn't match that when preparing the plan", rec->refname, recfield->fieldname);				values[i] = SPI_getbinval(rec->tup, rec->tupdesc, fno, &isnull);				if (isnull)					nulls[i] = 'n';				else					nulls[i] = ' ';				break;			case PLPGSQL_DTYPE_TRIGARG:				trigarg = (PLpgSQL_trigarg *) (estate->datums[expr->params[i]]);				tgargno = (int) exec_eval_expr(estate, trigarg->argnum,											   &isnull, &tgargoid);				if (isnull || tgargno < 0 || tgargno >= estate->trig_nargs)				{					values[i] = 0;					nulls[i] = 'n';				}				else				{					values[i] = estate->trig_argv[tgargno];					nulls[i] = ' ';				}				break;			default:				elog(ERROR, "unknown parameter dtype %d in exec_stmt_execsql()", estate->datums[expr->params[i]]->dtype);		}	}	nulls[i] = '\0';	/* ----------	 * Execute the plan	 * ----------	 */	rc = SPI_execp(expr->plan, values, nulls, 0);	switch (rc)	{		case SPI_OK_UTILITY:		case SPI_OK_SELINTO:		case SPI_OK_INSERT:		case SPI_OK_DELETE:		case SPI_OK_UPDATE:			break;		case SPI_OK_SELECT:			elog(ERROR, "unexpected SELECT query in exec_stmt_execsql()");		default:			elog(ERROR, "error executing query \"%s\"",				 expr->query);	}	pfree(values);	pfree(nulls);	return PLPGSQL_RC_OK;}/* ---------- * exec_assign_expr			Put an expressions result into *					a variable. * ---------- */static voidexec_assign_expr(PLpgSQL_execstate * estate, PLpgSQL_datum * target,				 PLpgSQL_expr * expr){	Datum		value;	Oid			valtype;	bool		isnull = false;	value = exec_eval_expr(estate, expr, &isnull, &valtype);	if (target != NULL)		exec_assign_value(estate, target, value, valtype, &isnull);}/* ---------- * exec_assign_value			Put a value into a target field * ---------- */static voidexec_assign_value(PLpgSQL_execstate * estate,				  PLpgSQL_datum * target,				  Datum value, Oid valtype, bool *isNull){	PLpgSQL_var *var;	PLpgSQL_rec *rec;	PLpgSQL_recfield *recfield;	int			fno;	int			i;	int			natts;	Datum	   *values;	char	   *nulls;	bool		attisnull;	Oid			atttype;	int4		atttypmod;	HeapTuple	typetup;	Form_pg_type typeStruct;	FmgrInfo	finfo_input;	switch (target->dtype)	{		case PLPGSQL_DTYPE_VAR:			/* ----------			 * Target field is a variable - that's easy			 * ----------			 */			var = (PLpgSQL_var *) target;			var->value = exec_cast_value(value, valtype, var->datatype->typoid,										 &(var->datatype->typinput),									   var->datatype->atttypmod, isNull);			if (isNull && var->notnull)				elog(ERROR, "NULL assignment to variable '%s' declared NOT NULL", var->refname);			var->isnull = *isNull;			break;		case PLPGSQL_DTYPE_RECFIELD:			/* ----------			 * Target field is a record			 * ----------			 */			recfield = (PLpgSQL_recfield *) target;			rec = (PLpgSQL_rec *) (estate->datums[recfield->recno]);			/* ----------			 * Check that there is already a tuple in the record.			 * We need that because records don't have any predefined			 * field structure.			 * ----------			 */			if (!HeapTupleIsValid(rec->tup))				elog(ERROR, "record %s is unassigned yet - don't know it's tuple structure", rec->refname);			/* ----------			 * Get the number of the records field to change and the			 * number of attributes in the tuple.			 * ----------			 */			fno = SPI_fnumber(rec->tupdesc, recfield->fieldname);			if (fno == SPI_ERROR_NOATTRIBUTE)				elog(ERROR, "record %s has no field %s", rec->refname, recfield->fieldname);			fno--;			natts = rec->tupdesc->natts;			/* ----------			 * We loop over the attributes of the rec's current tuple			 * and collect the values in a Datum array along with the			 * nulls information.			 * ----------			 */			values = palloc(sizeof(Datum) * natts);			nulls = palloc(natts + 1);			for (i = 0; i < natts; i++)			{				/* ----------				 * If this isn't the field we assign to, just use the				 * value that's already in the tuple.				 * ----------				 */				if (i != fno)				{					values[i] = SPI_getbinval(rec->tup, rec->tupdesc,											  i + 1, &attisnull);					if (attisnull)						nulls[i] = 'n';					else						nulls[i] = ' ';					continue;				}

⌨️ 快捷键说明

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