aboutsummaryrefslogtreecommitdiff
path: root/contrib/cube/cube.c
diff options
context:
space:
mode:
authorTeodor Sigaev <teodor@sigaev.ru>2018-01-11 14:49:36 +0300
committerTeodor Sigaev <teodor@sigaev.ru>2018-01-11 14:49:36 +0300
commitf50c80dbb17efa39c169f6c510e9464486ff5edc (patch)
tree28bd442434d2c59b6f2662e600440a4a30c4374a /contrib/cube/cube.c
parent563a053bdd4b91c5e5560f4bf91220e562326f7d (diff)
downloadpostgresql-f50c80dbb17efa39c169f6c510e9464486ff5edc.tar.gz
postgresql-f50c80dbb17efa39c169f6c510e9464486ff5edc.zip
llow negative coordinate for ~> (cube, int) operator
~> (cube, int) operator was especially designed for knn-gist search. However, knn-gist supports only ascending ordering of results. Nevertheless it would be useful to support descending ordering by ~> (cube, int) operator. We provide workaround for that: negative coordinate give us inversed value of corresponding cube bound. Therefore, knn search using negative coordinate gives us an effect of descending ordering by cube bound. Author: Alexander Korotkov Reviewed by: Tomas Vondra, Andrey Borodin Discussion: https://www.postgresql.org/message-id/flat/a9657f6a-b497-36ff-e56-482a2c7e3292@2ndquadrant.com
Diffstat (limited to 'contrib/cube/cube.c')
-rw-r--r--contrib/cube/cube.c44
1 files changed, 36 insertions, 8 deletions
diff --git a/contrib/cube/cube.c b/contrib/cube/cube.c
index dcc0850aa92..d96ca1ec1fd 100644
--- a/contrib/cube/cube.c
+++ b/contrib/cube/cube.c
@@ -1343,12 +1343,20 @@ g_cube_distance(PG_FUNCTION_ARGS)
*/
int coord = PG_GETARG_INT32(1);
bool isLeaf = GistPageIsLeaf(entry->page);
+ bool inverse = false;
/* 0 is the only unsupported coordinate value */
- if (coord <= 0)
+ if (coord == 0)
ereport(ERROR,
(errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
- errmsg("cube index %d is out of bounds", coord)));
+ errmsg("zero cube index is not defined")));
+
+ /* Return inversed value for negative coordinate */
+ if (coord < 0)
+ {
+ coord = -coord;
+ inverse = true;
+ }
if (coord <= 2 * DIM(cube))
{
@@ -1376,9 +1384,14 @@ g_cube_distance(PG_FUNCTION_ARGS)
/*
* 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.
+ * be as small as our lower bound. For inversed case we
+ * return upper bound because it becomes lower bound for
+ * inversed value.
*/
- retval = Min(cube->x[index], cube->x[index + DIM(cube)]);
+ if (!inverse)
+ retval = Min(cube->x[index], cube->x[index + DIM(cube)]);
+ else
+ retval = Max(cube->x[index], cube->x[index + DIM(cube)]);
}
}
}
@@ -1386,6 +1399,10 @@ g_cube_distance(PG_FUNCTION_ARGS)
{
retval = 0.0;
}
+
+ /* Inverse return value if needed */
+ if (inverse)
+ retval = -retval;
}
else
{
@@ -1542,11 +1559,15 @@ cube_coord(PG_FUNCTION_ARGS)
* 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.
+ * dimensions. Also, KNN-GiST supports only ascending sorting. In order to
+ * support descending sorting, this function returns inverse of value when
+ * negative coordinate is given.
*
* 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.
+ * # (2 * N) -- upper bound of Nth dimension,
+ * # - (2 * N - 1) -- negative of lower bound of Nth dimension,
+ * # - (2 * N) -- negative of 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).
@@ -1560,10 +1581,17 @@ cube_coord_llur(PG_FUNCTION_ARGS)
float8 result;
/* 0 is the only unsupported coordinate value */
- if (coord <= 0)
+ if (coord == 0)
ereport(ERROR,
(errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
- errmsg("cube index %d is out of bounds", coord)));
+ errmsg("zero cube index is not defined")));
+
+ /* Return inversed value for negative coordinate */
+ if (coord < 0)
+ {
+ coord = -coord;
+ inverse = true;
+ }
if (coord <= 2 * DIM(cube))
{