PostgreSQL Source Code git master
Loading...
Searching...
No Matches
ts_selfuncs.c File Reference
#include "postgres.h"
#include "access/htup_details.h"
#include "catalog/pg_statistic.h"
#include "catalog/pg_type.h"
#include "miscadmin.h"
#include "nodes/nodes.h"
#include "tsearch/ts_type.h"
#include "utils/fmgrprotos.h"
#include "utils/lsyscache.h"
#include "utils/selfuncs.h"
Include dependency graph for ts_selfuncs.c:

Go to the source code of this file.

Data Structures

struct  TextFreq
 
struct  LexemeKey
 

Macros

#define DEFAULT_TS_MATCH_SEL   0.005
 
#define tsquery_opr_selec_no_stats(query)    tsquery_opr_selec(GETQUERY(query), GETOPERAND(query), NULL, 0, 0)
 

Functions

static Selectivity tsquerysel (VariableStatData *vardata, Datum constval)
 
static Selectivity mcelem_tsquery_selec (TSQuery query, const Datum *mcelem, int nmcelem, const float4 *numbers, int nnumbers)
 
static Selectivity tsquery_opr_selec (QueryItem *item, char *operand, TextFreq *lookup, int length, float4 minfreq)
 
static int compare_lexeme_textfreq (const void *e1, const void *e2)
 
Datum tsmatchsel (PG_FUNCTION_ARGS)
 
Datum tsmatchjoinsel (PG_FUNCTION_ARGS)
 

Macro Definition Documentation

◆ DEFAULT_TS_MATCH_SEL

#define DEFAULT_TS_MATCH_SEL   0.005

Definition at line 32 of file ts_selfuncs.c.

◆ tsquery_opr_selec_no_stats

#define tsquery_opr_selec_no_stats (   query)     tsquery_opr_selec(GETQUERY(query), GETOPERAND(query), NULL, 0, 0)

Definition at line 56 of file ts_selfuncs.c.

