/*
 * fmgr.c --
 *	the C function manager interface.
 */

#include <stdio.h>
#include <varargs.h>
#include <sys/types.h>
#include <sys/stat.h>

#include "tmp/c.h"
#include "tmp/postgres.h"

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

#include "nodes/pg_lisp.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_language.h"
#include "catalog/syscache.h"
#include "rules/params.h"
#include "utils/oidcompos.h"

#include "utils/log.h"
RcsId("$Header: /private/postgres/src/utils/fmgr/RCS/fmgr.c,v 1.94 1992/08/16 03:48:52 mer Exp $");

/*
 *	procedure OID -> function mapping
 *
 *	XXX Keep this thing sorted by procedure OID!
 *	    It gets binary-searched ...
 */

typedef struct {
	ObjectId	proid;
	int16		nargs;
	func_ptr	func;
} FmgrCall;

static FmgrCall	builtins[] = {
	{ F_BOOLIN,		1, (func_ptr) boolin },
	{ F_BOOLOUT,		1, (func_ptr) boolout },
	{ F_BYTEAIN,		1, (func_ptr) byteain },
	{ F_BYTEAOUT,		1, (func_ptr) byteaout },
	{ F_CHARIN,		1, (func_ptr) charin },
	{ F_CHAROUT,		1, (func_ptr) charout },
	{ F_CHAR16IN,		1, (func_ptr) char16in },
	{ F_CHAR16OUT,		1, (func_ptr) char16out },
	{ F_DATETIMEIN,		1, (func_ptr) dtin },
	{ F_DATETIMEOUT,	1, (func_ptr) dtout },
	{ F_INT2IN,		1, (func_ptr) int2in },
	{ F_INT2OUT,		1, (func_ptr) int2out },
	{ F_INT28IN,		1, (func_ptr) int28in },
	{ F_INT28OUT,		1, (func_ptr) int28out },
	{ F_INT4IN,		1, (func_ptr) int4in },
	/* F_OIDIN == F_INT4IN */
	{ F_INT4OUT,		1, (func_ptr) int4out },
	/* F_OIDOUT == F_INT4OUT */
	{ F_REGPROCIN,		1, (func_ptr) regprocin },
	{ F_REGPROCOUT,		1, (func_ptr) regprocout },
	{ F_TEXTIN,		1, (func_ptr) textin },
	{ F_TEXTOUT,		1, (func_ptr) textout },
	{ F_TIDIN,		1, (func_ptr) tidin },
	{ F_TIDOUT,		1, (func_ptr) tidout },
	{ F_XIDIN,		1, (func_ptr) StringFormTransactionId },
	{ F_XIDOUT,		1, (func_ptr) TransactionIdFormString },
	{ F_CIDIN,		1, (func_ptr) cidin },
	{ F_CIDOUT,		1, (func_ptr) cidout },
	{ F_OID8IN,		1, (func_ptr) oid8in },
	{ F_OID8OUT,		1, (func_ptr) oid8out },
	{ F_LOCKIN,		1, (func_ptr) StringToRuleLock },
	{ F_LOCKOUT,		1, (func_ptr) RuleLockToString },
	{ F_STUBIN,		1, (func_ptr) stubin },
	{ F_STUBOUT,		1, (func_ptr) stubout },

 	{ F_BOOLEQ,		2, (func_ptr) chareq },
	{ F_CHAREQ,		2, (func_ptr) chareq },
	{ F_CHAR16EQ,		2, (func_ptr) char16eq },
	{ F_INT2EQ,		2, (func_ptr) int2eq },
	{ F_INT2LT,		2, (func_ptr) int2lt },
	{ F_INT4EQ,		2, (func_ptr) int4eq },
	{ F_INT4LT,		2, (func_ptr) int4lt },
	{ F_TEXTEQ,		2, (func_ptr) texteq },
	{ F_XIDEQ,		2, (func_ptr) TransactionIdEquals },
	{ F_CIDEQ,		2, (func_ptr) int4eq },
	{ F_CHARNE,		2, (func_ptr) charne },
	{ F_CHARLT,		2, (func_ptr) charlt },
	{ F_CHARLE,		2, (func_ptr) charle },
	{ F_CHARGT,		2, (func_ptr) chargt },
	{ F_CHARGE,		2, (func_ptr) charge },
	{ F_CHARPL,		2, (func_ptr) charpl },
	{ F_CHARMI,		2, (func_ptr) charmi },
	{ F_CHARMUL,		2, (func_ptr) charmul },
	{ F_CHARDIV,		2, (func_ptr) chardiv },
	{ F_CHAR16REGEXEQ,	2, (func_ptr) char16regexeq },
	{ F_CHAR16REGEXNE,	2, (func_ptr) char16regexne },
	{ F_TEXTREGEXEQ,	2, (func_ptr) textregexeq },
	{ F_TEXTREGEXNE,	2, (func_ptr) textregexne },

	{ F_BOOLNE,		2, (func_ptr) charne },

	{ F_RTSEL, 		7, (func_ptr) rtsel },
	{ F_RTNPAGE, 		7, (func_ptr) rtnpage },
	/*
	 * btree selectivity functions
	 */
	{ F_BTREESEL, 		7, (func_ptr) btreesel },
	{ F_BTREENPG, 		7, (func_ptr) btreenpage },

	{ F_EQSEL, 		5, (func_ptr) eqsel },
	{ F_NEQSEL, 		5, (func_ptr) neqsel },
	{ F_INTLTSEL, 		5, (func_ptr) intltsel },
	{ F_INTGTSEL, 		5, (func_ptr) intgtsel },
	{ F_EQJOINSEL, 		5, (func_ptr) eqjoinsel },
	{ F_NEQJOINSEL, 	5, (func_ptr) neqjoinsel },
	{ F_INTLTJOINSEL, 	5, (func_ptr) intltjoinsel },
	{ F_INTGTJOINSEL, 	5, (func_ptr) intgtjoinsel },

	{ F_POINT_IN,		1, (func_ptr) point_in },
	{ F_POINT_OUT,		1, (func_ptr) point_out },
	{ F_LSEG_IN,		1, (func_ptr) lseg_in },
	{ F_LSEG_OUT,		1, (func_ptr) lseg_out },
	{ F_PATH_IN,		1, (func_ptr) path_in },
	{ F_PATH_OUT,		1, (func_ptr) path_out },
	{ F_BOX_IN,		1, (func_ptr) box_in },
	{ F_BOX_OUT,		1, (func_ptr) box_out },
	{ F_BOX_OVERLAP,	2, (func_ptr) box_overlap },
	{ F_BOX_GE,		2, (func_ptr) box_ge },
	{ F_BOX_GT,		2, (func_ptr) box_gt },
	{ F_BOX_EQ,		2, (func_ptr) box_eq },
	{ F_BOX_LT,		2, (func_ptr) box_lt },
	{ F_BOX_LE,		2, (func_ptr) box_le },
	/*
	 *  F_BOX_SAME appears below -- no room here
	 */
	{ F_POINT_ABOVE,	2, (func_ptr) point_above },
	{ F_POINT_LEFT,		2, (func_ptr) point_left },
	{ F_POINT_RIGHT,	2, (func_ptr) point_right },
	{ F_POINT_BELOW,	2, (func_ptr) point_below },
	{ F_POINT_EQ,		2, (func_ptr) point_eq },
	{ F_ON_PB,		2, (func_ptr) on_pb },
	{ F_ON_PPATH,		2, (func_ptr) on_ppath },
	{ F_BOX_CENTER,		1, (func_ptr) box_center },
	{ F_AREASEL, 		5, (func_ptr) areasel },
	{ F_AREAJOINSEL, 	5, (func_ptr) areajoinsel },
	{ F_INT4MUL,		2, (func_ptr) int4mul },
	{ F_INT4FAC,		1, (func_ptr) int4fac },
	{ F_POINTDIST,		2, (func_ptr) pointdist },
	{ F_INT4NE,		2, (func_ptr) int4ne },
	{ F_INT2NE,		2, (func_ptr) int2ne },
	{ F_INT2GT,		2, (func_ptr) int2gt },
	{ F_INT4GT,		2, (func_ptr) int4gt },
	{ F_INT2LE,		2, (func_ptr) int2le },
	{ F_INT4LE,		2, (func_ptr) int4le },
	{ F_INT4GE,		2, (func_ptr) int4ge },
	{ F_INT2GE,		2, (func_ptr) int2ge },
	{ F_INT2MUL,		2, (func_ptr) int2mul },
	{ F_INT2DIV,		2, (func_ptr) int2div },
	{ F_INT4DIV,		2, (func_ptr) int4div },
	{ F_INT2MOD,		2, (func_ptr) int2mod },
	{ F_INT4MOD,		2, (func_ptr) int4mod },
	{ F_TEXTNE,		2, (func_ptr) textne },
	{ F_INT24EQ,		2, (func_ptr) int4eq },
	{ F_INT42EQ,		2, (func_ptr) int4eq },
	{ F_INT24LT,		2, (func_ptr) int4lt },
	{ F_INT42LT,		2, (func_ptr) int4lt },
	{ F_INT24GT,		2, (func_ptr) int4gt },
	{ F_INT42GT,		2, (func_ptr) int4gt },
	{ F_INT24NE,		2, (func_ptr) int4ne },
	{ F_INT42NE,		2, (func_ptr) int4ne },
	{ F_INT24LE,		2, (func_ptr) int4le },
	{ F_INT42LE,		2, (func_ptr) int4le },
	{ F_INT24GE,		2, (func_ptr) int4ge },
	{ F_INT42GE,		2, (func_ptr) int4ge },
	{ F_INT24MUL,		2, (func_ptr) int4mul },
	{ F_INT42MUL,		2, (func_ptr) int4mul },
	{ F_INT24DIV,		2, (func_ptr) int4div },
	{ F_INT42DIV,		2, (func_ptr) int4div },
	{ F_INT24MOD,		2, (func_ptr) int4mod },
	{ F_INT42MOD,		2, (func_ptr) int4mod },
	{ F_INT2PL,		2, (func_ptr) int2pl },
	{ F_INT4PL,		2, (func_ptr) int4pl },
	{ F_INT24PL,		2, (func_ptr) int4pl },
	{ F_INT42PL,		2, (func_ptr) int4pl },
	{ F_INT2MI,		2, (func_ptr) int2mi },
	{ F_INT4MI,		2, (func_ptr) int4mi },
	{ F_INT24MI,		2, (func_ptr) int4mi },
	{ F_INT42MI,		2, (func_ptr) int4mi },
	{ F_OIDEQ,		2, (func_ptr) int4eq },
	{ F_OIDNE,		2, (func_ptr) int4ne },
	{ F_BOX_SAME,		2, (func_ptr) box_same },
	{ F_BOX_CONTAIN,	2, (func_ptr) box_contain },
	{ F_BOX_LEFT,		2, (func_ptr) box_left },
	{ F_BOX_OVERLEFT,	2, (func_ptr) box_overleft },
	{ F_BOX_OVERRIGHT,	2, (func_ptr) box_overright },
	{ F_BOX_RIGHT,		2, (func_ptr) box_right },
	{ F_BOX_CONTAINED,	2, (func_ptr) box_contained },
	{ F_RT_BOX_UNION,	2, (func_ptr) rt_box_union },
	{ F_RT_BOX_INTER,	2, (func_ptr) rt_box_inter },
	{ F_RT_BOX_SIZE,	1, (func_ptr) rt_box_size },
	{ F_RT_BIGBOX_SIZE,	1, (func_ptr) rt_bigbox_size },
	{ F_RT_POLY_UNION,	2, (func_ptr) rt_poly_union },
	{ F_RT_POLY_INTER,	2, (func_ptr) rt_poly_inter },
	{ F_RT_POLY_SIZE,	1, (func_ptr) rt_poly_size },
	{ F_FLOAT4IN,		1, (func_ptr) float4in },
	{ F_FLOAT4OUT,		1, (func_ptr) float4out },
	{ F_FLOAT4MUL,		2, (func_ptr) float4mul },
	{ F_FLOAT4DIV,		2, (func_ptr) float4div },
	{ F_FLOAT4PL,		2, (func_ptr) float4pl },
	{ F_FLOAT4MI,		2, (func_ptr) float4mi },
	{ F_FLOAT4UM,		1, (func_ptr) float4um },
	{ F_FLOAT4ABS,		1, (func_ptr) float4abs },
	{ F_FLOAT4INC,		1, (func_ptr) float4inc },
	{ F_FLOAT4LARGER,	2, (func_ptr) float4larger },
	{ F_FLOAT4SMALLER,	2, (func_ptr) float4smaller },
	{ F_INT4UM,		1, (func_ptr) int4um },
	{ F_INT2UM,		1, (func_ptr) int2um },
	{ F_FLOAT8IN,		1, (func_ptr) float8in },
	{ F_FLOAT8OUT,		1, (func_ptr) float8out },
	{ F_FLOAT8MUL,		2, (func_ptr) float8mul },
	{ F_FLOAT8DIV,		2, (func_ptr) float8div },
	{ F_FLOAT8PL,		2, (func_ptr) float8pl },
	{ F_FLOAT8MI,		2, (func_ptr) float8mi },
	{ F_FLOAT8UM,		1, (func_ptr) float8um },
	{ F_FLOAT8ABS,		1, (func_ptr) float8abs },
	{ F_FLOAT8INC,		1, (func_ptr) float8inc },
	{ F_FLOAT8LARGER,	2, (func_ptr) float8larger },
	{ F_FLOAT8SMALLER,	2, (func_ptr) float8smaller },
	{ F_DROUND,		1, (func_ptr) dround },
	{ F_DTRUNC,		1, (func_ptr) dtrunc },
	{ F_DSQRT,		1, (func_ptr) dsqrt },
	{ F_DCBRT,		1, (func_ptr) dcbrt },
	{ F_DPOW,		2, (func_ptr) dpow },
	{ F_DEXP,		1, (func_ptr) dexp },
	{ F_DLOG,		1, (func_ptr) dlog1 },
	{ F_ABSTIMEIN,		1, (func_ptr) nabstimein },
	{ F_ABSTIMEOUT,		1, (func_ptr) nabstimeout },
	{ F_RELTIMEIN,		1, (func_ptr) reltimein },
	{ F_RELTIMEOUT,		1, (func_ptr) reltimeout },
	{ F_TIMEPL,		1, (func_ptr) timepl },
	 
	{ F_TIMEMI,		2, (func_ptr) timemi },
	{ F_TINTERVALIN,	1, (func_ptr) tintervalin },
	{ F_TINTERVALOUT,	1, (func_ptr) tintervalout },
	{ F_ININTERVAL,		2, (func_ptr) ininterval },
	{ F_INTERVALREL,	1, (func_ptr) intervalrel },
	{ F_TIMENOW,		0, (func_ptr) timenow },

	{ F_ABSTIMEEQ,		2, (func_ptr) abstimeeq },
	{ F_ABSTIMENE,		2, (func_ptr) abstimene },
	{ F_ABSTIMELT,		2, (func_ptr) abstimelt },
	{ F_ABSTIMEGT,		2, (func_ptr) abstimegt },
	{ F_ABSTIMELE,		2, (func_ptr) abstimele },
	{ F_ABSTIMEGE,		2, (func_ptr) abstimege },
	{ F_RELTIMEEQ,          2, (func_ptr) reltimeeq },
	{ F_RELTIMENE,          2, (func_ptr) reltimene },
	{ F_RELTIMELT,          2, (func_ptr) reltimelt },
	{ F_RELTIMEGT,          2, (func_ptr) reltimegt },
	{ F_RELTIMELE,          2, (func_ptr) reltimele },
	{ F_RELTIMEGE,          2, (func_ptr) reltimege },

	{ F_INTERVALEQ,         2, (func_ptr) intervaleq },
	{ F_INTERVALCT,         2, (func_ptr) intervalct },
	{ F_INTERVALOV,         2, (func_ptr) intervalov },
	{ F_INTERVALLENEQ,      2, (func_ptr) intervalleneq },
	{ F_INTERVALLENNE,      2, (func_ptr) intervallenne },
	{ F_INTERVALLENLT,      2, (func_ptr) intervallenlt },
	{ F_INTERVALLENGT,      2, (func_ptr) intervallengt },
	{ F_INTERVALLENLE,      2, (func_ptr) intervallenle },
	{ F_INTERVALLENGE,      2, (func_ptr) intervallenge },
	{ F_INTERVALSTART,      1, (func_ptr) intervalstart },
	{ F_INTERVALEND,        1, (func_ptr) intervalend },

	{ F_INT2FAC,		1, (func_ptr) int2fac },
	{ F_FLOAT48MUL,		2, (func_ptr) float48mul },
	{ F_FLOAT48DIV,		2, (func_ptr) float48div },
	{ F_FLOAT48PL,		2, (func_ptr) float48pl },
	{ F_FLOAT48MI,		2, (func_ptr) float48mi },
	{ F_FLOAT84MUL,		2, (func_ptr) float84mul },
	{ F_FLOAT84DIV,		2, (func_ptr) float84div },
	{ F_FLOAT84PL,		2, (func_ptr) float84pl },
	{ F_FLOAT84MI,		2, (func_ptr) float84mi },
	{ F_FLOAT4EQ,		2, (func_ptr) float4eq },
	{ F_FLOAT4NE,		2, (func_ptr) float4ne },
	{ F_FLOAT4LT,		2, (func_ptr) float4lt },
	{ F_FLOAT4LE,		2, (func_ptr) float4le },
	{ F_FLOAT4GT,		2, (func_ptr) float4gt },
	{ F_FLOAT4GE,		2, (func_ptr) float4ge },
	{ F_FLOAT8EQ,		2, (func_ptr) float8eq },
	{ F_FLOAT8NE,		2, (func_ptr) float8ne },
	{ F_FLOAT8LT,		2, (func_ptr) float8lt },
	{ F_FLOAT8LE,		2, (func_ptr) float8le },
	{ F_FLOAT8GT,		2, (func_ptr) float8gt },
	{ F_FLOAT8GE,		2, (func_ptr) float8ge },
	{ F_FLOAT48EQ,		2, (func_ptr) float48eq },
	{ F_FLOAT48NE,		2, (func_ptr) float48ne },
	{ F_FLOAT48LT,		2, (func_ptr) float48lt },
	{ F_FLOAT48LE,		2, (func_ptr) float48le },
	{ F_FLOAT48GT,		2, (func_ptr) float48gt },
	{ F_FLOAT48GE,		2, (func_ptr) float48ge },
	{ F_FLOAT84EQ,		2, (func_ptr) float84eq },
	{ F_FLOAT84NE,		2, (func_ptr) float84ne },
	{ F_FLOAT84LT,		2, (func_ptr) float84lt },
	{ F_FLOAT84LE,		2, (func_ptr) float84le },
	{ F_FLOAT84GT,		2, (func_ptr) float84gt },
	{ F_FLOAT84GE,		2, (func_ptr) float84ge },
	{ F_F4TOF8,		2, (func_ptr) ftod },
	{ F_F8TOF4,		2, (func_ptr) dtof },
	{ F_I2TOI4,		2, (func_ptr) itoi },
	{ F_I4TOI2,		2, (func_ptr) itoi },
	{ F_KEYFIRSTEQ,		2, (func_ptr) keyfirsteq },

	/* no room for this above */
	{ F_RTINSERT,		3, (func_ptr) rtinsert },
	{ F_RTDELETE,		2, (func_ptr) rtdelete },
	{ F_RTGETTUPLE, 	2, (func_ptr) rtgettuple },
	{ F_RTBUILD, 		9, (func_ptr) rtbuild },
	{ F_RTBEGINSCAN, 	4, (func_ptr) rtbeginscan },
	{ F_RTENDSCAN,		1, (func_ptr) rtendscan },
	{ F_RTMARKPOS,		1, (func_ptr) rtmarkpos },
	{ F_RTRESTRPOS,		1, (func_ptr) rtrestrpos },
	{ F_RTRESCAN,		3, (func_ptr) rtrescan },

	/* new btrees */
	{ F_NBTGETTUPLE,	2, (func_ptr) btgettuple },
	{ F_NBTINSERT,		3, (func_ptr) btinsert },
	{ F_NBTDELETE,		2, (func_ptr) btdelete },
	{ F_NBTBEGINSCAN,	4, (func_ptr) btbeginscan },
	{ F_NBTRESCAN,		3, (func_ptr) btrescan },
	{ F_NBTENDSCAN,		1, (func_ptr) btendscan },
	{ F_NBTMARKPOS,		1, (func_ptr) btmarkpos },
	{ F_NBTRESTRPOS,	1, (func_ptr) btrestrpos },
	{ F_NBTBUILD,		9, (func_ptr) btbuild },
	{ F_POLY_SAME,		2, (func_ptr) poly_same },
	{ F_POLY_CONTAIN,	2, (func_ptr) poly_contain },
	{ F_POLY_LEFT,		2, (func_ptr) poly_left },
	{ F_POLY_OVERLEFT,	2, (func_ptr) poly_overleft },
	{ F_POLY_OVERRIGHT,	2, (func_ptr) poly_overright },
	{ F_POLY_RIGHT,		2, (func_ptr) poly_right },
	{ F_POLY_CONTAINED,	2, (func_ptr) poly_contained },
	{ F_POLY_OVERLAP,	2, (func_ptr) poly_overlap },
	{ F_POLY_IN,		1, (func_ptr) poly_in },
	{ F_POLY_OUT,		1, (func_ptr) poly_out },
	/* per-opclass comparison functions for new btrees */
	{ F_BTINT2CMP,		2, (func_ptr) btint2cmp },
	{ F_BTINT4CMP,		2, (func_ptr) btint4cmp },
	{ F_BTINT42CMP,		2, (func_ptr) btint42cmp },
	{ F_BTINT24CMP,		2, (func_ptr) btint24cmp },
	{ F_BTFLOAT4CMP,	2, (func_ptr) btfloat4cmp },
	{ F_BTFLOAT8CMP,	2, (func_ptr) btfloat8cmp },
	{ F_BTOIDCMP,		2, (func_ptr) btoidcmp },
	{ F_BTABSTIMECMP,	2, (func_ptr) btabstimecmp },
	{ F_BTCHARCMP,		2, (func_ptr) btcharcmp },
	{ F_BTCHAR16CMP,	2, (func_ptr) btchar16cmp },
	{ F_BTTEXTCMP,		2, (func_ptr) bttextcmp },

	{ F_LSEG_DISTANCE,	2, (func_ptr) lseg_distance },
	{ F_LSEG_INTERPT,	2, (func_ptr) lseg_interpt },
	{ F_DIST_PS,		2, (func_ptr) dist_ps },
	{ F_DIST_PB,		2, (func_ptr) dist_pb },
	{ F_DIST_SB,		2, (func_ptr) dist_sb },
	{ F_CLOSE_PS,		2, (func_ptr) close_ps },
	{ F_CLOSE_PB,		2, (func_ptr) close_pb },
	{ F_CLOSE_SB,		2, (func_ptr) close_sb },
	{ F_ON_PS,		2, (func_ptr) on_ps },
	{ F_PATH_DISTANCE,	2, (func_ptr) path_distance },
	{ F_DIST_PPTH,		2, (func_ptr) dist_ppth },
	{ F_ON_SB,		2, (func_ptr) on_sb },
	{ F_INTER_SB,		2, (func_ptr) inter_sb },

	{ F_GETATTRIBUTEBYNAME,	3, (func_ptr) GetAttributeByName },
	{ F_INT4NOTIN, 		2, (func_ptr) int4notin },
	{ F_OIDNOTIN, 		2, (func_ptr) oidnotin },
	{ F_INT44IN,		1, (func_ptr) int44in },
	{ F_INT44OUT,		1, (func_ptr) int44out },
	{ F_GETATTRIBUTEBYNUM,	3, (func_ptr) GetAttributeByNum },

	{ F_CHAR16LT,		2, (func_ptr) char16lt },
	{ F_CHAR16LE,		2, (func_ptr) char16le },
	{ F_CHAR16GT,		2, (func_ptr) char16gt },
	{ F_CHAR16GE,		2, (func_ptr) char16ge },
	{ F_CHAR16NE,		2, (func_ptr) char16ne },

	{ F_LOCKADD,		2, (func_ptr) prs2LockUnion },
	{ F_LOCKRM,		2, (func_ptr) prs2RemoveAllLocksOfRule },
	{ F_PG_USERNAME,	0, (func_ptr) pg_username },
	{ F_USERFNTEST,		1, (func_ptr) userfntest },
	{ F_BYTEASIZE,		1, (func_ptr) byteaGetSize },
	{ F_BYTEAGETBYTE,	2, (func_ptr) byteaGetByte },
	{ F_BYTEASETBYTE,	3, (func_ptr) byteaSetByte },
	{ F_BYTEAGETBIT,	2, (func_ptr) byteaGetBit },
	{ F_BYTEASETBIT,	3, (func_ptr) byteaSetBit },
	{ F_PQTEST,		1, (func_ptr) pqtest },

	{ F_TEXTLT,		2, (func_ptr) text_lt },
	{ F_TEXTLE,		2, (func_ptr) text_le },
	{ F_TEXTGT,		2, (func_ptr) text_gt },
 	{ F_TEXTGE,		2, (func_ptr) text_ge },
	{ F_ARRAY_IN,	2, (func_ptr) array_in },
	{ F_ARRAY_OUT,	2, (func_ptr) array_out },
	{ F_FILENAME_IN,2, (func_ptr) filename_in },
	{ F_FILENAME_OUT,2, (func_ptr) filename_out },

	{ F_SMGRIN, 1, (func_ptr) smgrin },
	{ F_SMGROUT, 1, (func_ptr) smgrout },
	{ F_SMGREQ, 2, (func_ptr) smgreq },
	{ F_SMGRNE, 2, (func_ptr) smgrne },

	{ F_LO_FILEIN,  1, (func_ptr) lo_filein },
	{ F_LO_FILEOUT, 1, (func_ptr) lo_fileout},
	{ F_INT4INC,    1, (func_ptr) int4inc},
	{ F_INT2INC,    1, (func_ptr) int2inc},
	{ F_INT4LARGER, 2, (func_ptr) int4larger},
	{ F_INT4SMALLER,2, (func_ptr) int4smaller},
	{ F_INT2LARGER, 2, (func_ptr) int2larger},
	{ F_INT2SMALLER,2, (func_ptr) int2smaller},

#ifdef NOBTREE

	{ F_NOBTGETTUPLE,	6, (func_ptr) nobtgettuple },
	{ F_NOBTINSERT,		3, (func_ptr) nobtinsert },
	{ F_NOBTDELETE,		2, (func_ptr) nobtdelete },
	{ F_NOBTBEGINSCAN,	4, (func_ptr) nobtbeginscan },
	{ F_NOBTRESCAN,		3, (func_ptr) nobtrescan },
	{ F_NOBTENDSCAN,	1, (func_ptr) nobtendscan },
	{ F_NOBTMARKPOS,	1, (func_ptr) nobtmarkpos },
	{ F_NOBTRESTRPOS,	1, (func_ptr) nobtrestrpos },
	{ F_NOBTBUILD,		9, (func_ptr) nobtbuild },

#endif /* NOBTREE */

	{ F_FIMPORT,	1, (func_ptr) fimport },
	{ F_FEXPORT,	2, (func_ptr) fexport },
	{ F_FABSTRACT,	5, (func_ptr) fabstract },
	{ F_OIDINT4IN,	1, (func_ptr) oidint4in },
	{ F_OIDINT4OUT,	1, (func_ptr) oidint4out },
	{ F_OIDINT4LT,	2, (func_ptr) oidint4lt },
	{ F_OIDINT4LE,	2, (func_ptr) oidint4le },
	{ F_OIDINT4EQ,	2, (func_ptr) oidint4eq },
	{ F_OIDINT4GE,	2, (func_ptr) oidint4ge },
	{ F_OIDINT4GT,	2, (func_ptr) oidint4gt },
	{ F_OIDINT4NE,	2, (func_ptr) oidint4ne },
	{ F_OIDINT4CMP,	2, (func_ptr) oidint4cmp },
	{ F_MKOIDINT4,	2, (func_ptr) mkoidint4 },

	{ F_OIDCHAR16IN,	1, (func_ptr) oidchar16in },
	{ F_OIDCHAR16OUT,	1, (func_ptr) oidchar16out },
	{ F_OIDCHAR16LT,	2, (func_ptr) oidchar16lt },
	{ F_OIDCHAR16LE,	2, (func_ptr) oidchar16le },
	{ F_OIDCHAR16EQ,	2, (func_ptr) oidchar16eq },
	{ F_OIDCHAR16GE,	2, (func_ptr) oidchar16ge },
	{ F_OIDCHAR16GT,	2, (func_ptr) oidchar16gt },
	{ F_OIDCHAR16NE,	2, (func_ptr) oidchar16ne },
	{ F_OIDCHAR16CMP,	2, (func_ptr) oidchar16cmp },
	{ F_MKOIDCHAR16,	2, (func_ptr) mkoidchar16 },

        { F_FILETOOID,          1, (func_ptr) FilenameToOID },
        { F_LOCREATOID,         1, (func_ptr) LOcreatOID },
        { F_LOOPEN,             2, (func_ptr) LOopen },
        { F_LOCLOSE,            1, (func_ptr) LOclose },
        { F_LOREAD,             2, (func_ptr) LOread },
        { F_LOWRITE,            2, (func_ptr) LOwrite },
        { F_LOLSEEK,            3, (func_ptr) LOlseek },
        { F_LOCREAT,            3, (func_ptr) LOcreat },
        { F_LOTELL,             1, (func_ptr) LOtell },
        { F_LOFTRUNCATE,        2, (func_ptr) LOftruncate },
        { F_LOSTAT,             1, (func_ptr) LOstat },
        { F_LORENAME,           2, (func_ptr) LOrename },
        { F_LOMKDIR,            2, (func_ptr) LOmkdir },
        { F_LORMDIR,            1, (func_ptr) LOrmdir },
        { F_LOUNLINK,           1, (func_ptr) LOunlink },

        { F_PFTPREAD,           3, (func_ptr) pftp_read },
        { F_PFTPWRITE,          2, (func_ptr) pftp_write },
        { F_REGTOOID,		1, (func_ptr) RegprocToOid },

	{ F_PATH_INTER,		2, (func_ptr) path_inter },
	{ F_BOX_COPY,		1, (func_ptr) box_copy },
	{ F_BOX_AREA,		1, (func_ptr) box_area },
	{ F_BOX_LENGTH,		1, (func_ptr) box_length },
	{ F_BOX_HEIGHT,		1, (func_ptr) box_height },
	{ F_BOX_DISTANCE,	2, (func_ptr) box_distance },
	{ F_BOX_INTERSECT,	2, (func_ptr) box_intersect },
	{ F_BOX_DIAGONAL,	1, (func_ptr) box_diagonal },
	{ F_PATH_N_LT,		2, (func_ptr) path_n_lt },
	{ F_PATH_N_GT,		2, (func_ptr) path_n_gt },
	{ F_PATH_N_EQ,		2, (func_ptr) path_n_eq },
	{ F_PATH_N_LE,		2, (func_ptr) path_n_le },
	{ F_PATH_N_GE,		2, (func_ptr) path_n_ge },
	{ F_PATH_LENGTH,	1, (func_ptr) path_length },
	{ F_POINT_COPY,		1, (func_ptr) point_copy },
	{ F_POINT_VERT,		2, (func_ptr) point_vert },
	{ F_POINT_HORIZ,	2, (func_ptr) point_horiz },
	{ F_POINT_DISTANCE,	2, (func_ptr) point_distance },
	{ F_POINT_SLOPE,	2, (func_ptr) point_slope },
	{ F_LSEG_CONSTRUCT,	2, (func_ptr) lseg_construct },
	{ F_LSEG_INTERSECT,	2, (func_ptr) lseg_intersect },
	{ F_LSEG_PARALLEL,	2, (func_ptr) lseg_parallel },
	{ F_LSEG_PERP,		2, (func_ptr) lseg_perp },
	{ F_LSEG_VERTICAL,	1, (func_ptr) lseg_vertical },
	{ F_LSEG_HORIZONTAL,	1, (func_ptr) lseg_horizontal },
	{ F_LSEG_EQ,		2, (func_ptr) lseg_eq },
	{ F_NULLVALUE,             1, (func_ptr) NullValue },
	{ F_NONNULLVALUE,            1, (func_ptr) NonNullValue }
};

