/*
 * hamr.c --
 *	POSTGRES heap access method rule lock code.
 */

#include "c.h"

#include "buf.h"
#include "bufmgr.h"
#include "heapam.h"
#include "htup.h"
#include "log.h"
#include "rac.h"
#include "rel.h"
#include "rlock.h"
#include "tqual.h"

#include "hamr.h"

RcsId("$Header: hamr.c,v 1.2 89/02/02 16:28:02 dillon Exp $");

void
RelationSetHeapRuleLock(relation, heapItem, lock)
	Relation	relation;
	ItemPointer	heapItem;
	RuleLock	lock;
{
	HeapTuple	tuple;
	Buffer		buffer;

	Assert(RelationIsValid(relation));
	Assert(ItemPointerIsValid(heapItem));
	Assert(RuleLockIsValid(lock));

	tuple = RelationGetHeapTupleByItemPointer(relation, SelfTimeQual,
		heapItem, &buffer);
	if (!HeapTupleIsValid(tuple)) {
		elog(WARN, "RelationSetHeapRuleLock: tuple not found");
	}

	/* XXX sort just in case */
	if (RuleLockIsValid(lock)) {
		RuleLockIntermediate	*newP;

		newP = RuleLockInternalToIntermediate(lock);
		newP = RuleLockIntermediateSort(newP);
		/* form external representation */
		lock = RuleLockIntermediateToInternal(newP);
		RuleLockIntermediateFree(newP);
	}

	/* store lock */
	BufferPut(buffer, L_EX);
	HeapTupleStoreRuleLock(tuple, buffer, lock);
	BufferPut(buffer, L_UN | L_EX | L_WRITE);
	/* XXX may need to free MyAlloc'd data ??? */
}

void
RelationAddHeapRuleLock(relation, heapItem, newLock)
	Relation	relation;
	ItemPointer	heapItem;
	RuleLock	newLock;
{
	HeapTuple		tuple;
	Buffer			buffer;
	RuleLock		presentLock;
	RuleLockIntermediate	*newP;

	Assert(RelationIsValid(relation));
	Assert(ItemPointerIsValid(heapItem));
	Assert(RuleLockIsValid(newLock));

	tuple = RelationGetHeapTupleByItemPointer(relation, SelfTimeQual,
		heapItem, &buffer);
	if (!HeapTupleIsValid(tuple)) {
		elog(WARN, "RelationSetHeapRuleLock: tuple not found");
	}

	newP = RuleLockInternalToIntermediate(newLock);

	/* XXX sort just in case */
	newP = RuleLockIntermediateSort(newP);

	presentLock = HeapTupleGetRuleLock(tuple, buffer);
	if (RuleLockIsValid(presentLock)) {

		RuleLockIntermediate	*presentP =
			RuleLockInternalToIntermediate(presentLock);

		/* XXX sort just in case */
		presentP = RuleLockIntermediateSort(presentP);

		/* compute new lock */
		newP = RuleLockIntermediateUnion(presentP, newP);
	}

	/* form external representation */
	newLock = RuleLockIntermediateToInternal(newP);
	RuleLockIntermediateFree(newP);

	/* store lock */
	BufferPut(buffer, L_EX);
	HeapTupleStoreRuleLock(tuple, buffer, newLock);
	BufferPut(buffer, L_UN | L_EX | L_WRITE);
	/* XXX may need to free MyAlloc'd data ??? */
}

void
RelationRemoveHeapRuleLock(relation, heapItem, oldLock)
	Relation	relation;
	ItemPointer	heapItem;
	RuleLock	oldLock;
{
	HeapTuple		tuple;
	Buffer			buffer;
	RuleLock		presentLock;
	RuleLockIntermediate	*nextP;
	RuleLockIntermediate	*presentP;
	RuleLockIntermediate	*oldP;

	Assert(RelationIsValid(relation));
	Assert(ItemPointerIsValid(heapItem));
	Assert(RuleLockIsValid(oldLock));

	tuple = RelationGetHeapTupleByItemPointer(relation, SelfTimeQual,
		heapItem, &buffer);
	if (!HeapTupleIsValid(tuple)) {
		elog(WARN, "RelationSetHeapRuleLock: tuple not found");
	}

	presentLock = HeapTupleGetRuleLock(tuple, buffer);
	if (!RuleLockIsValid(presentLock)) {
		BufferPut(buffer, L_UNPIN);
		return;
	}

	presentP = RuleLockInternalToIntermediate(presentLock);
	oldP = RuleLockInternalToIntermediate(oldLock);

	/* XXX sort just in case and for efficiency? */
	presentP = RuleLockIntermediateSort(presentP);
	nextP = oldP = RuleLockIntermediateSort(oldP);

	/* compute new lock */
	while (PointerIsValid(nextP)) {

		ObjectId			ruleId = nextP->ruleid;
		RuleLockIntermediateLockData	*nextLockP = nextP->locks;
		int		status;

		while (PointerIsValid(nextLockP)) {
			presentP = RuleLockIntermediateRemove(presentP, ruleId,
				nextLockP->locktype, nextLockP->planno,
				nextLockP->attrno, &status);
			if (!status) {
				elog(FATAL,
					"RelationRemoveHeapRuleLock: bad arg");
			}
			nextLockP = nextLockP->next_lock;
		}
		nextP = nextP->next_rulepack;
	}

	/* form external representation */
	presentLock = RuleLockIntermediateToInternal(presentP);
	RuleLockIntermediateFree(presentP);
	RuleLockIntermediateFree(oldP);

	/* store lock */
	BufferPut(buffer, L_EX);
	HeapTupleStoreRuleLock(tuple, buffer, presentLock);
	BufferPut(buffer, L_UN | L_EX | L_WRITE);
	/* XXX may need to free MyAlloc'd data ??? */
}