67{
69
70#ifdef NOT_USED
71 Oid operator = PG_GETARG_OID(1);
72#endif
74 int varRelid = PG_GETARG_INT32(3);
76 Node *other;
77 bool varonleft;
79
80 /*
81 * If expression is not variable = something or something = variable, then
82 * punt and return a default estimate.
83 */
84 if (!get_restriction_variable(root, args, varRelid,
87
88 /*
89 * Can't do anything useful if the something is not a constant, either.
90 */
91 if (!IsA(other, Const))
92 {
95 }
96
97 /*
98 * The "@@" operator is strict, so we can cope with NULL right away
99 */
100 if (((Const *) other)->constisnull)
101 {
103 PG_RETURN_FLOAT8(0.0);
104 }
105
106 /*
107 * OK, there's a Var and a Const we're dealing with here. We need the
108 * Const to be a TSQuery, else we can't do anything useful. We have to
109 * check this because the Var might be the TSQuery not the TSVector.
110 */
111 if (((Const *) other)->consttype == TSQUERYOID)
112 {
113 /* tsvector @@ tsquery or the other way around */
114 Assert(vardata.vartype == TSVECTOROID);
115
117 }
118 else
119 {
120 /* If we can't see the query structure, must punt */
122 }
123
125
127
129}
130
131
132/*
133 * tsmatchjoinsel -- join selectivity of "@@"
134 *
135 * join selectivity function for tsvector @@ tsquery and tsquery @@ tsvector
136 */
137Datum
139{
140 /* for the moment we just punt */
142}
143
144
145/*
146 * @@ selectivity for tsvector var vs tsquery constant
147 */
148static Selectivity
150{
152 TSQuery query;
153
154 /* The caller made sure the const is a TSQuery, so get it now */
155 query = DatumGetTSQuery(constval);
156
157 /* Empty query matches nothing */
158 if (query->size == 0)
159 return (Selectivity) 0.0;
160
161 if (HeapTupleIsValid(vardata->statsTuple))
162 {
163 Form_pg_statistic stats;
165
166 stats = (Form_pg_statistic) GETSTRUCT(vardata->statsTuple);
167
168 /* MCELEM will be an array of TEXT elements for a tsvector column */
169 if (get_attstatsslot(&sslot, vardata->statsTuple,
172 {
173 /*
174 * There is a most-common-elements slot for the tsvector Var, so
175 * use that.
176 */
177 selec = mcelem_tsquery_selec(query, sslot.values, sslot.nvalues,
178 sslot.numbers, sslot.nnumbers);
180 }
181 else
182 {
183 /* No most-common-elements info, so do without */
185 }
186
187 /*
188 * MCE stats count only non-null rows, so adjust for null rows.
189 */
190 selec *= (1.0 - stats->stanullfrac);
191 }
192 else
193 {
194 /* No stats at all, so do without */
196 /* we assume no nulls here, so no stanullfrac correction */
197 }
198
199 return selec;
200}
201
202/*
203 * Extract data from the pg_statistic arrays into useful format.
204 */
205static Selectivity
207 const float4 *numbers, int nnumbers)
208{
212 int i;
213
214 /*
215 * There should be two more Numbers than Values, because the last two
216 * cells are taken for minimal and maximal frequency. Punt if not.
217 *
218 * (Note: the MCELEM statistics slot definition allows for a third extra
219 * number containing the frequency of nulls, but we're not expecting that
220 * to appear for a tsvector column.)
221 */
222 if (nnumbers != nmcelem + 2)
223 return tsquery_opr_selec_no_stats(query);
224
225 /*
226 * Transpose the data into a single array so we can use bsearch().
227 */
229 for (i = 0; i < nmcelem; i++)
230 {
231 /*
232 * The text Datums came from an array, so it cannot be compressed or
233 * stored out-of-line -- it's safe to use VARSIZE_ANY*.
234 */
236 lookup[i].element = (text *) DatumGetPointer(mcelem[i]);
237 lookup[i].frequency = numbers[i];
238 }
239
240 /*
241 * Grab the lowest MCE frequency. compute_tsvector_stats() stored it for
242 * us in the one before the last cell of the Numbers array.
243 */
244 minfreq = numbers[nnumbers - 2];
245
248
249 pfree(lookup);
250
251 return selec;
252}
253
254/*
255 * Traverse the tsquery in preorder, calculating selectivity as:
256 *
257 * selec(left_oper) * selec(right_oper) in AND & PHRASE nodes,
258 *
259 * selec(left_oper) + selec(right_oper) -
260 * selec(left_oper) * selec(right_oper) in OR nodes,
261 *
262 * 1 - select(oper) in NOT nodes
263 *
264 * histogram-based estimation in prefix VAL nodes
265 *
266 * freq[val] in exact VAL nodes, if the value is in MCELEM
267 * min(freq[MCELEM]) / 2 in VAL nodes, if it is not
268 *
269 * The MCELEM array is already sorted (see ts_typanalyze.c), so we can use
270 * binary search for determining freq[MCELEM].
271 *
272 * If we don't have stats for the tsvector, we still use this logic,
273 * except we use default estimates for VAL nodes. This case is signaled
274 * by lookup == NULL.
275 */
276static Selectivity
277tsquery_opr_selec(QueryItem *item, char *operand,
278 TextFreq *lookup, int length, float4 minfreq)
279{
281
282 /* since this function recurses, it could be driven to stack overflow */
284
285 if (item->type == QI_VAL)
286 {
287 QueryOperand *oper = (QueryOperand *) item;
289
290 /*
291 * Prepare the key for bsearch().
292 */
293 key.lexeme = operand + oper->distance;
294 key.length = oper->length;
295
296 if (oper->prefix)
297 {
298 /* Prefix match, ie the query item is lexeme:* */
299 Selectivity matched,
300 allmces;
301 int i,
302 n_matched;
303
304 /*
305 * Our strategy is to scan through the MCELEM list and combine the
306 * frequencies of the ones that match the prefix. We then
307 * extrapolate the fraction of matching MCELEMs to the remaining
308 * rows, assuming that the MCELEMs are representative of the whole
309 * lexeme population in this respect. (Compare
310 * histogram_selectivity().) Note that these are most common
311 * elements not most common values, so they're not mutually
312 * exclusive. We treat occurrences as independent events.
313 *
314 * This is only a good plan if we have a pretty fair number of
315 * MCELEMs available; we set the threshold at 100. If no stats or
316 * insufficient stats, arbitrarily use DEFAULT_TS_MATCH_SEL*4.
317 */
318 if (lookup == NULL || length < 100)
319 return (Selectivity) (DEFAULT_TS_MATCH_SEL * 4);
320
321 matched = allmces = 0;
322 n_matched = 0;
323 for (i = 0; i < length; i++)
324 {
325 TextFreq *t = lookup + i;
327
328 if (tlen >= key.length &&
329 strncmp(key.lexeme, VARDATA_ANY(t->element),
330 key.length) == 0)
331 {
332 matched += t->frequency - matched * t->frequency;
333 n_matched++;
334 }
335 allmces += t->frequency - allmces * t->frequency;
336 }
337
338 /* Clamp to ensure sanity in the face of roundoff error */
339 CLAMP_PROBABILITY(matched);
341
342 selec = matched + (1.0 - allmces) * ((double) n_matched / length);
343
344 /*
345 * In any case, never believe that a prefix match has selectivity
346 * less than we would assign for a non-MCELEM lexeme. This
347 * preserves the property that "word:*" should be estimated to
348 * match at least as many rows as "word" would be.
349 */
351 }
352 else
353 {
354 /* Regular exact lexeme match */
356
357 /* If no stats for the variable, use DEFAULT_TS_MATCH_SEL */
358 if (lookup == NULL)
360
361 searchres = (TextFreq *) bsearch(&key, lookup, length,
362 sizeof(TextFreq),
364
365 if (searchres)
366 {
367 /*
368 * The element is in MCELEM. Return precise selectivity (or
369 * at least as precise as ANALYZE could find out).
370 */
372 }
373 else
374 {
375 /*
376 * The element is not in MCELEM. Estimate its frequency as
377 * half that of the least-frequent MCE. (We know it cannot be
378 * more than minfreq, and it could be a great deal less. Half
379 * seems like a good compromise.) For probably-historical
380 * reasons, clamp to not more than DEFAULT_TS_MATCH_SEL.
381 */
383 }
384 }
385 }
386 else
387 {
388 /* Current TSQuery node is an operator */
390 s2;
391
392 switch (item->qoperator.oper)
393 {
394 case OP_NOT:
395 selec = 1.0 - tsquery_opr_selec(item + 1, operand,
396 lookup, length, minfreq);
397 break;
398
399 case OP_PHRASE:
400 case OP_AND:
401 s1 = tsquery_opr_selec(item + 1, operand,
402 lookup, length, minfreq);
403 s2 = tsquery_opr_selec(item + item->qoperator.left, operand,
404 lookup, length, minfreq);
405 selec = s1 * s2;
406 break;
407
408 case OP_OR:
409 s1 = tsquery_opr_selec(item + 1, operand,
410 lookup, length, minfreq);
411 s2 = tsquery_opr_selec(item + item->qoperator.left, operand,
412 lookup, length, minfreq);
413 selec = s1 + s2 - s1 * s2;
414 break;
415
416 default:
417 elog(ERROR, "unrecognized operator: %d", item->qoperator.oper);
418 selec = 0; /* keep compiler quiet */
419 break;
420 }
421 }
422
423 /* Clamp intermediate results to stay sane despite roundoff error */
425
426 return selec;
427}
428
429/*
430 * bsearch() comparator for a lexeme (non-NULL terminated string with length)
431 * and a TextFreq. Use length, then byte-for-byte comparison, because that's
432 * how ANALYZE code sorted data before storing it in a statistic tuple.
433 * See ts_typanalyze.c for details.
434 */
435static int
436compare_lexeme_textfreq(const void *e1, const void *e2)
437{
438 const LexemeKey *key = (const LexemeKey *) e1;
439 const TextFreq *t = (const TextFreq *) e2;
440 int len1,
441 len2;
442
443 len1 = key->length;
444 len2 = VARSIZE_ANY_EXHDR(t->element);
445
446 /* Compare lengths first, possibly avoiding a strncmp call */
447 if (len1 > len2)
448 return 1;
449 else if (len1 < len2)
450 return -1;
451
452 /* Fall back on byte-for-byte comparison */
453 return strncmp(key->lexeme, VARDATA_ANY(t->element), len1);
454}
#define GETQUERY(x)
Definition _int.h:157
#define Min(x, y)
Definition c.h:997
#define Max(x, y)
Definition c.h:991
#define Assert(condition)
Definition c.h:873
double float8
Definition c.h:644
float float4
Definition c.h:643
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
#define palloc_array(type, count)
Definition fe_memutils.h:76
#define PG_GETARG_OID(n)
Definition fmgr.h:275
#define PG_RETURN_FLOAT8(x)
Definition fmgr.h:369
#define PG_GETARG_POINTER(n)
Definition fmgr.h:277
#define PG_GETARG_INT32(n)
Definition fmgr.h:269
#define PG_FUNCTION_ARGS
Definition fmgr.h:193
#define HeapTupleIsValid(tuple)
Definition htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
int i
Definition isn.c:77
void free_attstatsslot(AttStatsSlot *sslot)
Definition lsyscache.c:3494
bool get_attstatsslot(AttStatsSlot *sslot, HeapTuple statstuple, int reqkind, Oid reqop, int flags)
Definition lsyscache.c:3384
#define ATTSTATSSLOT_NUMBERS
Definition lsyscache.h:44
#define ATTSTATSSLOT_VALUES
Definition lsyscache.h:43
#define GETOPERAND(x)
Definition ltree.h:167
void pfree(void *pointer)
Definition mcxt.c:1616
#define IsA(nodeptr, _type_)
Definition nodes.h:164
double Selectivity
Definition nodes.h:260
Operator oper(ParseState *pstate, List *opname, Oid ltypeId, Oid rtypeId, bool noError, int location)
Definition parse_oper.c:371
FormData_pg_statistic * Form_pg_statistic
uint64_t Datum
Definition postgres.h:70
static Pointer DatumGetPointer(Datum X)
Definition postgres.h:342
#define InvalidOid
unsigned int Oid
static int fb(int x)
char * s1
char * s2
tree ctl root
Definition radixtree.h:1857
bool get_restriction_variable(PlannerInfo *root, List *args, int varRelid, VariableStatData *vardata, Node **other, bool *varonleft)
Definition selfuncs.c:5507
#define ReleaseVariableStats(vardata)
Definition selfuncs.h:101
#define CLAMP_PROBABILITY(p)
Definition selfuncs.h:63
void check_stack_depth(void)
Definition stack_depth.c:95
Definition pg_list.h:54
Definition nodes.h:135
uint32 left
Definition ts_type.h:197
int32 size
Definition ts_type.h:221
text * element
Definition ts_selfuncs.c:37
float4 frequency
Definition ts_selfuncs.c:38
Definition zic.c:307
Definition c.h:706
#define tsquery_opr_selec_no_stats(query)
Definition ts_selfuncs.c:56
#define DEFAULT_TS_MATCH_SEL
Definition ts_selfuncs.c:32
Datum tsmatchjoinsel(PG_FUNCTION_ARGS)
static Selectivity tsquery_opr_selec(QueryItem *item, char *operand, TextFreq *lookup, int length, float4 minfreq)
static Selectivity tsquerysel(VariableStatData *vardata, Datum constval)
static int compare_lexeme_textfreq(const void *e1, const void *e2)
static Selectivity mcelem_tsquery_selec(TSQuery query, const Datum *mcelem, int nmcelem, const float4 *numbers, int nnumbers)
static TSQuery DatumGetTSQuery(Datum X)
Definition ts_type.h:249
#define QI_VAL
Definition ts_type.h:149
#define OP_AND
Definition ts_type.h:180
#define OP_PHRASE
Definition ts_type.h:182
#define OP_OR
Definition ts_type.h:181
#define OP_NOT
Definition ts_type.h:179
QueryOperator qoperator
Definition ts_type.h:209
QueryItemType type
Definition ts_type.h:208
static Size VARSIZE_ANY_EXHDR(const void *PTR)
Definition varatt.h:472
static bool VARATT_IS_EXTERNAL(const void *PTR)
Definition varatt.h:354
static char * VARDATA_ANY(const void *PTR)
Definition varatt.h:486
static bool VARATT_IS_COMPRESSED(const void *PTR)
Definition varatt.h:347

Function Documentation

◆ compare_lexeme_textfreq()

static int compare_lexeme_textfreq ( const void e1,
const void e2 
)
static

Definition at line 437 of file ts_selfuncs.c.

438{
439 const LexemeKey *key = (const LexemeKey *) e1;
440 const TextFreq *t = (const TextFreq *) e2;
441 int len1,
442 len2;
443
444 len1 = key->length;
445 len2 = VARSIZE_ANY_EXHDR(t->element);
446
447 /* Compare lengths first, possibly avoiding a strncmp call */
448 if (len1 > len2)
449 return 1;
450 else if (len1 < len2)
451 return -1;
452
453 /* Fall back on byte-for-byte comparison */
454 return strncmp(key->lexeme, VARDATA_ANY(t->element), len1);
455}

References TextFreq::element, fb(), VARDATA_ANY(), and VARSIZE_ANY_EXHDR().

Referenced by tsquery_opr_selec().

◆ mcelem_tsquery_selec()

static Selectivity mcelem_tsquery_selec ( TSQuery  query,
const Datum mcelem,
int  nmcelem,
const float4 numbers,
int  nnumbers 
)
static

Definition at line 207 of file ts_selfuncs.c.

209{
213 int i;
214
215 /*
216 * There should be two more Numbers than Values, because the last two
217 * cells are taken for minimal and maximal frequency. Punt if not.
218 *
219 * (Note: the MCELEM statistics slot definition allows for a third extra
220 * number containing the frequency of nulls, but we're not expecting that
221 * to appear for a tsvector column.)
222 */
223 if (nnumbers != nmcelem + 2)
224 return tsquery_opr_selec_no_stats(query);
225
226 /*
227 * Transpose the data into a single array so we can use bsearch().
228 */
230 for (i = 0; i < nmcelem; i++)
231 {
232 /*
233 * The text Datums came from an array, so it cannot be compressed or
234 * stored out-of-line -- it's safe to use VARSIZE_ANY*.
235 */
237 lookup[i].element = (text *) DatumGetPointer(mcelem[i]);
238 lookup[i].frequency = numbers[i];
239 }
240
241 /*
242 * Grab the lowest MCE frequency. compute_tsvector_stats() stored it for
243 * us in the one before the last cell of the Numbers array.
244 */
245 minfreq = numbers[nnumbers - 2];
246
249
250 pfree(lookup);
251
252 return selec;
253}

References Assert, DatumGetPointer(), fb(), GETOPERAND, GETQUERY, i, palloc_array, pfree(), tsquery_opr_selec(), tsquery_opr_selec_no_stats, VARATT_IS_COMPRESSED(), and VARATT_IS_EXTERNAL().

Referenced by tsquerysel().

◆ tsmatchjoinsel()

Datum tsmatchjoinsel ( PG_FUNCTION_ARGS  )

Definition at line 139 of file ts_selfuncs.c.

140{
141 /* for the moment we just punt */
143}

References DEFAULT_TS_MATCH_SEL, and PG_RETURN_FLOAT8.

◆ tsmatchsel()

Datum tsmatchsel ( PG_FUNCTION_ARGS  )

Definition at line 67 of file ts_selfuncs.c.

68{
70
71#ifdef NOT_USED
72 Oid operator = PG_GETARG_OID(1);
73#endif
75 int varRelid = PG_GETARG_INT32(3);
77 Node *other;
78 bool varonleft;
80
81 /*
82 * If expression is not variable = something or something = variable, then
83 * punt and return a default estimate.
84 */
85 if (!get_restriction_variable(root, args, varRelid,
88
89 /*
90 * Can't do anything useful if the something is not a constant, either.
91 */
92 if (!IsA(other, Const))
93 {
96 }
97
98 /*
99 * The "@@" operator is strict, so we can cope with NULL right away
100 */
101 if (((Const *) other)->constisnull)
102 {
104 PG_RETURN_FLOAT8(0.0);
105 }
106
107 /*
108 * OK, there's a Var and a Const we're dealing with here. We need the
109 * Const to be a TSQuery, else we can't do anything useful. We have to
110 * check this because the Var might be the TSQuery not the TSVector.
111 */
112 if (((Const *) other)->consttype == TSQUERYOID)
113 {
114 /* tsvector @@ tsquery or the other way around */
115 Assert(vardata.vartype == TSVECTOROID);
116
118 }
119 else
120 {
121 /* If we can't see the query structure, must punt */
123 }
124
126
128
130}

References Assert, CLAMP_PROBABILITY, DEFAULT_TS_MATCH_SEL, fb(), get_restriction_variable(), IsA, PG_GETARG_INT32, PG_GETARG_OID, PG_GETARG_POINTER, PG_RETURN_FLOAT8, ReleaseVariableStats, root, and tsquerysel().

◆ tsquery_opr_selec()

static Selectivity tsquery_opr_selec ( QueryItem item,
char operand,
TextFreq lookup,
int  length,
float4  minfreq 
)
static

Definition at line 278 of file ts_selfuncs.c.

280{
282
283 /* since this function recurses, it could be driven to stack overflow */
285
286 if (item->type == QI_VAL)
287 {
288 QueryOperand *oper = (QueryOperand *) item;
290
291 /*
292 * Prepare the key for bsearch().
293 */
294 key.lexeme = operand + oper->distance;
295 key.length = oper->length;
296
297 if (oper->prefix)
298 {
299 /* Prefix match, ie the query item is lexeme:* */
300 Selectivity matched,
301 allmces;
302 int i,
303 n_matched;
304
305 /*
306 * Our strategy is to scan through the MCELEM list and combine the
307 * frequencies of the ones that match the prefix. We then
308 * extrapolate the fraction of matching MCELEMs to the remaining
309 * rows, assuming that the MCELEMs are representative of the whole
310 * lexeme population in this respect. (Compare
311 * histogram_selectivity().) Note that these are most common
312 * elements not most common values, so they're not mutually
313 * exclusive. We treat occurrences as independent events.
314 *
315 * This is only a good plan if we have a pretty fair number of
316 * MCELEMs available; we set the threshold at 100. If no stats or
317 * insufficient stats, arbitrarily use DEFAULT_TS_MATCH_SEL*4.
318 */
319 if (lookup == NULL || length < 100)
320 return (Selectivity) (DEFAULT_TS_MATCH_SEL * 4);
321
322 matched = allmces = 0;
323 n_matched = 0;
324 for (i = 0; i < length; i++)
325 {
326 TextFreq *t = lookup + i;
328
329 if (tlen >= key.length &&
330 strncmp(key.lexeme, VARDATA_ANY(t->element),
331 key.length) == 0)
332 {
333 matched += t->frequency - matched * t->frequency;
334 n_matched++;
335 }
336 allmces += t->frequency - allmces * t->frequency;
337 }
338
339 /* Clamp to ensure sanity in the face of roundoff error */
340 CLAMP_PROBABILITY(matched);
342
343 selec = matched + (1.0 - allmces) * ((double) n_matched / length);
344
345 /*
346 * In any case, never believe that a prefix match has selectivity
347 * less than we would assign for a non-MCELEM lexeme. This
348 * preserves the property that "word:*" should be estimated to
349 * match at least as many rows as "word" would be.
350 */
352 }
353 else
354 {
355 /* Regular exact lexeme match */
357
358 /* If no stats for the variable, use DEFAULT_TS_MATCH_SEL */
359 if (lookup == NULL)
361
362 searchres = (TextFreq *) bsearch(&key, lookup, length,
363 sizeof(TextFreq),
365
366 if (searchres)
367 {
368 /*
369 * The element is in MCELEM. Return precise selectivity (or
370 * at least as precise as ANALYZE could find out).
371 */
373 }
374 else
375 {
376 /*
377 * The element is not in MCELEM. Estimate its frequency as
378 * half that of the least-frequent MCE. (We know it cannot be
379 * more than minfreq, and it could be a great deal less. Half
380 * seems like a good compromise.) For probably-historical
381 * reasons, clamp to not more than DEFAULT_TS_MATCH_SEL.
382 */
384 }
385 }
386 }
387 else
388 {
389 /* Current TSQuery node is an operator */
391 s2;
392
393 switch (item->qoperator.oper)
394 {
395 case OP_NOT:
396 selec = 1.0 - tsquery_opr_selec(item + 1, operand,
397 lookup, length, minfreq);
398 break;
399
400 case OP_PHRASE:
401 case OP_AND:
402 s1 = tsquery_opr_selec(item + 1, operand,
403 lookup, length, minfreq);
404 s2 = tsquery_opr_selec(item + item->qoperator.left, operand,
405 lookup, length, minfreq);
406 selec = s1 * s2;
407 break;
408
409 case OP_OR:
410 s1 = tsquery_opr_selec(item + 1, operand,
411 lookup, length, minfreq);
412 s2 = tsquery_opr_selec(item + item->qoperator.left, operand,
413 lookup, length, minfreq);
414 selec = s1 + s2 - s1 * s2;
415 break;
416
417 default:
418 elog(ERROR, "unrecognized operator: %d", item->qoperator.oper);
419 selec = 0; /* keep compiler quiet */
420 break;
421 }
422 }
423
424 /* Clamp intermediate results to stay sane despite roundoff error */
426
427 return selec;
428}

References check_stack_depth(), CLAMP_PROBABILITY, compare_lexeme_textfreq(), DEFAULT_TS_MATCH_SEL, TextFreq::element, elog, ERROR, fb(), TextFreq::frequency, i, QueryOperator::left, Max, Min, OP_AND, OP_NOT, OP_OR, OP_PHRASE, oper(), QueryOperator::oper, QI_VAL, QueryItem::qoperator, s1, s2, tsquery_opr_selec(), QueryItem::type, VARDATA_ANY(), and VARSIZE_ANY_EXHDR().

Referenced by mcelem_tsquery_selec(), and tsquery_opr_selec().

◆ tsquerysel()

static Selectivity tsquerysel ( VariableStatData vardata,
Datum  constval 
)
static

Definition at line 150 of file ts_selfuncs.c.

151{
153 TSQuery query;
154
155 /* The caller made sure the const is a TSQuery, so get it now */
156 query = DatumGetTSQuery(constval);
157
158 /* Empty query matches nothing */
159 if (query->size == 0)
160 return (Selectivity) 0.0;
161
162 if (HeapTupleIsValid(vardata->statsTuple))
163 {
164 Form_pg_statistic stats;
166
167 stats = (Form_pg_statistic) GETSTRUCT(vardata->statsTuple);
168
169 /* MCELEM will be an array of TEXT elements for a tsvector column */
170 if (get_attstatsslot(&sslot, vardata->statsTuple,
173 {
174 /*
175 * There is a most-common-elements slot for the tsvector Var, so
176 * use that.
177 */
178 selec = mcelem_tsquery_selec(query, sslot.values, sslot.nvalues,
179 sslot.numbers, sslot.nnumbers);
181 }
182 else
183 {
184 /* No most-common-elements info, so do without */
186 }
187
188 /*
189 * MCE stats count only non-null rows, so adjust for null rows.
190 */
191 selec *= (1.0 - stats->stanullfrac);
192 }
193 else
194 {
195 /* No stats at all, so do without */
197 /* we assume no nulls here, so no stanullfrac correction */
198 }
199
200 return selec;
201}

References ATTSTATSSLOT_NUMBERS, ATTSTATSSLOT_VALUES, DatumGetTSQuery(), fb(), free_attstatsslot(), get_attstatsslot(), GETSTRUCT(), HeapTupleIsValid, InvalidOid, mcelem_tsquery_selec(), TSQueryData::size, and tsquery_opr_selec_no_stats.

Referenced by tsmatchsel().