static 	n_builtins = lengthof(builtins);

char *c_lang_func_call_ptr(user_fn,n_arguments,values, isNull)
	int 		n_arguments;
	FmgrValues	values;
	func_ptr	user_fn;
	Boolean *isNull;		

{
    char		*returnValue = NULL;
    switch(n_arguments)
	{
	case 0:
	    returnValue = (*user_fn)();
	    break;
	case 1:
	    returnValue = (*user_fn)
		(values.data[0], isNull);
	    break;
	case 2:
	    returnValue = (*user_fn)
		(values.data[0],
		 values.data[1]);
	    break;
	case 3:
	    returnValue = (*user_fn)
		(values.data[0],
		 values.data[1],
		 values.data[2]);
	    break;
	case 4:
	    returnValue = (*user_fn)
		(values.data[0],
		 values.data[1],
		 values.data[2],
		 values.data[3]);
	    break;
	case 5:
	    returnValue = (*user_fn)
		(values.data[0],
		 values.data[1],
		 values.data[2],
		 values.data[3],
		 values.data[4]);
	    break;
	case 6:
	    returnValue = (*user_fn)
		(values.data[0],
		 values.data[1],
		 values.data[2],
		 values.data[3],
		 values.data[4],
		 values.data[5]);
	    break;
	case 7:
	    returnValue = (*user_fn)
		(values.data[0],
		 values.data[1],
		 values.data[2],
		 values.data[3],
		 values.data[4],
		 values.data[5],
		 values.data[6]);
	    break;
	case 8:
	    returnValue = (*user_fn)
		(values.data[0],
		 values.data[1],
		 values.data[2],
		 values.data[3],
		 values.data[4],
		 values.data[5],
		 values.data[6],
		 values.data[7]);
	    break;
	case 9:
	    returnValue = (*user_fn)
		(values.data[0],
		 values.data[1],
		 values.data[2],
		 values.data[3],
		 values.data[4],
		 values.data[5],
		 values.data[6],
		 values.data[7],
		 values.data[8]);
	    break;
	case 10:
	    returnValue = (*user_fn)
		(values.data[0],
		 values.data[1],
		 values.data[2],
		 values.data[3],
		 values.data[4],
		 values.data[5],
		 values.data[6],
		 values.data[7],
		 values.data[8],
		 values.data[9]);
	    break;
	default:
	    elog(WARN, "c_lang_call_ptr: too many args to function!");
	    break; /* Not really necessary, but why not? */
	}
    return(returnValue);
}

