diff options
Diffstat (limited to 'contrib/ltree/ltree.h')
-rw-r--r-- | contrib/ltree/ltree.h | 317 |
1 files changed, 317 insertions, 0 deletions
diff --git a/contrib/ltree/ltree.h b/contrib/ltree/ltree.h new file mode 100644 index 0000000..5e07616 --- /dev/null +++ b/contrib/ltree/ltree.h @@ -0,0 +1,317 @@ +/* contrib/ltree/ltree.h */ + +#ifndef __LTREE_H__ +#define __LTREE_H__ + +#include "fmgr.h" +#include "tsearch/ts_locale.h" +#include "utils/memutils.h" + + +/* ltree */ + +/* + * We want the maximum length of a label to be encoding-independent, so + * set it somewhat arbitrarily at 1000 characters (not bytes), while using + * uint16 fields to hold the byte length. + */ +#define LTREE_LABEL_MAX_CHARS 1000 + +/* + * LOWER_NODE used to be defined in the Makefile via the compile flags. + * However the MSVC build scripts neglected to do the same which resulted in + * MSVC builds not using LOWER_NODE. Since then, the MSVC scripts have been + * modified to look for -D compile flags in Makefiles, so here, in order to + * get the historic behavior of LOWER_NODE not being defined on MSVC, we only + * define it when not building in that environment. This is important as we + * want to maintain the same LOWER_NODE behavior after a pg_upgrade. + */ +#ifndef _MSC_VER +#define LOWER_NODE +#endif + +typedef struct +{ + uint16 len; /* label string length in bytes */ + char name[FLEXIBLE_ARRAY_MEMBER]; +} ltree_level; + +#define LEVEL_HDRSIZE (offsetof(ltree_level,name)) +#define LEVEL_NEXT(x) ( (ltree_level*)( ((char*)(x)) + MAXALIGN(((ltree_level*)(x))->len + LEVEL_HDRSIZE) ) ) + +typedef struct +{ + int32 vl_len_; /* varlena header (do not touch directly!) */ + uint16 numlevel; /* number of labels */ + /* Array of maxalign'd ltree_level structs follows: */ + char data[FLEXIBLE_ARRAY_MEMBER]; +} ltree; + +#define LTREE_HDRSIZE MAXALIGN( offsetof(ltree, data) ) +#define LTREE_FIRST(x) ( (ltree_level*)( ((char*)(x))+LTREE_HDRSIZE ) ) +#define LTREE_MAX_LEVELS PG_UINT16_MAX /* ltree.numlevel is uint16 */ + + +/* lquery */ + +/* lquery_variant: one branch of some OR'ed alternatives */ +typedef struct +{ + int32 val; /* CRC of label string */ + uint16 len; /* label string length in bytes */ + uint8 flag; /* see LVAR_xxx flags below */ + char name[FLEXIBLE_ARRAY_MEMBER]; +} lquery_variant; + +/* + * Note: these macros contain too many MAXALIGN calls and so will sometimes + * overestimate the space needed for an lquery_variant. However, we can't + * change it without breaking on-disk compatibility for lquery. + */ +#define LVAR_HDRSIZE MAXALIGN(offsetof(lquery_variant, name)) +#define LVAR_NEXT(x) ( (lquery_variant*)( ((char*)(x)) + MAXALIGN(((lquery_variant*)(x))->len) + LVAR_HDRSIZE ) ) + +#define LVAR_ANYEND 0x01 /* '*' flag: prefix match */ +#define LVAR_INCASE 0x02 /* '@' flag: case-insensitive match */ +#define LVAR_SUBLEXEME 0x04 /* '%' flag: word-wise match */ + +/* + * In an lquery_level, "flag" contains the union of the variants' flags + * along with possible LQL_xxx flags; so those bit sets can't overlap. + * + * "low" and "high" are nominally the minimum and maximum number of matches. + * However, for backwards compatibility with pre-v13 on-disk lqueries, + * non-'*' levels (those with numvar > 0) only have valid low/high if the + * LQL_COUNT flag is set; otherwise those fields are zero, but the behavior + * is as if they were both 1. + */ +typedef struct +{ + uint16 totallen; /* total length of this level, in bytes */ + uint16 flag; /* see LQL_xxx and LVAR_xxx flags */ + uint16 numvar; /* number of variants; 0 means '*' */ + uint16 low; /* minimum repeat count */ + uint16 high; /* maximum repeat count */ + /* Array of maxalign'd lquery_variant structs follows: */ + char variants[FLEXIBLE_ARRAY_MEMBER]; +} lquery_level; + +#define LQL_HDRSIZE MAXALIGN( offsetof(lquery_level,variants) ) +#define LQL_NEXT(x) ( (lquery_level*)( ((char*)(x)) + MAXALIGN(((lquery_level*)(x))->totallen) ) ) +#define LQL_FIRST(x) ( (lquery_variant*)( ((char*)(x))+LQL_HDRSIZE ) ) + +#define LQL_NOT 0x10 /* level has '!' (NOT) prefix */ +#define LQL_COUNT 0x20 /* level is non-'*' and has repeat counts */ + +#ifdef LOWER_NODE +#define FLG_CANLOOKSIGN(x) ( ( (x) & ( LQL_NOT | LVAR_ANYEND | LVAR_SUBLEXEME ) ) == 0 ) +#else +#define FLG_CANLOOKSIGN(x) ( ( (x) & ( LQL_NOT | LVAR_ANYEND | LVAR_SUBLEXEME | LVAR_INCASE ) ) == 0 ) +#endif +#define LQL_CANLOOKSIGN(x) FLG_CANLOOKSIGN( ((lquery_level*)(x))->flag ) + +typedef struct +{ + int32 vl_len_; /* varlena header (do not touch directly!) */ + uint16 numlevel; /* number of lquery_levels */ + uint16 firstgood; /* number of leading simple-match levels */ + uint16 flag; /* see LQUERY_xxx flags below */ + /* Array of maxalign'd lquery_level structs follows: */ + char data[FLEXIBLE_ARRAY_MEMBER]; +} lquery; + +#define LQUERY_HDRSIZE MAXALIGN( offsetof(lquery, data) ) +#define LQUERY_FIRST(x) ( (lquery_level*)( ((char*)(x))+LQUERY_HDRSIZE ) ) +#define LQUERY_MAX_LEVELS PG_UINT16_MAX /* lquery.numlevel is uint16 */ + +#define LQUERY_HASNOT 0x01 + +/* valid label chars are alphanumerics, underscores and hyphens */ +#define ISLABEL(x) ( t_isalnum(x) || t_iseq(x, '_') || t_iseq(x, '-') ) + +/* full text query */ + +/* + * item in polish notation with back link + * to left operand + */ +typedef struct ITEM +{ + int16 type; + int16 left; + int32 val; + uint8 flag; + /* user-friendly value */ + uint8 length; + uint16 distance; +} ITEM; + +/* + *Storage: + * (len)(size)(array of ITEM)(array of operand in user-friendly form) + */ +typedef struct +{ + int32 vl_len_; /* varlena header (do not touch directly!) */ + int32 size; + char data[FLEXIBLE_ARRAY_MEMBER]; +} ltxtquery; + +#define HDRSIZEQT MAXALIGN(VARHDRSZ + sizeof(int32)) +#define COMPUTESIZE(size,lenofoperand) ( HDRSIZEQT + (size) * sizeof(ITEM) + (lenofoperand) ) +#define LTXTQUERY_TOO_BIG(size,lenofoperand) \ + ((size) > (MaxAllocSize - HDRSIZEQT - (lenofoperand)) / sizeof(ITEM)) +#define GETQUERY(x) (ITEM*)( (char*)(x)+HDRSIZEQT ) +#define GETOPERAND(x) ( (char*)GETQUERY(x) + ((ltxtquery*)x)->size * sizeof(ITEM) ) + +#define ISOPERATOR(x) ( (x)=='!' || (x)=='&' || (x)=='|' || (x)=='(' || (x)==')' ) + +#define END 0 +#define ERR 1 +#define VAL 2 +#define OPR 3 +#define OPEN 4 +#define CLOSE 5 +#define VALTRUE 6 /* for stop words */ +#define VALFALSE 7 + + +/* use in array iterator */ +PGDLLEXPORT Datum ltree_isparent(PG_FUNCTION_ARGS); +PGDLLEXPORT Datum ltree_risparent(PG_FUNCTION_ARGS); +PGDLLEXPORT Datum ltq_regex(PG_FUNCTION_ARGS); +PGDLLEXPORT Datum ltq_rregex(PG_FUNCTION_ARGS); +PGDLLEXPORT Datum lt_q_regex(PG_FUNCTION_ARGS); +PGDLLEXPORT Datum lt_q_rregex(PG_FUNCTION_ARGS); +PGDLLEXPORT Datum ltxtq_exec(PG_FUNCTION_ARGS); +PGDLLEXPORT Datum ltxtq_rexec(PG_FUNCTION_ARGS); +PGDLLEXPORT Datum _ltq_regex(PG_FUNCTION_ARGS); +PGDLLEXPORT Datum _ltq_rregex(PG_FUNCTION_ARGS); +PGDLLEXPORT Datum _lt_q_regex(PG_FUNCTION_ARGS); +PGDLLEXPORT Datum _lt_q_rregex(PG_FUNCTION_ARGS); +PGDLLEXPORT Datum _ltxtq_exec(PG_FUNCTION_ARGS); +PGDLLEXPORT Datum _ltxtq_rexec(PG_FUNCTION_ARGS); +PGDLLEXPORT Datum _ltree_isparent(PG_FUNCTION_ARGS); +PGDLLEXPORT Datum _ltree_risparent(PG_FUNCTION_ARGS); + +/* Concatenation functions */ +PGDLLEXPORT Datum ltree_addltree(PG_FUNCTION_ARGS); +PGDLLEXPORT Datum ltree_addtext(PG_FUNCTION_ARGS); +PGDLLEXPORT Datum ltree_textadd(PG_FUNCTION_ARGS); + +/* Util function */ +PGDLLEXPORT Datum ltree_in(PG_FUNCTION_ARGS); + +bool ltree_execute(ITEM *curitem, void *checkval, + bool calcnot, bool (*chkcond) (void *checkval, ITEM *val)); + +int ltree_compare(const ltree *a, const ltree *b); +bool inner_isparent(const ltree *c, const ltree *p); +bool compare_subnode(ltree_level *t, char *qn, int len, + int (*cmpptr) (const char *, const char *, size_t), bool anyend); +ltree *lca_inner(ltree **a, int len); +int ltree_strncasecmp(const char *a, const char *b, size_t s); + +/* fmgr macros for ltree objects */ +#define DatumGetLtreeP(X) ((ltree *) PG_DETOAST_DATUM(X)) +#define DatumGetLtreePCopy(X) ((ltree *) PG_DETOAST_DATUM_COPY(X)) +#define PG_GETARG_LTREE_P(n) DatumGetLtreeP(PG_GETARG_DATUM(n)) +#define PG_GETARG_LTREE_P_COPY(n) DatumGetLtreePCopy(PG_GETARG_DATUM(n)) + +#define DatumGetLqueryP(X) ((lquery *) PG_DETOAST_DATUM(X)) +#define DatumGetLqueryPCopy(X) ((lquery *) PG_DETOAST_DATUM_COPY(X)) +#define PG_GETARG_LQUERY_P(n) DatumGetLqueryP(PG_GETARG_DATUM(n)) +#define PG_GETARG_LQUERY_P_COPY(n) DatumGetLqueryPCopy(PG_GETARG_DATUM(n)) + +#define DatumGetLtxtqueryP(X) ((ltxtquery *) PG_DETOAST_DATUM(X)) +#define DatumGetLtxtqueryPCopy(X) ((ltxtquery *) PG_DETOAST_DATUM_COPY(X)) +#define PG_GETARG_LTXTQUERY_P(n) DatumGetLtxtqueryP(PG_GETARG_DATUM(n)) +#define PG_GETARG_LTXTQUERY_P_COPY(n) DatumGetLtxtqueryPCopy(PG_GETARG_DATUM(n)) + +/* GiST support for ltree */ + +#define BITBYTE 8 +#define SIGLENBIT(siglen) ((siglen) * BITBYTE) +#define LTREE_SIGLEN_DEFAULT (2 * sizeof(int32)) +#define LTREE_SIGLEN_MAX GISTMaxIndexKeySize +#define LTREE_GET_SIGLEN() (PG_HAS_OPCLASS_OPTIONS() ? \ + ((LtreeGistOptions *) PG_GET_OPCLASS_OPTIONS())->siglen : \ + LTREE_SIGLEN_DEFAULT) + +typedef unsigned char *BITVECP; + +#define LOOPBYTE(siglen) \ + for(i = 0; i < (siglen); i++) + +#define GETBYTE(x,i) ( *( (BITVECP)(x) + (int)( (i) / BITBYTE ) ) ) +#define GETBITBYTE(x,i) ( ((unsigned char)(x)) >> i & 0x01 ) +#define CLRBIT(x,i) GETBYTE(x,i) &= ~( 0x01 << ( (i) % BITBYTE ) ) +#define SETBIT(x,i) GETBYTE(x,i) |= ( 0x01 << ( (i) % BITBYTE ) ) +#define GETBIT(x,i) ( (GETBYTE(x,i) >> ( (i) % BITBYTE )) & 0x01 ) + +#define HASHVAL(val, siglen) (((unsigned int)(val)) % SIGLENBIT(siglen)) +#define HASH(sign, val, siglen) SETBIT((sign), HASHVAL(val, siglen)) + +/* + * type of index key for ltree. Tree are combined B-Tree and R-Tree + * Storage: + * Leaf pages + * (len)(flag)(ltree) + * Non-Leaf + * (len)(flag)(sign)(left_ltree)(right_ltree) + * ALLTRUE: (len)(flag)(left_ltree)(right_ltree) + * + */ + +typedef struct +{ + int32 vl_len_; /* varlena header (do not touch directly!) */ + uint32 flag; + char data[FLEXIBLE_ARRAY_MEMBER]; +} ltree_gist; + +#define LTG_ONENODE 0x01 +#define LTG_ALLTRUE 0x02 +#define LTG_NORIGHT 0x04 + +#define LTG_HDRSIZE MAXALIGN(VARHDRSZ + sizeof(uint32)) +#define LTG_SIGN(x) ( (BITVECP)( ((char*)(x))+LTG_HDRSIZE ) ) +#define LTG_NODE(x) ( (ltree*)( ((char*)(x))+LTG_HDRSIZE ) ) +#define LTG_ISONENODE(x) ( ((ltree_gist*)(x))->flag & LTG_ONENODE ) +#define LTG_ISALLTRUE(x) ( ((ltree_gist*)(x))->flag & LTG_ALLTRUE ) +#define LTG_ISNORIGHT(x) ( ((ltree_gist*)(x))->flag & LTG_NORIGHT ) +#define LTG_LNODE(x, siglen) ( (ltree*)( ( ((char*)(x))+LTG_HDRSIZE ) + ( LTG_ISALLTRUE(x) ? 0 : (siglen) ) ) ) +#define LTG_RENODE(x, siglen) ( (ltree*)( ((char*)LTG_LNODE(x, siglen)) + VARSIZE(LTG_LNODE(x, siglen))) ) +#define LTG_RNODE(x, siglen) ( LTG_ISNORIGHT(x) ? LTG_LNODE(x, siglen) : LTG_RENODE(x, siglen) ) + +#define LTG_GETLNODE(x, siglen) ( LTG_ISONENODE(x) ? LTG_NODE(x) : LTG_LNODE(x, siglen) ) +#define LTG_GETRNODE(x, siglen) ( LTG_ISONENODE(x) ? LTG_NODE(x) : LTG_RNODE(x, siglen) ) + +extern ltree_gist *ltree_gist_alloc(bool isalltrue, BITVECP sign, int siglen, + ltree *left, ltree *right); + +/* GiST support for ltree[] */ + +#define LTREE_ASIGLEN_DEFAULT (7 * sizeof(int32)) +#define LTREE_ASIGLEN_MAX GISTMaxIndexKeySize +#define LTREE_GET_ASIGLEN() (PG_HAS_OPCLASS_OPTIONS() ? \ + ((LtreeGistOptions *) PG_GET_OPCLASS_OPTIONS())->siglen : \ + LTREE_ASIGLEN_DEFAULT) +#define ASIGLENBIT(siglen) ((siglen) * BITBYTE) + +#define ALOOPBYTE(siglen) \ + for (i = 0; i < (siglen); i++) + +#define AHASHVAL(val, siglen) (((unsigned int)(val)) % ASIGLENBIT(siglen)) +#define AHASH(sign, val, siglen) SETBIT((sign), AHASHVAL(val, siglen)) + +/* gist_ltree_ops and gist__ltree_ops opclass options */ +typedef struct +{ + int32 vl_len_; /* varlena header (do not touch directly!) */ + int siglen; /* signature length in bytes */ +} LtreeGistOptions; + +/* type of key is the same to ltree_gist */ + +#endif |