/* ----------------------------------------------------------------
 *   FILE
 *	catalog_utils.c
 *	
 *   NOTES
 *
 *   IDENTIFICATION
 *	$Header: /general/TFA/unclassified/src/utils/postgres-v3r1/src/parser/RCS/catalog_utils.c,v 1.35 1991/09/08 16:21:52 glass Exp $
 * ----------------------------------------------------------------
 */
#include "tmp/postgres.h"

RcsId("$Header: /general/TFA/unclassified/src/utils/postgres-v3r1/src/parser/RCS/catalog_utils.c,v 1.35 1991/09/08 16:21:52 glass Exp $");

#include "utils/log.h"
#include "utils/fmgr.h"

#include "nodes/pg_lisp.h"
#include "catalog/syscache.h"

#include "exceptions.h"
#include "catalog_utils.h"

struct {
    char *field;
    int code;
} special_attr[] =
	       {
		   { "ctid", SelfItemPointerAttributeNumber },
		   { "lock", RuleLockAttributeNumber },
		   { "oid", ObjectIdAttributeNumber },
		   { "xmin", MinTransactionIdAttributeNumber },
		   { "cmin", MinCommandIdAttributeNumber },
		   { "xmax", MaxTransactionIdAttributeNumber },
		   { "cmax", MaxCommandIdAttributeNumber },
		   { "chain", ChainItemPointerAttributeNumber },
		   { "anchor", AnchorItemPointerAttributeNumber },
		   { "tmin", MinAbsoluteTimeAttributeNumber },
		   { "tmax", MaxAbsoluteTimeAttributeNumber },
		   { "vtype", VersionTypeAttributeNumber }
	       };

#define SPECIALS (sizeof(special_attr)/sizeof(*special_attr))
  
static String attnum_type[SPECIALS] = {
    "tid",
    "lock",
    "oid",
    "xid",
    "cid",
    "xid",
    "cid",
    "tid",
    "tid",
    "abstime",
    "abstime",
    "char"
  };

struct tuple *SearchSysCache();

/* return a Type structure, given an typid */
Type
get_id_type(id)
long id;
{
    HeapTuple tup;

    if (!(tup = SearchSysCacheTuple(TYPOID, id))) {
	elog ( WARN, "type id lookup of %d failed", id);
	return(NULL);
    }
    return((Type) tup);
}

/* return a Type structure, given type name */
Type
type(s)
char *s;
{
    HeapTuple tup;

    if (s == NULL) {
	elog ( WARN , "type(): Null type" );
    }

    if (!(tup = SearchSysCacheTuple(TYPNAME, s))) {
	elog (WARN , "type name lookup of %s failed", s);
    }
    return((Type) tup);
}

/* given attribute id, return type of that attribute */
/* XXX Special case for pseudo-attributes is a hack */
OID
att_typeid(rd, attid)
Relation rd;
int attid;
{

    if (attid < 0) {
	return(typeid(type(attnum_type[-attid-1])));
    }
    /* -1 because varattno (where attid comes from) returns one
       more than index */
    return(rd->rd_att.data[attid-1]->atttypid);
}

/* given type, return the type OID */
OID
typeid(tp)
Type tp;
{
    if (tp == NULL) {
	elog ( WARN , "typeid() called with NULL type struct");
    }
    return(tp->t_oid);
}

/* given type (as type struct), return the length of type */
int16
tlen(t)
Type t;
{
    TypeTupleForm    typ;

    typ = (TypeTupleForm)GETSTRUCT(t);
    return(typ->typlen);
}

/* given type (as type struct), return the value of its 'byval' attribute.*/
bool
tbyval(t)
Type t;
{
    TypeTupleForm    typ;

    typ = (TypeTupleForm)GETSTRUCT(t);
    return(typ->typbyval);
}

/* given type (as type struct), return the name of type */
Name
tname(t)
Type t;
{
    TypeTupleForm    typ;

    typ = (TypeTupleForm)GETSTRUCT(t);
    return((Name)&(typ->typname));
}

/* given type (as type struct), return wether type is passed by value */
int
tbyvalue(t)
Type t;
{
    TypeTupleForm typ;

    typ = (TypeTupleForm) GETSTRUCT(t);
    return(typ->typbyval);
}

/* given operator, return the operator OID */
OID
oprid(op)
Operator op;
{
    return(op->t_oid);
}

/* Given operator, types of arg1, and arg2, return oper struct */
Operator
oper(op, arg1, arg2)
char *op;
int arg1, arg2;	/* typeids */
{
    HeapTuple tup;

    /*
    if (!OpCache) {
	init_op_cache();
    }
    */
    if (!(tup = SearchSysCacheTuple(OPRNAME, op, arg1, arg2, (char *) 'b'))) {
	op_error(op, arg1, arg2);
	return(NULL);
    }
    return((Operator) tup);
}
/* Find default type for right arg of binary operator */
Operator
oper_default(op, arg1)
char *op;
int arg1;       /* typeid */
{
    HeapTuple tup;

    /* see if there is only one type available for right arg. of binary op. */
    tup = (HeapTuple) FindDefaultType(op, arg1);
    if(!tup){  /* this could mean a) there is no operator named op.
                                b) there are more than one possible right arg */
       if (!(tup = SearchSysCacheTuple(OPRNAME, op, arg1, arg1, (char *) 'b')))
       {
          /* there's no reasonable default type for the right argument */
          return(NULL);
       }
    }

    return((Operator) tup);
}

