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-2026, 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 1138728 : ginarrayextract(PG_FUNCTION_ARGS) 34 : { 35 : /* Make copy of array input to ensure it doesn't disappear while in use */ 36 1138728 : ArrayType *array = PG_GETARG_ARRAYTYPE_P_COPY(0); 37 1138728 : int32 *nkeys = (int32 *) PG_GETARG_POINTER(1); 38 1138728 : 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 1138728 : get_typlenbyvalalign(ARR_ELEMTYPE(array), 47 : &elmlen, &elmbyval, &elmalign); 48 : 49 1138728 : deconstruct_array(array, 50 : ARR_ELEMTYPE(array), 51 : elmlen, elmbyval, elmalign, 52 : &elems, &nulls, &nelems); 53 : 54 1138728 : *nkeys = nelems; 55 1138728 : *nullFlags = nulls; 56 : 57 : /* we should not free array, elems[i] points into it */ 58 1138728 : 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 : #ifdef NOT_USED 86 : bool **pmatch = (bool **) PG_GETARG_POINTER(3); 87 : Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4); 88 : #endif 89 1332 : bool **nullFlags = (bool **) PG_GETARG_POINTER(5); 90 1332 : int32 *searchMode = (int32 *) PG_GETARG_POINTER(6); 91 : int16 elmlen; 92 : bool elmbyval; 93 : char elmalign; 94 : Datum *elems; 95 : bool *nulls; 96 : int nelems; 97 : 98 1332 : get_typlenbyvalalign(ARR_ELEMTYPE(array), 99 : &elmlen, &elmbyval, &elmalign); 100 : 101 1332 : deconstruct_array(array, 102 : ARR_ELEMTYPE(array), 103 : elmlen, elmbyval, elmalign, 104 : &elems, &nulls, &nelems); 105 : 106 1332 : *nkeys = nelems; 107 1332 : *nullFlags = nulls; 108 : 109 1332 : switch (strategy) 110 : { 111 164 : case GinOverlapStrategy: 112 164 : *searchMode = GIN_SEARCH_MODE_DEFAULT; 113 164 : break; 114 1060 : case GinContainsStrategy: 115 1060 : if (nelems > 0) 116 676 : *searchMode = GIN_SEARCH_MODE_DEFAULT; 117 : else /* everything contains the empty set */ 118 384 : *searchMode = GIN_SEARCH_MODE_ALL; 119 1060 : break; 120 48 : case GinContainedStrategy: 121 : /* empty set is contained in everything */ 122 48 : *searchMode = GIN_SEARCH_MODE_INCLUDE_EMPTY; 123 48 : break; 124 60 : case GinEqualStrategy: 125 60 : if (nelems > 0) 126 24 : *searchMode = GIN_SEARCH_MODE_DEFAULT; 127 : else 128 36 : *searchMode = GIN_SEARCH_MODE_INCLUDE_EMPTY; 129 60 : break; 130 0 : default: 131 0 : elog(ERROR, "ginqueryarrayextract: unknown strategy number: %d", 132 : strategy); 133 : } 134 : 135 : /* we should not free array, elems[i] points into it */ 136 1332 : PG_RETURN_POINTER(elems); 137 : } 138 : 139 : /* 140 : * consistent support function 141 : */ 142 : Datum 143 810 : ginarrayconsistent(PG_FUNCTION_ARGS) 144 : { 145 810 : bool *check = (bool *) PG_GETARG_POINTER(0); 146 810 : StrategyNumber strategy = PG_GETARG_UINT16(1); 147 : #ifdef NOT_USED 148 : ArrayType *query = PG_GETARG_ARRAYTYPE_P(2); 149 : #endif 150 810 : int32 nkeys = PG_GETARG_INT32(3); 151 : #ifdef NOT_USED 152 : Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4); 153 : #endif 154 810 : bool *recheck = (bool *) PG_GETARG_POINTER(5); 155 : #ifdef NOT_USED 156 : Datum *queryKeys = (Datum *) PG_GETARG_POINTER(6); 157 : #endif 158 810 : bool *nullFlags = (bool *) PG_GETARG_POINTER(7); 159 : bool res; 160 : int32 i; 161 : 162 810 : switch (strategy) 163 : { 164 0 : case GinOverlapStrategy: 165 : /* result is not lossy */ 166 0 : *recheck = false; 167 : /* must have a match for at least one non-null element */ 168 0 : res = false; 169 0 : for (i = 0; i < nkeys; i++) 170 : { 171 0 : if (check[i] && !nullFlags[i]) 172 : { 173 0 : res = true; 174 0 : break; 175 : } 176 : } 177 0 : break; 178 810 : case GinContainsStrategy: 179 : /* result is not lossy */ 180 810 : *recheck = false; 181 : /* must have all elements in check[] true, and no nulls */ 182 810 : res = true; 183 1110 : for (i = 0; i < nkeys; i++) 184 : { 185 300 : if (!check[i] || nullFlags[i]) 186 : { 187 0 : res = false; 188 0 : break; 189 : } 190 : } 191 810 : break; 192 0 : case GinContainedStrategy: 193 : /* we will need recheck */ 194 0 : *recheck = true; 195 : /* can't do anything else useful here */ 196 0 : res = true; 197 0 : break; 198 0 : case GinEqualStrategy: 199 : /* we will need recheck */ 200 0 : *recheck = true; 201 : 202 : /* 203 : * Must have all elements in check[] true; no discrimination 204 : * against nulls here. This is because array_contain_compare and 205 : * array_eq handle nulls differently ... 206 : */ 207 0 : res = true; 208 0 : for (i = 0; i < nkeys; i++) 209 : { 210 0 : if (!check[i]) 211 : { 212 0 : res = false; 213 0 : break; 214 : } 215 : } 216 0 : break; 217 0 : default: 218 0 : elog(ERROR, "ginarrayconsistent: unknown strategy number: %d", 219 : strategy); 220 : res = false; 221 : } 222 : 223 810 : PG_RETURN_BOOL(res); 224 : } 225 : 226 : /* 227 : * triconsistent support function 228 : */ 229 : Datum 230 808474 : ginarraytriconsistent(PG_FUNCTION_ARGS) 231 : { 232 808474 : GinTernaryValue *check = (GinTernaryValue *) PG_GETARG_POINTER(0); 233 808474 : StrategyNumber strategy = PG_GETARG_UINT16(1); 234 : #ifdef NOT_USED 235 : ArrayType *query = PG_GETARG_ARRAYTYPE_P(2); 236 : #endif 237 808474 : int32 nkeys = PG_GETARG_INT32(3); 238 : #ifdef NOT_USED 239 : Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4); 240 : Datum *queryKeys = (Datum *) PG_GETARG_POINTER(5); 241 : #endif 242 808474 : bool *nullFlags = (bool *) PG_GETARG_POINTER(6); 243 : GinTernaryValue res; 244 : int32 i; 245 : 246 808474 : switch (strategy) 247 : { 248 3492 : case GinOverlapStrategy: 249 : /* must have a match for at least one non-null element */ 250 3492 : res = GIN_FALSE; 251 922134 : for (i = 0; i < nkeys; i++) 252 : { 253 919132 : if (!nullFlags[i]) 254 : { 255 919132 : if (check[i] == GIN_TRUE) 256 : { 257 490 : res = GIN_TRUE; 258 490 : break; 259 : } 260 918642 : else if (check[i] == GIN_MAYBE && res == GIN_FALSE) 261 : { 262 3002 : res = GIN_MAYBE; 263 : } 264 : } 265 : } 266 3492 : break; 267 804574 : case GinContainsStrategy: 268 : /* must have all elements in check[] true, and no nulls */ 269 804574 : res = GIN_TRUE; 270 1487888 : for (i = 0; i < nkeys; i++) 271 : { 272 683362 : if (check[i] == GIN_FALSE || nullFlags[i]) 273 : { 274 48 : res = GIN_FALSE; 275 48 : break; 276 : } 277 683314 : if (check[i] == GIN_MAYBE) 278 : { 279 12 : res = GIN_MAYBE; 280 : } 281 : } 282 804574 : break; 283 336 : case GinContainedStrategy: 284 : /* can't do anything else useful here */ 285 336 : res = GIN_MAYBE; 286 336 : break; 287 72 : case GinEqualStrategy: 288 : 289 : /* 290 : * Must have all elements in check[] true; no discrimination 291 : * against nulls here. This is because array_contain_compare and 292 : * array_eq handle nulls differently ... 293 : */ 294 72 : res = GIN_MAYBE; 295 132 : for (i = 0; i < nkeys; i++) 296 : { 297 102 : if (check[i] == GIN_FALSE) 298 : { 299 42 : res = GIN_FALSE; 300 42 : break; 301 : } 302 : } 303 72 : break; 304 0 : default: 305 0 : elog(ERROR, "ginarrayconsistent: unknown strategy number: %d", 306 : strategy); 307 : res = false; 308 : } 309 : 310 808474 : PG_RETURN_GIN_TERNARY_VALUE(res); 311 : }