Пример #1
0
/* ----------------------------------------------------------------
 * 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;
}
Пример #2
0
/* ----------------------------------------------------------------
 * 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);
}
Пример #3
0
/* ----------------------------------------------------------------
 * 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);
}
Пример #4
0
/* ----------------------------------------------------------------
 * 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);
}
Пример #5
0
/* ----------------------------------------------------------------
 * 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 */
Пример #6
0
/* ----------------------------------------------------------------
 * 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);
}
Пример #7
0
/* ----------------------------------------------------------------
 * 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 */