diff options
Diffstat (limited to 'contrib/tsearch2/tsvector_op.c')
| -rw-r--r-- | contrib/tsearch2/tsvector_op.c | 264 |
1 files changed, 264 insertions, 0 deletions
diff --git a/contrib/tsearch2/tsvector_op.c b/contrib/tsearch2/tsvector_op.c new file mode 100644 index 0000000000..3f38014813 --- /dev/null +++ b/contrib/tsearch2/tsvector_op.c @@ -0,0 +1,264 @@ +/* + * Operations for tsvector type + * Teodor Sigaev <teodor@sigaev.ru> + */ +#include "postgres.h" + +#include "access/gist.h" +#include "access/itup.h" +#include "utils/elog.h" +#include "utils/palloc.h" +#include "utils/builtins.h" +#include "storage/bufpage.h" +#include "executor/spi.h" +#include "commands/trigger.h" +#include "nodes/pg_list.h" +#include "catalog/namespace.h" + +#include "utils/pg_locale.h" + +#include <ctype.h> /* tolower */ +#include "tsvector.h" +#include "query.h" +#include "ts_cfg.h" +#include "common.h" + +PG_FUNCTION_INFO_V1(strip); +Datum strip(PG_FUNCTION_ARGS); + +PG_FUNCTION_INFO_V1(setweight); +Datum setweight(PG_FUNCTION_ARGS); + +PG_FUNCTION_INFO_V1(concat); +Datum concat(PG_FUNCTION_ARGS); + +Datum +strip(PG_FUNCTION_ARGS) +{ + tsvector *in = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); + tsvector *out; + int i,len=0; + WordEntry *arrin=ARRPTR(in), *arrout; + char *cur; + + for(i=0;i<in->size;i++) + len += SHORTALIGN( arrin[i].len ); + + len = CALCDATASIZE(in->size, len); + out=(tsvector*)palloc(len); + memset(out,0,len); + out->len=len; + out->size=in->size; + arrout=ARRPTR(out); + cur=STRPTR(out); + for(i=0;i<in->size;i++) { + memcpy(cur, STRPTR(in)+arrin[i].pos, arrin[i].len); + arrout[i].haspos = 0; + arrout[i].len = arrin[i].len; + arrout[i].pos = cur - STRPTR(out); + cur += SHORTALIGN( arrout[i].len ); + } + + PG_FREE_IF_COPY(in, 0); + PG_RETURN_POINTER(out); +} + +Datum +setweight(PG_FUNCTION_ARGS) +{ + tsvector *in = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); + char cw = PG_GETARG_CHAR(1); + tsvector *out; + int i,j; + WordEntry *entry; + WordEntryPos *p; + int w=0; + + switch(tolower(cw)) { + case 'a': w=3; break; + case 'b': w=2; break; + case 'c': w=1; break; + case 'd': w=0; break; + default: elog(ERROR,"Unknown weight"); + } + + out=(tsvector*)palloc(in->len); + memcpy(out,in,in->len); + entry=ARRPTR(out); + i=out->size; + while(i--) { + if ( (j=POSDATALEN(out,entry)) != 0 ) { + p=POSDATAPTR(out,entry); + while(j--) { + p->weight=w; + p++; + } + } + entry++; + } + + PG_FREE_IF_COPY(in, 0); + PG_RETURN_POINTER(out); +} + +static int +compareEntry(char *ptra, WordEntry* a, char *ptrb, WordEntry* b) +{ + if ( a->len == b->len) + { + return strncmp( + ptra + a->pos, + ptrb + b->pos, + a->len); + } + return ( a->len > b->len ) ? 1 : -1; +} + +static int4 +add_pos(tsvector *src, WordEntry *srcptr, tsvector *dest, WordEntry *destptr, int4 maxpos ) { + uint16 *clen = (uint16*)_POSDATAPTR(dest,destptr); + int i; + uint16 slen = POSDATALEN(src, srcptr), startlen; + WordEntryPos *spos=POSDATAPTR(src, srcptr), *dpos=POSDATAPTR(dest,destptr); + + if ( ! destptr->haspos ) + *clen=0; + + startlen = *clen; + for(i=0; i<slen && *clen<MAXNUMPOS && ( *clen==0 || dpos[ *clen-1 ].pos != MAXENTRYPOS-1 ) ;i++) { + dpos[ *clen ].weight = spos[i].weight; + dpos[ *clen ].pos = LIMITPOS(spos[i].pos + maxpos); + (*clen)++; + } + + if ( *clen != startlen ) + destptr->haspos=1; + return *clen - startlen; +} + + +Datum +concat(PG_FUNCTION_ARGS) { + tsvector *in1 = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); + tsvector *in2 = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); + tsvector *out; + WordEntry *ptr; + WordEntry *ptr1,*ptr2; + WordEntryPos *p; + int maxpos=0,i,j,i1,i2; + char *cur; + char *data,*data1,*data2; + + ptr=ARRPTR(in1); + i=in1->size; + while(i--) { + if ( (j=POSDATALEN(in1,ptr)) != 0 ) { + p=POSDATAPTR(in1,ptr); + while(j--) { + if ( p->pos > maxpos ) + maxpos = p->pos; + p++; + } + } + ptr++; + } + + ptr1=ARRPTR(in1); ptr2=ARRPTR(in2); + data1=STRPTR(in1); data2=STRPTR(in2); + i1=in1->size; i2=in2->size; + out=(tsvector*)palloc( in1->len + in2->len ); + memset(out,0,in1->len + in2->len); + out->len = in1->len + in2->len; + out->size = in1->size + in2->size; + data=cur=STRPTR(out); + ptr=ARRPTR(out); + while( i1 && i2 ) { + int cmp=compareEntry(data1,ptr1,data2,ptr2); + if ( cmp < 0 ) { /* in1 first */ + ptr->haspos = ptr1->haspos; + ptr->len = ptr1->len; + memcpy( cur, data1 + ptr1->pos, ptr1->len ); + ptr->pos = cur - data; + cur+=SHORTALIGN(ptr1->len); + if ( ptr->haspos ) { + memcpy(cur, _POSDATAPTR(in1, ptr1), POSDATALEN(in1, ptr1)*sizeof(WordEntryPos) + sizeof(uint16)); + cur+=POSDATALEN(in1, ptr1)*sizeof(WordEntryPos) + sizeof(uint16); + } + ptr++; ptr1++; i1--; + } else if ( cmp>0 ) { /* in2 first */ + ptr->haspos = ptr2->haspos; + ptr->len = ptr2->len; + memcpy( cur, data2 + ptr2->pos, ptr2->len ); + ptr->pos = cur - data; + cur+=SHORTALIGN(ptr2->len); + if ( ptr->haspos ) { + int addlen = add_pos(in2, ptr2, out, ptr, maxpos ); + if ( addlen == 0 ) + ptr->haspos=0; + else + cur += addlen*sizeof(WordEntryPos) + sizeof(uint16); + } + ptr++; ptr2++; i2--; + } else { + ptr->haspos = ptr1->haspos | ptr2->haspos; + ptr->len = ptr1->len; + memcpy( cur, data1 + ptr1->pos, ptr1->len ); + ptr->pos = cur - data; + cur+=SHORTALIGN(ptr1->len); + if ( ptr->haspos ) { + if ( ptr1->haspos ) { + memcpy(cur, _POSDATAPTR(in1, ptr1), POSDATALEN(in1, ptr1)*sizeof(WordEntryPos) + sizeof(uint16)); + cur+=POSDATALEN(in1, ptr1)*sizeof(WordEntryPos) + sizeof(uint16); + if ( ptr2->haspos ) + cur += add_pos(in2, ptr2, out, ptr, maxpos )*sizeof(WordEntryPos); + } else if ( ptr2->haspos ) { + int addlen = add_pos(in2, ptr2, out, ptr, maxpos ); + if ( addlen == 0 ) + ptr->haspos=0; + else + cur += addlen*sizeof(WordEntryPos) + sizeof(uint16); + } + } + ptr++; ptr1++; ptr2++; i1--; i2--; + } + } + + while(i1) { + ptr->haspos = ptr1->haspos; + ptr->len = ptr1->len; + memcpy( cur, data1 + ptr1->pos, ptr1->len ); + ptr->pos = cur - data; + cur+=SHORTALIGN(ptr1->len); + if ( ptr->haspos ) { + memcpy(cur, _POSDATAPTR(in1, ptr1), POSDATALEN(in1, ptr1)*sizeof(WordEntryPos) + sizeof(uint16)); + cur+=POSDATALEN(in1, ptr1)*sizeof(WordEntryPos) + sizeof(uint16); + } + ptr++; ptr1++; i1--; + } + + while(i2) { + ptr->haspos = ptr2->haspos; + ptr->len = ptr2->len; + memcpy( cur, data2 + ptr2->pos, ptr2->len ); + ptr->pos = cur - data; + cur+=SHORTALIGN(ptr2->len); + if ( ptr->haspos ) { + int addlen = add_pos(in2, ptr2, out, ptr, maxpos ); + if ( addlen == 0 ) + ptr->haspos=0; + else + cur += addlen*sizeof(WordEntryPos) + sizeof(uint16); + } + ptr++; ptr2++; i2--; + } + + out->size=ptr-ARRPTR(out); + out->len = CALCDATASIZE( out->size, cur-data ); + if ( data != STRPTR(out) ) + memmove( STRPTR(out), data, cur-data ); + + PG_FREE_IF_COPY(in1, 0); + PG_FREE_IF_COPY(in2, 1); + PG_RETURN_POINTER(out); +} + |
