/* * @@ selectivity for tsvector var vs tsquery constant */ static Selectivity tsquerysel(VariableStatData *vardata, Datum constval) { Selectivity selec; TSQuery query; /* The caller made sure the const is a TSQuery, so get it now */ query = DatumGetTSQuery(constval); /* Empty query matches nothing */ if (query->size == 0) return (Selectivity) 0.0; if (HeapTupleIsValid(vardata->statsTuple)) { Form_pg_statistic stats; Datum *values; int nvalues; float4 *numbers; int nnumbers; stats = (Form_pg_statistic) GETSTRUCT(vardata->statsTuple); /* MCELEM will be an array of TEXT elements for a tsvector column */ if (get_attstatsslot(vardata->statsTuple, TEXTOID, -1, STATISTIC_KIND_MCELEM, InvalidOid, NULL, &values, &nvalues, &numbers, &nnumbers)) { /* * There is a most-common-elements slot for the tsvector Var, so * use that. */ selec = mcelem_tsquery_selec(query, values, nvalues, numbers, nnumbers); free_attstatsslot(TEXTOID, values, nvalues, numbers, nnumbers); } else { /* No most-common-elements info, so do without */ selec = tsquery_opr_selec_no_stats(query); } /* * MCE stats count only non-null rows, so adjust for null rows. */ selec *= (1.0 - stats->stanullfrac); } else { /* No stats at all, so do without */ selec = tsquery_opr_selec_no_stats(query); /* we assume no nulls here, so no stanullfrac correction */ } return selec; }
/* * @@ selectivity for tsvector var vs tsquery constant */ static Selectivity tsquerysel(VariableStatData *vardata, Datum constval) { Selectivity selec; TSQuery query; /* The caller made sure the const is a TSQuery, so get it now */ query = DatumGetTSQuery(constval); /* Empty query matches nothing */ if (query->size == 0) return (Selectivity) 0.0; if (HeapTupleIsValid(vardata->statsTuple)) { Form_pg_statistic stats; Datum *values; int nvalues; float4 *numbers; int nnumbers; stats = (Form_pg_statistic) GETSTRUCT(vardata->statsTuple); /* MCELEM will be an array of TEXT elements for a tsvector column */ if (get_attstatsslot(vardata->statsTuple, TEXTOID, -1, STATISTIC_KIND_MCELEM, InvalidOid, &values, &nvalues, &numbers, &nnumbers)) { /* * There is a most-common-elements slot for the tsvector Var, so * use that. */ selec = mcelem_tsquery_selec(query, values, nvalues, numbers, nnumbers); free_attstatsslot(TEXTOID, values, nvalues, numbers, nnumbers); } else { /* No most-common-elements info, so we must punt */ selec = (Selectivity) DEFAULT_TS_MATCH_SEL; } } else { /* No stats at all, so we must punt */ selec = (Selectivity) DEFAULT_TS_MATCH_SEL; } return selec; }
Datum gtsquery_compress(PG_FUNCTION_ARGS) { GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); GISTENTRY *retval = entry; if (entry->leafkey) { TSQuerySign *sign = (TSQuerySign *) palloc(sizeof(TSQuerySign)); retval = (GISTENTRY *) palloc(sizeof(GISTENTRY)); *sign = makeTSQuerySign(DatumGetTSQuery(entry->key)); gistentryinit(*retval, PointerGetDatum(sign), entry->rel, entry->page, entry->offset, FALSE); } PG_RETURN_POINTER(retval); }
Datum ts_match_tt(PG_FUNCTION_ARGS) { TSVector vector; TSQuery query; bool res; vector = DatumGetTSVector(DirectFunctionCall1(to_tsvector, PG_GETARG_DATUM(0))); query = DatumGetTSQuery(DirectFunctionCall1(plainto_tsquery, PG_GETARG_DATUM(1))); res = DatumGetBool(DirectFunctionCall2(ts_match_vq, TSVectorGetDatum(vector), TSQueryGetDatum(query))); pfree(vector); pfree(query); PG_RETURN_BOOL(res); }
Datum tsa_rewrite_accum(PG_FUNCTION_ARGS) { TSQuery acc; ArrayType *qa; TSQuery q; QTNode *qex = NULL, *subs = NULL, *acctree = NULL; bool isfind = false; Datum *elemsp; int nelemsp; MemoryContext aggcontext; MemoryContext oldcontext; aggcontext = ((AggState *) fcinfo->context)->aggcontext; if (PG_ARGISNULL(0) || PG_GETARG_POINTER(0) == NULL) { acc = (TSQuery) MemoryContextAlloc(aggcontext, HDRSIZETQ); SET_VARSIZE(acc, HDRSIZETQ); acc->size = 0; } else acc = PG_GETARG_TSQUERY(0); if (PG_ARGISNULL(1) || PG_GETARG_POINTER(1) == NULL) PG_RETURN_TSQUERY(acc); else qa = PG_GETARG_ARRAYTYPE_P_COPY(1); if (ARR_NDIM(qa) != 1) elog(ERROR, "array must be one-dimensional, not %d dimensions", ARR_NDIM(qa)); if (ArrayGetNItems(ARR_NDIM(qa), ARR_DIMS(qa)) != 3) elog(ERROR, "array must have three elements"); if (ARR_ELEMTYPE(qa) != TSQUERYOID) elog(ERROR, "array must contain tsquery elements"); deconstruct_array(qa, TSQUERYOID, -1, false, 'i', &elemsp, NULL, &nelemsp); q = DatumGetTSQuery(elemsp[0]); if (q->size == 0) { pfree(elemsp); PG_RETURN_POINTER(acc); } if (!acc->size) { if (VARSIZE(acc) > HDRSIZETQ) { pfree(elemsp); PG_RETURN_POINTER(acc); } else acctree = QT2QTN(GETQUERY(q), GETOPERAND(q)); } else acctree = QT2QTN(GETQUERY(acc), GETOPERAND(acc)); QTNTernary(acctree); QTNSort(acctree); q = DatumGetTSQuery(elemsp[1]); if (q->size == 0) { pfree(elemsp); PG_RETURN_POINTER(acc); } qex = QT2QTN(GETQUERY(q), GETOPERAND(q)); QTNTernary(qex); QTNSort(qex); q = DatumGetTSQuery(elemsp[2]); if (q->size) subs = QT2QTN(GETQUERY(q), GETOPERAND(q)); acctree = findsubquery(acctree, qex, subs, &isfind); if (isfind || !acc->size) { /* pfree( acc ); do not pfree(p), because nodeAgg.c will */ if (acctree) { QTNBinary(acctree); oldcontext = MemoryContextSwitchTo(aggcontext); acc = QTN2QT(acctree); MemoryContextSwitchTo(oldcontext); } else { acc = (TSQuery) MemoryContextAlloc(aggcontext, HDRSIZETQ); SET_VARSIZE(acc, HDRSIZETQ); acc->size = 0; } } pfree(elemsp); QTNFree(qex); QTNFree(subs); QTNFree(acctree); PG_RETURN_TSQUERY(acc); }
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); }
datum_t tsa_rewrite_accum(PG_FUNC_ARGS) { TSQuery acc; array_s *qa; TSQuery q; QTNode *qex = NULL, *subs = NULL, *acctree = NULL; bool isfind = false; datum_t *elemsp; int nelemsp; struct mctx * aggcontext; struct mctx * oldcontext; if (!AggCheckCallContext(fcinfo, &aggcontext)) elog(ERROR, "tsa_rewrite_accum called in non-aggregate context"); if (PG_ARG_ISNULL(0) || ARG_POINTER(0) == NULL) { acc = (TSQuery) mctx_alloc(aggcontext, HDRSIZETQ); VLA_SET_SZ_STND(acc, HDRSIZETQ); acc->size = 0; } else acc = ARG_TSQUERY(0); if (PG_ARG_ISNULL(1) || ARG_POINTER(1) == NULL) RET_TSQUERY(acc); else qa = ARG_ARRAY_P_COPY(1); if (ARR_NDIM(qa) != 1) elog(ERROR, "array must be one-dimensional, not %d dimensions", ARR_NDIM(qa)); if (ArrayGetNItems(ARR_NDIM(qa), ARR_DIMS(qa)) != 3) elog(ERROR, "array must have three elements"); if (ARR_ELEMTYPE(qa) != TSQUERYOID) elog(ERROR, "array must contain tsquery elements"); deconstruct_array(qa, TSQUERYOID, -1, false, 'i', &elemsp, NULL, &nelemsp); q = DatumGetTSQuery(elemsp[0]); if (q->size == 0) { pfree(elemsp); RET_POINTER(acc); } if (!acc->size) { if (VLA_SZ(acc) > HDRSIZETQ) { pfree(elemsp); RET_POINTER(acc); } else acctree = QT2QTN(GETQUERY(q), GETOPERAND(q)); } else acctree = QT2QTN(GETQUERY(acc), GETOPERAND(acc)); QTNTernary(acctree); QTNSort(acctree); q = DatumGetTSQuery(elemsp[1]); if (q->size == 0) { pfree(elemsp); RET_POINTER(acc); } qex = QT2QTN(GETQUERY(q), GETOPERAND(q)); QTNTernary(qex); QTNSort(qex); q = DatumGetTSQuery(elemsp[2]); if (q->size) subs = QT2QTN(GETQUERY(q), GETOPERAND(q)); acctree = findsubquery(acctree, qex, subs, &isfind); if (isfind || !acc->size) { /* pfree( acc ); do not pfree(p), because nodeAgg.c will */ if (acctree) { QTNBinary(acctree); oldcontext = mctx_switch(aggcontext); acc = QTN2QT(acctree); mctx_switch(oldcontext); } else { acc = (TSQuery) mctx_alloc(aggcontext, HDRSIZETQ); VLA_SET_SZ_STND(acc, HDRSIZETQ); acc->size = 0; } } pfree(elemsp); QTNFree(qex); QTNFree(subs); QTNFree(acctree); RET_TSQUERY(acc); }