text: /*-------------------------------------------------------------------------
   *
   * gist.h--
   *    common declarations for the GiST access method code.
   *
   *
   *
   * 
   *
   *-------------------------------------------------------------------------
   */
  #ifndef GIST_H
  #define GIST_H
  
  #include <access/funcindex.h>
  #include <access/itup.h>
  #include <access/relscan.h>
  #include <access/sdir.h>
  #include <storage/page.h>
  #include <storage/block.h>
  #include <utils/rel.h>
  #include <storage/off.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 */
  #define TRLOWER(tr) (((tr)->bytes))
  #define TRUPPER(tr) (&((tr)->bytes[MAXALIGN(VARSIZE(TRLOWER(tr)))]))
  
  typedef struct txtrange {
      /* flag: NINF means that lower is negative infinity; PINF means that
      ** upper is positive infinity.  0 means that both are numbers.
      */
      int32 vl_len;
      int32 flag;  
      char bytes[2];
  } TXTRANGE;
  
  typedef struct intrange {
      int lower;
      int upper;
      /* flag: NINF means that lower is negative infinity; PINF means that
      ** upper is positive infinity.  0 means that both are numbers.
      */
      int flag;  
  } INTRANGE;
  
  extern void gistbuild(Relation heap,
  	  Relation index, int natts,
  	  AttrNumber *attnum, IndexStrategy istrat,
  	  uint16 pint, Datum *params,
  	  FuncIndexInfo *finfo,
  	  PredInfo *predInfo);
  extern InsertIndexResult gistinsert(Relation r, Datum *datum,
  			char *nulls,ItemPointer ht_ctid, bool is_update);
  extern void _gistdump(Relation r);
  extern char *text_range_out(TXTRANGE *r);
  extern char *int_range_out(INTRANGE *r);
  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) ;
  extern StrategyNumber RelationGetGISTStrategy(Relation, AttrNumber, RegProcedure);
  
  /* gistget.c */
  extern RetrieveIndexResult gistgettuple(IndexScanDesc s, ScanDirection dir);
  extern bool gistindex_keytest(IndexTuple tuple, TupleDesc tupdesc,
  		  int scanKeySize, ScanKey key, GISTSTATE *giststate,
  		  Relation r, Page p, OffsetNumber offset);
  
  /* giststrat.c */
  extern bool RelationInvokeGISTStrategy(Relation r, AttrNumber attnum,
  			 StrategyNumber s, Datum left, Datum right);
  
  #endif /* GIST_H */
  