/* ---------------------------------------------------------------- * 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_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 */ } pCtx->cq_lasttup = tuple; /* need this for ReleaseSysCache */ return (tuple); }
/* ---------------------------------------------------------------- * 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); 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))) { /* 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); 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))) { 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); } 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); if (HeapTupleIsValid(tuple)) { result = HeapTupleGetOid(tuple); ReleaseSysCache(tuple); /* only one */ } caql_heapclose(pCtx); return (result); } if (HeapTupleIsValid(tuple = systable_getnext(pCtx->cq_sysScan))) { 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); } 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 */