postgresql/contrib/tsearch2/query_util.c
Teodor Sigaev 0645663e6c New features for tsearch2:
1 Comparison operation for tsquery
2 Btree index on tsquery
3 numnode(tsquery) - returns 'length' of tsquery
4 tsquery @ tsquery, tsquery ~ tsquery - contains, contained for tsquery.
  Note: They don't gurantee exact result, only MAY BE, so it
  useful only for speed up rewrite functions
5 GiST index support for @,~
6 rewrite():
        select rewrite(orig, what, to);
        select rewrite(ARRAY[orig, what, to]) from tsquery_table;
        select rewrite(orig, 'select what, to from tsquery_table;');
7 significantly improve cover algorithm
2005-11-08 17:08:46 +00:00

258 lines
5.7 KiB
C

#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;
}