diff options
Diffstat (limited to 'src/backend/access/gin/ginarrayproc.c')
-rw-r--r-- | src/backend/access/gin/ginarrayproc.c | 168 |
1 files changed, 105 insertions, 63 deletions
diff --git a/src/backend/access/gin/ginarrayproc.c b/src/backend/access/gin/ginarrayproc.c index 1837a0d5a10..2100c5fd0e4 100644 --- a/src/backend/access/gin/ginarrayproc.c +++ b/src/backend/access/gin/ginarrayproc.c @@ -14,7 +14,9 @@ #include "postgres.h" #include "access/gin.h" +#include "access/skey.h" #include "utils/array.h" +#include "utils/builtins.h" #include "utils/lsyscache.h" @@ -23,34 +25,23 @@ #define GinContainedStrategy 3 #define GinEqualStrategy 4 -#define ARRAYCHECK(x) do { \ - if ( ARR_HASNULL(x) ) \ - ereport(ERROR, \ - (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), \ - errmsg("array must not contain null values"))); \ -} while(0) - /* - * Function used as extractValue and extractQuery both + * extractValue support function */ Datum ginarrayextract(PG_FUNCTION_ARGS) { - ArrayType *array; - int32 *nentries = (int32 *) PG_GETARG_POINTER(1); - Datum *entries = NULL; + /* Make copy of array input to ensure it doesn't disappear while in use */ + ArrayType *array = PG_GETARG_ARRAYTYPE_P_COPY(0); + int32 *nkeys = (int32 *) PG_GETARG_POINTER(1); + bool **nullFlags = (bool **) PG_GETARG_POINTER(2); int16 elmlen; bool elmbyval; char elmalign; - - /* - * we should guarantee that array will not be destroyed during all - * operation - */ - array = PG_GETARG_ARRAYTYPE_P_COPY(0); - - ARRAYCHECK(array); + Datum *elems; + bool *nulls; + int nelems; get_typlenbyvalalign(ARR_ELEMTYPE(array), &elmlen, &elmbyval, &elmalign); @@ -58,89 +49,140 @@ ginarrayextract(PG_FUNCTION_ARGS) deconstruct_array(array, ARR_ELEMTYPE(array), elmlen, elmbyval, elmalign, - &entries, NULL, (int *) nentries); + &elems, &nulls, &nelems); - if (*nentries == 0 && PG_NARGS() == 3) - { - switch (PG_GETARG_UINT16(2)) /* StrategyNumber */ - { - case GinOverlapStrategy: - *nentries = -1; /* nobody can be found */ - break; - case GinContainsStrategy: - case GinContainedStrategy: - case GinEqualStrategy: - default: /* require fullscan: GIN can't find void - * arrays */ - break; - } - } + *nkeys = nelems; + *nullFlags = nulls; - /* we should not free array, entries[i] points into it */ - PG_RETURN_POINTER(entries); + /* we should not free array, elems[i] points into it */ + PG_RETURN_POINTER(elems); } +/* + * extractQuery support function + */ Datum ginqueryarrayextract(PG_FUNCTION_ARGS) { - PG_RETURN_DATUM(DirectFunctionCall3(ginarrayextract, - PG_GETARG_DATUM(0), - PG_GETARG_DATUM(1), - PG_GETARG_DATUM(2))); + /* Make copy of array input to ensure it doesn't disappear while in use */ + ArrayType *array = PG_GETARG_ARRAYTYPE_P_COPY(0); + int32 *nkeys = (int32 *) PG_GETARG_POINTER(1); + StrategyNumber strategy = PG_GETARG_UINT16(2); + /* bool **pmatch = (bool **) PG_GETARG_POINTER(3); */ + /* Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4); */ + bool **nullFlags = (bool **) PG_GETARG_POINTER(5); + int32 *searchMode = (int32 *) PG_GETARG_POINTER(6); + int16 elmlen; + bool elmbyval; + char elmalign; + Datum *elems; + bool *nulls; + int nelems; + + get_typlenbyvalalign(ARR_ELEMTYPE(array), + &elmlen, &elmbyval, &elmalign); + + deconstruct_array(array, + ARR_ELEMTYPE(array), + elmlen, elmbyval, elmalign, + &elems, &nulls, &nelems); + + *nkeys = nelems; + *nullFlags = nulls; + + switch (strategy) + { + case GinOverlapStrategy: + *searchMode = GIN_SEARCH_MODE_DEFAULT; + break; + case GinContainsStrategy: + if (nelems > 0) + *searchMode = GIN_SEARCH_MODE_DEFAULT; + else /* everything contains the empty set */ + *searchMode = GIN_SEARCH_MODE_ALL; + break; + case GinContainedStrategy: + /* empty set is contained in everything */ + *searchMode = GIN_SEARCH_MODE_INCLUDE_EMPTY; + break; + case GinEqualStrategy: + if (nelems > 0) + *searchMode = GIN_SEARCH_MODE_DEFAULT; + else + *searchMode = GIN_SEARCH_MODE_INCLUDE_EMPTY; + break; + default: + elog(ERROR, "ginqueryarrayextract: unknown strategy number: %d", + strategy); + } + + /* we should not free array, elems[i] points into it */ + PG_RETURN_POINTER(elems); } +/* + * consistent support function + */ Datum ginarrayconsistent(PG_FUNCTION_ARGS) { bool *check = (bool *) PG_GETARG_POINTER(0); StrategyNumber strategy = PG_GETARG_UINT16(1); - ArrayType *query = PG_GETARG_ARRAYTYPE_P(2); - - /* int32 nkeys = PG_GETARG_INT32(3); */ + /* ArrayType *query = PG_GETARG_ARRAYTYPE_P(2); */ + int32 nkeys = PG_GETARG_INT32(3); /* Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4); */ bool *recheck = (bool *) PG_GETARG_POINTER(5); + /* Datum *queryKeys = (Datum *) PG_GETARG_POINTER(6); */ + bool *nullFlags = (bool *) PG_GETARG_POINTER(7); bool res; - int i, - nentries; - - /* ARRAYCHECK was already done by previous ginarrayextract call */ + int32 i; switch (strategy) { case GinOverlapStrategy: /* result is not lossy */ *recheck = false; - /* at least one element in check[] is true, so result = true */ - res = true; - break; - case GinContainedStrategy: - /* we will need recheck */ - *recheck = true; - /* at least one element in check[] is true, so result = true */ - res = true; + /* must have a match for at least one non-null element */ + res = false; + for (i = 0; i < nkeys; i++) + { + if (check[i] && !nullFlags[i]) + { + res = true; + break; + } + } break; case GinContainsStrategy: /* result is not lossy */ *recheck = false; - /* must have all elements in check[] true */ - nentries = ArrayGetNItems(ARR_NDIM(query), ARR_DIMS(query)); + /* must have all elements in check[] true, and no nulls */ res = true; - for (i = 0; i < nentries; i++) + for (i = 0; i < nkeys; i++) { - if (!check[i]) + if (!check[i] || nullFlags[i]) { res = false; break; } } break; + case GinContainedStrategy: + /* we will need recheck */ + *recheck = true; + /* can't do anything else useful here */ + res = true; + break; case GinEqualStrategy: /* we will need recheck */ *recheck = true; - /* must have all elements in check[] true */ - nentries = ArrayGetNItems(ARR_NDIM(query), ARR_DIMS(query)); + /* + * Must have all elements in check[] true; no discrimination + * against nulls here. This is because array_contain_compare + * and array_eq handle nulls differently ... + */ res = true; - for (i = 0; i < nentries; i++) + for (i = 0; i < nkeys; i++) { if (!check[i]) { |