diff options
| author | Tom Lane <tgl@sss.pgh.pa.us> | 2001-10-12 23:19:09 +0000 |
|---|---|---|
| committer | Tom Lane <tgl@sss.pgh.pa.us> | 2001-10-12 23:19:09 +0000 |
| commit | b57705673d02483b6e20d8a4d55a8aa182055d08 (patch) | |
| tree | cb974bb78b96509ab7b8e69f1f43d2bb9658adcf /contrib/tsearch/rewrite.c | |
| parent | c24216bea8ae43b251900d1ce6ca9250943c33e0 (diff) | |
| download | postgresql-b57705673d02483b6e20d8a4d55a8aa182055d08.tar.gz | |
txtidx datatype for full text indexing with GiST.
From Oleg Bartunov and Teodor Sigaev.
Diffstat (limited to 'contrib/tsearch/rewrite.c')
| -rw-r--r-- | contrib/tsearch/rewrite.c | 234 |
1 files changed, 234 insertions, 0 deletions
diff --git a/contrib/tsearch/rewrite.c b/contrib/tsearch/rewrite.c new file mode 100644 index 0000000000..590b15e7ca --- /dev/null +++ b/contrib/tsearch/rewrite.c @@ -0,0 +1,234 @@ +/* + * Rewrite routines of query tree + * Teodor Sigaev <teodor@stack.net> + */ + +#include "postgres.h" + +#include <float.h> + +#include "access/gist.h" +#include "access/itup.h" +#include "access/rtree.h" +#include "utils/elog.h" +#include "utils/palloc.h" +#include "utils/array.h" +#include "utils/builtins.h" +#include "storage/bufpage.h" + +#include "query.h" +#include "rewrite.h" + +typedef struct NODE { + struct NODE *left; + struct NODE *right; + ITEM* valnode; +} NODE; + +/* + * make query tree from plain view of query + */ +static NODE* +maketree(ITEM *in) { + NODE *node = (NODE*)palloc(sizeof(NODE)); + node->valnode = in; + node->right = node->left = NULL; + if ( in->type == OPR ) { + node->right = maketree( in + 1 ); + if ( in->val != (int4)'!' ) + node->left = maketree( in + in->left ); + } + return node; +} + +typedef struct { + ITEM* ptr; + int4 len; + int4 cur; +} PLAINTREE; + +static void +plainnode(PLAINTREE *state, NODE* node) { + if ( state->cur == state->len ) { + state->len *= 2; + state->ptr=(ITEM*)repalloc( (void*)state->ptr, state->len*sizeof(ITEM) ); + } + memcpy( (void*)&(state->ptr[state->cur]), (void*)node->valnode, sizeof(ITEM) ); + if ( node->valnode->type == VAL ) { + state->cur++; + } else if ( node->valnode->val == (int4)'!' ) { + state->ptr[state->cur].left=1; + state->cur++; + plainnode(state, node->right); + } else { + int4 cur = state->cur; + state->cur++; + plainnode(state, node->right); + state->ptr[cur].left = state->cur - cur; + plainnode(state, node->left); + } + pfree(node); +} + +/* + * make plain view of tree from 'normal' view of tree + */ +static ITEM* +plaintree(NODE *root, int4 *len) { + PLAINTREE pl; + pl.cur=0; + pl.len=16; + if ( root && (root->valnode->type == VAL || root->valnode->type == OPR) ) { + pl.ptr = (ITEM*)palloc( pl.len*sizeof(ITEM) ); + plainnode(&pl, root); + } else { + pl.ptr = NULL; + } + *len = pl.cur; + return pl.ptr; +} + +static void +freetree(NODE *node) { + if ( !node ) return; + if ( node->left ) freetree(node->left); + if ( node->right ) freetree(node->right); + pfree( node ); +} + +/* + * clean tree for ! operator. + * It's usefull for debug, but in + * other case, such view is used with search in index. + * Operator ! always return TRUE + */ +static NODE* +clean_NOT_intree( NODE* node ) { + if ( node->valnode->type == VAL ) + return node; + + if ( node->valnode->val == (int4)'!' ) { + freetree(node); + return NULL; + } + + /* operator & or | */ + if ( node->valnode->val == (int4)'|' ) { + if ( (node->left=clean_NOT_intree(node->left)) == NULL || + (node->right=clean_NOT_intree(node->right)) == NULL ) { + freetree(node); + return NULL; + } + } else { + NODE *res = node; + node->left=clean_NOT_intree(node->left); + node->right=clean_NOT_intree(node->right); + if ( node->left == NULL && node->right == NULL ) { + pfree(node); + res = NULL; + } else if ( node->left == NULL ) { + res = node->right; + pfree(node); + } else if ( node->right == NULL ) { + res = node->left; + pfree(node); + } + return res; + } + return node; +} + +ITEM* +clean_NOT(ITEM* ptr, int4 *len) { + NODE *root = maketree( ptr ); + return plaintree(clean_NOT_intree(root), len); +} + +#define V_UNKNOWN 0 +#define V_TRUE 1 +#define V_FALSE 2 + +/* + * Clean query tree from values which is always in + * text (stopword) + */ +static NODE* +clean_fakeval_intree( NODE* node, char *result ) { + char lresult = V_UNKNOWN, rresult = V_UNKNOWN; + if ( node->valnode->type == VAL ) + return node; + else if ( node->valnode->type == VALTRUE ) { + pfree( node ); + *result = V_TRUE; + return NULL; + } + + + if ( node->valnode->val == (int4)'!' ) { + node->right = clean_fakeval_intree( node->right, &rresult ); + if ( ! node->right ) { + *result = ( rresult == V_TRUE ) ? V_FALSE : V_TRUE; + freetree(node); + return NULL; + } + } else if ( node->valnode->val == (int4)'|' ) { + NODE *res = node; + node->left =clean_fakeval_intree(node->left, &lresult); + node->right=clean_fakeval_intree(node->right,&rresult); + if ( lresult == V_TRUE || rresult == V_TRUE ) { + freetree(node); + *result=V_TRUE; + return NULL; + } else if ( lresult == V_FALSE && rresult == V_FALSE ) { + freetree(node); + *result=V_FALSE; + return NULL; + } else if ( lresult == V_FALSE ) { + res = node->right; + pfree(node); + } else if ( rresult == V_FALSE ) { + res = node->left; + pfree(node); + } + return res; + } else { + NODE *res = node; + node->left =clean_fakeval_intree(node->left, &lresult); + node->right=clean_fakeval_intree(node->right,&rresult); + if ( lresult == V_FALSE || rresult == V_FALSE ) { + freetree(node); + *result=V_FALSE; + return NULL; + } else if ( lresult == V_TRUE && rresult == V_TRUE ) { + freetree(node); + *result=V_TRUE; + return NULL; + } else if ( lresult == V_TRUE ) { + res = node->right; + pfree(node); + } else if ( rresult == V_TRUE ) { + res = node->left; + pfree(node); + } + return res; + } + return node; +} + +ITEM* +clean_fakeval(ITEM* ptr, int4 *len) { + NODE *root = maketree( ptr ); + char result = V_UNKNOWN; + NODE *resroot; + + resroot = clean_fakeval_intree(root, &result); + if ( result != V_UNKNOWN ) { + elog(ERROR,"Your query contained only stopword(s), ignored"); + *len = 0; + return NULL; + } + + return plaintree(resroot, len); +} + + |
