Skip to content
Snippets Groups Projects
tid.c 7.77 KiB
Newer Older
/*-------------------------------------------------------------------------
 *
 *	  Functions for the built-in type tuple id
PostgreSQL Daemon's avatar
 
PostgreSQL Daemon committed
 * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
Bruce Momjian's avatar
Bruce Momjian committed
 * Portions Copyright (c) 1994, Regents of the University of California
 *	  $PostgreSQL: pgsql/src/backend/utils/adt/tid.c,v 1.51 2006/02/27 01:41:16 momjian Exp $
 *	  input routine largely stolen from boxin().
 *
 *-------------------------------------------------------------------------
 */
#include <errno.h>
#include <math.h>
#include <limits.h>

#include "catalog/namespace.h"
Hiroshi Inoue's avatar
Hiroshi Inoue committed
#include "catalog/pg_type.h"
#define DatumGetItemPointer(X)	 ((ItemPointer) DatumGetPointer(X))
#define ItemPointerGetDatum(X)	 PointerGetDatum(X)
#define PG_GETARG_ITEMPOINTER(n) DatumGetItemPointer(PG_GETARG_DATUM(n))
#define PG_RETURN_ITEMPOINTER(x) return ItemPointerGetDatum(x)

#define LDELIM			'('
#define RDELIM			')'
#define DELIM			','
#define NTIDARGS		2

