#include "postgres.h" #include "fmgr.h" #include "query_util.h" PG_FUNCTION_INFO_V1(tsquery_numnode); Datum tsquery_numnode(PG_FUNCTION_ARGS); Datum tsquery_numnode(PG_FUNCTION_ARGS) { QUERYTYPE *query = (QUERYTYPE *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0))); int nnode = query->size; PG_FREE_IF_COPY(query,0); PG_RETURN_INT32(nnode); } static QTNode* join_tsqueries(QUERYTYPE *a, QUERYTYPE *b) { QTNode *res=(QTNode*)palloc0( sizeof(QTNode) ); res->flags |= QTN_NEEDFREE; res->valnode = (ITEM*)palloc0( sizeof(ITEM) ); res->valnode->type = OPR; 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; } PG_FUNCTION_INFO_V1(tsquery_and); Datum tsquery_and(PG_FUNCTION_ARGS); Datum tsquery_and(PG_FUNCTION_ARGS) { QUERYTYPE *a = (QUERYTYPE *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0))); QUERYTYPE *b = (QUERYTYPE *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(1))); QTNode *res; QUERYTYPE *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); res->valnode->val = '&'; query = QTN2QT( res, PlainMemory ); QTNFree(res); PG_FREE_IF_COPY(a,0); PG_FREE_IF_COPY(b,1); PG_RETURN_POINTER(query); } PG_FUNCTION_INFO_V1(tsquery_or); Datum tsquery_or(PG_FUNCTION_ARGS); Datum tsquery_or(PG_FUNCTION_ARGS) { QUERYTYPE *a = (QUERYTYPE *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0))); QUERYTYPE *b = (QUERYTYPE *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(1))); QTNode *res; QUERYTYPE *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); res->valnode->val = '|'; query = QTN2QT( res, PlainMemory ); QTNFree(res); PG_FREE_IF_COPY(a,0); PG_FREE_IF_COPY(b,1); PG_RETURN_POINTER(query); } PG_FUNCTION_INFO_V1(tsquery_not); Datum tsquery_not(PG_FUNCTION_ARGS); Datum tsquery_not(PG_FUNCTION_ARGS) { QUERYTYPE *a = (QUERYTYPE *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0))); QTNode *res; QUERYTYPE *query; if ( a->size == 0 ) PG_RETURN_POINTER(a); res=(QTNode*)palloc0( sizeof(QTNode) ); res->flags |= QTN_NEEDFREE; res->valnode = (ITEM*)palloc0( sizeof(ITEM) ); res->valnode->type = OPR; res->valnode->val = '!'; res->child = (QTNode**)palloc0( sizeof(QTNode*) ); res->child[0] = QT2QTN( GETQUERY(a), GETOPERAND(a) ); res->nchild = 1; query = QTN2QT( res, PlainMemory ); QTNFree(res); PG_FREE_IF_COPY(a,0); PG_RETURN_POINTER(query); } static int CompareTSQ( QUERYTYPE *a, QUERYTYPE *b ) { if ( a->size != b->size ) { return ( a->size < b->size ) ? -1 : 1; } else if ( a->len != b->len ) { return ( a->len < b->len ) ? -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; } PG_FUNCTION_INFO_V1(tsquery_cmp); \ Datum tsquery_cmp(PG_FUNCTION_ARGS); Datum tsquery_cmp(PG_FUNCTION_ARGS) { QUERYTYPE *a = (QUERYTYPE *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0))); QUERYTYPE *b = (QUERYTYPE *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(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, ACTION ) \ PG_FUNCTION_INFO_V1(NAME); \ Datum NAME(PG_FUNCTION_ARGS); \ \ Datum \ NAME(PG_FUNCTION_ARGS) { \ QUERYTYPE *a = (QUERYTYPE *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0))); \ QUERYTYPE *b = (QUERYTYPE *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(1))); \ int res = CompareTSQ(a,b); \ \ PG_FREE_IF_COPY(a,0); \ PG_FREE_IF_COPY(b,1); \ \ PG_RETURN_BOOL( ACTION ); \ } 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 );