]> granicus.if.org Git - postgresql/commitdiff
llow negative coordinate for ~> (cube, int) operator
authorTeodor Sigaev <teodor@sigaev.ru>
Thu, 11 Jan 2018 11:49:36 +0000 (14:49 +0300)
committerTeodor Sigaev <teodor@sigaev.ru>
Thu, 11 Jan 2018 11:49:36 +0000 (14:49 +0300)
~> (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

contrib/cube/cube.c
contrib/cube/expected/cube.out
contrib/cube/expected/cube_2.out
contrib/cube/sql/cube.sql
doc/src/sgml/cube.sgml

index dcc0850aa922c9496dedcece913d77fcd863937a..d96ca1ec1fda1aa1997a22ec3b36d7dcf6b4b205 100644 (file)
@@ -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))
        {
index c586a73727d6e9f2e775fc30a0d2c98fe8303571..6378db3004e7264bac5d46ba09e2903f579f3f6e 100644 (file)
@@ -1554,7 +1554,7 @@ SELECT cube(array[40,50,60], array[10,20,30])~>3;
 (1 row)
 
 SELECT cube(array[40,50,60], array[10,20,30])~>0;
-ERROR:  cube index 0 is out of bounds
+ERROR:  zero cube index is not defined
 SELECT cube(array[40,50,60], array[10,20,30])~>4;
  ?column? 
 ----------
@@ -1562,7 +1562,11 @@ SELECT cube(array[40,50,60], array[10,20,30])~>4;
 (1 row)
 
 SELECT cube(array[40,50,60], array[10,20,30])~>(-1);
-ERROR:  cube index -1 is out of bounds
+ ?column? 
+----------
+      -10
+(1 row)
+
 -- Load some example data and build the index
 --
 CREATE TABLE test_cube (c cube);
@@ -1726,6 +1730,86 @@ SELECT c~>4, c FROM test_cube ORDER BY c~>4 LIMIT 15; -- ascending by upper boun
       266 | (22684, 266),(22656, 181)
 (15 rows)
 
+SELECT c~>(-1), c FROM test_cube ORDER BY c~>(-1) LIMIT 15; -- descending by left bound
+ ?column? |               c               
+----------+-------------------------------
+  -100000 | (100000)
+   -49951 | (50027, 49230),(49951, 49214)
+   -49937 | (49980, 35004),(49937, 34963)
+   -49927 | (49985, 6436),(49927, 6338)
+   -49908 | (49999, 27218),(49908, 27176)
+   -49905 | (49954, 1340),(49905, 1294)
+   -49902 | (49944, 25163),(49902, 25153)
+   -49898 | (49981, 34876),(49898, 34786)
+   -49897 | (49957, 43390),(49897, 43384)
+   -49848 | (49853, 18504),(49848, 18503)
+   -49818 | (49902, 41752),(49818, 41746)
+   -49810 | (49907, 30225),(49810, 30158)
+   -49808 | (49843, 5175),(49808, 5145)
+   -49805 | (49887, 24274),(49805, 24184)
+   -49798 | (49847, 7128),(49798, 7067)
+(15 rows)
+
+SELECT c~>(-2), c FROM test_cube ORDER BY c~>(-2) LIMIT 15; -- descending by right bound
+ ?column? |               c               
+----------+-------------------------------
+  -100000 | (100000)
+   -50027 | (50027, 49230),(49951, 49214)
+   -49999 | (49999, 27218),(49908, 27176)
+   -49985 | (49985, 6436),(49927, 6338)
+   -49981 | (49981, 34876),(49898, 34786)
+   -49980 | (49980, 35004),(49937, 34963)
+   -49957 | (49957, 43390),(49897, 43384)
+   -49954 | (49954, 1340),(49905, 1294)
+   -49944 | (49944, 25163),(49902, 25153)
+   -49907 | (49907, 30225),(49810, 30158)
+   -49902 | (49902, 41752),(49818, 41746)
+   -49887 | (49887, 24274),(49805, 24184)
+   -49853 | (49853, 18504),(49848, 18503)
+   -49847 | (49847, 7128),(49798, 7067)
+   -49843 | (49843, 5175),(49808, 5145)
+(15 rows)
+
+SELECT c~>(-3), c FROM test_cube ORDER BY c~>(-3) LIMIT 15; -- descending by lower bound
+ ?column? |               c               
+----------+-------------------------------
+  -100000 | (0, 100000)
+   -49992 | (30746, 50040),(30727, 49992)
+   -49987 | (36311, 50073),(36258, 49987)
+   -49934 | (3531, 49962),(3463, 49934)
+   -49915 | (17954, 49975),(17865, 49915)
+   -49914 | (2168, 50012),(2108, 49914)
+   -49913 | (31287, 49923),(31236, 49913)
+   -49885 | (21551, 49983),(21492, 49885)
+   -49878 | (43925, 49912),(43888, 49878)
+   -49849 | (19128, 49932),(19112, 49849)
+   -49844 | (38266, 49852),(38233, 49844)
+   -49836 | (14913, 49873),(14849, 49836)
+   -49834 | (37595, 49849),(37581, 49834)
+   -49830 | (46151, 49848),(46058, 49830)
+   -49818 | (29261, 49910),(29247, 49818)
+(15 rows)
+
+SELECT c~>(-4), c FROM test_cube ORDER BY c~>(-4) LIMIT 15; -- descending by upper bound
+ ?column? |               c               
+----------+-------------------------------
+  -100000 | (0, 100000)
+   -50073 | (36311, 50073),(36258, 49987)
+   -50040 | (30746, 50040),(30727, 49992)
+   -50012 | (2168, 50012),(2108, 49914)
+   -49983 | (21551, 49983),(21492, 49885)
+   -49975 | (17954, 49975),(17865, 49915)
+   -49962 | (3531, 49962),(3463, 49934)
+   -49932 | (19128, 49932),(19112, 49849)
+   -49923 | (31287, 49923),(31236, 49913)
+   -49912 | (43925, 49912),(43888, 49878)
+   -49910 | (29261, 49910),(29247, 49818)
+   -49873 | (14913, 49873),(14849, 49836)
+   -49858 | (20007, 49858),(19921, 49778)
+   -49852 | (38266, 49852),(38233, 49844)
+   -49849 | (37595, 49849),(37581, 49834)
+(15 rows)
+
 -- Same queries with sequential scan (should give the same results as above)
 RESET enable_seqscan;
 SET enable_indexscan = OFF;
@@ -1839,4 +1923,84 @@ SELECT c~>4, c FROM test_cube ORDER BY c~>4 LIMIT 15; -- ascending by upper boun
       266 | (22684, 266),(22656, 181)
 (15 rows)
 
+SELECT c~>(-1), c FROM test_cube ORDER BY c~>(-1) LIMIT 15; -- descending by left bound
+ ?column? |               c               
+----------+-------------------------------
+  -100000 | (100000)
+   -49951 | (50027, 49230),(49951, 49214)
+   -49937 | (49980, 35004),(49937, 34963)
+   -49927 | (49985, 6436),(49927, 6338)
+   -49908 | (49999, 27218),(49908, 27176)
+   -49905 | (49954, 1340),(49905, 1294)
+   -49902 | (49944, 25163),(49902, 25153)
+   -49898 | (49981, 34876),(49898, 34786)
+   -49897 | (49957, 43390),(49897, 43384)
+   -49848 | (49853, 18504),(49848, 18503)
+   -49818 | (49902, 41752),(49818, 41746)
+   -49810 | (49907, 30225),(49810, 30158)
+   -49808 | (49843, 5175),(49808, 5145)
+   -49805 | (49887, 24274),(49805, 24184)
+   -49798 | (49847, 7128),(49798, 7067)
+(15 rows)
+
+SELECT c~>(-2), c FROM test_cube ORDER BY c~>(-2) LIMIT 15; -- descending by right bound
+ ?column? |               c               
+----------+-------------------------------
+  -100000 | (100000)
+   -50027 | (50027, 49230),(49951, 49214)
+   -49999 | (49999, 27218),(49908, 27176)
+   -49985 | (49985, 6436),(49927, 6338)
+   -49981 | (49981, 34876),(49898, 34786)
+   -49980 | (49980, 35004),(49937, 34963)
+   -49957 | (49957, 43390),(49897, 43384)
+   -49954 | (49954, 1340),(49905, 1294)
+   -49944 | (49944, 25163),(49902, 25153)
+   -49907 | (49907, 30225),(49810, 30158)
+   -49902 | (49902, 41752),(49818, 41746)
+   -49887 | (49887, 24274),(49805, 24184)
+   -49853 | (49853, 18504),(49848, 18503)
+   -49847 | (49847, 7128),(49798, 7067)
+   -49843 | (49843, 5175),(49808, 5145)
+(15 rows)
+
+SELECT c~>(-3), c FROM test_cube ORDER BY c~>(-3) LIMIT 15; -- descending by lower bound
+ ?column? |               c               
+----------+-------------------------------
+  -100000 | (0, 100000)
+   -49992 | (30746, 50040),(30727, 49992)
+   -49987 | (36311, 50073),(36258, 49987)
+   -49934 | (3531, 49962),(3463, 49934)
+   -49915 | (17954, 49975),(17865, 49915)
+   -49914 | (2168, 50012),(2108, 49914)
+   -49913 | (31287, 49923),(31236, 49913)
+   -49885 | (21551, 49983),(21492, 49885)
+   -49878 | (43925, 49912),(43888, 49878)
+   -49849 | (19128, 49932),(19112, 49849)
+   -49844 | (38266, 49852),(38233, 49844)
+   -49836 | (14913, 49873),(14849, 49836)
+   -49834 | (37595, 49849),(37581, 49834)
+   -49830 | (46151, 49848),(46058, 49830)
+   -49818 | (29261, 49910),(29247, 49818)
+(15 rows)
+
+SELECT c~>(-4), c FROM test_cube ORDER BY c~>(-4) LIMIT 15; -- descending by upper bound
+ ?column? |               c               
+----------+-------------------------------
+  -100000 | (0, 100000)
+   -50073 | (36311, 50073),(36258, 49987)
+   -50040 | (30746, 50040),(30727, 49992)
+   -50012 | (2168, 50012),(2108, 49914)
+   -49983 | (21551, 49983),(21492, 49885)
+   -49975 | (17954, 49975),(17865, 49915)
+   -49962 | (3531, 49962),(3463, 49934)
+   -49932 | (19128, 49932),(19112, 49849)
+   -49923 | (31287, 49923),(31236, 49913)
+   -49912 | (43925, 49912),(43888, 49878)
+   -49910 | (29261, 49910),(29247, 49818)
+   -49873 | (14913, 49873),(14849, 49836)
+   -49858 | (20007, 49858),(19921, 49778)
+   -49852 | (38266, 49852),(38233, 49844)
+   -49849 | (37595, 49849),(37581, 49834)
+(15 rows)
+
 RESET enable_indexscan;
index 8c75e27b4654eb45aafbf06546c778b1b66a6b12..75fe405c497f56aae03458ef00aab2310bc6dfc3 100644 (file)
@@ -1554,7 +1554,7 @@ SELECT cube(array[40,50,60], array[10,20,30])~>3;
 (1 row)
 
 SELECT cube(array[40,50,60], array[10,20,30])~>0;
-ERROR:  cube index 0 is out of bounds
+ERROR:  zero cube index is not defined
 SELECT cube(array[40,50,60], array[10,20,30])~>4;
  ?column? 
 ----------
@@ -1562,7 +1562,11 @@ SELECT cube(array[40,50,60], array[10,20,30])~>4;
 (1 row)
 
 SELECT cube(array[40,50,60], array[10,20,30])~>(-1);
-ERROR:  cube index -1 is out of bounds
+ ?column? 
+----------
+      -10
+(1 row)
+
 -- Load some example data and build the index
 --
 CREATE TABLE test_cube (c cube);
@@ -1726,6 +1730,86 @@ SELECT c~>4, c FROM test_cube ORDER BY c~>4 LIMIT 15; -- ascending by upper boun
       266 | (22684, 266),(22656, 181)
 (15 rows)
 
+SELECT c~>(-1), c FROM test_cube ORDER BY c~>(-1) LIMIT 15; -- descending by left bound
+ ?column? |               c               
+----------+-------------------------------
+  -100000 | (100000)
+   -49951 | (50027, 49230),(49951, 49214)
+   -49937 | (49980, 35004),(49937, 34963)
+   -49927 | (49985, 6436),(49927, 6338)
+   -49908 | (49999, 27218),(49908, 27176)
+   -49905 | (49954, 1340),(49905, 1294)
+   -49902 | (49944, 25163),(49902, 25153)
+   -49898 | (49981, 34876),(49898, 34786)
+   -49897 | (49957, 43390),(49897, 43384)
+   -49848 | (49853, 18504),(49848, 18503)
+   -49818 | (49902, 41752),(49818, 41746)
+   -49810 | (49907, 30225),(49810, 30158)
+   -49808 | (49843, 5175),(49808, 5145)
+   -49805 | (49887, 24274),(49805, 24184)
+   -49798 | (49847, 7128),(49798, 7067)
+(15 rows)
+
+SELECT c~>(-2), c FROM test_cube ORDER BY c~>(-2) LIMIT 15; -- descending by right bound
+ ?column? |               c               
+----------+-------------------------------
+  -100000 | (100000)
+   -50027 | (50027, 49230),(49951, 49214)
+   -49999 | (49999, 27218),(49908, 27176)
+   -49985 | (49985, 6436),(49927, 6338)
+   -49981 | (49981, 34876),(49898, 34786)
+   -49980 | (49980, 35004),(49937, 34963)
+   -49957 | (49957, 43390),(49897, 43384)
+   -49954 | (49954, 1340),(49905, 1294)
+   -49944 | (49944, 25163),(49902, 25153)
+   -49907 | (49907, 30225),(49810, 30158)
+   -49902 | (49902, 41752),(49818, 41746)
+   -49887 | (49887, 24274),(49805, 24184)
+   -49853 | (49853, 18504),(49848, 18503)
+   -49847 | (49847, 7128),(49798, 7067)
+   -49843 | (49843, 5175),(49808, 5145)
+(15 rows)
+
+SELECT c~>(-3), c FROM test_cube ORDER BY c~>(-3) LIMIT 15; -- descending by lower bound
+ ?column? |               c               
+----------+-------------------------------
+  -100000 | (0, 100000)
+   -49992 | (30746, 50040),(30727, 49992)
+   -49987 | (36311, 50073),(36258, 49987)
+   -49934 | (3531, 49962),(3463, 49934)
+   -49915 | (17954, 49975),(17865, 49915)
+   -49914 | (2168, 50012),(2108, 49914)
+   -49913 | (31287, 49923),(31236, 49913)
+   -49885 | (21551, 49983),(21492, 49885)
+   -49878 | (43925, 49912),(43888, 49878)
+   -49849 | (19128, 49932),(19112, 49849)
+   -49844 | (38266, 49852),(38233, 49844)
+   -49836 | (14913, 49873),(14849, 49836)
+   -49834 | (37595, 49849),(37581, 49834)
+   -49830 | (46151, 49848),(46058, 49830)
+   -49818 | (29261, 49910),(29247, 49818)
+(15 rows)
+
+SELECT c~>(-4), c FROM test_cube ORDER BY c~>(-4) LIMIT 15; -- descending by upper bound
+ ?column? |               c               
+----------+-------------------------------
+  -100000 | (0, 100000)
+   -50073 | (36311, 50073),(36258, 49987)
+   -50040 | (30746, 50040),(30727, 49992)
+   -50012 | (2168, 50012),(2108, 49914)
+   -49983 | (21551, 49983),(21492, 49885)
+   -49975 | (17954, 49975),(17865, 49915)
+   -49962 | (3531, 49962),(3463, 49934)
+   -49932 | (19128, 49932),(19112, 49849)
+   -49923 | (31287, 49923),(31236, 49913)
+   -49912 | (43925, 49912),(43888, 49878)
+   -49910 | (29261, 49910),(29247, 49818)
+   -49873 | (14913, 49873),(14849, 49836)
+   -49858 | (20007, 49858),(19921, 49778)
+   -49852 | (38266, 49852),(38233, 49844)
+   -49849 | (37595, 49849),(37581, 49834)
+(15 rows)
+
 -- Same queries with sequential scan (should give the same results as above)
 RESET enable_seqscan;
 SET enable_indexscan = OFF;
@@ -1839,4 +1923,84 @@ SELECT c~>4, c FROM test_cube ORDER BY c~>4 LIMIT 15; -- ascending by upper boun
       266 | (22684, 266),(22656, 181)
 (15 rows)
 
+SELECT c~>(-1), c FROM test_cube ORDER BY c~>(-1) LIMIT 15; -- descending by left bound
+ ?column? |               c               
+----------+-------------------------------
+  -100000 | (100000)
+   -49951 | (50027, 49230),(49951, 49214)
+   -49937 | (49980, 35004),(49937, 34963)
+   -49927 | (49985, 6436),(49927, 6338)
+   -49908 | (49999, 27218),(49908, 27176)
+   -49905 | (49954, 1340),(49905, 1294)
+   -49902 | (49944, 25163),(49902, 25153)
+   -49898 | (49981, 34876),(49898, 34786)
+   -49897 | (49957, 43390),(49897, 43384)
+   -49848 | (49853, 18504),(49848, 18503)
+   -49818 | (49902, 41752),(49818, 41746)
+   -49810 | (49907, 30225),(49810, 30158)
+   -49808 | (49843, 5175),(49808, 5145)
+   -49805 | (49887, 24274),(49805, 24184)
+   -49798 | (49847, 7128),(49798, 7067)
+(15 rows)
+
+SELECT c~>(-2), c FROM test_cube ORDER BY c~>(-2) LIMIT 15; -- descending by right bound
+ ?column? |               c               
+----------+-------------------------------
+  -100000 | (100000)
+   -50027 | (50027, 49230),(49951, 49214)
+   -49999 | (49999, 27218),(49908, 27176)
+   -49985 | (49985, 6436),(49927, 6338)
+   -49981 | (49981, 34876),(49898, 34786)
+   -49980 | (49980, 35004),(49937, 34963)
+   -49957 | (49957, 43390),(49897, 43384)
+   -49954 | (49954, 1340),(49905, 1294)
+   -49944 | (49944, 25163),(49902, 25153)
+   -49907 | (49907, 30225),(49810, 30158)
+   -49902 | (49902, 41752),(49818, 41746)
+   -49887 | (49887, 24274),(49805, 24184)
+   -49853 | (49853, 18504),(49848, 18503)
+   -49847 | (49847, 7128),(49798, 7067)
+   -49843 | (49843, 5175),(49808, 5145)
+(15 rows)
+
+SELECT c~>(-3), c FROM test_cube ORDER BY c~>(-3) LIMIT 15; -- descending by lower bound
+ ?column? |               c               
+----------+-------------------------------
+  -100000 | (0, 100000)
+   -49992 | (30746, 50040),(30727, 49992)
+   -49987 | (36311, 50073),(36258, 49987)
+   -49934 | (3531, 49962),(3463, 49934)
+   -49915 | (17954, 49975),(17865, 49915)
+   -49914 | (2168, 50012),(2108, 49914)
+   -49913 | (31287, 49923),(31236, 49913)
+   -49885 | (21551, 49983),(21492, 49885)
+   -49878 | (43925, 49912),(43888, 49878)
+   -49849 | (19128, 49932),(19112, 49849)
+   -49844 | (38266, 49852),(38233, 49844)
+   -49836 | (14913, 49873),(14849, 49836)
+   -49834 | (37595, 49849),(37581, 49834)
+   -49830 | (46151, 49848),(46058, 49830)
+   -49818 | (29261, 49910),(29247, 49818)
+(15 rows)
+
+SELECT c~>(-4), c FROM test_cube ORDER BY c~>(-4) LIMIT 15; -- descending by upper bound
+ ?column? |               c               
+----------+-------------------------------
+  -100000 | (0, 100000)
+   -50073 | (36311, 50073),(36258, 49987)
+   -50040 | (30746, 50040),(30727, 49992)
+   -50012 | (2168, 50012),(2108, 49914)
+   -49983 | (21551, 49983),(21492, 49885)
+   -49975 | (17954, 49975),(17865, 49915)
+   -49962 | (3531, 49962),(3463, 49934)
+   -49932 | (19128, 49932),(19112, 49849)
+   -49923 | (31287, 49923),(31236, 49913)
+   -49912 | (43925, 49912),(43888, 49878)
+   -49910 | (29261, 49910),(29247, 49818)
+   -49873 | (14913, 49873),(14849, 49836)
+   -49858 | (20007, 49858),(19921, 49778)
+   -49852 | (38266, 49852),(38233, 49844)
+   -49849 | (37595, 49849),(37581, 49834)
+(15 rows)
+
 RESET enable_indexscan;
index efa1dbe9e89cf3f5f79bde02e3d553ce1f35e94c..f599e7f7c031180c9fc190f0e982d1705edb52a4 100644 (file)
@@ -403,6 +403,10 @@ SELECT c~>1, c FROM test_cube ORDER BY c~>1 LIMIT 15; -- ascending by left bound
 SELECT c~>2, c FROM test_cube ORDER BY c~>2 LIMIT 15; -- ascending by right bound
 SELECT c~>3, c FROM test_cube ORDER BY c~>3 LIMIT 15; -- ascending by lower bound
 SELECT c~>4, c FROM test_cube ORDER BY c~>4 LIMIT 15; -- ascending by upper bound
+SELECT c~>(-1), c FROM test_cube ORDER BY c~>(-1) LIMIT 15; -- descending by left bound
+SELECT c~>(-2), c FROM test_cube ORDER BY c~>(-2) LIMIT 15; -- descending by right bound
+SELECT c~>(-3), c FROM test_cube ORDER BY c~>(-3) LIMIT 15; -- descending by lower bound
+SELECT c~>(-4), c FROM test_cube ORDER BY c~>(-4) LIMIT 15; -- descending by upper bound
 
 -- Same queries with sequential scan (should give the same results as above)
 RESET enable_seqscan;
@@ -414,4 +418,8 @@ SELECT c~>1, c FROM test_cube ORDER BY c~>1 LIMIT 15; -- ascending by left bound
 SELECT c~>2, c FROM test_cube ORDER BY c~>2 LIMIT 15; -- ascending by right bound
 SELECT c~>3, c FROM test_cube ORDER BY c~>3 LIMIT 15; -- ascending by lower bound
 SELECT c~>4, c FROM test_cube ORDER BY c~>4 LIMIT 15; -- ascending by upper bound
+SELECT c~>(-1), c FROM test_cube ORDER BY c~>(-1) LIMIT 15; -- descending by left bound
+SELECT c~>(-2), c FROM test_cube ORDER BY c~>(-2) LIMIT 15; -- descending by right bound
+SELECT c~>(-3), c FROM test_cube ORDER BY c~>(-3) LIMIT 15; -- descending by lower bound
+SELECT c~>(-4), c FROM test_cube ORDER BY c~>(-4) LIMIT 15; -- descending by upper bound
 RESET enable_indexscan;
index 9cda8cac972f7f38290aa1745d2a1bd3001781dd..e010305d848074a981fd25a8d27c6b14693d9eaa 100644 (file)
         Get <replaceable>n</replaceable>-th coordinate of cube in following way:
         n = 2 * k - 1 means lower bound of <replaceable>k</replaceable>-th
         dimension, n = 2 * k means upper bound of
-        <replaceable>k</replaceable>-th dimension.  This operator is designed
-        for KNN-GiST support.
+        <replaceable>k</replaceable>-th dimension.  Negative
+        <replaceable>n</replaceable> denotes inversed value of corresponding
+        positive coordinate.  This operator is designed for KNN-GiST support.
       </entry>
      </row>