/*-------------------------------------------------------------------------
 *
 * gist.h--
 *    common declarations for the GiST access method code.
 *
 *
 *
 * 
 *
 *-------------------------------------------------------------------------
 */
#ifndef GIST_H
#define GIST_H

#include "storage/bufpage.h"


/* 
** You can have as many strategies as you please in GiSTs, as
** long as your consistent method can handle them
*/
#define GISTNStrategies			100

/*
** Helper routines
*/
#define GISTNProcs			8
#define GIST_CONSISTENT_PROC		1
#define GIST_UNION_PROC			2
#define GIST_COMPRESS_PROC		3
#define GIST_DECOMPRESS_PROC		4
#define GIST_PENALTY_PROC		5
#define GIST_PICKSPLIT_PROC		6
#define GIST_EQUAL_PROC 		7
#define GIST_INFO_PROC			8

#define F_LEAF		(1 << 0)

typedef struct GISTPageOpaqueData {
	uint32		flags;
} GISTPageOpaqueData;

typedef GISTPageOpaqueData	*GISTPageOpaque;

#define GIST_LEAF(entry) (((GISTPageOpaque) PageGetSpecialPointer((entry)->page))->flags & F_LEAF)

/*
 *  When we descend a tree, we keep a stack of parent pointers.
 */

typedef struct GISTSTACK {
	struct GISTSTACK *gs_parent;
	OffsetNumber	gs_child;
	BlockNumber	gs_blk;
} GISTSTACK;

typedef struct GISTSTATE {
    func_ptr consistentFn;
    func_ptr unionFn;
    func_ptr compressFn;
    func_ptr decompressFn;
    func_ptr penaltyFn;
    func_ptr picksplitFn;
    func_ptr equalFn;
    bool     haskeytype;
    bool     keytypbyval;
} GISTSTATE;


/*
**  When we're doing a scan, we need to keep track of the parent stack
**  for the marked and current items.  
*/

typedef struct GISTScanOpaqueData {
	struct GISTSTACK	*s_stack;
	struct GISTSTACK	*s_markstk;
	uint16		s_flags;
	struct GISTSTATE        *giststate;
} GISTScanOpaqueData;

typedef GISTScanOpaqueData	*GISTScanOpaque;

/*
**  When we're doing a scan and updating a tree at the same time, the
**  updates may affect the scan.  We use the flags entry of the scan's
**  opaque space to record our actual position in response to updates
**  that we can't handle simply by adjusting pointers.
*/

#define GS_CURBEFORE	((uint16) (1 << 0))
#define GS_MRKBEFORE	((uint16) (1 << 1))

/* root page of a gist */
#define GISTP_ROOT		0

/*
**  When we update a relation on which we're doing a scan, we need to
**  check the scan and fix it if the update affected any of the pages it
**  touches.  Otherwise, we can miss records that we should see.  The only
**  times we need to do this are for deletions and splits.  See the code in
**  gistscan.c for how the scan is fixed. These two constants tell us what sort
**  of operation changed the index.
*/

#define	GISTOP_DEL	0
#define	GISTOP_SPLIT	1

/*
** This is the Split Vector to be returned by the PickSplit method.
*/
typedef struct GIST_SPLITVEC {
    OffsetNumber	*spl_left;    /* array of entries that go left */
    int			spl_nleft;    /* size of this array */
    char		*spl_ldatum;  /* Union of keys in spl_left */
    OffsetNumber	*spl_right;   /* array of entries that go right */
    int			spl_nright;   /* size of the array */
    char		*spl_rdatum;  /* Union of keys in spl_right */
} GIST_SPLITVEC;

/*
** An entry on a GiST node.  Contains the key (pred), as well as 
** its own location (rel,page,offset) which can supply the matching
** pointer.  The size of the pred is in bytes, and leafkey is a flag to
** tell us if the entry is in a leaf node.
*/
typedef struct GISTENTRY {
    char *pred;
    Relation rel;
    Page page;
    OffsetNumber offset;
    int bytes;
    bool leafkey;
} GISTENTRY;

/*
** macro to initialize a GISTENTRY
*/
#define gistentryinit(e, pr, r, pg, o, b, l)\
   {(e).pred = pr; (e).rel = r; (e).page = pg; (e).offset = o; (e).bytes = b; (e).leafkey = l;}

/* defined in gist.c */
extern void gistfreestack(GISTSTACK *s);
extern void initGISTstate(GISTSTATE *giststate, Relation index);
extern void gistdentryinit(GISTSTATE *giststate, GISTENTRY *e, char *pr, 
			   Relation r, Page pg, OffsetNumber o, int b, bool l) ;
extern void gistcentryinit(GISTSTATE *giststate, GISTENTRY *e, char *pr, 
			   Relation r, Page pg, OffsetNumber o, int b, bool l) ;
#endif /* GIST_H */