/* The *isNull flag is set to true if one of the arguments to
   the ADT functions is NULL, so it should not be initialised
   to anything, the old value needs to be propagated or set
   to true if necessary at the ADT functions */

char *c_lang_func_call_ptr_array(user_fn,nargs,args, isNull)
     int 		nargs;
     char *args[];
     func_ptr	user_fn;
     Boolean *isNull;

{
    char *returnValue;
    switch (nargs)
	{
	case 0:
	    returnValue = (*user_fn)();
	    break;
	case 1:
	    returnValue = (*user_fn)
		(args[0], isNull);		/* This is because the ADT fn */
	    break;				/* NullValue() use isNull for */
						/* checking if args[0] is NULL*/
	case 2:
	    returnValue = (*user_fn)
		(args[0],
		 args[1]);
	    break;
	case 3:
	    returnValue = (*user_fn)
		(args[0],
		 args[1],
		 args[2]);
	    break;
	case 4:
	    returnValue = (*user_fn)
		(args[0],
		 args[1],
		 args[2],
		 args[3]);
	    break;
	case 5:
	    returnValue = (*user_fn)
		(args[0],
		 args[1],
		 args[2],
		 args[3],
		 args[4]);
	    break;
	case 6:
	    returnValue = (*user_fn)
		(args[0],
		 args[1],
		 args[2],
		 args[3],
		 args[4],
		 args[5]);
	    break;
	case 7:
	    returnValue = (*user_fn)
		(args[0],
		 args[1],
		 args[2],
		 args[3],
		 args[4],
		 args[5],
		 args[6]);
	    break;
	case 8:
	    returnValue = (*user_fn)
		(args[0],
		 args[1],
		 args[2],
		 args[3],
		 args[4],
		 args[5],
		 args[6],
		 args[7]);
	    break;
	case 9:
	    returnValue = (*user_fn)
		(args[0],
		 args[1],
		 args[2],
		 args[3],
		 args[4],
		 args[5],
		 args[6],
		 args[7],
		 args[8]);
	    break;
	case 10:
	    returnValue = (*user_fn)
		(args[0],
		 args[1],
		 args[2],
		 args[3],
		 args[4],
		 args[5],
		 args[6],
		 args[7],
		 args[8],
		 args[9]);
	    break;
	default:
	    elog(WARN, "fmgr: too many args to function");
	    break; /* Not really necessary, but why not? */
	}
    return(returnValue);
}
char *postquel_lang_func_call_array(procedureId,pronargs,args)
     ObjectId procedureId;
     int	pronargs;
     char *args[];    
{
    List query_descriptor = LispNil, qd = LispNil;
    HeapTuple   procedureTuple;
    ParamListInfo paramlist;
    char *plan_str;
    int status,x;
    Datum *value;
    Boolean *isnull;
    

    plan_str = (char *)
	SearchSysCacheGetAttribute(PROOID,Anum_pg_proc_prosrc, procedureId);
    qd = StringToPlanWithParams(textout((struct varlena *)plan_str),&paramlist);
    x=0; 
    while(paramlist[x].kind != PARAM_INVALID) {
	paramlist[x].value = (Datum) args[x];
	x++;
    }
    if (prs2RunOnePlanAndGetValue(qd,paramlist, NULL, &value, &isnull))
	return (char *) value;
    else return (char *)NULL;
}
char *postquel_lang_func_call(procedureId,pronargs,values)
     ObjectId procedureId;
     int	pronargs;
     FmgrValues	values;
{


    
}






