*
* tsquery_op.c
* Various operations with tsquery
*
* Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
*
*
* IDENTIFICATION
* src/backend/utils/adt/tsquery_op.c
*
* -------------------------------------------------------------------------
*/
#include "postgres.h"
#include "knl/knl_variable.h"
#include "tsearch/ts_utils.h"
Datum tsquery_numnode(PG_FUNCTION_ARGS)
{
ts_check_feature_disable();
TSQuery query = PG_GETARG_TSQUERY(0);
int nnode = query->size;
PG_FREE_IF_COPY(query, 0);
PG_RETURN_INT32(nnode);
}
static QTNode* join_tsqueries(TSQuery a, TSQuery b, int8 opera)
{
QTNode* res = (QTNode*)palloc0(sizeof(QTNode));
res->flags |= QTN_NEEDFREE;
res->valnode = (QueryItem*)palloc0(sizeof(QueryItem));
res->valnode->type = QI_OPR;
res->valnode->qoperator.oper = opera;
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 = NULL;
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);
}
res = join_tsqueries(a, b, OP_AND);
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 = NULL;
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);
}
res = join_tsqueries(a, b, OP_OR);
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 = NULL;
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));
res->valnode->type = QI_OPR;
res->valnode->qoperator.oper = OP_NOT;
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 if (a->size != 0) {
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); \
} \
\
extern int no_such_variable
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++) {
if (ptr->type == QI_VAL)
sign |= ((TSQuerySign)1) << (((unsigned int)ptr->qoperand.valcrc) % TSQS_SIGLEN);
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 = NULL;
QueryItem* ie = NULL;
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);
}
iq = GETQUERY(query);
ie = GETQUERY(ex);
for (i = 0; i < ex->size; i++) {
if (ie[i].type != QI_VAL)
continue;
for (j = 0; j < query->size; j++) {
if (iq[j].type == QI_VAL && ie[i].qoperand.valcrc == iq[j].qoperand.valcrc)
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)));
}