/* * Print the value of a Datum given its type. */ static void _outDatum(StringInfo str, Datum value, int typlen, bool typbyval) { Size length; char *s; if (typbyval) { s = (char *) (&value); appendBinaryStringInfo(str, s, sizeof(Datum)); } else { s = (char *) DatumGetPointer(value); if (!PointerIsValid(s)) { length = 0; appendBinaryStringInfo(str, (char *)&length, sizeof(Size)); } else { length = datumGetSize(value, typbyval, typlen); appendBinaryStringInfo(str, (char *)&length, sizeof(Size)); appendBinaryStringInfo(str, s, length); } } }
/* * CleanupInvalidationState * Mark the current backend as no longer active. * * This function is called via on_shmem_exit() during backend shutdown. * * arg is really of type "SISeg*". */ static void CleanupInvalidationState(int status, Datum arg) { SISeg *segP = (SISeg *) DatumGetPointer(arg); ProcState *stateP; int i; Assert(PointerIsValid(segP)); LWLockAcquire(SInvalWriteLock, LW_EXCLUSIVE); stateP = &segP->procState[MyBackendId - 1]; /* Update next local transaction ID for next holder of this backendID */ stateP->nextLXID = nextLocalTransactionId; /* Mark myself inactive */ stateP->procPid = 0; stateP->proc = NULL; stateP->nextMsgNum = 0; stateP->resetState = false; stateP->signaled = false; /* Recompute index of last active backend */ for (i = segP->lastBackend; i > 0; i--) { if (segP->procState[i - 1].procPid != 0) break; } segP->lastBackend = i; LWLockRelease(SInvalWriteLock); }
int inv_seek(LargeObjectDesc *obj_desc, int offset, int whence) { Assert(PointerIsValid(obj_desc)); switch (whence) { case SEEK_SET: if (offset < 0) elog(ERROR, "invalid seek offset: %d", offset); obj_desc->offset = offset; break; case SEEK_CUR: if (offset < 0 && obj_desc->offset < ((uint32) (-offset))) elog(ERROR, "invalid seek offset: %d", offset); obj_desc->offset += offset; break; case SEEK_END: { uint32 size = inv_getsize(obj_desc); if (offset < 0 && size < ((uint32) (-offset))) elog(ERROR, "invalid seek offset: %d", offset); obj_desc->offset = size + offset; } break; default: elog(ERROR, "invalid whence: %d", whence); } return obj_desc->offset; }
/* * InitCatalogCache - initialize the caches * * Note that no database access is done here; we only allocate memory * and initialize the cache structure. Interrogation of the database * to complete initialization of a cache happens upon first use * of that cache. */ void InitCatalogCache(void) { int cacheId; int i, j; StaticAssertStmt(SysCacheSize == (int) lengthof(cacheinfo), "SysCacheSize does not match syscache.c's array"); Assert(!CacheInitialized); SysCacheRelationOidSize = SysCacheSupportingRelOidSize = 0; for (cacheId = 0; cacheId < SysCacheSize; cacheId++) { SysCache[cacheId] = InitCatCache(cacheId, cacheinfo[cacheId].reloid, cacheinfo[cacheId].indoid, cacheinfo[cacheId].nkeys, cacheinfo[cacheId].key, cacheinfo[cacheId].nbuckets); if (!PointerIsValid(SysCache[cacheId])) elog(ERROR, "could not initialize cache %u (%d)", cacheinfo[cacheId].reloid, cacheId); /* Accumulate data for OID lists, too */ SysCacheRelationOid[SysCacheRelationOidSize++] = cacheinfo[cacheId].reloid; SysCacheSupportingRelOid[SysCacheSupportingRelOidSize++] = cacheinfo[cacheId].reloid; SysCacheSupportingRelOid[SysCacheSupportingRelOidSize++] = cacheinfo[cacheId].indoid; /* see comments for RelationInvalidatesSnapshotsOnly */ Assert(!RelationInvalidatesSnapshotsOnly(cacheinfo[cacheId].reloid)); } Assert(SysCacheRelationOidSize <= lengthof(SysCacheRelationOid)); Assert(SysCacheSupportingRelOidSize <= lengthof(SysCacheSupportingRelOid)); /* Sort and de-dup OID arrays, so we can use binary search. */ pg_qsort(SysCacheRelationOid, SysCacheRelationOidSize, sizeof(Oid), oid_compare); for (i = 1, j = 0; i < SysCacheRelationOidSize; i++) { if (SysCacheRelationOid[i] != SysCacheRelationOid[j]) SysCacheRelationOid[++j] = SysCacheRelationOid[i]; } SysCacheRelationOidSize = j + 1; pg_qsort(SysCacheSupportingRelOid, SysCacheSupportingRelOidSize, sizeof(Oid), oid_compare); for (i = 1, j = 0; i < SysCacheSupportingRelOidSize; i++) { if (SysCacheSupportingRelOid[i] != SysCacheSupportingRelOid[j]) SysCacheSupportingRelOid[++j] = SysCacheSupportingRelOid[i]; } SysCacheSupportingRelOidSize = j + 1; CacheInitialized = true; }
Datum zlib_constructor(PG_FUNCTION_ARGS) { /* PG_GETARG_POINTER(0) is TupleDesc that is currently unused. * It is passed as NULL */ StorageAttributes *sa = PG_GETARG_POINTER(1); CompressionState *cs = palloc0(sizeof(CompressionState)); zlib_state *state = palloc0(sizeof(zlib_state)); bool compress = PG_GETARG_BOOL(2); cs->opaque = (void *) state; cs->desired_sz = NULL; Insist(PointerIsValid(sa->comptype)); if (sa->complevel == 0) sa->complevel = 1; state->level = sa->complevel; state->compress = compress; state->compress_fn = compress2; state->decompress_fn = uncompress; PG_RETURN_POINTER(cs); }
/* * CleanupInvalidationState * Mark the current backend as no longer active. * * This function is called via on_shmem_exit() during backend shutdown, * so the caller has NOT acquired the lock for us. * * arg is really of type "SISeg*". */ static void CleanupInvalidationState(int status, Datum arg) { SISeg *segP = (SISeg *) DatumGetPointer(arg); int i; Assert(PointerIsValid(segP)); LWLockAcquire(SInvalLock, LW_EXCLUSIVE); /* Update next local transaction ID for next holder of this backendID */ segP->nextLXID[MyBackendId - 1] = nextLocalTransactionId; /* Mark myself inactive */ segP->procState[MyBackendId - 1].nextMsgNum = -1; segP->procState[MyBackendId - 1].resetState = false; /* Recompute index of last active backend */ for (i = segP->lastBackend; i > 0; i--) { if (segP->procState[i - 1].nextMsgNum >= 0) break; } segP->lastBackend = i; /* Adjust free slot count */ segP->freeBackends++; LWLockRelease(SInvalLock); }
int64 inv_tell(LargeObjectDesc *obj_desc) { Assert(PointerIsValid(obj_desc)); return obj_desc->offset; }
/* * Determine size of a large object * * NOTE: LOs can contain gaps, just like Unix files. We actually return * the offset of the last byte + 1. */ static uint32 inv_getsize(LargeObjectDesc *obj_desc) { bool found = false; uint32 lastbyte = 0; ScanKeyData skey[1]; IndexScanDesc sd; HeapTuple tuple; Assert(PointerIsValid(obj_desc)); open_lo_relation(); ScanKeyInit(&skey[0], Anum_pg_largeobject_loid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(obj_desc->id)); sd = index_beginscan(lo_heap_r, lo_index_r, obj_desc->snapshot, 1, skey); /* * Because the pg_largeobject index is on both loid and pageno, but we * constrain only loid, a backwards scan should visit all pages of the * large object in reverse pageno order. So, it's sufficient to examine * the first valid tuple (== last valid page). */ while ((tuple = index_getnext(sd, BackwardScanDirection)) != NULL) { Form_pg_largeobject data; bytea *datafield; bool pfreeit; found = true; if (HeapTupleHasNulls(tuple)) /* paranoia */ elog(ERROR, "null field found in pg_largeobject"); data = (Form_pg_largeobject) GETSTRUCT(tuple); datafield = &(data->data); /* see note at top of file */ pfreeit = false; if (VARATT_IS_EXTENDED(datafield)) { datafield = (bytea *) heap_tuple_untoast_attr((struct varlena *) datafield); pfreeit = true; } lastbyte = data->pageno * LOBLKSIZE + getbytealen(datafield); if (pfreeit) pfree(datafield); break; } index_endscan(sd); if (!found) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("large object %u does not exist", obj_desc->id))); return lastbyte; }
/* * Closes a large object descriptor previously made by inv_open(), and * releases the long-term memory used by it. */ void inv_close(LargeObjectDesc *obj_desc) { Assert(PointerIsValid(obj_desc)); if (obj_desc->snapshot != SnapshotNow) FreeSnapshot(obj_desc->snapshot); pfree(obj_desc); }
/* * Closes a large object descriptor previously made by inv_open(), and * releases the long-term memory used by it. */ void inv_close(LargeObjectDesc *obj_desc) { Assert(PointerIsValid(obj_desc)); UnregisterSnapshotFromOwner(obj_desc->snapshot, TopTransactionResourceOwner); pfree(obj_desc); }
HeapTuple SearchSysCache4(int cacheId, Datum key1, Datum key2, Datum key3, Datum key4) { Assert(cacheId >= 0 && cacheId < SysCacheSize && PointerIsValid(SysCache[cacheId])); Assert(SysCache[cacheId]->cc_nkeys == 4); return SearchCatCache4(SysCache[cacheId], key1, key2, key3, key4); }
HeapTuple SearchSysCache1(int cacheId, Datum key1) { Assert(cacheId >= 0 && cacheId < SysCacheSize && PointerIsValid(SysCache[cacheId])); Assert(SysCache[cacheId]->cc_nkeys == 1); return SearchCatCache1(SysCache[cacheId], key1); }
struct catclist * SearchSysCacheList(int cacheId, int nkeys, Datum key1, Datum key2, Datum key3, Datum key4) { if (cacheId < 0 || cacheId >= SysCacheSize || !PointerIsValid(SysCache[cacheId])) elog(ERROR, "invalid cache id: %d", cacheId); return SearchCatCacheList(SysCache[cacheId], nkeys, key1, key2, key3, key4); }
Datum zlib_destructor(PG_FUNCTION_ARGS) { CompressionState *cs = PG_GETARG_POINTER(0); Insist(PointerIsValid(cs->opaque)); pfree(cs->opaque); PG_RETURN_VOID(); }
/* * ExceptionalCondition - Handles the failure of an Assert() */ void ExceptionalCondition(const char *conditionName, const char *errorType, const char *fileName, int lineNumber) { void *array[32]; size_t size; if (!PointerIsValid(conditionName) || !PointerIsValid(fileName) || !PointerIsValid(errorType)) write_stderr("TRAP: ExceptionalCondition: bad arguments\n"); else { write_stderr("TRAP: %s(\"%s\", File: \"%s\", Line: %d, PID: %d, Query: %s)\n", errorType, conditionName, fileName, lineNumber, getpid(), debug_query_string); } /* dump stack trace */ size = backtrace(array, 32); fprintf(stderr, "Assertion failure (PID %d)\n", MyProcPid); fprintf(stderr, "version: %s\n", PIPELINE_VERSION_STR); fprintf(stderr, "backtrace:\n"); backtrace_symbols_fd(array, size, STDERR_FILENO); /* Usually this shouldn't be needed, but make sure the msg went out */ fflush(stderr); #ifdef SLEEP_ON_ASSERT /* * It would be nice to use pg_usleep() here, but only does 2000 sec or 33 * minutes, which seems too short. */ sleep(1000000); #endif abort(); }
/* * SysCacheGetAttr * * Given a tuple previously fetched by SearchSysCache(), * extract a specific attribute. * * This is equivalent to using heap_getattr() on a tuple fetched * from a non-cached relation. Usually, this is only used for attributes * that could be NULL or variable length; the fixed-size attributes in * a system table are accessed just by mapping the tuple onto the C struct * declarations from include/catalog/. * * As with heap_getattr(), if the attribute is of a pass-by-reference type * then a pointer into the tuple data area is returned --- the caller must * not modify or pfree the datum! */ Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull) { /* * We just need to get the TupleDesc out of the cache entry, and then * we can apply heap_getattr(). We expect that the cache control data * is currently valid --- if the caller recently fetched the tuple, * then it should be. */ if (cacheId < 0 || cacheId >= SysCacheSize) elog(ERROR, "invalid cache id: %d", cacheId); if (!PointerIsValid(SysCache[cacheId]) || !PointerIsValid(SysCache[cacheId]->cc_tupdesc)) elog(ERROR, "missing cache data for cache id %d", cacheId); return heap_getattr(tup, attributeNumber, SysCache[cacheId]->cc_tupdesc, isNull); }
/* * SysCacheInvalidate * * Invalidate entries in the specified cache, given a hash value. * See CatCacheInvalidate() for more info. * * This routine is only quasi-public: it should only be used by inval.c. */ void SysCacheInvalidate(int cacheId, uint32 hashValue) { if (cacheId < 0 || cacheId >= SysCacheSize) elog(ERROR, "invalid cache ID: %d", cacheId); /* if this cache isn't initialized yet, no need to do anything */ if (!PointerIsValid(SysCache[cacheId])) return; CatCacheInvalidate(SysCache[cacheId], hashValue); }
/* * Determine size of a large object * * NOTE: LOs can contain gaps, just like Unix files. We actually return * the offset of the last byte + 1. */ static uint64 inv_getsize(LargeObjectDesc *obj_desc) { uint64 lastbyte = 0; ScanKeyData skey[1]; SysScanDesc sd; HeapTuple tuple; Assert(PointerIsValid(obj_desc)); open_lo_relation(); ScanKeyInit(&skey[0], Anum_pg_largeobject_loid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(obj_desc->id)); sd = systable_beginscan_ordered(lo_heap_r, lo_index_r, obj_desc->snapshot, 1, skey); /* * Because the pg_largeobject index is on both loid and pageno, but we * constrain only loid, a backwards scan should visit all pages of the * large object in reverse pageno order. So, it's sufficient to examine * the first valid tuple (== last valid page). */ tuple = systable_getnext_ordered(sd, BackwardScanDirection); if (HeapTupleIsValid(tuple)) { Form_pg_largeobject data; bytea *datafield; bool pfreeit; if (HeapTupleHasNulls(tuple)) /* paranoia */ elog(ERROR, "null field found in pg_largeobject"); data = (Form_pg_largeobject) GETSTRUCT(tuple); datafield = &(data->data); /* see note at top of file */ pfreeit = false; if (VARATT_IS_EXTENDED(datafield)) { datafield = (bytea *) heap_tuple_untoast_attr((struct varlena *) datafield); pfreeit = true; } lastbyte = (uint64) data->pageno * LOBLKSIZE + getbytealen(datafield); if (pfreeit) pfree(datafield); } systable_endscan_ordered(sd); return lastbyte; }
/* * GetPortalByName * Returns a portal given a portal name, or NULL if name not found. */ Portal GetPortalByName(const char *name) { Portal portal; if (PointerIsValid(name)) PortalHashTableLookup(name, portal); else portal = NULL; return portal; }
/* * SearchSysCache * * A layer on top of SearchCatCache that does the initialization and * key-setting for you. * * Returns the cache copy of the tuple if one is found, NULL if not. * The tuple is the 'cache' copy and must NOT be modified! * * When the caller is done using the tuple, call ReleaseSysCache() * to release the reference count grabbed by SearchSysCache(). If this * is not done, the tuple will remain locked in cache until end of * transaction, which is tolerable but not desirable. * * CAUTION: The tuple that is returned must NOT be freed by the caller! */ HeapTuple SearchSysCache(int cacheId, Datum key1, Datum key2, Datum key3, Datum key4) { if (cacheId < 0 || cacheId >= SysCacheSize || !PointerIsValid(SysCache[cacheId])) elog(ERROR, "invalid cache id: %d", cacheId); return SearchCatCache(SysCache[cacheId], key1, key2, key3, key4); }
/* * GetSysCacheHashValue * * Get the hash value that would be used for a tuple in the specified cache * with the given search keys. * * The reason for exposing this as part of the API is that the hash value is * exposed in cache invalidation operations, so there are places outside the * catcache code that need to be able to compute the hash values. */ uint32 GetSysCacheHashValue(int cacheId, Datum key1, Datum key2, Datum key3, Datum key4) { if (cacheId < 0 || cacheId >= SysCacheSize || !PointerIsValid(SysCache[cacheId])) elog(ERROR, "invalid cache ID: %d", cacheId); return GetCatCacheHashValue(SysCache[cacheId], key1, key2, key3, key4); }
/* * TupleDescInitEntryCollation * * Assign a nondefault collation to a previously initialized tuple descriptor * entry. */ void TupleDescInitEntryCollation(TupleDesc desc, AttrNumber attributeNumber, Oid collationid) { /* * sanity checks */ AssertArg(PointerIsValid(desc)); AssertArg(attributeNumber >= 1); AssertArg(attributeNumber <= desc->natts); desc->attrs[attributeNumber - 1]->attcollation = collationid; }
/* * CreatePortal * Returns a new portal given a name. * * allowDup: if true, automatically drop any pre-existing portal of the * same name (if false, an error is raised). * * dupSilent: if true, don't even emit a WARNING. */ Portal CreatePortal(const char *name, bool allowDup, bool dupSilent) { Portal portal; AssertArg(PointerIsValid(name)); portal = GetPortalByName(name); if (PortalIsValid(portal)) { if (!allowDup) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_CURSOR), errmsg("cursor \"%s\" already exists", name))); if (!dupSilent) ereport(WARNING, (errcode(ERRCODE_DUPLICATE_CURSOR), errmsg("closing existing cursor \"%s\"", name))); PortalDrop(portal, false); } /* make new portal structure */ portal = (Portal) MemoryContextAllocZero(PortalMemory, sizeof *portal); /* initialize portal heap context; typically it won't store much */ portal->heap = AllocSetContextCreate(PortalMemory, "PortalHeapMemory", ALLOCSET_SMALL_MINSIZE, ALLOCSET_SMALL_INITSIZE, ALLOCSET_SMALL_MAXSIZE); /* create a resource owner for the portal */ portal->resowner = ResourceOwnerCreate(CurTransactionResourceOwner, "Portal"); /* initialize portal fields that don't start off zero */ portal->cleanup = PortalCleanup; portal->createSubid = GetCurrentSubTransactionId(); portal->strategy = PORTAL_MULTI_QUERY; portal->cursorOptions = CURSOR_OPT_NO_SCROLL; portal->atStart = true; portal->atEnd = true; /* disallow fetches until query is set */ /* put portal in table (sets portal->name) */ PortalHashTableInsert(portal, name); return portal; }
/* * SysCacheGetAttr * * Given a tuple previously fetched by SearchSysCache(), * extract a specific attribute. * * This is equivalent to using heap_getattr() on a tuple fetched * from a non-cached relation. Usually, this is only used for attributes * that could be NULL or variable length; the fixed-size attributes in * a system table are accessed just by mapping the tuple onto the C struct * declarations from include/catalog/. * * As with heap_getattr(), if the attribute is of a pass-by-reference type * then a pointer into the tuple data area is returned --- the caller must * not modify or pfree the datum! * * Note: it is legal to use SysCacheGetAttr() with a cacheId referencing * a different cache for the same catalog the tuple was fetched from. */ Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull) { /* * We just need to get the TupleDesc out of the cache entry, and then we * can apply heap_getattr(). Normally the cache control data is already * valid (because the caller recently fetched the tuple via this same * cache), but there are cases where we have to initialize the cache here. */ if (cacheId < 0 || cacheId >= SysCacheSize || !PointerIsValid(SysCache[cacheId])) elog(ERROR, "invalid cache id: %d", cacheId); if (!PointerIsValid(SysCache[cacheId]->cc_tupdesc)) { InitCatCachePhase2(SysCache[cacheId], false); Assert(PointerIsValid(SysCache[cacheId]->cc_tupdesc)); } return heap_getattr(tup, attributeNumber, SysCache[cacheId]->cc_tupdesc, isNull); }
/* * Get the set of functions implementing a compression algorithm. * * Intercept requests for "none", since that is not a real compression * implementation but a fake one to indicate no compression desired. */ PGFunction * get_funcs_for_compression(char *compresstype) { PGFunction *func = NULL; if (!compresstype) return func; if (pg_strcasecmp("none", compresstype) != 0) { func = GetCompressionImplementation(compresstype); Insist(PointerIsValid(func)); } return func; }
/* * PortalDrop * Destroy the portal. * * isError: if true, we are destroying portals at the end of a failed * transaction. (This causes PortalCleanup to skip unneeded steps.) */ void PortalDrop(Portal portal, bool isError) { AssertArg(PortalIsValid(portal)); /* Not sure if this case can validly happen or not... */ if (portal->portalActive) elog(ERROR, "cannot drop active portal"); /* * Remove portal from hash table. Because we do this first, we will * not come back to try to remove the portal again if there's any * error in the subsequent steps. Better to leak a little memory than * to get into an infinite error-recovery loop. */ PortalHashTableDelete(portal); /* let portalcmds.c clean up the state it knows about */ if (PointerIsValid(portal->cleanup)) (*portal->cleanup) (portal, isError); /* * Delete tuplestore if present. We should do this even under error * conditions; since the tuplestore would have been using cross- * transaction storage, its temp files need to be explicitly deleted. */ if (portal->holdStore) { MemoryContext oldcontext; oldcontext = MemoryContextSwitchTo(portal->holdContext); tuplestore_end(portal->holdStore); MemoryContextSwitchTo(oldcontext); portal->holdStore = NULL; } /* delete tuplestore storage, if any */ if (portal->holdContext) MemoryContextDelete(portal->holdContext); /* release subsidiary storage */ MemoryContextDelete(PortalGetHeapMemory(portal)); /* release portal struct (it's in PortalMemory) */ pfree(portal); }
/* --------------------------------------------------------------------- * Quicklz constructor and destructor * --------------------------------------------------------------------- */ Datum quicklz_constructor(PG_FUNCTION_ARGS) { #ifdef FAULT_INJECTOR FaultInjector_InjectFaultIfSet(MallocFailure, DDLNotSpecified, "", // databaseName ""); // tableName #endif /* PG_GETARG_POINTER(0) is TupleDesc that is currently unused. * It is passed as NULL */ StorageAttributes *sa = (StorageAttributes *) PG_GETARG_POINTER(1); CompressionState *cs = palloc0(sizeof(CompressionState)); quicklz_state *state = palloc0(sizeof(quicklz_state)); bool compress = PG_GETARG_BOOL(2); size_t scratchlen = 0; cs->opaque = (void *)state; Insist(PointerIsValid(sa->comptype)); Insist(strcmp(sa->comptype, "quicklz") == 0); Insist(sa->complevel == 1); state->level = sa->complevel; state->compress = compress; if (sa->complevel == 1) { state->compress_fn = quicklz_compressor; state->decompress_fn = quicklz_decompressor; if (compress) scratchlen = sizeof(qlz_state_compress); else scratchlen = sizeof(qlz_state_decompress); } else Insist(false); /* shouldn't get here but code defensively */ state->scratch = palloc0(scratchlen); cs->desired_sz = quicklz_desired_sz; PG_RETURN_POINTER(cs); }
static void appendDatum(StringInfo str, const void *ptr, size_t length, int format) { if (!PointerIsValid(ptr)) appendStringInfoChar(str, ':'); else { const unsigned char *s = (const unsigned char *) ptr; const char *formatstr; size_t i; switch (format) { case 8: formatstr = "%ho"; break; case 10: formatstr = "%hu"; break; case 16: formatstr = "%hx"; break; case 17: formatstr = "%hc"; break; default: elog(ERROR, "unknown format"); formatstr = NULL; /* quite compiler */ } /* append a byte array with the specified format */ for (i = 0; i < length; i++) { if (i > 0) appendStringInfoChar(str, ','); /* print only ANSI visible chars */ if (format == 17 && (iscntrl(s[i]) || !isascii(s[i]))) appendStringInfoChar(str, '?'); else appendStringInfo(str, formatstr, s[i]); } } }
int64 inv_seek(LargeObjectDesc *obj_desc, int64 offset, int whence) { int64 newoffset; Assert(PointerIsValid(obj_desc)); /* * Note: overflow in the additions is possible, but since we will reject * negative results, we don't need any extra test for that. */ switch (whence) { case SEEK_SET: newoffset = offset; break; case SEEK_CUR: newoffset = obj_desc->offset + offset; break; case SEEK_END: newoffset = inv_getsize(obj_desc) + offset; break; default: ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid whence setting: %d", whence))); newoffset = 0; /* keep compiler quiet */ break; } /* * use errmsg_internal here because we don't want to expose INT64_FORMAT * in translatable strings; doing better is not worth the trouble */ if (newoffset < 0 || newoffset > MAX_LARGE_OBJECT_SIZE) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg_internal("invalid large object seek target: " INT64_FORMAT, newoffset))); obj_desc->offset = newoffset; return newoffset; }
PyObj PyPgObject_Initialize(PyObj self, Datum d) { PyPgTypeInfo typinfo = PyPgTypeInfo(Py_TYPE(self)); MemoryContext former = CurrentMemoryContext; MemoryContextSwitchTo(PythonMemoryContext); d = Py_datumCopy(d, typinfo->typbyval, typinfo->typlen); MemoryContextSwitchTo(former); if (!typinfo->typbyval && !PointerIsValid(DatumGetPointer(d))) { Py_DECREF(self); return(NULL); } PyPgObject_SetDatum(self, d); return(self); }