ObjectId fmgr_func_lang(procedureId)
     ObjectId procedureId;
{
    HeapTuple   procedureTuple;
    ObjectId language;
    int low, high,i;

    low = 0;
    high = n_builtins;
    while (low <= high) {
	i = low + (high - low) / 2;
	if (procedureId == builtins[i].proid)
	    break;
	else if (procedureId > builtins[i].proid)
	    low = i + 1;
	else
	    high = i - 1;
    }

	/*
	 * If we found the procedure in the above loop, wonderful.  Otherwise,
	 * it could be a 'language' procedure
	 * it is a dynamically loaded function - get its pointer and number
	 * of arguments from fmgr_dynamic().
	 */
    if (procedureId == builtins[i].proid) return INTERNALlanguageId;

    procedureTuple = SearchSysCacheTuple(PROOID, (char *) procedureId,
					 NULL, NULL, NULL);
    if (!HeapTupleIsValid(procedureTuple)) {
	elog(WARN, "fmgr: Cache lookup failed for procedure %d\n",
	     procedureId);
	return(NULL);
    }
    language = ((struct proc *) GETSTRUCT(procedureTuple))->prolang;
    return language;
}

void fmgr_info(procedureId, function, nargs)
     ObjectId procedureId;
     func_ptr *function;
     int	*nargs;
{
	int low, high, i;

	int arg_count;
	func_ptr user_fn, fmgr_dynamic();

	/*
	 * Binary-search the function array for the appropriate procedure.
	 */

	low = 0;
	high = n_builtins;
	while (low <= high) {
		i = low + (high - low) / 2;
		if (procedureId == builtins[i].proid)
			break;
		else if (procedureId > builtins[i].proid)
			low = i + 1;
		else
			high = i - 1;
	}

	/*
	 * If we found the procedure in the above loop, wonderful.  Otherwise,
	 * it could be a 'language' procedure
	 * it is a dynamically loaded function - get its pointer and number
	 * of arguments from fmgr_dynamic().
	 */

	if (procedureId != builtins[i].proid) {
	    HeapTuple   procedureTuple;
	    struct proc *procedureStruct;
	    ObjectId language;

	    procedureTuple = SearchSysCacheTuple(PROOID, (char *) procedureId,
						 NULL, NULL, NULL);
	    if (!HeapTupleIsValid(procedureTuple)) {
		elog(WARN, "fmgr: Cache lookup failed for procedure %d\n",
		     procedureId);
	    }
	    procedureStruct = (struct proc *) GETSTRUCT(procedureTuple);
	    language = procedureStruct->prolang;
	    switch (language) {
	    case INTERNALlanguageId:
		elog(WARN,
		     "internal procedure %d is not in the 'builtins' table",
		     procedureId);
		break;
	    case ClanguageId:
		user_fn = fmgr_dynamic(procedureId, nargs);
		break;
	    case POSTQUELlanguageId:
		user_fn = NULL;
		*nargs = procedureStruct->pronargs;
		break;
	    default:
		elog(WARN,
		     "procedure %d is of an unknown language %d",
		     procedureId, language);
	    }
	}
	else
	{
		user_fn = builtins[i].func;
		*nargs = builtins[i].nargs;
	}
	*function = user_fn;
}

