diff options
Diffstat (limited to 'contrib/tsearch2/query_util.c')
-rw-r--r-- | contrib/tsearch2/query_util.c | 257 |
1 files changed, 257 insertions, 0 deletions
diff --git a/contrib/tsearch2/query_util.c b/contrib/tsearch2/query_util.c new file mode 100644 index 00000000000..f509d9b6424 --- /dev/null +++ b/contrib/tsearch2/query_util.c @@ -0,0 +1,257 @@ +#include "postgres.h" +#include "executor/spi.h" +#include "query_util.h" + +QTNode* +QT2QTN( ITEM *in, char *operand ) { + QTNode *node = (QTNode*)palloc0( sizeof(QTNode) ); + + node->valnode = in; + + if (in->type == OPR) { + node->child = (QTNode**)palloc0( sizeof(QTNode*) * 2 ); + node->child[0] = QT2QTN( in + 1, operand ); + node->sign = node->child[0]->sign; + if (in->val == (int4) '!') + node->nchild = 1; + else { + node->nchild = 2; + node->child[1] = QT2QTN( in + in->left, operand ); + node->sign |= node->child[1]->sign; + } + } else if ( operand ) { + node->word = operand + in->distance; + node->sign = 1 << ( in->val % 32 ); + } + + return node; +} + +void +QTNFree( QTNode* in ) { + if ( !in ) + return; + + if ( in->valnode->type == VAL && in->word && (in->flags & QTN_WORDFREE) !=0 ) + pfree( in->word ); + + if ( in->child ) { + if ( in->valnode ) { + if ( in->valnode->type == OPR && in->nchild > 0 ) { + int i; + for (i=0;i<in->nchild;i++) + QTNFree( in->child[i] ); + } + if ( in->flags & QTN_NEEDFREE ) + pfree( in->valnode ); + } + pfree( in->child ); + } + + pfree( in ); +} + +int +QTNodeCompare( QTNode *an, QTNode *bn ) { + if ( an->valnode->type != bn->valnode->type ) + return ( an->valnode->type > bn->valnode->type ) ? -1 : 1; + else if ( an->valnode->val != bn->valnode->val ) + return ( an->valnode->val > bn->valnode->val ) ? -1 : 1; + else if ( an->valnode->type == VAL ) { + if ( an->valnode->length == bn->valnode->length ) + return strncmp( an->word, bn->word, an->valnode->length ); + else + return ( an->valnode->length > bn->valnode->length ) ? -1 : 1; + } else if ( an->nchild != bn->nchild ) { + return ( an->nchild > bn->nchild ) ? -1 : 1; + } else { + int i,res; + + for( i=0; i<an->nchild; i++ ) + if ( (res=QTNodeCompare(an->child[i], bn->child[i]))!=0 ) + return res; + } + + return 0; +} + +static int +cmpQTN( const void *a, const void *b ) { + return QTNodeCompare( *(QTNode**)a, *(QTNode**)b ); +} + +void +QTNSort( QTNode* in ) { + int i; + + if ( in->valnode->type != OPR ) + return; + + for (i=0;i<in->nchild;i++) + QTNSort( in->child[i] ); + if ( in->nchild > 1 ) + qsort((void *) in->child, in->nchild, sizeof(QTNode*), cmpQTN); +} + +bool +QTNEq( QTNode* a, QTNode* b ) { + uint32 sign = a->sign & b->sign; + if ( !(sign == a->sign && sign == b->sign) ) + return 0; + + return ( QTNodeCompare(a,b) == 0 ) ? true : false; +} + +void +QTNTernary( QTNode* in ) { + int i; + + if ( in->valnode->type != OPR ) + return; + + for (i=0;i<in->nchild;i++) + QTNTernary( in->child[i] ); + + for (i=0;i<in->nchild;i++) { + if ( in->valnode->type == in->child[i]->valnode->type && in->valnode->val == in->child[i]->valnode->val ) { + QTNode* cc = in->child[i]; + int oldnchild = in->nchild; + + in->nchild += cc->nchild-1; + in->child = (QTNode**)repalloc( in->child, in->nchild * sizeof(QTNode*) ); + + if ( i+1 != oldnchild ) + memmove( in->child + i + cc->nchild, in->child + i + 1, + (oldnchild-i-1)*sizeof(QTNode*) ); + + memcpy( in->child + i, cc->child, cc->nchild * sizeof(QTNode*) ); + i += cc->nchild-1; + + pfree(cc); + } + } +} + +void +QTNBinary( QTNode* in ) { + int i; + + if ( in->valnode->type != OPR ) + return; + + for (i=0;i<in->nchild;i++) + QTNBinary( in->child[i] ); + + if ( in->nchild <= 2 ) + return; + + while( in->nchild > 2 ) { + QTNode *nn = (QTNode*)palloc0( sizeof(QTNode) ); + nn->valnode = (ITEM*)palloc0( sizeof(ITEM) ); + nn->child = (QTNode**)palloc0( sizeof(QTNode*) * 2 ); + + nn->nchild = 2; + nn->flags = QTN_NEEDFREE; + + nn->child[0] = in->child[0]; + nn->child[1] = in->child[1]; + nn->sign = nn->child[0]->sign | nn->child[1]->sign; + + nn->valnode->type = in->valnode->type; + nn->valnode->val = in->valnode->val; + + in->child[0] = nn; + in->child[1] = in->child[ in->nchild-1 ]; + in->nchild--; + } +} + +static void +cntsize(QTNode *in, int4 *sumlen, int4 *nnode) { + *nnode += 1; + if ( in->valnode->type == OPR ) { + int i; + for (i=0;i<in->nchild;i++) + cntsize(in->child[i], sumlen, nnode); + } else { + *sumlen += in->valnode->length+1; + } +} + +typedef struct { + ITEM *curitem; + char *operand; + char *curoperand; +} QTN2QTState; + +static void +fillQT( QTN2QTState *state, QTNode *in ) { + *(state->curitem) = *(in->valnode); + + if ( in->valnode->type == VAL ) { + memcpy( state->curoperand, in->word, in->valnode->length ); + state->curitem->distance = state->curoperand - state->operand; + state->curoperand[ in->valnode->length ] = '\0'; + state->curoperand += in->valnode->length + 1; + state->curitem++; + } else { + ITEM *curitem = state->curitem; + + Assert( in->nchild<=2 ); + state->curitem++; + + fillQT( state, in->child[0] ); + + if ( in->nchild==2 ) { + curitem->left = state->curitem - curitem; + fillQT( state, in->child[1] ); + } + } +} + +QUERYTYPE* +QTN2QT( QTNode* in, MemoryType memtype ) { + QUERYTYPE *out; + int len; + int sumlen=0, nnode=0; + QTN2QTState state; + + cntsize(in, &sumlen, &nnode); + len = COMPUTESIZE( nnode, sumlen ); + + out = (QUERYTYPE*)MEMALLOC(memtype, len); + out->len = len; + out->size = nnode; + + state.curitem = GETQUERY( out ); + state.operand = state.curoperand = GETOPERAND( out ); + + fillQT( &state, in ); + return out; +} + +QTNode * +QTNCopy( QTNode* in, MemoryType memtype ) { + QTNode *out = (QTNode*)MEMALLOC( memtype, sizeof(QTNode) ); + + *out = *in; + out->valnode = (ITEM*)MEMALLOC( memtype, sizeof(ITEM) ); + *(out->valnode) = *(in->valnode); + out->flags |= QTN_NEEDFREE; + + if ( in->valnode->type == VAL ) { + out->word = MEMALLOC( memtype, in->valnode->length + 1 ); + memcpy( out->word, in->word, in->valnode->length ); + out->word[ in->valnode->length ] = '\0'; + out->flags |= QTN_WORDFREE; + } else { + int i; + + out->child = (QTNode**)MEMALLOC( memtype, sizeof(QTNode*) * in->nchild ); + + for(i=0;i<in->nchild;i++) + out->child[i] = QTNCopy( in->child[i], memtype ); + } + + return out; +} |