summaryrefslogtreecommitdiff
path: root/contrib/tsearch/rewrite.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2001-10-12 23:19:09 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2001-10-12 23:19:09 +0000
commitb57705673d02483b6e20d8a4d55a8aa182055d08 (patch)
treecb974bb78b96509ab7b8e69f1f43d2bb9658adcf /contrib/tsearch/rewrite.c
parentc24216bea8ae43b251900d1ce6ca9250943c33e0 (diff)
downloadpostgresql-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.c234
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);
+}
+
+