/* ----------------------------------------------------------------
 * ----------------------------------------------------------------
 */
	char	   *str = PG_GETARG_CSTRING(0);
	char	   *p,
			   *coord[NTIDARGS];
	int			i;
	ItemPointer result;
	BlockNumber blockNumber;
	OffsetNumber offsetNumber;
	char	   *badp;
	int			hold_offset;

	for (i = 0, p = str; *p && i < NTIDARGS && *p != RDELIM; p++)
		if (*p == DELIM || (*p == LDELIM && !i))
			coord[i++] = p + 1;

		ereport(ERROR,
				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
				 errmsg("invalid input syntax for type tid: \"%s\"",
	errno = 0;
	blockNumber = strtoul(coord[0], &badp, 10);
	if (errno || *badp != DELIM)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
				 errmsg("invalid input syntax for type tid: \"%s\"",

	hold_offset = strtol(coord[1], &badp, 10);
	if (errno || *badp != RDELIM ||
		hold_offset > USHRT_MAX || hold_offset < 0)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
				 errmsg("invalid input syntax for type tid: \"%s\"",
	offsetNumber = hold_offset;

	result = (ItemPointer) palloc(sizeof(ItemPointerData));

	ItemPointerSet(result, blockNumber, offsetNumber);

}

/* ----------------------------------------------------------------
 * ----------------------------------------------------------------
 */
	ItemPointer itemPtr = PG_GETARG_ITEMPOINTER(0);
	BlockNumber blockNumber;
	OffsetNumber offsetNumber;
	char		buf[32];
	if (!ItemPointerIsValid(itemPtr))
		PG_RETURN_CSTRING(pstrdup("()"));

	blockId = &(itemPtr->ip_blkid);
	blockNumber = BlockIdGetBlockNumber(blockId);
	offsetNumber = itemPtr->ip_posid;

	/* Perhaps someday we should output this as a record. */
	snprintf(buf, sizeof(buf), "(%u,%u)", blockNumber, offsetNumber);
	PG_RETURN_CSTRING(pstrdup(buf));
/*
 *		tidrecv			- converts external binary format to tid
 */
Datum
tidrecv(PG_FUNCTION_ARGS)
{
	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
	ItemPointer result;
	BlockNumber blockNumber;
	OffsetNumber offsetNumber;

	blockNumber = pq_getmsgint(buf, sizeof(blockNumber));
	offsetNumber = pq_getmsgint(buf, sizeof(offsetNumber));

	result = (ItemPointer) palloc(sizeof(ItemPointerData));

	ItemPointerSet(result, blockNumber, offsetNumber);

	PG_RETURN_ITEMPOINTER(result);
}

/*
 *		tidsend			- converts tid to binary format
 */
Datum
tidsend(PG_FUNCTION_ARGS)
{
	ItemPointer itemPtr = PG_GETARG_ITEMPOINTER(0);
	BlockId		blockId;
	BlockNumber blockNumber;
	OffsetNumber offsetNumber;
	StringInfoData buf;

	blockId = &(itemPtr->ip_blkid);
	blockNumber = BlockIdGetBlockNumber(blockId);
	offsetNumber = itemPtr->ip_posid;

	pq_begintypsend(&buf);
	pq_sendint(&buf, blockNumber, sizeof(blockNumber));
	pq_sendint(&buf, offsetNumber, sizeof(offsetNumber));
	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
}

/*****************************************************************************
 *	 PUBLIC ROUTINES														 *
 *****************************************************************************/

	ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
	ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
	PG_RETURN_BOOL(BlockIdGetBlockNumber(&(arg1->ip_blkid)) ==
				   BlockIdGetBlockNumber(&(arg2->ip_blkid)) &&
				   arg1->ip_posid == arg2->ip_posid);
	ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
	ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);

	PG_RETURN_BOOL(BlockIdGetBlockNumber(&(arg1->ip_blkid)) !=
				   BlockIdGetBlockNumber(&(arg2->ip_blkid)) ||
				   arg1->ip_posid != arg2->ip_posid);
}

/*
 *	Functions to get latest tid of a specified tuple.
 *
 *	Maybe these implementations should be moved to another place
 */
static ItemPointerData Current_last_tid = {{0, 0}, 0};
Tom Lane's avatar
Tom Lane committed

void
setLastTid(const ItemPointer tid)
{
	Current_last_tid = *tid;
}

Hiroshi Inoue's avatar
Hiroshi Inoue committed
/*
 *	Handle CTIDs of views.
 *		CTID should be defined in the view and it must
 *		correspond to the CTID of a base relation.
 */
static Datum
Bruce Momjian's avatar
Bruce Momjian committed
currtid_for_view(Relation viewrel, ItemPointer tid)
Hiroshi Inoue's avatar
Hiroshi Inoue committed
{
	TupleDesc	att = RelationGetDescr(viewrel);
Bruce Momjian's avatar
Bruce Momjian committed
	RuleLock   *rulelock;
	RewriteRule *rewrite;
	int			i,
				natts = att->natts,
				tididx = -1;
Hiroshi Inoue's avatar
Hiroshi Inoue committed

Bruce Momjian's avatar
Bruce Momjian committed
	for (i = 0; i < natts; i++)
Hiroshi Inoue's avatar
Hiroshi Inoue committed
	{
		if (strcmp(NameStr(att->attrs[i]->attname), "ctid") == 0)
Hiroshi Inoue's avatar
Hiroshi Inoue committed
		{
			if (att->attrs[i]->atttypid != TIDOID)
				elog(ERROR, "ctid isn't of type TID");
			tididx = i;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
		}
	}
	if (tididx < 0)
		elog(ERROR, "currtid cannot handle views with no CTID");
	rulelock = viewrel->rd_rules;
	if (!rulelock)
Hiroshi Inoue's avatar
Hiroshi Inoue committed
		elog(ERROR, "the view has no rules");
	for (i = 0; i < rulelock->numLocks; i++)
	{
		rewrite = rulelock->rules[i];
		if (rewrite->event == CMD_SELECT)
		{
Bruce Momjian's avatar
Bruce Momjian committed
			Query	   *query;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
			TargetEntry *tle;

			if (list_length(rewrite->actions) != 1)
Hiroshi Inoue's avatar
Hiroshi Inoue committed
				elog(ERROR, "only one select rule is allowed in views");
			query = (Query *) linitial(rewrite->actions);
Bruce Momjian's avatar
Bruce Momjian committed
			tle = get_tle_by_resno(query->targetList, tididx + 1);
			if (tle && tle->expr && IsA(tle->expr, Var))
Hiroshi Inoue's avatar
Hiroshi Inoue committed
			{
Bruce Momjian's avatar
Bruce Momjian committed
				Var		   *var = (Var *) tle->expr;
Hiroshi Inoue's avatar
Hiroshi Inoue committed
				RangeTblEntry *rte;
Bruce Momjian's avatar
Bruce Momjian committed

				if (var->varno > 0 && var->varno < INNER &&
					var->varattno == SelfItemPointerAttributeNumber)
Hiroshi Inoue's avatar
Hiroshi Inoue committed
				{
					rte = rt_fetch(var->varno, query->rtable);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
					if (rte)
					{
						heap_close(viewrel, AccessShareLock);
						return DirectFunctionCall2(currtid_byreloid, ObjectIdGetDatum(rte->relid), PointerGetDatum(tid));
					}
				}
			}
			break;
		}
	}
	elog(ERROR, "currtid cannot handle this view");
Hiroshi Inoue's avatar
Hiroshi Inoue committed
	return (Datum) 0;
}

Datum
currtid_byreloid(PG_FUNCTION_ARGS)
	Oid			reloid = PG_GETARG_OID(0);
	ItemPointer tid = PG_GETARG_ITEMPOINTER(1);
	Relation	rel;

	result = (ItemPointer) palloc(sizeof(ItemPointerData));
	if (!reloid)
	{
		*result = Current_last_tid;
		PG_RETURN_ITEMPOINTER(result);
	}

	rel = heap_open(reloid, AccessShareLock);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
	if (rel->rd_rel->relkind == RELKIND_VIEW)
		return currtid_for_view(rel, tid);
	ItemPointerCopy(tid, result);
	heap_get_latest_tid(rel, SnapshotNow, result);

	heap_close(rel, AccessShareLock);
Datum
currtid_byrelname(PG_FUNCTION_ARGS)
	text	   *relname = PG_GETARG_TEXT_P(0);
	ItemPointer tid = PG_GETARG_ITEMPOINTER(1);
	Relation	rel;
	relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
	rel = heap_openrv(relrv, AccessShareLock);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
	if (rel->rd_rel->relkind == RELKIND_VIEW)
		return currtid_for_view(rel, tid);

	result = (ItemPointer) palloc(sizeof(ItemPointerData));
	ItemPointerCopy(tid, result);
	heap_get_latest_tid(rel, SnapshotNow, result);

	heap_close(rel, AccessShareLock);