2007-08-21 03:11:32 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* tsquery_op.c
|
|
|
|
* Various operations with tsquery
|
|
|
|
*
|
2009-01-01 18:24:05 +01:00
|
|
|
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
|
2007-08-21 03:11:32 +02:00
|
|
|
*
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
2009-07-16 08:33:46 +02:00
|
|
|
* $PostgreSQL: pgsql/src/backend/utils/adt/tsquery_op.c,v 1.7 2009/07/16 06:33:44 petere Exp $
|
2007-08-21 03:11:32 +02:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "postgres.h"
|
|
|
|
|
|
|
|
#include "tsearch/ts_type.h"
|
|
|
|
#include "tsearch/ts_locale.h"
|
|
|
|
#include "tsearch/ts_utils.h"
|
|
|
|
#include "utils/pg_crc.h"
|
|
|
|
|
|
|
|
Datum
|
|
|
|
tsquery_numnode(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
TSQuery query = PG_GETARG_TSQUERY(0);
|
|
|
|
int nnode = query->size;
|
|
|
|
|
|
|
|
PG_FREE_IF_COPY(query, 0);
|
|
|
|
PG_RETURN_INT32(nnode);
|
|
|
|
}
|
|
|
|
|
|
|
|
static QTNode *
|
2007-09-07 17:09:56 +02:00
|
|
|
join_tsqueries(TSQuery a, TSQuery b, int8 operator)
|
2007-08-21 03:11:32 +02:00
|
|
|
{
|
|
|
|
QTNode *res = (QTNode *) palloc0(sizeof(QTNode));
|
|
|
|
|
|
|
|
res->flags |= QTN_NEEDFREE;
|
|
|
|
|
|
|
|
res->valnode = (QueryItem *) palloc0(sizeof(QueryItem));
|
2007-09-07 17:09:56 +02:00
|
|
|
res->valnode->type = QI_OPR;
|
2009-07-16 08:33:46 +02:00
|
|
|
res->valnode->qoperator.oper = operator;
|
2007-08-21 03:11:32 +02:00
|
|
|
|
|
|
|
res->child = (QTNode **) palloc0(sizeof(QTNode *) * 2);
|
|
|
|
res->child[0] = QT2QTN(GETQUERY(b), GETOPERAND(b));
|
|
|
|
res->child[1] = QT2QTN(GETQUERY(a), GETOPERAND(a));
|
|
|
|
res->nchild = 2;
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
tsquery_and(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
TSQuery a = PG_GETARG_TSQUERY_COPY(0);
|
|
|
|
TSQuery b = PG_GETARG_TSQUERY_COPY(1);
|
|
|
|
QTNode *res;
|
|
|
|
TSQuery query;
|
|
|
|
|
|
|
|
if (a->size == 0)
|
|
|
|
{
|
|
|
|
PG_FREE_IF_COPY(a, 1);
|
|
|
|
PG_RETURN_POINTER(b);
|
|
|
|
}
|
|
|
|
else if (b->size == 0)
|
|
|
|
{
|
|
|
|
PG_FREE_IF_COPY(b, 1);
|
|
|
|
PG_RETURN_POINTER(a);
|
|
|
|
}
|
|
|
|
|
2007-09-07 17:09:56 +02:00
|
|
|
res = join_tsqueries(a, b, OP_AND);
|
2007-08-21 03:11:32 +02:00
|
|
|
|
|
|
|
query = QTN2QT(res);
|
|
|
|
|
|
|
|
QTNFree(res);
|
|
|
|
PG_FREE_IF_COPY(a, 0);
|
|
|
|
PG_FREE_IF_COPY(b, 1);
|
|
|
|
|
|
|
|
PG_RETURN_TSQUERY(query);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
tsquery_or(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
TSQuery a = PG_GETARG_TSQUERY_COPY(0);
|
|
|
|
TSQuery b = PG_GETARG_TSQUERY_COPY(1);
|
|
|
|
QTNode *res;
|
|
|
|
TSQuery query;
|
|
|
|
|
|
|
|
if (a->size == 0)
|
|
|
|
{
|
|
|
|
PG_FREE_IF_COPY(a, 1);
|
|
|
|
PG_RETURN_POINTER(b);
|
|
|
|
}
|
|
|
|
else if (b->size == 0)
|
|
|
|
{
|
|
|
|
PG_FREE_IF_COPY(b, 1);
|
|
|
|
PG_RETURN_POINTER(a);
|
|
|
|
}
|
|
|
|
|
2007-09-07 17:09:56 +02:00
|
|
|
res = join_tsqueries(a, b, OP_OR);
|
2007-08-21 03:11:32 +02:00
|
|
|
|
|
|
|
query = QTN2QT(res);
|
|
|
|
|
|
|
|
QTNFree(res);
|
|
|
|
PG_FREE_IF_COPY(a, 0);
|
|
|
|
PG_FREE_IF_COPY(b, 1);
|
|
|
|
|
|
|
|
PG_RETURN_POINTER(query);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
tsquery_not(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
TSQuery a = PG_GETARG_TSQUERY_COPY(0);
|
|
|
|
QTNode *res;
|
|
|
|
TSQuery query;
|
|
|
|
|
|
|
|
if (a->size == 0)
|
|
|
|
PG_RETURN_POINTER(a);
|
|
|
|
|
|
|
|
res = (QTNode *) palloc0(sizeof(QTNode));
|
|
|
|
|
|
|
|
res->flags |= QTN_NEEDFREE;
|
|
|
|
|
|
|
|
res->valnode = (QueryItem *) palloc0(sizeof(QueryItem));
|
2007-09-07 17:09:56 +02:00
|
|
|
res->valnode->type = QI_OPR;
|
2009-07-16 08:33:46 +02:00
|
|
|
res->valnode->qoperator.oper = OP_NOT;
|
2007-08-21 03:11:32 +02:00
|
|
|
|
|
|
|
res->child = (QTNode **) palloc0(sizeof(QTNode *));
|
|
|
|
res->child[0] = QT2QTN(GETQUERY(a), GETOPERAND(a));
|
|
|
|
res->nchild = 1;
|
|
|
|
|
|
|
|
query = QTN2QT(res);
|
|
|
|
|
|
|
|
QTNFree(res);
|
|
|
|
PG_FREE_IF_COPY(a, 0);
|
|
|
|
|
|
|
|
PG_RETURN_POINTER(query);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
CompareTSQ(TSQuery a, TSQuery b)
|
|
|
|
{
|
|
|
|
if (a->size != b->size)
|
|
|
|
{
|
|
|
|
return (a->size < b->size) ? -1 : 1;
|
|
|
|
}
|
|
|
|
else if (VARSIZE(a) != VARSIZE(b))
|
|
|
|
{
|
|
|
|
return (VARSIZE(a) < VARSIZE(b)) ? -1 : 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
QTNode *an = QT2QTN(GETQUERY(a), GETOPERAND(a));
|
|
|
|
QTNode *bn = QT2QTN(GETQUERY(b), GETOPERAND(b));
|
|
|
|
int res = QTNodeCompare(an, bn);
|
|
|
|
|
|
|
|
QTNFree(an);
|
|
|
|
QTNFree(bn);
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
tsquery_cmp(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
TSQuery a = PG_GETARG_TSQUERY_COPY(0);
|
|
|
|
TSQuery b = PG_GETARG_TSQUERY_COPY(1);
|
|
|
|
int res = CompareTSQ(a, b);
|
|
|
|
|
|
|
|
PG_FREE_IF_COPY(a, 0);
|
|
|
|
PG_FREE_IF_COPY(b, 1);
|
|
|
|
|
|
|
|
PG_RETURN_INT32(res);
|
|
|
|
}
|
|
|
|
|
|
|
|
#define CMPFUNC( NAME, CONDITION ) \
|
|
|
|
Datum \
|
|
|
|
NAME(PG_FUNCTION_ARGS) { \
|
|
|
|
TSQuery a = PG_GETARG_TSQUERY_COPY(0); \
|
|
|
|
TSQuery b = PG_GETARG_TSQUERY_COPY(1); \
|
|
|
|
int res = CompareTSQ(a,b); \
|
|
|
|
\
|
|
|
|
PG_FREE_IF_COPY(a,0); \
|
|
|
|
PG_FREE_IF_COPY(b,1); \
|
|
|
|
\
|
|
|
|
PG_RETURN_BOOL( CONDITION ); \
|
2009-06-11 16:49:15 +02:00
|
|
|
} \
|
2009-05-27 21:41:58 +02:00
|
|
|
/* keep compiler quiet - no extra ; */ \
|
|
|
|
extern int no_such_variable
|
2007-08-21 03:11:32 +02:00
|
|
|
|
|
|
|
CMPFUNC(tsquery_lt, res < 0);
|
|
|
|
CMPFUNC(tsquery_le, res <= 0);
|
|
|
|
CMPFUNC(tsquery_eq, res == 0);
|
|
|
|
CMPFUNC(tsquery_ge, res >= 0);
|
|
|
|
CMPFUNC(tsquery_gt, res > 0);
|
|
|
|
CMPFUNC(tsquery_ne, res != 0);
|
|
|
|
|
|
|
|
TSQuerySign
|
|
|
|
makeTSQuerySign(TSQuery a)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
QueryItem *ptr = GETQUERY(a);
|
|
|
|
TSQuerySign sign = 0;
|
|
|
|
|
|
|
|
for (i = 0; i < a->size; i++)
|
|
|
|
{
|
2007-09-07 17:09:56 +02:00
|
|
|
if (ptr->type == QI_VAL)
|
2009-07-16 08:33:46 +02:00
|
|
|
sign |= ((TSQuerySign) 1) << (ptr->qoperand.valcrc % TSQS_SIGLEN);
|
2007-08-21 03:11:32 +02:00
|
|
|
ptr++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return sign;
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
tsq_mcontains(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
TSQuery query = PG_GETARG_TSQUERY(0);
|
|
|
|
TSQuery ex = PG_GETARG_TSQUERY(1);
|
|
|
|
TSQuerySign sq,
|
|
|
|
se;
|
|
|
|
int i,
|
|
|
|
j;
|
|
|
|
QueryItem *iq,
|
|
|
|
*ie;
|
|
|
|
|
|
|
|
if (query->size < ex->size)
|
|
|
|
{
|
|
|
|
PG_FREE_IF_COPY(query, 0);
|
|
|
|
PG_FREE_IF_COPY(ex, 1);
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
sq = makeTSQuerySign(query);
|
|
|
|
se = makeTSQuerySign(ex);
|
|
|
|
|
|
|
|
if ((sq & se) != se)
|
|
|
|
{
|
|
|
|
PG_FREE_IF_COPY(query, 0);
|
|
|
|
PG_FREE_IF_COPY(ex, 1);
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
ie = GETQUERY(ex);
|
|
|
|
|
|
|
|
for (i = 0; i < ex->size; i++)
|
|
|
|
{
|
|
|
|
iq = GETQUERY(query);
|
2007-09-07 17:09:56 +02:00
|
|
|
if (ie[i].type != QI_VAL)
|
2007-08-21 03:11:32 +02:00
|
|
|
continue;
|
|
|
|
for (j = 0; j < query->size; j++)
|
2009-07-16 08:33:46 +02:00
|
|
|
if (iq[j].type == QI_VAL && ie[i].qoperand.valcrc == iq[j].qoperand.valcrc)
|
2007-08-21 03:11:32 +02:00
|
|
|
{
|
|
|
|
j = query->size + 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (j == query->size)
|
|
|
|
{
|
|
|
|
PG_FREE_IF_COPY(query, 0);
|
|
|
|
PG_FREE_IF_COPY(ex, 1);
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
PG_FREE_IF_COPY(query, 0);
|
|
|
|
PG_FREE_IF_COPY(ex, 1);
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
tsq_mcontained(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
PG_RETURN_DATUM(
|
|
|
|
DirectFunctionCall2(
|
|
|
|
tsq_mcontains,
|
|
|
|
PG_GETARG_DATUM(1),
|
|
|
|
PG_GETARG_DATUM(0)
|
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|