/*-------------------------------------------------------------------------
 *
 * nbtree.h--
 *    header file for postgres btree access method implementation.
 *
 *
 * Copyright (c) 1994, Regents of the University of California
 *
 * $Id: nbtree.h,v 1.5 1995/04/09 20:27:03 andrew Exp $
 *
 *-------------------------------------------------------------------------
 */
#ifndef	NBTREE_H
#define	NBTREE_H

#include "storage/pagenum.h"

#include "access/attnum.h"
#include "access/itup.h"
#include "access/htup.h"
#include "access/tupdesc.h"

#include "access/istrat.h"
#include "access/funcindex.h"
#include "access/relscan.h"
#include "access/sdir.h"
#include "nodes/pg_list.h"

/*
 *  BTPageOpaqueData -- At the end of every page, we store a pointer to
 *  both siblings in the tree.  See Lehman and Yao's paper for more info.
 *  In addition, we need to know what sort of page this is (leaf or internal),
 *  and whether the page is available for reuse.
 *
 *  Lehman and Yao's algorithm requires a ``high key'' on every page.  The
 *  high key on a page is guaranteed to be greater than or equal to any key
 *  that appears on this page.  Our insertion algorithm guarantees that we
 *  can use the initial least key on our right sibling as the high key.  We
 *  allocate space for the line pointer to the high key in the opaque data
 *  at the end of the page.
 *
 *  Rightmost pages in the tree have no high key.
 */

typedef struct BTPageOpaqueData {
    PageNumber	btpo_prev;
    PageNumber	btpo_next;
    uint16	btpo_flags;

#define BTP_LEAF	(1 << 0)
#define BTP_ROOT	(1 << 1)
#define BTP_FREE	(1 << 2)

} BTPageOpaqueData;

typedef BTPageOpaqueData	*BTPageOpaque;

/*
 *  ScanOpaqueData is used to remember which buffers we're currently
 *  examining in the scan.  We keep these buffers locked and pinned and
 *  recorded in the opaque entry of the scan in order to avoid doing a
 *  ReadBuffer() for every tuple in the index.  This avoids semop() calls,
 *  which are expensive.
 */

typedef struct BTScanOpaqueData {
    Buffer	btso_curbuf;
    Buffer	btso_mrkbuf;
} BTScanOpaqueData;

typedef BTScanOpaqueData	*BTScanOpaque;

/*
 *  BTItems are what we store in the btree.  Each item has an index tuple,
 *  including key and pointer values.  In addition, we must guarantee that
 *  all tuples in the index are unique, in order to satisfy some assumptions
 *  in Lehman and Yao.  The way that we do this is by generating a new OID
 *  for every insertion that we do in the tree.  This adds four bytes to the
 *  size of btree index tuples.
 */

typedef struct BTItemData {
    Oid				bti_oid;
    int32			bti_dummy;	/* padding to make bti_itup
						 * align at 8-byte boundary
						 */
    IndexTupleData		bti_itup;
} BTItemData;

typedef BTItemData	*BTItem;

/*
 *  BTStackData -- As we descend a tree, we push the (key, pointer) pairs
 *  from internal nodes onto a private stack.  If we split a leaf, we use
 *  this stack to walk back up the tree and insert data into parent nodes
 *  (and possibly to split them, too).  Lehman and Yao's update algorithm
 *  guarantees that under no circumstances can our private stack give us
 *  an irredeemably bad picture up the tree.  Again, see the paper for
 *  details.
 */

typedef struct BTStackData {
    PageNumber		bts_blkno;
    OffsetIndex		bts_offset;
    BTItem			bts_btitem;
    struct BTStackData	*bts_parent;
} BTStackData;

typedef BTStackData	*BTStack;

/*
 *  We need to be able to tell the difference between read and write
 *  requests for pages, in order to do locking correctly.
 */

#define	BT_READ		0
#define	BT_WRITE	1

/*
 *  Similarly, the difference between insertion and non-insertion binary
 *  searches on a given page makes a difference when we're descending the
 *  tree.
 */

#define BT_INSERTION	0
#define BT_DESCENT	1

/*
 *  In general, the btree code tries to localize its knowledge about page
 *  layout to a couple of routines.  However, we need a special value to
 *  indicate "no page number" in those places where we expect page numbers.
 */

#define P_NONE		0

/*
 *  Strategy numbers -- ordering of these is <, <=, =, >=, > 
 */

#define BTLessStrategyNumber		1
#define BTLessEqualStrategyNumber	2
#define BTEqualStrategyNumber		3
#define BTGreaterEqualStrategyNumber	4
#define BTGreaterStrategyNumber		5
#define BTMaxStrategyNumber		5

/*
 *  When a new operator class is declared, we require that the user supply
 *  us with an amproc procudure for determining whether, for two keys a and
 *  b, a < b, a = b, or a > b.  This routine must return < 0, 0, > 0,
 *  respectively, in these three cases.  Since we only have one such proc
 *  in amproc, it's number 1.
 */

#define BTORDER_PROC	1


/*
 * prototypes for functions in nbtinsert.c
 */
extern InsertIndexResult _bt_doinsert(Relation rel, BTItem btitem);
extern InsertIndexResult _bt_insertonpg(Relation rel, Buffer buf,
	BTStack stack, int keysz, ScanKey scankey, BTItem btitem,
	BTItem afteritem);
extern Buffer _bt_split(Relation rel, Buffer buf);
extern OffsetIndex  _bt_findsplitloc(Relation rel, Page page,
	OffsetIndex start, OffsetIndex maxoff, Size llimit);
