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

📄 spi.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 3 页
字号:
	for (res = 0; res < tupdesc->natts; res++)	{		if (namestrcmp(&tupdesc->attrs[res]->attname, fname) == 0)			return res + 1;	}	sysatt = SystemAttributeByName(fname, true /* "oid" will be accepted */ );	if (sysatt != NULL)		return sysatt->attnum;	/* SPI_ERROR_NOATTRIBUTE is different from all sys column numbers */	return SPI_ERROR_NOATTRIBUTE;}char *SPI_fname(TupleDesc tupdesc, int fnumber){	Form_pg_attribute att;	SPI_result = 0;	if (fnumber > tupdesc->natts || fnumber == 0 ||		fnumber <= FirstLowInvalidHeapAttributeNumber)	{		SPI_result = SPI_ERROR_NOATTRIBUTE;		return NULL;	}	if (fnumber > 0)		att = tupdesc->attrs[fnumber - 1];	else		att = SystemAttributeDefinition(fnumber, true);	return pstrdup(NameStr(att->attname));}char *SPI_getvalue(HeapTuple tuple, TupleDesc tupdesc, int fnumber){	Datum		origval,				val,				result;	bool		isnull;	Oid			typoid,				foutoid;	bool		typisvarlena;	SPI_result = 0;	if (fnumber > tuple->t_data->t_natts || fnumber == 0 ||		fnumber <= FirstLowInvalidHeapAttributeNumber)	{		SPI_result = SPI_ERROR_NOATTRIBUTE;		return NULL;	}	origval = heap_getattr(tuple, fnumber, tupdesc, &isnull);	if (isnull)		return NULL;	if (fnumber > 0)		typoid = tupdesc->attrs[fnumber - 1]->atttypid;	else		typoid = (SystemAttributeDefinition(fnumber, true))->atttypid;	getTypeOutputInfo(typoid, &foutoid, &typisvarlena);	/*	 * If we have a toasted datum, forcibly detoast it here to avoid memory	 * leakage inside the type's output routine.	 */	if (typisvarlena)		val = PointerGetDatum(PG_DETOAST_DATUM(origval));	else		val = origval;	result = OidFunctionCall1(foutoid,							  val);	/* Clean up detoasted copy, if any */	if (val != origval)		pfree(DatumGetPointer(val));	return DatumGetCString(result);}DatumSPI_getbinval(HeapTuple tuple, TupleDesc tupdesc, int fnumber, bool *isnull){	SPI_result = 0;	if (fnumber > tuple->t_data->t_natts || fnumber == 0 ||		fnumber <= FirstLowInvalidHeapAttributeNumber)	{		SPI_result = SPI_ERROR_NOATTRIBUTE;		*isnull = true;		return (Datum) NULL;	}	return heap_getattr(tuple, fnumber, tupdesc, isnull);}char *SPI_gettype(TupleDesc tupdesc, int fnumber){	Oid			typoid;	HeapTuple	typeTuple;	char	   *result;	SPI_result = 0;	if (fnumber > tupdesc->natts || fnumber == 0 ||		fnumber <= FirstLowInvalidHeapAttributeNumber)	{		SPI_result = SPI_ERROR_NOATTRIBUTE;		return NULL;	}	if (fnumber > 0)		typoid = tupdesc->attrs[fnumber - 1]->atttypid;	else		typoid = (SystemAttributeDefinition(fnumber, true))->atttypid;	typeTuple = SearchSysCache(TYPEOID,							   ObjectIdGetDatum(typoid),							   0, 0, 0);	if (!HeapTupleIsValid(typeTuple))	{		SPI_result = SPI_ERROR_TYPUNKNOWN;		return NULL;	}	result = pstrdup(NameStr(((Form_pg_type) GETSTRUCT(typeTuple))->typname));	ReleaseSysCache(typeTuple);	return result;}OidSPI_gettypeid(TupleDesc tupdesc, int fnumber){	SPI_result = 0;	if (fnumber > tupdesc->natts || fnumber == 0 ||		fnumber <= FirstLowInvalidHeapAttributeNumber)	{		SPI_result = SPI_ERROR_NOATTRIBUTE;		return InvalidOid;	}	if (fnumber > 0)		return tupdesc->attrs[fnumber - 1]->atttypid;	else		return (SystemAttributeDefinition(fnumber, true))->atttypid;}char *SPI_getrelname(Relation rel){	return pstrdup(RelationGetRelationName(rel));}char *SPI_getnspname(Relation rel){	return get_namespace_name(RelationGetNamespace(rel));}void *SPI_palloc(Size size){	MemoryContext oldcxt = NULL;	void	   *pointer;	if (_SPI_curid + 1 == _SPI_connected)		/* connected */	{		if (_SPI_current != &(_SPI_stack[_SPI_curid + 1]))			elog(ERROR, "SPI stack corrupted");		oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);	}	pointer = palloc(size);	if (oldcxt)		MemoryContextSwitchTo(oldcxt);	return pointer;}void *SPI_repalloc(void *pointer, Size size){	/* No longer need to worry which context chunk was in... */	return repalloc(pointer, size);}voidSPI_pfree(void *pointer){	/* No longer need to worry which context chunk was in... */	pfree(pointer);}voidSPI_freetuple(HeapTuple tuple){	/* No longer need to worry which context tuple was in... */	heap_freetuple(tuple);}voidSPI_freetuptable(SPITupleTable *tuptable){	if (tuptable != NULL)		MemoryContextDelete(tuptable->tuptabcxt);}/* * SPI_cursor_open() * *	Open a prepared SPI plan as a portal */PortalSPI_cursor_open(const char *name, void *plan,				Datum *Values, const char *Nulls,				bool read_only){	_SPI_plan  *spiplan = (_SPI_plan *) plan;	List	   *qtlist = spiplan->qtlist;	List	   *ptlist = spiplan->ptlist;	Query	   *queryTree;	Plan	   *planTree;	ParamListInfo paramLI;	Snapshot	snapshot;	MemoryContext oldcontext;	Portal		portal;	int			k;	/* Ensure that the plan contains only one query */	if (list_length(ptlist) != 1 || list_length(qtlist) != 1)		ereport(ERROR,				(errcode(ERRCODE_INVALID_CURSOR_DEFINITION),				 errmsg("cannot open multi-query plan as cursor")));	queryTree = (Query *) linitial((List *) linitial(qtlist));	planTree = (Plan *) linitial(ptlist);	/* Must be a query that returns tuples */	switch (queryTree->commandType)	{		case CMD_SELECT:			if (queryTree->into != NULL)				ereport(ERROR,						(errcode(ERRCODE_INVALID_CURSOR_DEFINITION),						 errmsg("cannot open SELECT INTO query as cursor")));			break;		case CMD_UTILITY:			if (!UtilityReturnsTuples(queryTree->utilityStmt))				ereport(ERROR,						(errcode(ERRCODE_INVALID_CURSOR_DEFINITION),						 errmsg("cannot open non-SELECT query as cursor")));			break;		default:			ereport(ERROR,					(errcode(ERRCODE_INVALID_CURSOR_DEFINITION),					 errmsg("cannot open non-SELECT query as cursor")));			break;	}	/* Reset SPI result (note we deliberately don't touch lastoid) */	SPI_processed = 0;	SPI_tuptable = NULL;	_SPI_current->processed = 0;	_SPI_current->tuptable = NULL;	/* Create the portal */	if (name == NULL || name[0] == '\0')	{		/* Use a random nonconflicting name */		portal = CreateNewPortal();	}	else	{		/* In this path, error if portal of same name already exists */		portal = CreatePortal(name, false, false);	}	/* Switch to portals memory and copy the parsetree and plan to there */	oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));	queryTree = copyObject(queryTree);	planTree = copyObject(planTree);	/* If the plan has parameters, set them up */	if (spiplan->nargs > 0)	{		paramLI = (ParamListInfo) palloc0((spiplan->nargs + 1) *										  sizeof(ParamListInfoData));		for (k = 0; k < spiplan->nargs; k++)		{			paramLI[k].kind = PARAM_NUM;			paramLI[k].id = k + 1;			paramLI[k].ptype = spiplan->argtypes[k];			paramLI[k].isnull = (Nulls && Nulls[k] == 'n');			if (paramLI[k].isnull)			{				/* nulls just copy */				paramLI[k].value = Values[k];			}			else			{				/* pass-by-ref values must be copied into portal context */				int16		paramTypLen;				bool		paramTypByVal;				get_typlenbyval(spiplan->argtypes[k],								&paramTypLen, &paramTypByVal);				paramLI[k].value = datumCopy(Values[k],											 paramTypByVal, paramTypLen);			}		}		paramLI[k].kind = PARAM_INVALID;	}	else		paramLI = NULL;	/*	 * Set up the portal.	 */	PortalDefineQuery(portal,					  NULL,		/* unfortunately don't have sourceText */					  "SELECT", /* nor the raw parse tree... */					  list_make1(queryTree),					  list_make1(planTree),					  PortalGetHeapMemory(portal));	MemoryContextSwitchTo(oldcontext);	/*	 * Set up options for portal.	 */	portal->cursorOptions &= ~(CURSOR_OPT_SCROLL | CURSOR_OPT_NO_SCROLL);	if (planTree == NULL || ExecSupportsBackwardScan(planTree))		portal->cursorOptions |= CURSOR_OPT_SCROLL;	else		portal->cursorOptions |= CURSOR_OPT_NO_SCROLL;	/*	 * Set up the snapshot to use.	(PortalStart will do CopySnapshot, so we	 * skip that here.)	 */	if (read_only)		snapshot = ActiveSnapshot;	else	{		CommandCounterIncrement();		snapshot = GetTransactionSnapshot();	}	/*	 * Start portal execution.	 */	PortalStart(portal, paramLI, snapshot);	Assert(portal->strategy == PORTAL_ONE_SELECT ||		   portal->strategy == PORTAL_UTIL_SELECT);	/* Return the created portal */	return portal;}/* * SPI_cursor_find() * *	Find the portal of an existing open cursor */PortalSPI_cursor_find(const char *name){	return GetPortalByName(name);}/* * SPI_cursor_fetch() * *	Fetch rows in a cursor */voidSPI_cursor_fetch(Portal portal, bool forward, long count){	_SPI_cursor_operation(portal, forward, count,						  CreateDestReceiver(DestSPI, NULL));	/* we know that the DestSPI receiver doesn't need a destroy call */}/* * SPI_cursor_move() * *	Move in a cursor */voidSPI_cursor_move(Portal portal, bool forward, long count){	_SPI_cursor_operation(portal, forward, count, None_Receiver);}/* * SPI_cursor_close() * *	Close a cursor */voidSPI_cursor_close(Portal portal){	if (!PortalIsValid(portal))		elog(ERROR, "invalid portal in SPI cursor operation");	PortalDrop(portal, false);}/* * Returns the Oid representing the type id for argument at argIndex. First * parameter is at index zero. */OidSPI_getargtypeid(void *plan, int argIndex){	if (plan == NULL || argIndex < 0 || argIndex >= ((_SPI_plan *) plan)->nargs)	{		SPI_result = SPI_ERROR_ARGUMENT;		return InvalidOid;	}	return ((_SPI_plan *) plan)->argtypes[argIndex];}/* * Returns the number of arguments for the prepared plan. */intSPI_getargcount(void *plan){	if (plan == NULL)	{		SPI_result = SPI_ERROR_ARGUMENT;		return -1;	}	return ((_SPI_plan *) plan)->nargs;}/* * Returns true if the plan contains exactly one command * and that command originates from normal SELECT (i.e. * *not* a SELECT ... INTO). In essence, the result indicates * if the command can be used with SPI_cursor_open * * Parameters *	  plan A plan previously prepared using SPI_prepare */boolSPI_is_cursor_plan(void *plan){	_SPI_plan  *spiplan = (_SPI_plan *) plan;	List	   *qtlist;	if (spiplan == NULL)	{		SPI_result = SPI_ERROR_ARGUMENT;		return false;	}	qtlist = spiplan->qtlist;	if (list_length(spiplan->ptlist) == 1 && list_length(qtlist) == 1)	{		Query	   *queryTree = (Query *) linitial((List *) linitial(qtlist));		if (queryTree->commandType == CMD_SELECT && queryTree->into == NULL)			return true;	}	return false;}/* * SPI_result_code_string --- convert any SPI return code to a string * * This is often useful in error messages.	Most callers will probably * only pass negative (error-case) codes, but for generality we recognize * the success codes too. */const char *SPI_result_code_string(int code){	static char buf[64];	switch (code)	{		case SPI_ERROR_CONNECT:			return "SPI_ERROR_CONNECT";		case SPI_ERROR_COPY:			return "SPI_ERROR_COPY";		case SPI_ERROR_OPUNKNOWN:			return "SPI_ERROR_OPUNKNOWN";		case SPI_ERROR_UNCONNECTED:			return "SPI_ERROR_UNCONNECTED";		case SPI_ERROR_CURSOR:			return "SPI_ERROR_CURSOR";		case SPI_ERROR_ARGUMENT:			return "SPI_ERROR_ARGUMENT";		case SPI_ERROR_PARAM:			return "SPI_ERROR_PARAM";		case SPI_ERROR_TRANSACTION:			return "SPI_ERROR_TRANSACTION";		case SPI_ERROR_NOATTRIBUTE:			return "SPI_ERROR_NOATTRIBUTE";		case SPI_ERROR_NOOUTFUNC:			return "SPI_ERROR_NOOUTFUNC";		case SPI_ERROR_TYPUNKNOWN:			return "SPI_ERROR_TYPUNKNOWN";		case SPI_OK_CONNECT:			return "SPI_OK_CONNECT";		case SPI_OK_FINISH:			return "SPI_OK_FINISH";		case SPI_OK_FETCH:			return "SPI_OK_FETCH";		case SPI_OK_UTILITY:			return "SPI_OK_UTILITY";		case SPI_OK_SELECT:			return "SPI_OK_SELECT";		case SPI_OK_SELINTO:			return "SPI_OK_SELINTO";		case SPI_OK_INSERT:			return "SPI_OK_INSERT";		case SPI_OK_DELETE:			return "SPI_OK_DELETE";		case SPI_OK_UPDATE:			return "SPI_OK_UPDATE";		case SPI_OK_CURSOR:			return "SPI_OK_CURSOR";	}	/* Unrecognized code ... return something useful ... */	sprintf(buf, "Unrecognized SPI code %d", code);	return buf;}/* =================== private functions =================== *//* * spi_dest_startup *		Initialize to receive tuples from Executor into SPITupleTable *		of current SPI procedure */voidspi_dest_startup(DestReceiver *self, int operation, TupleDesc typeinfo){	SPITupleTable *tuptable;	MemoryContext oldcxt;	MemoryContext tuptabcxt;	/*	 * When called by Executor _SPI_curid expected to be equal to	 * _SPI_connected	 */	if (_SPI_curid != _SPI_connected || _SPI_connected < 0)		elog(ERROR, "improper call to spi_dest_startup");	if (_SPI_current != &(_SPI_stack[_SPI_curid]))		elog(ERROR, "SPI stack corrupted");	if (_SPI_current->tuptable != NULL)		elog(ERROR, "improper call to spi_dest_startup");	oldcxt = _SPI_procmem();	/* switch to procedure memory context */	tuptabcxt = AllocSetContextCreate(CurrentMemoryContext,									  "SPI TupTable",									  ALLOCSET_DEFAULT_MINSIZE,									  ALLOCSET_DEFAULT_INITSIZE,									  ALLOCSET_DEFAULT_MAXSIZE);	MemoryContextSwitchTo(tuptabcxt);	_SPI_current->tuptable = tuptable = (SPITupleTable *)		palloc(sizeof(SPITupleTable));	tuptable->tuptabcxt = tuptabcxt;	tuptable->alloced = tuptable->free = 128;	tuptable->vals = (HeapTuple *) palloc(tuptable->alloced * sizeof(HeapTuple));	tuptable->tupdesc = CreateTupleDescCopy(typeinfo);	MemoryContextSwitchTo(oldcxt);}

⌨️ 快捷键说明

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