/* ---------------------------------------------------------------- * caql_insert_inmem() * during beginscan/endscan iteration, insert a tuple to in-memory-only relation * ---------------------------------------------------------------- */ void caql_insert_inmem(cqContext *pCtx, HeapTuple tup) { InMemHeapRelation inmemrel = NULL; Relation rel = pCtx->cq_heap_rel; Assert(RelationIsValid(rel)); disable_catalog_check(pCtx, tup); { /* scope for caql_iud_switch */ caql_iud_switch(pCtx, 1, NULL, tup, true /* dontWait */); inmemrel = OidGetInMemHeapRelation(rel->rd_id, INMEM_ONLY_MAPPING); if (NULL == inmemrel) { inmemrel = InMemHeap_Create(rel->rd_id, rel, FALSE /* ownRel */, 10 /* initSize */, pCtx->cq_lockmode /*AccessShareLock*/, RelationGetRelationName(rel), FALSE /* createIndex */, 0 /* keyAttrno */, INMEM_ONLY_MAPPING); elog(DEBUG2, "Created new entry for in memory table %s", RelationGetRelationName(rel)); } Assert(NULL != inmemrel); InMemHeap_CheckConstraints(inmemrel, tup); InMemHeap_Insert(inmemrel, tup, -1 /* valid for all segments */); // TODO: is it relevant for in-memory? /* keep the catalog indexes up to date (if has any) */ //caql_UpdateIndexes(pCtx, rel, tup); } }
/* ---------------------------------------------------------------- * caql_getprev() * NOTE: similar to caql_getnext(), but backwards. * Usage is rare and potentially dangerous. * The scankey should be set to point to the *last* key, not the * first, typically using COLNAME <= BINDVALUE, but this assumes * a unique index. (with a non-unique index the beginscan could * potentially position at the *start* of a group of duplicates, * not the end) * ---------------------------------------------------------------- */ HeapTuple caql_getprev(cqContext *pCtx) { HeapTuple tuple; /* set EOF when get invalid tuple */ if (pCtx->cq_EOF) return (NULL); if (!pCtx->cq_usesyscache) { tuple = systable_getprev(pCtx->cq_sysScan); pCtx->cq_EOF = !(HeapTupleIsValid(tuple)); } else { Insist(0); /* XXX XXX: illegal ? */ /* syscache is always 0 or 1 entry */ tuple = SearchSysCacheKeyArray(pCtx->cq_cacheId, pCtx->cq_NumKeys, pCtx->cq_cacheKeys); pCtx->cq_EOF = true; /* at EOF always, because only 0 or 1 */ } disable_catalog_check(pCtx, tuple); pCtx->cq_lasttup = tuple; /* need this for ReleaseSysCache */ return (tuple); }
/* ---------------------------------------------------------------- * caql_getnext() * Return a tuple. The tuple is only valid until caql_endscan(), * or until the next call of caql_getnext(). * NOTE: this function will return NULL when no tuples remain to * satisfy the caql predicate -- use HeapTupleIsValid() to detect * this condition. * ---------------------------------------------------------------- */ HeapTuple caql_getnext(cqContext *pCtx) { HeapTuple tuple; /* set EOF when get invalid tuple */ if (pCtx->cq_EOF) return (NULL); if (!pCtx->cq_usesyscache) { tuple = systable_getnext(pCtx->cq_sysScan); pCtx->cq_EOF = !(HeapTupleIsValid(tuple)); } else { /* syscache is always 0 or 1 entry */ tuple = SearchSysCacheKeyArray(pCtx->cq_cacheId, pCtx->cq_NumKeys, pCtx->cq_cacheKeys); pCtx->cq_EOF = true; /* at EOF always, because only 0 or 1 */ } disable_catalog_check(pCtx, tuple); if (pCtx->cq_setpklock) caql_iud_switch(pCtx, 0, tuple, NULL, false /* Wait */); pCtx->cq_lasttup = tuple; /* need this for ReleaseSysCache */ return tuple; }
/* ---------------------------------------------------------------- * caql_delete_current() * during beginscan/endscan iteration, delete current tuple * ---------------------------------------------------------------- */ void caql_delete_current(cqContext *pCtx) { Relation rel; rel = pCtx->cq_heap_rel; Assert(RelationIsValid(rel)); disable_catalog_check(pCtx, pCtx->cq_lasttup); if (HeapTupleIsValid(pCtx->cq_lasttup)) simple_heap_delete(rel, &(pCtx->cq_lasttup)->t_self); }
/* ---------------------------------------------------------------- * caql_delete_current() * during beginscan/endscan iteration, delete current tuple * ---------------------------------------------------------------- */ void caql_delete_current(cqContext *pCtx) { Relation rel; rel = pCtx->cq_heap_rel; Assert(RelationIsValid(rel)); disable_catalog_check(pCtx, pCtx->cq_lasttup); if (HeapTupleIsValid(pCtx->cq_lasttup)) { caql_iud_switch(pCtx, 0, pCtx->cq_lasttup, NULL, true /* dontWait */); simple_heap_delete(rel, &(pCtx->cq_lasttup)->t_self); } }
/* ---------------------------------------------------------------- * caql_update_current() * during beginscan/endscan iteration, update current tuple, * and update catalog indexes if necessary * NOTE: a separate call to CatalogUpdateIndexes after this will * cause an error * ---------------------------------------------------------------- */ void caql_update_current(cqContext *pCtx, HeapTuple tup) { Relation rel; rel = pCtx->cq_heap_rel; Assert(RelationIsValid(rel)); Insist(HeapTupleIsValid(pCtx->cq_lasttup)); disable_catalog_check(pCtx, pCtx->cq_lasttup); simple_heap_update(rel, &(pCtx->cq_lasttup)->t_self, tup); /* keep the catalog indexes up to date (if has any) */ caql_UpdateIndexes(pCtx, rel, tup); }
/* ---------------------------------------------------------------- * caql_insert() * during beginscan/endscan iteration, insert a tuple * NOTE: a separate call to CatalogUpdateIndexes after this will * cause an error * ---------------------------------------------------------------- */ Oid caql_insert(cqContext *pCtx, HeapTuple tup) { Relation rel; Oid result; rel = pCtx->cq_heap_rel; Assert(RelationIsValid(rel)); disable_catalog_check(pCtx, tup); result = simple_heap_insert(rel, tup); /* keep the catalog indexes up to date (if has any) */ caql_UpdateIndexes(pCtx, rel, tup); return (result); }
/* ---------------------------------------------------------------- * caql_getfirst_only() * Return a copy the first tuple, pallocd in the current memory context, * and end the scan. Clients should heap_freetuple() as necessary. * If pbOnly is not NULL, return TRUE if a second tuple is not found, * else return FALSE * NOTE: this function will return NULL if no tuples satisfy the * caql predicate -- use HeapTupleIsValid() to detect this condition. * ---------------------------------------------------------------- */ HeapTuple caql_getfirst_only(cqContext *pCtx0, bool *pbOnly, cq_list *pcql) { const char* caql_str = pcql->caqlStr; const char* filenam = pcql->filename; int lineno = pcql->lineno; struct caql_hash_cookie *pchn = cq_lookup(caql_str, strlen(caql_str), pcql); cqContext *pCtx; cqContext cqc; HeapTuple tuple, newTup = NULL; if (NULL == pchn) elog(ERROR, "invalid caql string: %s\nfile: %s, line %d", caql_str, filenam, lineno); Assert(!pchn->bInsert); /* INSERT not allowed */ /* use the provided context, or provide a clean local ctx */ if (pCtx0) pCtx = pCtx0; else pCtx = cqclr(&cqc); pCtx = caql_switch(pchn, pCtx, pcql); /* NOTE: caql_switch frees the pcql */ if (pbOnly) *pbOnly = true; /* use the SysCache */ if (pCtx->cq_usesyscache) { tuple = SearchSysCacheKeyArray(pCtx->cq_cacheId, pCtx->cq_NumKeys, pCtx->cq_cacheKeys); disable_catalog_check(pCtx, tuple); if (HeapTupleIsValid(tuple)) { newTup = heap_copytuple(tuple); ReleaseSysCache(tuple); /* only one */ } caql_heapclose(pCtx); pCtx->cq_lasttup = newTup; /* need this for update/delete */ return (newTup); } if (HeapTupleIsValid(tuple = systable_getnext(pCtx->cq_sysScan))) { disable_catalog_check(pCtx, tuple); /* always copy the tuple, because the endscan releases tup memory */ newTup = heap_copytuple(tuple); if (pbOnly) { *pbOnly = !(HeapTupleIsValid(systable_getnext(pCtx->cq_sysScan))); } } systable_endscan(pCtx->cq_sysScan); caql_heapclose(pCtx); pCtx->cq_lasttup = newTup; /* need this for update/delete */ return (newTup); }
/* ---------------------------------------------------------------- * caql_getcount() * Perform COUNT(*) or DELETE * ---------------------------------------------------------------- */ int caql_getcount(cqContext *pCtx0, cq_list *pcql) { const char* caql_str = pcql->caqlStr; const char* filenam = pcql->filename; int lineno = pcql->lineno; struct caql_hash_cookie *pchn = cq_lookup(caql_str, strlen(caql_str), pcql); cqContext *pCtx; cqContext cqc; HeapTuple tuple; Relation rel; int ii = 0; if (NULL == pchn) elog(ERROR, "invalid caql string: %s\nfile: %s, line %d", caql_str, filenam, lineno); Assert(!pchn->bInsert); /* INSERT not allowed */ /* use the provided context, or provide a clean local ctx */ if (pCtx0) pCtx = pCtx0; else pCtx = cqclr(&cqc); pCtx = caql_switch(pchn, pCtx, pcql); /* NOTE: caql_switch frees the pcql */ rel = pCtx->cq_heap_rel; /* use the SysCache */ if (pCtx->cq_usesyscache) { tuple = SearchSysCacheKeyArray(pCtx->cq_cacheId, pCtx->cq_NumKeys, pCtx->cq_cacheKeys); disable_catalog_check(pCtx, tuple); if (HeapTupleIsValid(tuple)) { ii++; pCtx->cq_lasttup = tuple; if (pchn->bDelete) simple_heap_delete(rel, &tuple->t_self); ReleaseSysCache(tuple); /* only one */ } caql_heapclose(pCtx); return (ii); } while (HeapTupleIsValid(tuple = systable_getnext(pCtx->cq_sysScan))) { disable_catalog_check(pCtx, tuple); if (HeapTupleIsValid(tuple) && pchn->bDelete) { pCtx->cq_lasttup = tuple; if (pchn->bDelete) simple_heap_delete(rel, &tuple->t_self); } ii++; } systable_endscan(pCtx->cq_sysScan); caql_heapclose(pCtx); return (ii); }
/* ---------------------------------------------------------------- * caql_getcstring_plus() * Return a cstring column from the first tuple and end the scan. * ---------------------------------------------------------------- */ char *caql_getcstring_plus(cqContext *pCtx0, int *pFetchcount, bool *pbIsNull, cq_list *pcql) { const char *caql_str = pcql->caqlStr; const char *filenam = pcql->filename; int lineno = pcql->lineno; struct caql_hash_cookie *pchn = cq_lookup(caql_str, strlen(caql_str), pcql); cqContext *pCtx; cqContext cqc; HeapTuple tuple; char *result = NULL; if (NULL == pchn) elog(ERROR, "invalid caql string: %s\nfile: %s, line %d", caql_str, filenam, lineno); Assert(!pchn->bInsert); /* INSERT not allowed */ /* use the provided context, or provide a clean local ctx */ if (pCtx0) pCtx = pCtx0; else pCtx = cqclr(&cqc); pCtx = caql_switch(pchn, pCtx, pcql); /* NOTE: caql_switch frees the pcql */ if (pFetchcount) *pFetchcount = 0; if (pbIsNull) *pbIsNull = true; /* use the SysCache */ if (pCtx->cq_usesyscache) { tuple = SearchSysCacheKeyArray(pCtx->cq_cacheId, pCtx->cq_NumKeys, pCtx->cq_cacheKeys); } else { tuple = systable_getnext(pCtx->cq_sysScan); } disable_catalog_check(pCtx, tuple); if (HeapTupleIsValid(tuple)) { bool isnull; Datum d; if (pFetchcount) *pFetchcount = 1; d = caql_getattr_internal(pCtx, tuple, pchn->attnum, &isnull); if (!isnull) { switch (pchn->atttype) { case NAMEOID: result = DatumGetCString(DirectFunctionCall1(nameout, d)); break; case TEXTOID: result = DatumGetCString(DirectFunctionCall1(textout, d)); break; default: elog(ERROR, "column not a cstring: %s\nfile: %s, line %d", caql_str, filenam, lineno); } } if (pbIsNull) *pbIsNull = isnull; } /* end HeapTupleIsValid */ if (pCtx->cq_usesyscache) { if (HeapTupleIsValid(tuple)) ReleaseSysCache(tuple); } else { if (pFetchcount && HeapTupleIsValid(tuple)) { if (HeapTupleIsValid(systable_getnext(pCtx->cq_sysScan))) { *pFetchcount = 2; } } systable_endscan(pCtx->cq_sysScan); } caql_heapclose(pCtx); return (result); } /* end caql_getcstring_plus */
/* ---------------------------------------------------------------- * caql_getoid_only() * Return the oid of the first tuple and end the scan * If pbOnly is not NULL, return TRUE if a second tuple is not found, * else return FALSE * ---------------------------------------------------------------- */ Oid caql_getoid_only(cqContext *pCtx0, bool *pbOnly, cq_list *pcql) { const char *caql_str = pcql->caqlStr; const char *filenam = pcql->filename; int lineno = pcql->lineno; struct caql_hash_cookie *pchn = cq_lookup(caql_str, strlen(caql_str), pcql); cqContext *pCtx; cqContext cqc; HeapTuple tuple; Oid result = InvalidOid; if (NULL == pchn) elog(ERROR, "invalid caql string: %s\nfile: %s, line %d", caql_str, filenam, lineno); Assert(!pchn->bInsert); /* INSERT not allowed */ /* use the provided context, or provide a clean local ctx */ if (pCtx0) pCtx = pCtx0; else pCtx = cqclr(&cqc); pCtx = caql_switch(pchn, pCtx, pcql); /* NOTE: caql_switch frees the pcql */ if (pbOnly) *pbOnly = true; /* use the SysCache */ if (pCtx->cq_usesyscache) { tuple = SearchSysCacheKeyArray(pCtx->cq_cacheId, pCtx->cq_NumKeys, pCtx->cq_cacheKeys); disable_catalog_check(pCtx, tuple); if (HeapTupleIsValid(tuple)) { result = HeapTupleGetOid(tuple); ReleaseSysCache(tuple); /* only one */ } caql_heapclose(pCtx); return (result); } if (HeapTupleIsValid(tuple = systable_getnext(pCtx->cq_sysScan))) { disable_catalog_check(pCtx, tuple); result = HeapTupleGetOid(tuple); if (pbOnly) { *pbOnly = !(HeapTupleIsValid(tuple = systable_getnext(pCtx->cq_sysScan))); } } systable_endscan(pCtx->cq_sysScan); caql_heapclose(pCtx); return (result); }
/* ---------------------------------------------------------------- * caql_getoid_plus() * Return an oid column from the first tuple and end the scan. * Note: this works for regproc columns as well, but you should cast * the output as RegProcedure. * ---------------------------------------------------------------- */ Oid caql_getoid_plus(cqContext *pCtx0, int *pFetchcount, bool *pbIsNull, cq_list *pcql) { const char *caql_str = pcql->caqlStr; const char *filenam = pcql->filename; int lineno = pcql->lineno; struct caql_hash_cookie *pchn = cq_lookup(caql_str, strlen(caql_str), pcql); cqContext *pCtx; cqContext cqc; HeapTuple tuple; Oid result = InvalidOid; if (NULL == pchn) elog(ERROR, "invalid caql string: %s\nfile: %s, line %d", caql_str, filenam, lineno); Assert(!pchn->bInsert); /* INSERT not allowed */ /* use the provided context, or provide a clean local ctx */ if (pCtx0) pCtx = pCtx0; else pCtx = cqclr(&cqc); pCtx = caql_switch(pchn, pCtx, pcql); /* NOTE: caql_switch frees the pcql */ if (pFetchcount) *pFetchcount = 0; if (pbIsNull) *pbIsNull = true; /* use the SysCache */ if (pCtx->cq_usesyscache) { tuple = SearchSysCacheKeyArray(pCtx->cq_cacheId, pCtx->cq_NumKeys, pCtx->cq_cacheKeys); } else { tuple = systable_getnext(pCtx->cq_sysScan); } disable_catalog_check(pCtx, tuple); if (HeapTupleIsValid(tuple)) { if (pFetchcount) *pFetchcount = 1; /* if attnum not set, (InvalidAttrNumber == 0) * use tuple oid, else extract oid from column * (includes ObjectIdAttributeNumber == -2) */ if (pchn->attnum <= InvalidAttrNumber) { if (pbIsNull) *pbIsNull = false; result = HeapTupleGetOid(tuple); } else /* find oid column */ { bool isnull; Datum d = caql_getattr_internal(pCtx, tuple, pchn->attnum, &isnull); if (!isnull) { switch (pchn->atttype) { case OIDOID: case REGPROCOID: result = DatumGetObjectId(d); break; default: elog(ERROR, "column not an oid: %s\nfile: %s, line %d", caql_str, filenam, lineno); } } if (pbIsNull) *pbIsNull = isnull; } } /* end HeapTupleIsValid */ if (pCtx->cq_usesyscache) { if (HeapTupleIsValid(tuple)) ReleaseSysCache(tuple); } else { if (pFetchcount && HeapTupleIsValid(tuple)) { if (HeapTupleIsValid(systable_getnext(pCtx->cq_sysScan))) { *pFetchcount = 2; } } systable_endscan(pCtx->cq_sysScan); } caql_heapclose(pCtx); return (result); } /* end caql_getoid_plus */