/*------------------------------------------------------------------------- * * tsquery_op.c * Various operations with tsquery * * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group * * * IDENTIFICATION * src/backend/utils/adt/tsquery_op.c * *------------------------------------------------------------------------- */ #include "postgres.h" #include "tsearch/ts_utils.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 * join_tsqueries(TSQuery a, TSQuery b, int8 operator) { 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 = operator; 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); } 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; 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; 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 ); \ } \ /* keep compiler quiet - no extra ; */ \ 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, *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); } 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) ) ); }