/* Given unary right-side operator (argument on right), return oper struct */
Operator
right_oper(op, arg)
char *op;
int arg; /* type id */
{
    HeapTuple tup;

    /*
    if (!OpCache) {
	init_op_cache();
    }
    */
    if (!(tup = SearchSysCacheTuple(OPRNAME, op, 0, arg, (char *) 'r'))) {
	elog ( WARN ,
	      "Can't find right op: %s for type %d", op, arg );
	return(NULL);
    }
    return((Operator) tup);
}

/* Given unary left-side operator (argument on left), return oper struct */
Operator
left_oper(op, arg)
     char *op;
     int arg; /* type id */
{
	HeapTuple tup;
	
	if (!(tup = SearchSysCacheTuple(OPRNAME, op, arg, 0, (char *) 'l'))) {
		elog (WARN ,
			"Can't find left op: %s for type %d", op, arg);
		return(NULL);
	}
	return ((Operator) tup);
}

/* given range variable, return id of variable */
   
int
varattno ( rd , a)
     Relation rd;
     char *a;
{
	int i;
	
	for (i = 0; i < rd->rd_rel->relnatts; i++) {
		if (!strcmp(&rd->rd_att.data[i]->attname, a)) {
			return(i+1);
		}
	}
	for (i = 0; i < SPECIALS; i++) {
		if (!strcmp(special_attr[i].field, a)) {
			return(special_attr[i].code);
		}
	}

	elog(WARN,"Relation %s does not have attribute %s\n", 
	     RelationGetRelationName(rd), a );
	return(-1);
}
/*-------------
 * given an attribute number and a relation, return its relation name
 */
Name
getAttrName(rd, attrno)
Relation rd;
int attrno;
{
    Name name;
    int i;

    if (attrno<0) {
	for (i = 0; i < SPECIALS; i++) {
		if (special_attr[i].code == attrno) {
		    name = (Name) special_attr[i].field;
		    return(name);
		}
	}
	elog(WARN, "Illegal attr no %d for relation %s\n",
	    attrno, RelationGetRelationName(rd));
    } else if (attrno >=1 && attrno<= RelationGetNumberOfAttributes(rd)) {
	name = &(rd->rd_att.data[attrno-1]->attname);
	return(name);
    } else {
	elog(WARN, "Illegal attr no %d for relation %s\n",
	    attrno, RelationGetRelationName(rd));
    }

    /*
     * Shouldn't get here, but we want lint to be happy...
     */

    return(NULL);
}

/* given range variable, return id of variable */
RangeTablePosn ( rangevar , options )
     char *rangevar;
     List options;
{
	int index = 1;
	extern LispValue p_rtable;
	LispValue temp = p_rtable;
	int inherit = 0;
	int timerange = 0;

	index = 1;
	temp = p_rtable;
	while ( ! lispNullp (temp )) {
	    LispValue refvalue = ( CAR ( CAR (temp )));
	    if ( IsA (refvalue,LispStr)) {
		if ( (! strcmp ( CString ( refvalue ),
				rangevar ) ) &&
		    (inherit == inherit) &&
		    (timerange == timerange))
		  return (index );
	    } else {
		List i;
		foreach ( i , refvalue ) {
		    Name actual_ref = (Name)CString(CAR(i));
		    if ( !strcmp ( actual_ref , rangevar ) &&
			 inherit == inherit &&
			 timerange == timerange )
		      return ( index );
		}
	    }
		temp = CDR(temp);
		index++;
	}
		return(0);
}

/* given range variable, return id of variable */
List
RangeTablePositions ( rangevar , options )
     char *rangevar;
     List options;
{
    int index = 1;
    extern LispValue p_rtable;
    LispValue temp = p_rtable;
    List list_of_positions = NULL;
    int inherit = 0;
    int timerange = 0;
    
    index = 1;
    temp = p_rtable;

    while ( ! lispNullp (temp )) {
	LispValue refvalue = CAR ( CAR ( temp ));
	if ( IsA (refvalue,LispStr)) {
	    if ( (! strcmp ( CString ( refvalue ),
			    rangevar ) ) &&
		(inherit == inherit) &&
		(timerange == timerange)) {
		
		list_of_positions = lispCons ( lispInteger ( index ),
					      list_of_positions );
	    } 
	} else {
	    List i;
	    foreach ( i , refvalue ) {
		Name actual_ref = (Name)CString(CAR(i));
		if ( !strcmp ( actual_ref , rangevar ) &&
		    inherit == inherit &&
		    timerange == timerange ) {
		    
		list_of_positions = lispCons ( lispInteger ( index ),
					      list_of_positions );
		}
	    }
	}
	temp = CDR(temp);
	index++;
    }

    return(list_of_positions);
}

/* Given a typename and value, returns the ascii form of the value */