/*
 *	fmgr		- return the value of a function call
 *
 *	If the function is a system routine, it's compiled in, so call
 *	it directly.
 *
 *      Otherwise pass it to the the appropriate 'language' function caller.
 *
 *	Returns the return value of the invoked function if succesful,
 *	0 if unsuccessful.
 *
 */
char *
fmgr(va_alist)
	va_dcl
{
	va_list		pvar;
	register	i, j;
	ObjectId	procedureId;
	int 		pronargs;
	FmgrValues	values;
	func_ptr	user_fn;
	Boolean isNull;
	isNull = false;

	va_start(pvar);
	procedureId = va_arg(pvar, ObjectId);

	fmgr_info(procedureId, &user_fn, &pronargs);

	if (pronargs > MAXFMGRARGS)
	{
		elog(WARN,
		    "fmgr: can\'t pass enough args to function: fid=%d",
		     procedureId); 
	}

	for (j = 0; j < pronargs; ++j)
		values.data[j] = va_arg(pvar, char *);

	va_end(pvar);


	return c_lang_func_call_ptr(user_fn,pronargs,values, &isNull);

#ifdef WAY_COOL_ORTHOGONAL_FUNCTIONS
	switch (fmgr_func_lang(procedureId)) {
	case INTERNALlanguageId:
	case ClanguageId:
	    return c_lang_func_call_ptr(user_fn,pronargs,values, &isNull);
	    break;
	case POSTQUELlanguageId:
	    return postquel_lang_func_call(procedureId,pronargs,values);
	    break;
	default:
	    elog(WARN,
		 "No function caller registered for language");
	}
#endif WAY_COOL_ORTHOGONAL_FUNCTIONS
}

