/*-------------------------------------------------------------------------
 *
 * spgist.h
 *	  Public header file for SP-GiST access method.
 *
 *
 * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * src/include/access/spgist.h
 *
 *-------------------------------------------------------------------------
 */
#ifndef SPGIST_H
#define SPGIST_H

#include "access/amapi.h"
#include "access/xlogreader.h"
#include "fmgr.h"
#include "lib/stringinfo.h"


/* reloption parameters */
#define SPGIST_MIN_FILLFACTOR			10
#define SPGIST_DEFAULT_FILLFACTOR		80

/* SPGiST opclass support function numbers */
#define SPGIST_CONFIG_PROC				1
#define SPGIST_CHOOSE_PROC				2
#define SPGIST_PICKSPLIT_PROC			3
#define SPGIST_INNER_CONSISTENT_PROC	4
#define SPGIST_LEAF_CONSISTENT_PROC		5
#define SPGISTNProc						5

/*
 * Argument structs for spg_config method
 */
typedef struct spgConfigIn
{
	Oid			attType;		/* Data type to be indexed */
} spgConfigIn;

typedef struct spgConfigOut
{
	Oid			prefixType;		/* Data type of inner-tuple prefixes */
	Oid			labelType;		/* Data type of inner-tuple node labels */
	bool		canReturnData;	/* Opclass can reconstruct original data */
	bool		longValuesOK;	/* Opclass can cope with values > 1 page */
} spgConfigOut;

/*
 * Argument structs for spg_choose method
 */
typedef struct spgChooseIn
{
	Datum		datum;			/* original datum to be indexed */
	Datum		leafDatum;		/* current datum to be stored at leaf */
	int			level;			/* current level (counting from zero) */

	/* Data from current inner tuple */
	bool		allTheSame;		/* tuple is marked all-the-same? */
	bool		hasPrefix;		/* tuple has a prefix? */
	Datum		prefixDatum;	/* if so, the prefix value */
	int			nNodes;			/* number of nodes in the inner tuple */
	Datum	   *nodeLabels;		/* node label values (NULL if none) */
} spgChooseIn;

typedef enum spgChooseResultType
{
	spgMatchNode = 1,			/* descend into existing node */
	spgAddNode,					/* add a node to the inner tuple */
	spgSplitTuple				/* split inner tuple (change its prefix) */
} spgChooseResultType;

typedef struct spgChooseOut
{
	spgChooseResultType resultType; /* action code, see above */
	union
	{
		struct					/* results for spgMatchNode */
		{
			int			nodeN;	/* descend to this node (index from 0) */
			int			levelAdd;	/* increment level by this much */
			Datum		restDatum;	/* new leaf datum */
		}			matchNode;
		struct					/* results for spgAddNode */
		{
			Datum		nodeLabel;	/* new node's label */
			int			nodeN;	/* where to insert it (index from 0) */
		}			addNode;
		struct					/* results for spgSplitTuple */
		{
			/* Info to form new upper-level inner tuple with one child tuple */
			bool		prefixHasPrefix;	/* tuple should have a prefix? */
			Datum		prefixPrefixDatum;	/* if so, its value */
			int			prefixNNodes;	/* number of nodes */
			Datum	   *prefixNodeLabels;	/* their labels (or NULL for no
											 * labels) */
			int			childNodeN; /* which node gets child tuple */

			/* Info to form new lower-level inner tuple with all old nodes */
			bool		postfixHasPrefix;	/* tuple should have a prefix? */
			Datum		postfixPrefixDatum; /* if so, its value */
		}			splitTuple;
	}			result;
} spgChooseOut;

/*
 * Argument structs for spg_picksplit method
 */
typedef struct spgPickSplitIn
{
	int			nTuples;		/* number of leaf tuples */
	Datum	   *datums;			/* their datums (array of length nTuples) */
	int			level;			/* current level (counting from zero) */
} spgPickSplitIn;