char *
outstr(typename, value)
char *typename;	/* Name of type of value */
char *value;	/* Could be of any type */
{
    TypeTupleForm tp;
    OID op;

    tp = (TypeTupleForm ) GETSTRUCT(type(typename));
    op = tp->typoutput;
    return((char *) fmgr(op, value));
}

/* Given a Type and a string, return the internal form of that string */
char *
instr2(tp, string)
Type tp;
char *string;
{
    return(instr1((TypeTupleForm ) GETSTRUCT(tp), string));
}

/* Given a type structure and a string, returns the internal form of
   that string */
char *
instr1(tp, string)
TypeTupleForm tp;
char *string;
{
    OID op;
	OID typelem;
	
    op = tp->typinput;
	typelem = tp->typelem; /* XXX - used for array_in */
    return((char *) fmgr(op, string, typelem));
}

/* Given a typename and string, returns the internal form of that string */
char *
instr(typename, string)
char *typename;	/* Name of type to turn string into */
char *string;
{
    TypeTupleForm tp;

    tp = (TypeTupleForm) GETSTRUCT(type(typename));
    return(instr1(tp, string));
}

OID
funcname_get_rettype ( function_name )
     char *function_name;
{
    HeapTuple func_tuple = NULL;
    OID funcrettype = (OID)0;

    func_tuple = SearchSysCacheTuple(PRONAME,function_name,0,0,0);

    if ( !HeapTupleIsValid ( func_tuple )) 
	elog (WARN, "function named %s does not exist", function_name);
    
    funcrettype = (OID)
      ((struct proc *)GETSTRUCT(func_tuple))->prorettype ;

    return (funcrettype);
}
int 
funcname_get_funcnargs ( function_name )
     char *function_name;
{
    HeapTuple func_tuple = NULL;
    int2 nargs = -1;

    func_tuple = SearchSysCacheTuple(PRONAME,function_name,0,0,0);

    if ( !HeapTupleIsValid ( func_tuple )) 
	elog (WARN, "function named %s does not exist", function_name);
    
    nargs = (int2) 
      ((struct proc *)GETSTRUCT(func_tuple))->pronargs ;

    return (nargs);
}
ObjectId *
funcname_get_funcargtypes ( function_name )
     char *function_name;
{
    HeapTuple func_tuple = NULL;
    ObjectId *oid_array = NULL;
    struct proc *foo;
    func_tuple = SearchSysCacheTuple(PRONAME,function_name,0,0,0);

    if ( !HeapTupleIsValid ( func_tuple )) 
	elog (WARN, "function named %s does not exist", function_name);
    
    foo = (struct proc *)GETSTRUCT(func_tuple);
    oid_array = foo->proargtypes.data;
    return (oid_array);
}

OID
funcname_get_funcid ( function_name )
     char *function_name;
{
    HeapTuple func_tuple = NULL;

    func_tuple = SearchSysCacheTuple(PRONAME,function_name,0,0,0);

    if ( func_tuple != NULL )
      return ( func_tuple->t_oid );
    else
      return ( (OID) 0 );
}

/* Given a type id, returns the in-conversion function of the type */
OID
typeid_get_retinfunc(type_id)
        int type_id;
{
        HeapTuple     typeTuple;
        TypeTupleForm   type;
        OID             infunc;
        typeTuple = SearchSysCacheTuple(TYPOID, (char *) type_id,
                  (char *) NULL, (char *) NULL, (char *) NULL);
        type = (TypeTupleForm) GETSTRUCT(typeTuple);
        infunc = type->typinput;
        return(infunc);
}

OID
get_typelem(type_id)

OID type_id;

{
    HeapTuple     typeTuple;
    TypeTupleForm   type;

	if (!(typeTuple = SearchSysCacheTuple(TYPOID, type_id, NULL, NULL, NULL))) {
		elog (WARN , "type name lookup of %d failed", type_id);
	}
    type = (TypeTupleForm) GETSTRUCT(typeTuple);

    return (type->typelem);
}

char
FindDelimiter(typename)
char *typename;
{
    char delim;
    HeapTuple     typeTuple;
    TypeTupleForm   type;


    if (!(typeTuple = SearchSysCacheTuple(TYPNAME, typename))) {
        elog (WARN , "type name lookup of %s failed", typename);
    }
    type = (TypeTupleForm) GETSTRUCT(typeTuple);

    delim = type->typdelim;
    return (delim);
}

/*
 * Give a somewhat useful error message when the operator for two types
 * is not found.
 */

op_error(op, arg1, arg2)

char *op;
int arg1, arg2;

{
	Type tp, get_id_type();
	char p1[16], p2[16];

	tp = get_id_type(arg1);
	strncpy(p1, tname(tp), 16);

	tp = get_id_type(arg2);
	strncpy(p2, tname(tp), 16);

	elog(NOTICE, "there is no operator %s for types %s and %s", op, p1, p2);
	elog(NOTICE, "You will either have to retype this query using an");
	elog(NOTICE, "explicit cast, or you will have to define the operator");
	elog(WARN, "%s for %s and %s using DEFINE OPERATOR", op, p1, p2);
}
