PostgreSQL Source Code git master
Loading...
Searching...
No Matches
_int_selfuncs.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * _int_selfuncs.c
4 * Functions for selectivity estimation of intarray operators
5 *
6 * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
8 *
9 *
10 * IDENTIFICATION
11 * contrib/intarray/_int_selfuncs.c
12 *
13 *-------------------------------------------------------------------------
14 */
15#include "postgres.h"
16
17#include "_int.h"
18#include "access/htup_details.h"
19#include "catalog/pg_operator.h"
21#include "catalog/pg_type.h"
22#include "commands/extension.h"
23#include "miscadmin.h"
24#include "utils/fmgrprotos.h"
25#include "utils/lsyscache.h"
26#include "utils/selfuncs.h"
27
35
36
39static int compare_val_int4(const void *a, const void *b);
40
41/*
42 * Wrappers around the default array selectivity estimation functions.
43 *
44 * The default array selectivity operators for the @>, && and @< operators
45 * work fine for integer arrays. However, if we tried to just use arraycontsel
46 * and arraycontjoinsel directly as the cost estimator functions for our
47 * operators, they would not work as intended, because they look at the
48 * operator's OID. Our operators behave exactly like the built-in anyarray
49 * versions, but we must tell the cost estimator functions which built-in
50 * operators they correspond to. These wrappers just replace the operator
51 * OID with the corresponding built-in operator's OID, and call the built-in
52 * function.
53 */
54
64
74
84
95
106
107Datum
117
118
119/*
120 * _int_matchsel -- restriction selectivity function for intarray @@ query_int
121 */
122Datum
124{
126
127 List *args = (List *) PG_GETARG_POINTER(2);
128 int varRelid = PG_GETARG_INT32(3);
130 Node *other;
131 bool varonleft;
133 QUERYTYPE *query;
134 Datum *mcelems = NULL;
136 int nmcelems = 0;
137 float4 minfreq = 0.0;
138 float4 nullfrac = 0.0;
140
141 /*
142 * If expression is not "variable @@ something" or "something @@ variable"
143 * then punt and return a default estimate.
144 */
145 if (!get_restriction_variable(root, args, varRelid,
146 &vardata, &other, &varonleft))
148
149 /*
150 * Variable should be int[]. We don't support cases where variable is
151 * query_int.
152 */
153 if (vardata.vartype != INT4ARRAYOID)
155
156 /*
157 * Can't do anything useful if the something is not a constant, either.
158 */
159 if (!IsA(other, Const))
160 {
163 }
164
165 /*
166 * The "@@" operator is strict, so we can cope with NULL right away.
167 */
168 if (((Const *) other)->constisnull)
169 {
171 PG_RETURN_FLOAT8(0.0);
172 }
173
174 /*
175 * Verify that the Const is a query_int, else return a default estimate.
176 * (This could only fail if someone attached this estimator to the wrong
177 * operator.)
178 */
179 if (((Const *) other)->consttype !=
180 get_function_sibling_type(fcinfo->flinfo->fn_oid, "query_int"))
181 {
184 }
185
187
188 /* Empty query matches nothing */
189 if (query->size == 0)
190 {
192 PG_RETURN_FLOAT8(0.0);
193 }
194
195 /*
196 * Get the statistics for the intarray column.
197 *
198 * We're interested in the Most-Common-Elements list, and the NULL
199 * fraction.
200 */
201 if (HeapTupleIsValid(vardata.statsTuple))
202 {
203 Form_pg_statistic stats;
204
205 stats = (Form_pg_statistic) GETSTRUCT(vardata.statsTuple);
206 nullfrac = stats->stanullfrac;
207
208 /*
209 * For an int4 array, the default array type analyze function will
210 * collect a Most Common Elements list, which is an array of int4s.
211 */
212 if (get_attstatsslot(&sslot, vardata.statsTuple,
215 {
216 Assert(sslot.valuetype == INT4OID);
217
218 /*
219 * There should be three more Numbers than Values, because the
220 * last three (for intarray) cells are taken for minimal, maximal
221 * and nulls frequency. Punt if not.
222 */
223 if (sslot.nnumbers == sslot.nvalues + 3)
224 {
225 /* Grab the minimal MCE frequency. */
226 minfreq = sslot.numbers[sslot.nvalues];
227
228 mcelems = sslot.values;
229 mcefreqs = sslot.numbers;
230 nmcelems = sslot.nvalues;
231 }
232 }
233 }
234 else
235 memset(&sslot, 0, sizeof(sslot));
236
237 /* Process the logical expression in the query, using the stats */
238 selec = int_query_opr_selec(GETQUERY(query) + query->size - 1,
240
241 /* MCE stats count only non-null rows, so adjust for null rows. */
242 selec *= (1.0 - nullfrac);
243
246
248
250}
251
252/*
253 * Estimate selectivity of single intquery operator
254 */
255static Selectivity
258{
260
261 /* since this function recurses, it could be driven to stack overflow */
263
264 if (item->type == VAL)
265 {
267
268 if (mcelems == NULL)
270
271 searchres = (Datum *) bsearch(&item->val, mcelems, nmcelems,
272 sizeof(Datum), compare_val_int4);
273 if (searchres)
274 {
275 /*
276 * The element is in MCELEM. Return precise selectivity (or at
277 * least as precise as ANALYZE could find out).
278 */
280 }
281 else
282 {
283 /*
284 * The element is not in MCELEM. Estimate its frequency as half
285 * that of the least-frequent MCE. (We know it cannot be more
286 * than minfreq, and it could be a great deal less. Half seems
287 * like a good compromise.) For probably-historical reasons,
288 * clamp to not more than DEFAULT_EQ_SEL.
289 */
291 }
292 }
293 else if (item->type == OPR)
294 {
295 /* Current query node is an operator */
297 s2;
298
300 minfreq);
301 switch (item->val)
302 {
303 case (int32) '!':
304 selec = 1.0 - s1;
305 break;
306
307 case (int32) '&':
308 s2 = int_query_opr_selec(item + item->left, mcelems, mcefreqs,
310 selec = s1 * s2;
311 break;
312
313 case (int32) '|':
314 s2 = int_query_opr_selec(item + item->left, mcelems, mcefreqs,
316 selec = s1 + s2 - s1 * s2;
317 break;
318
319 default:
320 elog(ERROR, "unrecognized operator: %d", item->val);
321 selec = 0; /* keep compiler quiet */
322 break;
323 }
324 }
325 else
326 {
327 elog(ERROR, "unrecognized int query item type: %u", item->type);
328 selec = 0; /* keep compiler quiet */
329 }
330
331 /* Clamp intermediate results to stay sane despite roundoff error */
333
334 return selec;
335}
336
337/*
338 * Comparison function for binary search in mcelem array.
339 */
340static int
341compare_val_int4(const void *a, const void *b)
342{
343 int32 key = *(const int32 *) a;
344 int32 value = DatumGetInt32(*(const Datum *) b);
345
346 if (key < value)
347 return -1;
348 else if (key > value)
349 return 1;
350 else
351 return 0;
352}
#define OPR
Definition _int.h:163
#define VAL
Definition _int.h:162
#define GETQUERY(x)
Definition _int.h:157
#define DatumGetQueryTypeP(X)
Definition _int.h:168
static int compare_val_int4(const void *a, const void *b)
Datum _int_overlap_joinsel(PG_FUNCTION_ARGS)
static Selectivity int_query_opr_selec(ITEM *item, Datum *mcelems, float4 *mcefreqs, int nmcelems, float4 minfreq)
Datum _int_matchsel(PG_FUNCTION_ARGS)
Datum _int_contains_sel(PG_FUNCTION_ARGS)
Datum _int_contained_sel(PG_FUNCTION_ARGS)
Datum _int_contains_joinsel(PG_FUNCTION_ARGS)
Datum _int_overlap_sel(PG_FUNCTION_ARGS)
Datum _int_contained_joinsel(PG_FUNCTION_ARGS)
Datum arraycontsel(PG_FUNCTION_ARGS)
Datum arraycontjoinsel(PG_FUNCTION_ARGS)
#define Min(x, y)
Definition c.h:1019
#define Assert(condition)
Definition c.h:885
double float8
Definition c.h:656
int32_t int32
Definition c.h:554
float float4
Definition c.h:655
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
Oid get_function_sibling_type(Oid funcoid, const char *typname)
Definition extension.c:312
#define PG_RETURN_FLOAT8(x)
Definition fmgr.h:369
#define DirectFunctionCall4(func, arg1, arg2, arg3, arg4)
Definition fmgr.h:690
#define PG_GETARG_POINTER(n)
Definition fmgr.h:277
#define PG_GETARG_DATUM(n)
Definition fmgr.h:268
#define PG_FUNCTION_INFO_V1(funcname)
Definition fmgr.h:417
#define PG_GETARG_INT32(n)
Definition fmgr.h:269
#define PG_RETURN_DATUM(x)
Definition fmgr.h:354
#define DirectFunctionCall5(func, arg1, arg2, arg3, arg4, arg5)
Definition fmgr.h:692
#define PG_FUNCTION_ARGS
Definition fmgr.h:193
#define HeapTupleIsValid(tuple)
Definition htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
static struct @174 value
int b
Definition isn.c:74
int a
Definition isn.c:73
void free_attstatsslot(AttStatsSlot *sslot)
Definition lsyscache.c:3496
bool get_attstatsslot(AttStatsSlot *sslot, HeapTuple statstuple, int reqkind, Oid reqop, int flags)
Definition lsyscache.c:3386
#define ATTSTATSSLOT_NUMBERS
Definition lsyscache.h:44
#define ATTSTATSSLOT_VALUES
Definition lsyscache.h:43
#define IsA(nodeptr, _type_)
Definition nodes.h:164
double Selectivity
Definition nodes.h:260
FormData_pg_statistic * Form_pg_statistic
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:262
uint64_t Datum
Definition postgres.h:70
static int32 DatumGetInt32(Datum X)
Definition postgres.h:212
#define InvalidOid
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
#define DEFAULT_EQ_SEL
Definition selfuncs.h:34
void check_stack_depth(void)
Definition stack_depth.c:95
Definition _int.h:141
int16 left
Definition _int.h:143
int32 val
Definition _int.h:144
int16 type
Definition _int.h:142
Definition pg_list.h:54
Definition nodes.h:135
int32 size
Definition _int.h:150