/* pg_transactionid.c:
 *	Utility functions for handling the pg_transactionid
 *	table used for partial replication
 *
 * $Id: pg_transactionid.c,v 1.0 2003/09/015 10:27:22 swu Exp $
 *
 *   First version used simply the PQexec function, which does not work all the times
 *   since the parser does not seem to bee "reentrant"
 *   So we use direct access
 */

#include <stdlib.h>

#include "postgres.h"
#include "replication/replication.h"
#include "libpq/libpq.h"
#include "utils/portal.h"
#include "miscadmin.h"
#include "access/heapam.h"
#include "access/relscan.h"
#include "catalog/catname.h"
#include "catalog/indexing.h"
#include "catalog/pg_transactionid.h"
#include "fmgr.h"
#include "utils/builtins.h"
#include "storage/lmgr.h"

#include "miscadmin.h"
#include "utils/fmgroids.h"
#include "utils/syscache.h"

#define MAXQUERYLEN 500


/*static HeapTuple
TransactionIdGetWithOpenRelation(Relation pg_transactionid_relation, TransactionId *localTxnId)
{
	HeapScanDesc	scan;
	HeapTuple	tup;
	ScanKeyData	transactionidKey[1];

	initialize the scan key and begin a scan of pg_type
	ScanKeyEntryInitialize(&transactionidKey[0], 0,
			       Anum_pg_transactionid_localtxnid,
			       F_OIDEQ, PointerGetDatum(localTxnId));

	scan = heap_beginscan(pg_transactionid_relation, 0,
			      SnapshotSelf, 1, transactionidKey);

	 get the tuple 
	tup = heap_getnext(scan, 0);

	heap_endscan(scan);
	
	return tup;
}*/

void AddNewTxn(TransactionId newLocalTxnId, TransactionId newGlobalTxnId)
{
	Relation	pg_transactionid_dec;
	HeapTuple	tup;
	Datum		values[Natts_pg_transactionid];
	char		nulls[Natts_pg_transactionid];
	TupleDesc	tupDesc;

	// JM Milan
	Relation	idescs[Num_pg_transactionid_indices];

	/* set the values */
	values[Anum_pg_transactionid_localtxnid-1] = Int32GetDatum(newLocalTxnId);
	values[Anum_pg_transactionid_globaltxnid-1] = Int32GetDatum(newGlobalTxnId);
	values[Anum_pg_transactionid_bkndid-1] = ObjectIdGetDatum(InvalidOid);
	values[Anum_pg_transactionid_dbid-1] = ObjectIdGetDatum(InvalidOid);
	values[Anum_pg_transactionid_firstlogid-1] = Int32GetDatum(0);
	values[Anum_pg_transactionid_firstlogrecoff-1] = Int32GetDatum(0);
	values[Anum_pg_transactionid_lastlogid-1] = Int32GetDatum(0);
	values[Anum_pg_transactionid_lastlogrecoff-1] = Int32GetDatum(0);

	/*  swu (rem) */
	/*elog(DEBUG, "AddNewTxn: reset nulls");*/
	MemSet(nulls, ' ', Natts_pg_transactionid * sizeof(char));

	/*  swu (rem) */
	/*elog(DEBUG, "AddNewTxn: tuple open");*/
	/* open the pg_transactionid relation */
	pg_transactionid_dec = heap_openr(TransactionIdRelationName, RowExclusiveLock);

	/* Create the tuple and insert it */
	tupDesc = pg_transactionid_dec->rd_att;

	/*  swu (rem) */
	/*elog(DEBUG, "AddNewTxn: form tuple");*/
	tup = heap_formtuple(tupDesc, values, nulls);

	/*  swu (rem) */
	/*elog(DEBUG, "AddNewTxn: insert the tuple");*/
	heap_insert(pg_transactionid_dec, tup);

	/* Update the index */
	//	Relation	idescs[Num_pg_transactionid_indices];
		
	CatalogOpenIndices(Num_pg_transactionid_indices, 
				   Name_pg_transactionid_indices, idescs);
	CatalogIndexInsert(idescs, Num_pg_transactionid_indices, 
				   pg_transactionid_dec, tup);
	CatalogCloseIndices(Num_pg_transactionid_indices, idescs);

	/*  swu (rem) */
	/*elog(DEBUG, "AddNewTxn: heap close");*/
	heap_close(pg_transactionid_dec, RowExclusiveLock);
}


void SetGlobalTxnId(TransactionId localTxnId, TransactionId globalTxnId)
{
	Relation	pg_transactionid_desc;
	Relation	idescs[Num_pg_transactionid_indices];
	HeapTuple	tuple;

	pg_transactionid_desc = heap_openr(TransactionIdRelationName, RowExclusiveLock);

	tuple = SearchSysCacheCopy(TXNLOCALID,
							   Int32GetDatum(localTxnId),
							   0, 0, 0);
	if (!HeapTupleIsValid(tuple))
		elog(ERROR, "SetGlobalTxnId: localTxnId %d does not exist in "
					"pg_transactionid", localTxnId);

	((Form_pg_transactionid) GETSTRUCT(tuple))->globaltxnid = (int4)globalTxnId;

	simple_heap_update(pg_transactionid_desc, &tuple->t_self, tuple);

	/* update the system catalog indices */
	CatalogOpenIndices(Num_pg_transactionid_indices, Name_pg_transactionid_indices, idescs);
	CatalogIndexInsert(idescs, Num_pg_transactionid_indices, pg_transactionid_desc, tuple);
	CatalogCloseIndices(Num_pg_transactionid_indices, idescs);

	heap_freetuple(tuple);
	heap_close(pg_transactionid_desc, RowExclusiveLock);
}

TransactionId 
LocalTxnidGetGlobalTxnid(TransactionId localTxnId)
{
	Relation	pg_transactionid_desc;
	HeapTuple	tuple;

	pg_transactionid_desc = heap_openr(TransactionIdRelationName, RowExclusiveLock);

	tuple = SearchSysCacheCopy(TXNLOCALID,
							   Int32GetDatum(localTxnId),
							   0, 0, 0);
	if (!HeapTupleIsValid(tuple)){
#ifdef EXEC_DEBUG
		elog(DEBUG, "LocalTxnidGetGlobalTxnid: localTxnId %d does not exist in "
					"pg_transactionid", localTxnId);
#endif
		return InvalidTransactionId;
	}

	return ((Form_pg_transactionid) GETSTRUCT(tuple))->globaltxnid;
}

/*void SetXLogRec(TransactionId localTxnId, int4 firstRec, int4 lastRec)
{
	char   q[MAXQUERYLEN];
	TransactionType tmp;

	MemSet(q, '\0', MAXQUERYLEN * sizeof(char));

	tmp = txn_type;
	txn_type = NOT_REPLICATED;

	sprintf(q, "UPDATE pg_transactionid SET firstlogrec = %d, lastlogrec = %X "
		"WHERE localtxnid = %X", (int) localTxnId, firstRec, lastRec);
		
	pg_exec_query(q);

	txn_type = tmp;
}*/

