📄 spi.c
字号:
if (rel->rd_rel->relhasoids) HeapTupleSetOid(mtuple, HeapTupleGetOid(tuple)); } else { mtuple = NULL; SPI_result = SPI_ERROR_NOATTRIBUTE; } pfree(v); pfree(n); if (oldcxt) MemoryContextSwitchTo(oldcxt); return mtuple;}intSPI_fnumber(TupleDesc tupdesc, const char *fname){ int res; Form_pg_attribute sysatt; 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, typelem; int32 typmod; 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; typmod = tupdesc->attrs[fnumber - 1]->atttypmod; } else { typoid = (SystemAttributeDefinition(fnumber, true))->atttypid; typmod = -1; } getTypeOutputInfo(typoid, &foutoid, &typelem, &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 = OidFunctionCall3(foutoid, val, ObjectIdGetDatum(typelem), Int32GetDatum(typmod)); /* 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));}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){ _SPI_plan *spiplan = (_SPI_plan *) plan; List *qtlist = spiplan->qtlist; List *ptlist = spiplan->ptlist; Query *queryTree; Plan *planTree; ParamListInfo paramLI; MemoryContext oldcontext; Portal portal; int k; /* Ensure that the plan contains only one regular SELECT query */ if (length(ptlist) != 1 || length(qtlist) != 1) ereport(ERROR, (errcode(ERRCODE_INVALID_CURSOR_DEFINITION), errmsg("cannot open multi-query plan as cursor"))); queryTree = (Query *) lfirst((List *) lfirst(qtlist)); planTree = (Plan *) lfirst(ptlist); if (queryTree->commandType != CMD_SELECT) ereport(ERROR, (errcode(ERRCODE_INVALID_CURSOR_DEFINITION), errmsg("cannot open non-SELECT query as cursor"))); if (queryTree->into != NULL) ereport(ERROR, (errcode(ERRCODE_INVALID_CURSOR_DEFINITION), errmsg("cannot open SELECT INTO query as cursor"))); /* Increment CommandCounter to see changes made by now */ CommandCounterIncrement(); /* Reset SPI result */ 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].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], ¶mTypLen, ¶mTypByVal); 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", /* cursor's query is always a SELECT */ makeList1(queryTree), makeList1(planTree), PortalGetHeapMemory(portal)); MemoryContextSwitchTo(oldcontext); /* * Set up options for portal. */ portal->cursorOptions &= ~(CURSOR_OPT_SCROLL | CURSOR_OPT_NO_SCROLL); if (ExecSupportsBackwardScan(plan)) portal->cursorOptions |= CURSOR_OPT_SCROLL; else portal->cursorOptions |= CURSOR_OPT_NO_SCROLL; /* * Start portal execution. */ PortalStart(portal, paramLI); Assert(portal->strategy == PORTAL_ONE_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, int count){ _SPI_cursor_operation(portal, forward, count, CreateDestReceiver(SPI, NULL)); /* we know that the SPI receiver doesn't need a destroy call */}/* * SPI_cursor_move() * * Move in a cursor */voidSPI_cursor_move(Portal portal, bool forward, int 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);}/* =================== 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);}/* * spi_printtup * store tuple retrieved by Executor into SPITupleTable * of current SPI procedure */voidspi_printtup(HeapTuple tuple, TupleDesc tupdesc, DestReceiver *self){ SPITupleTable *tuptable; MemoryContext oldcxt; /* * When called by Executor _SPI_curid expected to be equal to * _SPI_connected */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -