/*-------------------------------------------------------------------------
 *
 * lsyscache.c--
 *	  Routines to access information within system caches
 *
 * Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
 *	  $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.18 1998/08/11 18:28:18 momjian Exp $
 *
 * NOTES
 *	  Eventually, the index information should go through here, too.
 *
 *	  Most of these routines call SearchSysCacheStruct() and thus simply
 *	  (1) allocate some space for the return struct and (2) call it.
 *
 *-------------------------------------------------------------------------
 */
#include <string.h>
#include "postgres.h"

#include "nodes/pg_list.h"
#include "utils/syscache.h"
#include "utils/lsyscache.h"
#include "access/tupmacs.h"
#include "utils/rel.h"
#include "utils/palloc.h"
#include "utils/elog.h"
#include "access/attnum.h"
#include "access/heapam.h"

#include "catalog/pg_amop.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_type.h"

/*				---------- AMOP CACHES ----------						 */

/*
 * op_class -
 *
 *		Return t iff operator 'opno' is in operator class 'opclass'.
 *
 */
bool
op_class(Oid oprno, int32 opclass, Oid amopid)
{
	FormData_pg_amop amoptup;

	if (SearchSysCacheStruct(AMOPOPID,
							 (char *) &amoptup,
							 ObjectIdGetDatum(opclass),
							 ObjectIdGetDatum(oprno),
							 ObjectIdGetDatum(amopid),
							 0))
		return true;
	else
		return false;
}

/*				---------- ATTRIBUTE CACHES ----------					 */

/*
 * get_attname -
 *
 *		Given the relation id and the attribute number,
 *		return the "attname" field from the attribute relation.
 *
 */
char *
get_attname(Oid relid, AttrNumber attnum)
{
	FormData_pg_attribute att_tup;

	if (SearchSysCacheStruct(ATTNUM,
							 (char *) &att_tup,
							 ObjectIdGetDatum(relid),
							 UInt16GetDatum(attnum),
							 0, 0))
		return pstrdup(att_tup.attname.data);
	else
		return NULL;
}

/*
 * get_attnum -
 *
 *		Given the relation id and the attribute name,
 *		return the "attnum" field from the attribute relation.
 *
 */
AttrNumber
get_attnum(Oid relid, char *attname)
{
	FormData_pg_attribute att_tup;

	if (SearchSysCacheStruct(ATTNAME, (char *) &att_tup,
							 ObjectIdGetDatum(relid),
							 PointerGetDatum(attname),
							 0, 0))
		return att_tup.attnum;
	else
		return InvalidAttrNumber;
}

/*
 * get_atttype -
 *
 *		Given the relation OID and the attribute number with the relation,
 *		return the attribute type OID.
 *
 */
Oid
get_atttype(Oid relid, AttrNumber attnum)
{
	AttributeTupleForm att_tup = (AttributeTupleForm) palloc(sizeof(*att_tup));

	if (SearchSysCacheStruct(ATTNUM,
							 (char *) att_tup,
							 ObjectIdGetDatum(relid),
							 UInt16GetDatum(attnum),
							 0, 0))
		return att_tup->atttypid;
	else
		return (Oid) NULL;
}

/* This routine uses the attname instead of the attnum because it
 * replaces the routine find_atttype, which is called sometimes when
 * only the attname, not the attno, is available.
 */
bool
get_attisset(Oid relid, char *attname)
{
	HeapTuple	htup;
	AttrNumber	attno;
	AttributeTupleForm att_tup;

	attno = get_attnum(relid, attname);

	htup = SearchSysCacheTuple(ATTNAME,
							   ObjectIdGetDatum(relid),
							   PointerGetDatum(attname),
							   0, 0);
	if (!HeapTupleIsValid(htup))
		elog(ERROR, "get_attisset: no attribute %s in relation %d",
			 attname, relid);
	if (heap_attisnull(htup, attno))
		return false;
	else
	{
		att_tup = (AttributeTupleForm) GETSTRUCT(htup);
		return att_tup->attisset;
	}
}

/*
 * get_atttypmod -
 *
 *		Given the relation id and the attribute number,
 *		return the "atttypmod" field from the attribute relation.
 *
 */
int32
get_atttypmod(Oid relid, AttrNumber attnum)
{
	FormData_pg_attribute att_tup;

	if (SearchSysCacheStruct(ATTNUM,
							 (char *) &att_tup,
							 ObjectIdGetDatum(relid),
							 Int32GetDatum(attnum),
							 0, 0))
		return att_tup.atttypmod;
	else
		return -1;
}

/*				---------- INDEX CACHE ----------						 */

/*		watch this space...
 */

/*				---------- OPERATOR CACHE ----------					 */

/*
 * get_opcode -
 *
 *		Returns the regproc id of the routine used to implement an
 *		operator given the operator uid.
 *
 */
RegProcedure
get_opcode(Oid opno)
{
	FormData_pg_operator optup;

	if (SearchSysCacheStruct(OPROID, (char *) &optup,
							 ObjectIdGetDatum(opno),
							 0, 0, 0))
		return optup.oprcode;
	else
		return (RegProcedure) NULL;
}

/*
 * get_opname -
 *	  returns the name of the operator with the given opno
 *
 * Note: return the struct so that it gets copied.
 */
char *
get_opname(Oid opno)
{
	FormData_pg_operator optup;

	if (SearchSysCacheStruct(OPROID, (char *) &optup,
							 ObjectIdGetDatum(opno),
							 0, 0, 0))
		return pstrdup(optup.oprname.data);
	else
	{
		elog(ERROR, "can't look up operator %d\n", opno);
		return NULL;
	}
}

/*
 * op_mergejoinable -
 *
 *		Returns the left and right sort operators and types corresponding to a
 *		mergejoinable operator, or nil if the operator is not mergejoinable.
 *
 */
bool
op_mergejoinable(Oid opno, Oid ltype, Oid rtype, Oid *leftOp, Oid *rightOp)
{
	FormData_pg_operator optup;

	if (SearchSysCacheStruct(OPROID, (char *) &optup,
							 ObjectIdGetDatum(opno),
							 0, 0, 0) &&
		optup.oprlsortop &&
		optup.oprrsortop &&
		optup.oprleft == ltype &&
		optup.oprright == rtype)
	{
		*leftOp = ObjectIdGetDatum(optup.oprlsortop);
		*rightOp = ObjectIdGetDatum(optup.oprrsortop);
		return TRUE;
	}
	else
		return FALSE;
}

/*
 * op_hashjoinable--
 *
 * Returns the hash operator corresponding to a hashjoinable operator,
 * or nil if the operator is not hashjoinable.
 *
 */
Oid
op_hashjoinable(Oid opno, Oid ltype, Oid rtype)
{
	FormData_pg_operator optup;

	if (SearchSysCacheStruct(OPROID, (char *) &optup,
							 ObjectIdGetDatum(opno),
							 0, 0, 0) &&
		optup.oprcanhash &&
		optup.oprleft == ltype &&
		optup.oprright == rtype)
		return opno;
	else
		return InvalidOid;
}

/*
 * get_commutator -
 *
 *		Returns the corresponding commutator of an operator.
 *
 */
Oid
get_commutator(Oid opno)
{
	FormData_pg_operator optup;

	if (SearchSysCacheStruct(OPROID, (char *) &optup,
							 ObjectIdGetDatum(opno),
							 0, 0, 0))
		return optup.oprcom;
	else
		return (Oid) NULL;
}

HeapTuple
get_operator_tuple(Oid opno)
{
	HeapTuple	optup;

	if ((optup = SearchSysCacheTuple(OPROID,
									 ObjectIdGetDatum(opno),
									 0, 0, 0)))
		return optup;
	else
		return (HeapTuple) NULL;
}

/*
 * get_negator -
 *
 *		Returns the corresponding negator of an operator.
 *
 */
Oid
get_negator(Oid opno)
{
	FormData_pg_operator optup;

	if (SearchSysCacheStruct(OPROID, (char *) &optup,
							 ObjectIdGetDatum(opno),
							 0, 0, 0))
		return optup.oprnegate;
	else
		return (Oid) NULL;
}

/*
 * get_oprrest -
 *
 *		Returns procedure id for computing selectivity of an operator.
 *
 */
RegProcedure
get_oprrest(Oid opno)
{
	FormData_pg_operator optup;

	if (SearchSysCacheStruct(OPROID, (char *) &optup,
							 ObjectIdGetDatum(opno),
							 0, 0, 0))
		return optup.oprrest;
	else
		return (RegProcedure) NULL;
}

/*
 * get_oprjoin -
 *
 *		Returns procedure id for computing selectivity of a join.
 *
 */
RegProcedure
get_oprjoin(Oid opno)
{
	FormData_pg_operator optup;

	if (SearchSysCacheStruct(OPROID, (char *) &optup,
							 ObjectIdGetDatum(opno),
							 0, 0, 0))
		return optup.oprjoin;
	else
		return (RegProcedure) NULL;
}

/*				---------- RELATION CACHE ----------					 */

/*
 * get_relnatts -
 *
 *		Returns the number of attributes for a given relation.
 *
 */
int
get_relnatts(Oid relid)
{
	FormData_pg_class reltup;

	if (SearchSysCacheStruct(RELOID, (char *) &reltup,
							 ObjectIdGetDatum(relid),
							 0, 0, 0))
		return reltup.relnatts;
	else
		return InvalidAttrNumber;
}

/*
 * get_rel_name -
 *
 *		Returns the name of a given relation.
 *
 */
char *
get_rel_name(Oid relid)
{
	FormData_pg_class reltup;

	if ((SearchSysCacheStruct(RELOID,
							  (char *) &reltup,
							  ObjectIdGetDatum(relid),
							  0, 0, 0)))
		return pstrdup(reltup.relname.data);
	else
		return NULL;
}

/*				---------- TYPE CACHE ----------						 */

/*
 * get_typlen -
 *
 *		Given the type OID, return the length of the type.
 *
 */
int16
get_typlen(Oid typid)
{
	TypeTupleFormData typtup;

	if (SearchSysCacheStruct(TYPOID, (char *) &typtup,
							 ObjectIdGetDatum(typid),
							 0, 0, 0))
		return typtup.typlen;
	else
		return (int16) NULL;
}

/*
 * get_typbyval -
 *
 *		Given the type OID, determine whether the type is returned by value or
 *		not.  Returns 1 if by value, 0 if by reference.
 *
 */
bool
get_typbyval(Oid typid)
{
	TypeTupleFormData typtup;

	if (SearchSysCacheStruct(TYPOID, (char *) &typtup,
							 ObjectIdGetDatum(typid),
							 0, 0, 0))
		return (bool) typtup.typbyval;
	else
		return false;
}

/*
 * get_typbyval -
 *
 *		Given the type OID, determine whether the type is returned by value or
 *		not.  Returns 1 if by value, 0 if by reference.
 *
 */
#ifdef NOT_USED
char
get_typalign(Oid typid)
{
	TypeTupleFormData typtup;

	if (SearchSysCacheStruct(TYPOID, (char *) &typtup,
							 ObjectIdGetDatum(typid),
							 0, 0, 0))
		return typtup.typalign;
	else
		return 'i';
}

#endif

/*
 * get_typdefault -
 *
 *		Given the type OID, return the default value of the ADT.
 *
 */
struct varlena *
get_typdefault(Oid typid)
{
	struct varlena *typdefault =
	(struct varlena *) TypeDefaultRetrieve(typid);

	return typdefault;
}

/*
 * get_typtype -
 *
 *		Given the type OID, find if it is a basic type, a named relation
 *		or the generic type 'relation'.
 *		It returns the null char if the cache lookup fails...
 *
 */
#ifdef NOT_USED
char
get_typtype(Oid typid)
{
	TypeTupleFormData typtup;

	if (SearchSysCacheStruct(TYPOID, (char *) &typtup,
							 ObjectIdGetDatum(typid),
							 0, 0, 0))
		return typtup.typtype;
	else
		return '\0';
}

#endif
