diff options
Diffstat (limited to 'contrib/cube/cube.c')
-rw-r--r-- | contrib/cube/cube.c | 120 |
1 files changed, 95 insertions, 25 deletions
diff --git a/contrib/cube/cube.c b/contrib/cube/cube.c index 3e3d83323c8..dcc0850aa92 100644 --- a/contrib/cube/cube.c +++ b/contrib/cube/cube.c @@ -1337,15 +1337,55 @@ g_cube_distance(PG_FUNCTION_ARGS) if (strategy == CubeKNNDistanceCoord) { + /* + * Handle ordering by ~> operator. See comments of cube_coord_llur() + * for details + */ int coord = PG_GETARG_INT32(1); + bool isLeaf = GistPageIsLeaf(entry->page); - if (DIM(cube) == 0) - retval = 0.0; - else if (IS_POINT(cube)) - retval = cube->x[(coord - 1) % DIM(cube)]; + /* 0 is the only unsupported coordinate value */ + if (coord <= 0) + ereport(ERROR, + (errcode(ERRCODE_ARRAY_ELEMENT_ERROR), + errmsg("cube index %d is out of bounds", coord))); + + if (coord <= 2 * DIM(cube)) + { + /* dimension index */ + int index = (coord - 1) / 2; + /* whether this is upper bound (lower bound otherwise) */ + bool upper = ((coord - 1) % 2 == 1); + + if (IS_POINT(cube)) + { + retval = cube->x[index]; + } + else + { + if (isLeaf) + { + /* For leaf just return required upper/lower bound */ + if (upper) + retval = Max(cube->x[index], cube->x[index + DIM(cube)]); + else + retval = Min(cube->x[index], cube->x[index + DIM(cube)]); + } + else + { + /* + * For non-leaf we should always return lower bound, + * because even upper bound of a child in the subtree can + * be as small as our lower bound. + */ + retval = Min(cube->x[index], cube->x[index + DIM(cube)]); + } + } + } else - retval = Min(cube->x[(coord - 1) % DIM(cube)], - cube->x[(coord - 1) % DIM(cube) + DIM(cube)]); + { + retval = 0.0; + } } else { @@ -1492,43 +1532,73 @@ cube_coord(PG_FUNCTION_ARGS) } -/* - * This function works like cube_coord(), - * but rearranges coordinates of corners to get cube representation - * in the form of (lower left, upper right). - * For historical reasons that extension allows us to create cubes in form - * ((2,1),(1,2)) and instead of normalizing such cube to ((1,1),(2,2)) it - * stores cube in original way. But to get cubes ordered by one of dimensions - * directly from the index without extra sort step we need some - * representation-independent coordinate getter. This function implements it. +/*---- + * This function works like cube_coord(), but rearranges coordinates in the + * way suitable to support coordinate ordering using KNN-GiST. For historical + * reasons this extension allows us to create cubes in form ((2,1),(1,2)) and + * instead of normalizing such cube to ((1,1),(2,2)) it stores cube in original + * way. But in order to get cubes ordered by one of dimensions from the index + * without explicit sort step we need this representation-independent coordinate + * getter. Moreover, indexed dataset may contain cubes of different dimensions + * number. Accordingly, this coordinate getter should be able to return + * lower/upper bound for particular dimension independently on number of cube + * dimensions. + * + * Long story short, this function uses following meaning of coordinates: + * # (2 * N - 1) -- lower bound of Nth dimension, + * # (2 * N) -- upper bound of Nth dimension. + * + * When given coordinate exceeds number of cube dimensions, then 0 returned + * (reproducing logic of GiST indexing of variable-length cubes). */ Datum cube_coord_llur(PG_FUNCTION_ARGS) { NDBOX *cube = PG_GETARG_NDBOX_P(0); int coord = PG_GETARG_INT32(1); + bool inverse = false; + float8 result; - if (coord <= 0 || coord > 2 * DIM(cube)) + /* 0 is the only unsupported coordinate value */ + if (coord <= 0) ereport(ERROR, (errcode(ERRCODE_ARRAY_ELEMENT_ERROR), errmsg("cube index %d is out of bounds", coord))); - if (coord <= DIM(cube)) + if (coord <= 2 * DIM(cube)) { + /* dimension index */ + int index = (coord - 1) / 2; + /* whether this is upper bound (lower bound otherwise) */ + bool upper = ((coord - 1) % 2 == 1); + if (IS_POINT(cube)) - PG_RETURN_FLOAT8(cube->x[coord - 1]); + { + result = cube->x[index]; + } else - PG_RETURN_FLOAT8(Min(cube->x[coord - 1], - cube->x[coord - 1 + DIM(cube)])); + { + if (upper) + result = Max(cube->x[index], cube->x[index + DIM(cube)]); + else + result = Min(cube->x[index], cube->x[index + DIM(cube)]); + } } else { - if (IS_POINT(cube)) - PG_RETURN_FLOAT8(cube->x[(coord - 1) % DIM(cube)]); - else - PG_RETURN_FLOAT8(Max(cube->x[coord - 1], - cube->x[coord - 1 - DIM(cube)])); + /* + * Return zero if coordinate is out of bound. That reproduces logic of + * how cubes with low dimension number are expanded during GiST + * indexing. + */ + result = 0.0; } + + /* Inverse value if needed */ + if (inverse) + result = -result; + + PG_RETURN_FLOAT8(result); } /* Increase or decrease box size by a radius in at least n dimensions. */ |