char *
fmgr_array_args(procedureId, nargs, args, isNull)
    ObjectId procedureId;
	int nargs;
	char * args[];
	Boolean *isNull;
{
	func_ptr user_fn;
	int true_arguments;
	char *returnValue;

	fmgr_info(procedureId, &user_fn, &true_arguments);

	return c_lang_func_call_ptr_array(user_fn,true_arguments,args, isNull);

#ifdef WAY_COOL_ORTHOGONAL_FUNCTIONS
	switch (fmgr_func_lang(procedureId)) {
	case INTERNALlanguageId:
	case ClanguageId:
	    return c_lang_func_call_ptr_array(user_fn,true_arguments,args, isNull);
	    break;
	case POSTQUELlanguageId:
	    return postquel_lang_func_call_array(procedureId,
						 true_arguments,args);
	    break;
	default:
	    elog(WARN,
		 "No function caller for arrays args registered for language");
	}
#endif WAY_COOL_ORTHOGONAL_FUNCTIONS
}
	
/*
 * varargs
 * 
 * func_ptr, n_arguments, args...
 *
 */

char *
fmgr_by_ptr(va_alist)
	va_dcl
{
	va_list		pvar;
	FmgrValues	values;
	int			n_arguments, j;
	char		*returnValue = NULL;
	func_ptr	user_fn;
	Boolean isNull;
	isNull = false;

	va_start(pvar);

	user_fn = va_arg(pvar, func_ptr);
	n_arguments = va_arg(pvar, int);

	for (j = 0; j < n_arguments; ++j)
		values.data[j] = va_arg(pvar, char *);

	va_end(pvar);

	if (n_arguments > MAXFMGRARGS)
 	{
		elog(WARN,
		    "fmgr_by_ptr; can\'t pass enough args to function: nargs=%d",
		     n_arguments); 
	}
	return c_lang_func_call_ptr(user_fn,n_arguments,values, &isNull);
}

char *
fmgr_by_ptr_array_args(user_fn, nargs, args, isNull)
     func_ptr user_fn;
     int nargs;
     char * args[];
     Boolean *isNull;
{
	char *returnValue;
	return c_lang_func_call_ptr_array(user_fn,nargs,args, isNull);
    }