extern void _bt_newroot(Relation rel, Buffer lbuf, Buffer rbuf);
extern OffsetIndex _bt_pgaddtup(Relation rel, Buffer buf, int keysz,
	ScanKey itup_scankey, Size itemsize, BTItem btitem, BTItem afteritem);
extern bool _bt_goesonpg(Relation rel, Buffer buf, Size keysz, ScanKey scankey,
	BTItem afteritem);
extern bool _bt_itemcmp(Relation rel, Size keysz, BTItem item1,
	BTItem item2, StrategyNumber strat);
extern void _bt_updateitem(Relation rel, Size keysz, Buffer buf,
	Oid bti_oid, BTItem newItem);

/*
 * prototypes for functions in nbtpage.c
 */
extern void _bt_metapinit(Relation rel);
extern void _bt_checkmeta(Relation rel);
extern Buffer _bt_getroot(Relation rel, int access);
extern Buffer _bt_getbuf(Relation rel, BlockNumber blkno, int access);
extern void _bt_relbuf(Relation rel, Buffer buf, int access);
extern void _bt_wrtbuf(Relation rel, Buffer buf);
extern void _bt_wrtnorelbuf(Relation rel, Buffer buf);
extern void _bt_pageinit(Page page);
extern void _bt_metaproot(Relation rel, BlockNumber rootbknum);
extern Buffer _bt_getstackbuf(Relation rel, BTStack stack, int access);
extern void _bt_setpagelock(Relation rel, BlockNumber blkno, int access);
extern void _bt_unsetpagelock(Relation rel, BlockNumber blkno, int access);
extern void _bt_pagedel(Relation rel, ItemPointer tid);

/*
 * prototypes for functions in nbtree.c
 */
extern bool BuildingBtree;	/* in nbtree.c */

extern void btbuild(Relation heap, Relation index, int natts,
	AttrNumber *attnum, IndexStrategy istrat, uint16 pcount,
	Datum *params, FuncIndexInfo *finfo, PredInfo *predInfo);
extern InsertIndexResult btinsert(Relation rel, IndexTuple itup);
extern char *btgettuple(IndexScanDesc scan, ScanDirection dir);
extern char *btbeginscan(Relation rel, bool fromEnd, uint16 keysz,
			 ScanKey scankey);

extern void btrescan(IndexScanDesc scan, bool fromEnd, ScanKey scankey);
extern void btmovescan(IndexScanDesc scan, Datum v);
extern void btendscan(IndexScanDesc scan);
extern void btmarkpos(IndexScanDesc scan);
extern void btrestrpos(IndexScanDesc scan);
extern void btdelete(Relation rel, ItemPointer tid);

/*
 * prototypes for functions in nbtscan.c
 */
extern void _bt_regscan(IndexScanDesc scan);
extern void _bt_dropscan(IndexScanDesc scan);
extern void _bt_adjscans(Relation rel, ItemPointer tid);
extern void _bt_scandel(IndexScanDesc scan, BlockNumber blkno,
			OffsetNumber offno);
extern bool _bt_scantouched(IndexScanDesc scan, BlockNumber blkno,
			    OffsetNumber offno);

/*
 * prototypes for functions in nbtsearch.c
 */
extern BTStack _bt_search(Relation rel, int keysz, ScanKey scankey,
			  Buffer *bufP);
extern BTStack _bt_searchr(Relation rel, int keysz, ScanKey scankey,
			   Buffer *bufP, BTStack stack_in);
extern Buffer _bt_moveright(Relation rel, Buffer buf, int keysz,
			    ScanKey scankey, int access);
extern bool _bt_skeycmp(Relation rel, Size keysz, ScanKey scankey,
			Page page, ItemId itemid, StrategyNumber strat);
extern OffsetIndex _bt_binsrch(Relation rel, Buffer buf, int keysz,
			       ScanKey scankey, int srchtype);
extern OffsetIndex _bt_firsteq(Relation rel, TupleDesc itupdesc,
	Page page, Size keysz, ScanKey scankey, OffsetIndex offind);
extern int _bt_compare(Relation rel, TupleDesc itupdesc,
	Page page, int keysz, ScanKey scankey, OffsetIndex offind);
extern RetrieveIndexResult _bt_next(IndexScanDesc scan, ScanDirection dir);
extern RetrieveIndexResult _bt_first(IndexScanDesc scan, ScanDirection dir);
extern bool _bt_step(IndexScanDesc scan, Buffer *bufP, ScanDirection dir);
extern bool _bt_twostep(IndexScanDesc scan, Buffer *bufP, ScanDirection dir);
extern RetrieveIndexResult _bt_endpoint(IndexScanDesc scan, ScanDirection dir);

/*
 * prototypes for functions in nbtstrat.c
 */
extern StrategyNumber _bt_getstrat(Relation rel, AttrNumber attno,
				   RegProcedure proc);
extern bool _bt_invokestrat(Relation rel, AttrNumber attno,
			    StrategyNumber strat, Datum left, Datum right);

/*
 * prototypes for functions in nbtutils.c
 */
extern ScanKey  _bt_mkscankey(Relation rel, IndexTuple itup);
extern void _bt_freeskey(ScanKey skey);
extern void _bt_freestack(BTStack stack);
extern void _bt_orderkeys(Relation relation, uint16 *numberOfKeys,
			  ScanKey key);
extern bool _bt_checkqual(IndexScanDesc scan, IndexTuple itup);
extern BTItem _bt_formitem(IndexTuple itup);

#endif	/* NBTREE_H */