typedef struct spgPickSplitOut
{
	bool		hasPrefix;		/* new inner tuple should have a prefix? */
	Datum		prefixDatum;	/* if so, its value */

	int			nNodes;			/* number of nodes for new inner tuple */
	Datum	   *nodeLabels;		/* their labels (or NULL for no labels) */

	int		   *mapTuplesToNodes;	/* node index for each leaf tuple */
	Datum	   *leafTupleDatums;	/* datum to store in each new leaf tuple */
} spgPickSplitOut;

/*
 * Argument structs for spg_inner_consistent method
 */
typedef struct spgInnerConsistentIn
{
	ScanKey		scankeys;		/* array of operators and comparison values */
	int			nkeys;			/* length of array */

	Datum		reconstructedValue; /* value reconstructed at parent */
	void	   *traversalValue; /* opclass-specific traverse value */
	MemoryContext traversalMemoryContext;	/* put new traverse values here */
	int			level;			/* current level (counting from zero) */
	bool		returnData;		/* original data must be returned? */

	/* Data from current inner tuple */
	bool		allTheSame;		/* tuple is marked all-the-same? */
	bool		hasPrefix;		/* tuple has a prefix? */
	Datum		prefixDatum;	/* if so, the prefix value */
	int			nNodes;			/* number of nodes in the inner tuple */
	Datum	   *nodeLabels;		/* node label values (NULL if none) */
} spgInnerConsistentIn;

typedef struct spgInnerConsistentOut
{
	int			nNodes;			/* number of child nodes to be visited */
	int		   *nodeNumbers;	/* their indexes in the node array */
	int		   *levelAdds;		/* increment level by this much for each */
	Datum	   *reconstructedValues;	/* associated reconstructed values */
	void	  **traversalValues;	/* opclass-specific traverse values */
} spgInnerConsistentOut;

/*
 * Argument structs for spg_leaf_consistent method
 */
typedef struct spgLeafConsistentIn
{
	ScanKey		scankeys;		/* array of operators and comparison values */
	int			nkeys;			/* length of array */

	Datum		reconstructedValue; /* value reconstructed at parent */
	void	   *traversalValue; /* opclass-specific traverse value */
	int			level;			/* current level (counting from zero) */
	bool		returnData;		/* original data must be returned? */

	Datum		leafDatum;		/* datum in leaf tuple */
} spgLeafConsistentIn;

typedef struct spgLeafConsistentOut
{
	Datum		leafValue;		/* reconstructed original data, if any */
	bool		recheck;		/* set true if operator must be rechecked */
} spgLeafConsistentOut;


/* spgutils.c */
extern bytea *spgoptions(Datum reloptions, bool validate);

/* spginsert.c */
extern IndexBuildResult *spgbuild(Relation heap, Relation index,
		 struct IndexInfo *indexInfo);
extern void spgbuildempty(Relation index);
extern bool spginsert(Relation index, Datum *values, bool *isnull,
		  ItemPointer ht_ctid, Relation heapRel,
		  IndexUniqueCheck checkUnique,
		  struct IndexInfo *indexInfo);

/* spgscan.c */
extern IndexScanDesc spgbeginscan(Relation rel, int keysz, int orderbysz);
extern void spgendscan(IndexScanDesc scan);
extern void spgrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys,
		  ScanKey orderbys, int norderbys);
extern int64 spggetbitmap(IndexScanDesc scan, TIDBitmap *tbm);
extern bool spggettuple(IndexScanDesc scan, ScanDirection dir);
extern bool spgcanreturn(Relation index, int attno);

/* spgvacuum.c */
extern IndexBulkDeleteResult *spgbulkdelete(IndexVacuumInfo *info,
			  IndexBulkDeleteResult *stats,
			  IndexBulkDeleteCallback callback,
			  void *callback_state);
extern IndexBulkDeleteResult *spgvacuumcleanup(IndexVacuumInfo *info,
				 IndexBulkDeleteResult *stats);

/* spgvalidate.c */
extern bool spgvalidate(Oid opclassoid);

#endif							/* SPGIST_H */
