Line data Source code
1 : /*------------------------------------------------------------------------- 2 : * 3 : * ginarrayproc.c 4 : * support functions for GIN's indexing of any array 5 : * 6 : * 7 : * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group 8 : * Portions Copyright (c) 1994, Regents of the University of California 9 : * 10 : * IDENTIFICATION 11 : * src/backend/access/gin/ginarrayproc.c 12 : *------------------------------------------------------------------------- 13 : */ 14 : #include "postgres.h" 15 : 16 : #include "access/gin.h" 17 : #include "access/stratnum.h" 18 : #include "utils/array.h" 19 : #include "utils/fmgrprotos.h" 20 : #include "utils/lsyscache.h" 21 : 22 : 23 : #define GinOverlapStrategy 1 24 : #define GinContainsStrategy 2 25 : #define GinContainedStrategy 3 26 : #define GinEqualStrategy 4 27 : 28 : 29 : /* 30 : * extractValue support function 31 : */ 32 : Datum 33 1057922 : ginarrayextract(PG_FUNCTION_ARGS) 34 : { 35 : /* Make copy of array input to ensure it doesn't disappear while in use */ 36 1057922 : ArrayType *array = PG_GETARG_ARRAYTYPE_P_COPY(0); 37 1057922 : int32 *nkeys = (int32 *) PG_GETARG_POINTER(1); 38 1057922 : bool **nullFlags = (bool **) PG_GETARG_POINTER(2); 39 : int16 elmlen; 40 : bool elmbyval; 41 : char elmalign; 42 : Datum *elems; 43 : bool *nulls; 44 : int nelems; 45 : 46 1057922 : get_typlenbyvalalign(ARR_ELEMTYPE(array), 47 : &elmlen, &elmbyval, &elmalign); 48 : 49 1057922 : deconstruct_array(array, 50 : ARR_ELEMTYPE(array), 51 : elmlen, elmbyval, elmalign, 52 : &elems, &nulls, &nelems); 53 : 54 1057922 : *nkeys = nelems; 55 1057922 : *nullFlags = nulls; 56 : 57 : /* we should not free array, elems[i] points into it */ 58 1057922 : PG_RETURN_POINTER(elems); 59 : } 60 : 61 : /* 62 : * Formerly, ginarrayextract had only two arguments. Now it has three, 63 : * but we still need a pg_proc entry with two args to support reloading 64 : * pre-9.1 contrib/intarray opclass declarations. This compatibility 65 : * function should go away eventually. 66 : */ 67 : Datum 68 0 : ginarrayextract_2args(PG_FUNCTION_ARGS) 69 : { 70 0 : if (PG_NARGS() < 3) /* should not happen */ 71 0 : elog(ERROR, "ginarrayextract requires three arguments"); 72 0 : return ginarrayextract(fcinfo); 73 : } 74 : 75 : /* 76 : * extractQuery support function 77 : */ 78 : Datum 79 1332 : ginqueryarrayextract(PG_FUNCTION_ARGS) 80 : { 81 : /* Make copy of array input to ensure it doesn't disappear while in use */ 82 1332 : ArrayType *array = PG_GETARG_ARRAYTYPE_P_COPY(0); 83 1332 : int32 *nkeys = (int32 *) PG_GETARG_POINTER(1); 84 1332 : StrategyNumber strategy = PG_GETARG_UINT16(2); 85 : 86 : /* bool **pmatch = (bool **) PG_GETARG_POINTER(3); */ 87 : /* Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4); */ 88 1332 : bool **nullFlags = (bool **) PG_GETARG_POINTER(5); 89 1332 : int32 *searchMode = (int32 *) PG_GETARG_POINTER(6); 90 : int16 elmlen; 91 : bool elmbyval; 92 : char elmalign; 93 : Datum *elems; 94 : bool *nulls; 95 : int nelems; 96 : 97 1332 : get_typlenbyvalalign(ARR_ELEMTYPE(array), 98 : &elmlen, &elmbyval, &elmalign); 99 : 100 1332 : deconstruct_array(array, 101 : ARR_ELEMTYPE(array), 102 : elmlen, elmbyval, elmalign, 103 : &elems, &nulls, &nelems); 104 : 105 1332 : *nkeys = nelems; 106 1332 : *nullFlags = nulls; 107 : 108 1332 : switch (strategy) 109 : { 110 164 : case GinOverlapStrategy: 111 164 : *searchMode = GIN_SEARCH_MODE_DEFAULT; 112 164 : break; 113 1060 : case GinContainsStrategy: 114 1060 : if (nelems > 0) 115 676 : *searchMode = GIN_SEARCH_MODE_DEFAULT; 116 : else /* everything contains the empty set */ 117 384 : *searchMode = GIN_SEARCH_MODE_ALL; 118 1060 : break; 119 48 : case GinContainedStrategy: 120 : /* empty set is contained in everything */ 121 48 : *searchMode = GIN_SEARCH_MODE_INCLUDE_EMPTY; 122 48 : break; 123 60 : case GinEqualStrategy: 124 60 : if (nelems > 0) 125 24 : *searchMode = GIN_SEARCH_MODE_DEFAULT; 126 : else 127 36 : *searchMode = GIN_SEARCH_MODE_INCLUDE_EMPTY; 128 60 : break; 129 0 : default: 130 0 : elog(ERROR, "ginqueryarrayextract: unknown strategy number: %d", 131 : strategy); 132 : } 133 : 134 : /* we should not free array, elems[i] points into it */ 135 1332 : PG_RETURN_POINTER(elems); 136 : } 137 : 138 : /* 139 : * consistent support function 140 : */ 141 : Datum 142 810 : ginarrayconsistent(PG_FUNCTION_ARGS) 143 : { 144 810 : bool *check = (bool *) PG_GETARG_POINTER(0); 145 810 : StrategyNumber strategy = PG_GETARG_UINT16(1); 146 : 147 : /* ArrayType *query = PG_GETARG_ARRAYTYPE_P(2); */ 148 810 : int32 nkeys = PG_GETARG_INT32(3); 149 : 150 : /* Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4); */ 151 810 : bool *recheck = (bool *) PG_GETARG_POINTER(5); 152 : 153 : /* Datum *queryKeys = (Datum *) PG_GETARG_POINTER(6); */ 154 810 : bool *nullFlags = (bool *) PG_GETARG_POINTER(7); 155 : bool res; 156 : int32 i; 157 : 158 810 : switch (strategy) 159 : { 160 0 : case GinOverlapStrategy: 161 : /* result is not lossy */ 162 0 : *recheck = false; 163 : /* must have a match for at least one non-null element */ 164 0 : res = false; 165 0 : for (i = 0; i < nkeys; i++) 166 : { 167 0 : if (check[i] && !nullFlags[i]) 168 : { 169 0 : res = true; 170 0 : break; 171 : } 172 : } 173 0 : break; 174 810 : case GinContainsStrategy: 175 : /* result is not lossy */ 176 810 : *recheck = false; 177 : /* must have all elements in check[] true, and no nulls */ 178 810 : res = true; 179 1110 : for (i = 0; i < nkeys; i++) 180 : { 181 300 : if (!check[i] || nullFlags[i]) 182 : { 183 0 : res = false; 184 0 : break; 185 : } 186 : } 187 810 : break; 188 0 : case GinContainedStrategy: 189 : /* we will need recheck */ 190 0 : *recheck = true; 191 : /* can't do anything else useful here */ 192 0 : res = true; 193 0 : break; 194 0 : case GinEqualStrategy: 195 : /* we will need recheck */ 196 0 : *recheck = true; 197 : 198 : /* 199 : * Must have all elements in check[] true; no discrimination 200 : * against nulls here. This is because array_contain_compare and 201 : * array_eq handle nulls differently ... 202 : */ 203 0 : res = true; 204 0 : for (i = 0; i < nkeys; i++) 205 : { 206 0 : if (!check[i]) 207 : { 208 0 : res = false; 209 0 : break; 210 : } 211 : } 212 0 : break; 213 0 : default: 214 0 : elog(ERROR, "ginarrayconsistent: unknown strategy number: %d", 215 : strategy); 216 : res = false; 217 : } 218 : 219 810 : PG_RETURN_BOOL(res); 220 : } 221 : 222 : /* 223 : * triconsistent support function 224 : */ 225 : Datum 226 808620 : ginarraytriconsistent(PG_FUNCTION_ARGS) 227 : { 228 808620 : GinTernaryValue *check = (GinTernaryValue *) PG_GETARG_POINTER(0); 229 808620 : StrategyNumber strategy = PG_GETARG_UINT16(1); 230 : 231 : /* ArrayType *query = PG_GETARG_ARRAYTYPE_P(2); */ 232 808620 : int32 nkeys = PG_GETARG_INT32(3); 233 : 234 : /* Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4); */ 235 : /* Datum *queryKeys = (Datum *) PG_GETARG_POINTER(5); */ 236 808620 : bool *nullFlags = (bool *) PG_GETARG_POINTER(6); 237 : GinTernaryValue res; 238 : int32 i; 239 : 240 808620 : switch (strategy) 241 : { 242 3492 : case GinOverlapStrategy: 243 : /* must have a match for at least one non-null element */ 244 3492 : res = GIN_FALSE; 245 922134 : for (i = 0; i < nkeys; i++) 246 : { 247 919132 : if (!nullFlags[i]) 248 : { 249 919132 : if (check[i] == GIN_TRUE) 250 : { 251 490 : res = GIN_TRUE; 252 490 : break; 253 : } 254 918642 : else if (check[i] == GIN_MAYBE && res == GIN_FALSE) 255 : { 256 3002 : res = GIN_MAYBE; 257 : } 258 : } 259 : } 260 3492 : break; 261 804720 : case GinContainsStrategy: 262 : /* must have all elements in check[] true, and no nulls */ 263 804720 : res = GIN_TRUE; 264 1488180 : for (i = 0; i < nkeys; i++) 265 : { 266 683508 : if (check[i] == GIN_FALSE || nullFlags[i]) 267 : { 268 48 : res = GIN_FALSE; 269 48 : break; 270 : } 271 683460 : if (check[i] == GIN_MAYBE) 272 : { 273 12 : res = GIN_MAYBE; 274 : } 275 : } 276 804720 : break; 277 336 : case GinContainedStrategy: 278 : /* can't do anything else useful here */ 279 336 : res = GIN_MAYBE; 280 336 : break; 281 72 : case GinEqualStrategy: 282 : 283 : /* 284 : * Must have all elements in check[] true; no discrimination 285 : * against nulls here. This is because array_contain_compare and 286 : * array_eq handle nulls differently ... 287 : */ 288 72 : res = GIN_MAYBE; 289 132 : for (i = 0; i < nkeys; i++) 290 : { 291 102 : if (check[i] == GIN_FALSE) 292 : { 293 42 : res = GIN_FALSE; 294 42 : break; 295 : } 296 : } 297 72 : break; 298 0 : default: 299 0 : elog(ERROR, "ginarrayconsistent: unknown strategy number: %d", 300 : strategy); 301 : res = false; 302 : } 303 : 304 808620 : PG_RETURN_GIN_TERNARY_VALUE(res); 305 : }