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, 0); query = QTN2QT(res); QTNFree(res); PG_FREE_IF_COPY(a, 0); PG_FREE_IF_COPY(b, 1); PG_RETURN_TSQUERY(query); }
Datum tsquery_phrase_distance(PG_FUNCTION_ARGS) { TSQuery a = PG_GETARG_TSQUERY_COPY(0); TSQuery b = PG_GETARG_TSQUERY_COPY(1); QTNode *res; TSQuery query; int32 distance = PG_GETARG_INT32(2); if (distance < 0 || distance > MAXENTRYPOS) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("distance in phrase operator should be non-negative and less than %d", MAXENTRYPOS))); 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_PHRASE, (uint16) distance); query = QTN2QT(res); QTNFree(res); PG_FREE_IF_COPY(a, 0); PG_FREE_IF_COPY(b, 1); PG_RETURN_TSQUERY(query); }
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); }
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); }
Datum tsquery_rewrite(PG_FUNCTION_ARGS) { TSQuery query = PG_GETARG_TSQUERY_COPY(0); TSQuery ex = PG_GETARG_TSQUERY(1); TSQuery subst = PG_GETARG_TSQUERY(2); TSQuery rewrited = query; QTNode *tree, *qex, *subs = NULL; if (query->size == 0 || ex->size == 0) { PG_FREE_IF_COPY(ex, 1); PG_FREE_IF_COPY(subst, 2); PG_RETURN_POINTER(rewrited); } tree = QT2QTN(GETQUERY(query), GETOPERAND(query)); QTNTernary(tree); QTNSort(tree); qex = QT2QTN(GETQUERY(ex), GETOPERAND(ex)); QTNTernary(qex); QTNSort(qex); if (subst->size) subs = QT2QTN(GETQUERY(subst), GETOPERAND(subst)); tree = findsubquery(tree, qex, subs, NULL); QTNFree(qex); QTNFree(subs); if (!tree) { SET_VARSIZE(rewrited, HDRSIZETQ); rewrited->size = 0; PG_FREE_IF_COPY(ex, 1); PG_FREE_IF_COPY(subst, 2); PG_RETURN_POINTER(rewrited); } else { QTNBinary(tree); rewrited = QTN2QT(tree); QTNFree(tree); } PG_FREE_IF_COPY(query, 0); PG_FREE_IF_COPY(ex, 1); PG_FREE_IF_COPY(subst, 2); PG_RETURN_POINTER(rewrited); }
Datum tsquery_rewrite_query(PG_FUNCTION_ARGS) { TSQuery query = PG_GETARG_TSQUERY_COPY(0); text *in = PG_GETARG_TEXT_P(1); TSQuery rewrited = query; MemoryContext outercontext = CurrentMemoryContext; MemoryContext oldcontext; QTNode *tree; char *buf; SPIPlanPtr plan; Portal portal; bool isnull; if (query->size == 0) { PG_FREE_IF_COPY(in, 1); PG_RETURN_POINTER(rewrited); } tree = QT2QTN(GETQUERY(query), GETOPERAND(query)); QTNTernary(tree); QTNSort(tree); buf = text_to_cstring(in); SPI_connect(); if ((plan = SPI_prepare(buf, 0, NULL)) == NULL) elog(ERROR, "SPI_prepare(\"%s\") failed", buf); if ((portal = SPI_cursor_open(NULL, plan, NULL, NULL, true)) == NULL) elog(ERROR, "SPI_cursor_open(\"%s\") failed", buf); SPI_cursor_fetch(portal, true, 100); if (SPI_tuptable == NULL || SPI_tuptable->tupdesc->natts != 2 || SPI_gettypeid(SPI_tuptable->tupdesc, 1) != TSQUERYOID || SPI_gettypeid(SPI_tuptable->tupdesc, 2) != TSQUERYOID) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("ts_rewrite query must return two tsquery columns"))); while (SPI_processed > 0 && tree) { uint64 i; for (i = 0; i < SPI_processed && tree; i++) { Datum qdata = SPI_getbinval(SPI_tuptable->vals[i], SPI_tuptable->tupdesc, 1, &isnull); Datum sdata; if (isnull) continue; sdata = SPI_getbinval(SPI_tuptable->vals[i], SPI_tuptable->tupdesc, 2, &isnull); if (!isnull) { TSQuery qtex = DatumGetTSQuery(qdata); TSQuery qtsubs = DatumGetTSQuery(sdata); QTNode *qex, *qsubs = NULL; if (qtex->size == 0) { if (qtex != (TSQuery) DatumGetPointer(qdata)) pfree(qtex); if (qtsubs != (TSQuery) DatumGetPointer(sdata)) pfree(qtsubs); continue; } qex = QT2QTN(GETQUERY(qtex), GETOPERAND(qtex)); QTNTernary(qex); QTNSort(qex); if (qtsubs->size) qsubs = QT2QTN(GETQUERY(qtsubs), GETOPERAND(qtsubs)); oldcontext = MemoryContextSwitchTo(outercontext); tree = findsubquery(tree, qex, qsubs, NULL); MemoryContextSwitchTo(oldcontext); QTNFree(qex); if (qtex != (TSQuery) DatumGetPointer(qdata)) pfree(qtex); QTNFree(qsubs); if (qtsubs != (TSQuery) DatumGetPointer(sdata)) pfree(qtsubs); if (tree) { /* ready the tree for another pass */ QTNClearFlags(tree, QTN_NOCHANGE); QTNSort(tree); } } } SPI_freetuptable(SPI_tuptable); SPI_cursor_fetch(portal, true, 100); } SPI_freetuptable(SPI_tuptable); SPI_cursor_close(portal); SPI_freeplan(plan); SPI_finish(); if (tree) { QTNBinary(tree); rewrited = QTN2QT(tree); QTNFree(tree); PG_FREE_IF_COPY(query, 0); } else { SET_VARSIZE(rewrited, HDRSIZETQ); rewrited->size = 0; } pfree(buf); PG_FREE_IF_COPY(in, 1); PG_RETURN_POINTER(rewrited); }