mirror of
https://git.postgresql.org/git/postgresql.git
synced 2025-03-07 19:47:50 +08:00
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
258 lines
5.7 KiB
C
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;
|
|
}
|