diff --git a/contrib/cube/cube.c b/contrib/cube/cube.c new file mode 100644 index b770271..d2d67d9 *** a/contrib/cube/cube.c --- b/contrib/cube/cube.c *************** g_cube_distance(PG_FUNCTION_ARGS) *** 1337,1351 **** if (strategy == CubeKNNDistanceCoord) { int coord = PG_GETARG_INT32(1); ! if (DIM(cube) == 0) ! retval = 0.0; ! else if (IS_POINT(cube)) ! retval = cube->x[(coord - 1) % DIM(cube)]; else ! retval = Min(cube->x[(coord - 1) % DIM(cube)], ! cube->x[(coord - 1) % DIM(cube) + DIM(cube)]); } else { --- 1337,1402 ---- 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); + bool inverse = false; ! /* Return inversed value for negative coordinate */ ! if (coord < 0) ! { ! coord = -coord; ! inverse = true; ! } ! ! 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. For inversed case we ! * return upper bound because it becomes lower bound for ! * inversed value. ! */ ! if (!inverse) ! retval = Min(cube->x[index], cube->x[index + DIM(cube)]); ! else ! retval = Max(cube->x[index], cube->x[index + DIM(cube)]); ! } ! } ! } else ! { ! retval = 0.0; ! } ! ! /* Inverse return value if needed */ ! if (inverse) ! retval = -retval; } else { *************** cube_coord(PG_FUNCTION_ARGS) *** 1492,1534 **** } ! /* ! * 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. */ Datum cube_coord_llur(PG_FUNCTION_ARGS) { NDBOX *cube = PG_GETARG_NDBOX_P(0); int coord = PG_GETARG_INT32(1); ! if (coord <= 0 || coord > 2 * DIM(cube)) ereport(ERROR, (errcode(ERRCODE_ARRAY_ELEMENT_ERROR), ! errmsg("cube index %d is out of bounds", coord))); ! if (coord <= DIM(cube)) { if (IS_POINT(cube)) ! PG_RETURN_FLOAT8(cube->x[coord - 1]); else ! PG_RETURN_FLOAT8(Min(cube->x[coord - 1], ! cube->x[coord - 1 + 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)])); } } /* Increase or decrease box size by a radius in at least n dimensions. */ --- 1543,1625 ---- } ! /*---- ! * 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 corrdinate getter should be able to return ! * lower/upper bound for particular dimension independently on number of cube ! * dimenstions. Also, KNN-GiST supports only ascending sorting. In order to ! * support descinding sorting, this function returns inverse of value when ! * negative coordinate is given. ! * ! * Long stoty short, this function uses following meaning of coordinates: ! * # (2 * N - 1) -- lower bound of Nth dimension, ! * # (2 * N) -- upper bound of Nth dimenstion, ! * # - (2 * N - 1) -- negative of lower bound of Nth dimension, ! * # - (2 * N) -- negative of upper bound of Nth dimenstion. ! * ! * 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; ! /* 0 is the only unsupported coordinate value */ ! if (coord == 0) ereport(ERROR, (errcode(ERRCODE_ARRAY_ELEMENT_ERROR), ! 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)) + { + /* 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)) ! { ! result = cube->x[index]; ! } else ! { ! if (upper) ! result = Max(cube->x[index], cube->x[index + DIM(cube)]); ! else ! result = Min(cube->x[index], cube->x[index + DIM(cube)]); ! } } else { ! /* ! * Return zero if coordinate is out of bound. That reproduces logic of ! * how cubes with low dimension number are expanded duing 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. */ diff --git a/contrib/cube/expected/cube.out b/contrib/cube/expected/cube.out new file mode 100644 index 328b3b5..b6a694e *** a/contrib/cube/expected/cube.out --- b/contrib/cube/expected/cube.out *************** SELECT cube(array[40,50,60], array[10,20 *** 1532,1568 **** SELECT cube(array[10,20,30], array[40,50,60])~>2; ?column? ---------- ! 20 (1 row) SELECT cube(array[40,50,60], array[10,20,30])~>2; ?column? ---------- ! 20 (1 row) SELECT cube(array[10,20,30], array[40,50,60])~>3; ?column? ---------- ! 30 (1 row) SELECT cube(array[40,50,60], array[10,20,30])~>3; ?column? ---------- ! 30 (1 row) SELECT cube(array[40,50,60], array[10,20,30])~>0; ! ERROR: cube index 0 is out of bounds SELECT cube(array[40,50,60], array[10,20,30])~>4; ?column? ---------- ! 40 (1 row) SELECT cube(array[40,50,60], array[10,20,30])~>(-1); ! ERROR: cube index -1 is out of bounds -- Load some example data and build the index -- CREATE TABLE test_cube (c cube); --- 1532,1572 ---- SELECT cube(array[10,20,30], array[40,50,60])~>2; ?column? ---------- ! 40 (1 row) SELECT cube(array[40,50,60], array[10,20,30])~>2; ?column? ---------- ! 40 (1 row) SELECT cube(array[10,20,30], array[40,50,60])~>3; ?column? ---------- ! 20 (1 row) SELECT cube(array[40,50,60], array[10,20,30])~>3; ?column? ---------- ! 20 (1 row) SELECT cube(array[40,50,60], array[10,20,30])~>0; ! ERROR: zero cube index is not defined SELECT cube(array[40,50,60], array[10,20,30])~>4; ?column? ---------- ! 50 (1 row) SELECT cube(array[40,50,60], array[10,20,30])~>(-1); ! ?column? ! ---------- ! -10 ! (1 row) ! -- Load some example data and build the index -- CREATE TABLE test_cube (c cube); *************** SELECT * FROM test_cube WHERE c && '(300 *** 1589,1747 **** (2424, 160),(2424, 81) (5 rows) ! -- kNN with index SELECT *, c <-> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <-> '(100, 100),(500, 500)'::cube LIMIT 5; c | dist -------------------------+------------------ (337, 455),(240, 359) | 0 (759, 187),(662, 163) | 162 (948, 1201),(907, 1156) | 772.000647668122 (1444, 403),(1346, 344) | 846 - (369, 1457),(278, 1409) | 909 (5 rows) SELECT *, c <=> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <=> '(100, 100),(500, 500)'::cube LIMIT 5; c | dist -------------------------+------ (337, 455),(240, 359) | 0 (759, 187),(662, 163) | 162 (948, 1201),(907, 1156) | 656 (1444, 403),(1346, 344) | 846 (369, 1457),(278, 1409) | 909 (5 rows) SELECT *, c <#> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <#> '(100, 100),(500, 500)'::cube LIMIT 5; c | dist -------------------------+------ (337, 455),(240, 359) | 0 (759, 187),(662, 163) | 162 (1444, 403),(1346, 344) | 846 (369, 1457),(278, 1409) | 909 - (948, 1201),(907, 1156) | 1063 (5 rows) ! -- kNN-based sorting ! SELECT * FROM test_cube ORDER BY c~>1 LIMIT 15; -- ascending by 1st coordinate of lower left corner ! c ! --------------------------- ! (54, 38679),(3, 38602) ! (83, 10271),(15, 10265) ! (122, 46832),(64, 46762) ! (167, 17214),(92, 17184) ! (161, 24465),(107, 24374) ! (162, 26040),(120, 25963) ! (154, 4019),(138, 3990) ! (259, 1850),(175, 1820) ! (207, 40886),(179, 40879) ! (288, 49588),(204, 49571) ! (270, 32616),(226, 32607) ! (318, 31489),(235, 31404) ! (337, 455),(240, 359) ! (270, 29508),(264, 29440) ! (369, 1457),(278, 1409) (15 rows) ! SELECT * FROM test_cube ORDER BY c~>4 LIMIT 15; -- ascending by 2nd coordinate or upper right corner ! c ! --------------------------- ! (30333, 50),(30273, 6) ! (43301, 75),(43227, 43) ! (19650, 142),(19630, 51) ! (2424, 160),(2424, 81) ! (3449, 171),(3354, 108) ! (18037, 155),(17941, 109) ! (28511, 208),(28479, 114) ! (19946, 217),(19941, 118) ! (16906, 191),(16816, 139) ! (759, 187),(662, 163) ! (22684, 266),(22656, 181) ! (24423, 255),(24360, 213) ! (45989, 249),(45910, 222) ! (11399, 377),(11360, 294) ! (12162, 389),(12103, 309) (15 rows) ! SELECT * FROM test_cube ORDER BY c~>1 DESC LIMIT 15; -- descending by 1st coordinate of lower left corner ! c ! ------------------------------- ! (50027, 49230),(49951, 49214) ! (49980, 35004),(49937, 34963) ! (49985, 6436),(49927, 6338) ! (49999, 27218),(49908, 27176) ! (49954, 1340),(49905, 1294) ! (49944, 25163),(49902, 25153) ! (49981, 34876),(49898, 34786) ! (49957, 43390),(49897, 43384) ! (49853, 18504),(49848, 18503) ! (49902, 41752),(49818, 41746) ! (49907, 30225),(49810, 30158) ! (49843, 5175),(49808, 5145) ! (49887, 24274),(49805, 24184) ! (49847, 7128),(49798, 7067) ! (49820, 7990),(49771, 7967) (15 rows) ! SELECT * FROM test_cube ORDER BY c~>4 DESC LIMIT 15; -- descending by 2nd coordinate or upper right corner ! c ! ------------------------------- ! (36311, 50073),(36258, 49987) ! (30746, 50040),(30727, 49992) ! (2168, 50012),(2108, 49914) ! (21551, 49983),(21492, 49885) ! (17954, 49975),(17865, 49915) ! (3531, 49962),(3463, 49934) ! (19128, 49932),(19112, 49849) ! (31287, 49923),(31236, 49913) ! (43925, 49912),(43888, 49878) ! (29261, 49910),(29247, 49818) ! (14913, 49873),(14849, 49836) ! (20007, 49858),(19921, 49778) ! (38266, 49852),(38233, 49844) ! (37595, 49849),(37581, 49834) ! (46151, 49848),(46058, 49830) (15 rows) ! -- same thing for index with points ! CREATE TABLE test_point(c cube); ! INSERT INTO test_point(SELECT cube(array[c->1,c->2,c->3,c->4]) FROM test_cube); ! CREATE INDEX ON test_point USING gist(c); ! SELECT * FROM test_point ORDER BY c~>1, c~>2 LIMIT 15; -- ascending by 1st then by 2nd coordinate ! c ! -------------------------- ! (54, 38679, 3, 38602) ! (83, 10271, 15, 10265) ! (122, 46832, 64, 46762) ! (154, 4019, 138, 3990) ! (161, 24465, 107, 24374) ! (162, 26040, 120, 25963) ! (167, 17214, 92, 17184) ! (207, 40886, 179, 40879) ! (259, 1850, 175, 1820) ! (270, 29508, 264, 29440) ! (270, 32616, 226, 32607) ! (288, 49588, 204, 49571) ! (318, 31489, 235, 31404) ! (326, 18837, 285, 18817) ! (337, 455, 240, 359) (15 rows) ! SELECT * FROM test_point ORDER BY c~>4 DESC LIMIT 15; -- descending by 1st coordinate ! c ! ------------------------------ ! (30746, 50040, 30727, 49992) ! (36311, 50073, 36258, 49987) ! (3531, 49962, 3463, 49934) ! (17954, 49975, 17865, 49915) ! (2168, 50012, 2108, 49914) ! (31287, 49923, 31236, 49913) ! (21551, 49983, 21492, 49885) ! (43925, 49912, 43888, 49878) ! (19128, 49932, 19112, 49849) ! (38266, 49852, 38233, 49844) ! (14913, 49873, 14849, 49836) ! (37595, 49849, 37581, 49834) ! (46151, 49848, 46058, 49830) ! (29261, 49910, 29247, 49818) ! (19233, 49824, 19185, 49794) (15 rows) --- 1593,1984 ---- (2424, 160),(2424, 81) (5 rows) ! -- Test kNN ! INSERT INTO test_cube VALUES ('(1,1)'), ('(100000)'), ('(0, 100000)'); -- Some corner cases ! SET enable_seqscan = OFF; ! SET enable_indexscan = ON; ! -- Test different metrics SELECT *, c <-> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <-> '(100, 100),(500, 500)'::cube LIMIT 5; c | dist -------------------------+------------------ (337, 455),(240, 359) | 0 + (1, 1) | 140.007142674936 (759, 187),(662, 163) | 162 (948, 1201),(907, 1156) | 772.000647668122 (1444, 403),(1346, 344) | 846 (5 rows) SELECT *, c <=> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <=> '(100, 100),(500, 500)'::cube LIMIT 5; c | dist -------------------------+------ (337, 455),(240, 359) | 0 + (1, 1) | 99 (759, 187),(662, 163) | 162 (948, 1201),(907, 1156) | 656 (1444, 403),(1346, 344) | 846 + (5 rows) + + SELECT *, c <#> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <#> '(100, 100),(500, 500)'::cube LIMIT 5; + c | dist + -------------------------+------ + (337, 455),(240, 359) | 0 + (759, 187),(662, 163) | 162 + (1, 1) | 198 + (1444, 403),(1346, 344) | 846 (369, 1457),(278, 1409) | 909 (5 rows) + -- Test sorting by coordinates + SELECT c~>1, c FROM test_cube ORDER BY c~>1 LIMIT 15; -- ascending by left bound + ?column? | c + ----------+--------------------------- + 0 | (0, 100000) + 1 | (1, 1) + 3 | (54, 38679),(3, 38602) + 15 | (83, 10271),(15, 10265) + 64 | (122, 46832),(64, 46762) + 92 | (167, 17214),(92, 17184) + 107 | (161, 24465),(107, 24374) + 120 | (162, 26040),(120, 25963) + 138 | (154, 4019),(138, 3990) + 175 | (259, 1850),(175, 1820) + 179 | (207, 40886),(179, 40879) + 204 | (288, 49588),(204, 49571) + 226 | (270, 32616),(226, 32607) + 235 | (318, 31489),(235, 31404) + 240 | (337, 455),(240, 359) + (15 rows) + + SELECT c~>2, c FROM test_cube ORDER BY c~>2 LIMIT 15; -- ascending by right bound + ?column? | c + ----------+--------------------------- + 0 | (0, 100000) + 1 | (1, 1) + 54 | (54, 38679),(3, 38602) + 83 | (83, 10271),(15, 10265) + 122 | (122, 46832),(64, 46762) + 154 | (154, 4019),(138, 3990) + 161 | (161, 24465),(107, 24374) + 162 | (162, 26040),(120, 25963) + 167 | (167, 17214),(92, 17184) + 207 | (207, 40886),(179, 40879) + 259 | (259, 1850),(175, 1820) + 270 | (270, 29508),(264, 29440) + 270 | (270, 32616),(226, 32607) + 288 | (288, 49588),(204, 49571) + 318 | (318, 31489),(235, 31404) + (15 rows) + + SELECT c~>3, c FROM test_cube ORDER BY c~>3 LIMIT 15; -- ascending by lower bound + ?column? | c + ----------+--------------------------- + 0 | (100000) + 1 | (1, 1) + 6 | (30333, 50),(30273, 6) + 43 | (43301, 75),(43227, 43) + 51 | (19650, 142),(19630, 51) + 81 | (2424, 160),(2424, 81) + 108 | (3449, 171),(3354, 108) + 109 | (18037, 155),(17941, 109) + 114 | (28511, 208),(28479, 114) + 118 | (19946, 217),(19941, 118) + 139 | (16906, 191),(16816, 139) + 163 | (759, 187),(662, 163) + 181 | (22684, 266),(22656, 181) + 213 | (24423, 255),(24360, 213) + 222 | (45989, 249),(45910, 222) + (15 rows) + + SELECT c~>4, c FROM test_cube ORDER BY c~>4 LIMIT 15; -- ascending by upper bound + ?column? | c + ----------+--------------------------- + 0 | (100000) + 1 | (1, 1) + 50 | (30333, 50),(30273, 6) + 75 | (43301, 75),(43227, 43) + 142 | (19650, 142),(19630, 51) + 155 | (18037, 155),(17941, 109) + 160 | (2424, 160),(2424, 81) + 171 | (3449, 171),(3354, 108) + 187 | (759, 187),(662, 163) + 191 | (16906, 191),(16816, 139) + 208 | (28511, 208),(28479, 114) + 217 | (19946, 217),(19941, 118) + 249 | (45989, 249),(45910, 222) + 255 | (24423, 255),(24360, 213) + 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) + SET enable_seqscan = ON; + SET enable_indexscan = OFF; + SELECT *, c <-> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <-> '(100, 100),(500, 500)'::cube LIMIT 5; + c | dist + -------------------------+------------------ + (337, 455),(240, 359) | 0 + (1, 1) | 140.007142674936 + (759, 187),(662, 163) | 162 + (948, 1201),(907, 1156) | 772.000647668122 + (1444, 403),(1346, 344) | 846 + (5 rows) + + SELECT *, c <=> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <=> '(100, 100),(500, 500)'::cube LIMIT 5; + c | dist + -------------------------+------ + (337, 455),(240, 359) | 0 + (1, 1) | 99 + (759, 187),(662, 163) | 162 + (948, 1201),(907, 1156) | 656 + (1444, 403),(1346, 344) | 846 + (5 rows) + SELECT *, c <#> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <#> '(100, 100),(500, 500)'::cube LIMIT 5; c | dist -------------------------+------ (337, 455),(240, 359) | 0 (759, 187),(662, 163) | 162 + (1, 1) | 198 (1444, 403),(1346, 344) | 846 (369, 1457),(278, 1409) | 909 (5 rows) ! SELECT c~>1, c FROM test_cube ORDER BY c~>1 LIMIT 15; -- ascending by left bound ! ?column? | c ! ----------+--------------------------- ! 0 | (0, 100000) ! 1 | (1, 1) ! 3 | (54, 38679),(3, 38602) ! 15 | (83, 10271),(15, 10265) ! 64 | (122, 46832),(64, 46762) ! 92 | (167, 17214),(92, 17184) ! 107 | (161, 24465),(107, 24374) ! 120 | (162, 26040),(120, 25963) ! 138 | (154, 4019),(138, 3990) ! 175 | (259, 1850),(175, 1820) ! 179 | (207, 40886),(179, 40879) ! 204 | (288, 49588),(204, 49571) ! 226 | (270, 32616),(226, 32607) ! 235 | (318, 31489),(235, 31404) ! 240 | (337, 455),(240, 359) (15 rows) ! SELECT c~>2, c FROM test_cube ORDER BY c~>2 LIMIT 15; -- ascending by right bound ! ?column? | c ! ----------+--------------------------- ! 0 | (0, 100000) ! 1 | (1, 1) ! 54 | (54, 38679),(3, 38602) ! 83 | (83, 10271),(15, 10265) ! 122 | (122, 46832),(64, 46762) ! 154 | (154, 4019),(138, 3990) ! 161 | (161, 24465),(107, 24374) ! 162 | (162, 26040),(120, 25963) ! 167 | (167, 17214),(92, 17184) ! 207 | (207, 40886),(179, 40879) ! 259 | (259, 1850),(175, 1820) ! 270 | (270, 29508),(264, 29440) ! 270 | (270, 32616),(226, 32607) ! 288 | (288, 49588),(204, 49571) ! 318 | (318, 31489),(235, 31404) (15 rows) ! SELECT c~>3, c FROM test_cube ORDER BY c~>3 LIMIT 15; -- ascending by lower bound ! ?column? | c ! ----------+--------------------------- ! 0 | (100000) ! 1 | (1, 1) ! 6 | (30333, 50),(30273, 6) ! 43 | (43301, 75),(43227, 43) ! 51 | (19650, 142),(19630, 51) ! 81 | (2424, 160),(2424, 81) ! 108 | (3449, 171),(3354, 108) ! 109 | (18037, 155),(17941, 109) ! 114 | (28511, 208),(28479, 114) ! 118 | (19946, 217),(19941, 118) ! 139 | (16906, 191),(16816, 139) ! 163 | (759, 187),(662, 163) ! 181 | (22684, 266),(22656, 181) ! 213 | (24423, 255),(24360, 213) ! 222 | (45989, 249),(45910, 222) (15 rows) ! SELECT c~>4, c FROM test_cube ORDER BY c~>4 LIMIT 15; -- ascending by upper bound ! ?column? | c ! ----------+--------------------------- ! 0 | (100000) ! 1 | (1, 1) ! 50 | (30333, 50),(30273, 6) ! 75 | (43301, 75),(43227, 43) ! 142 | (19650, 142),(19630, 51) ! 155 | (18037, 155),(17941, 109) ! 160 | (2424, 160),(2424, 81) ! 171 | (3449, 171),(3354, 108) ! 187 | (759, 187),(662, 163) ! 191 | (16906, 191),(16816, 139) ! 208 | (28511, 208),(28479, 114) ! 217 | (19946, 217),(19941, 118) ! 249 | (45989, 249),(45910, 222) ! 255 | (24423, 255),(24360, 213) ! 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) diff --git a/contrib/cube/expected/cube_2.out b/contrib/cube/expected/cube_2.out new file mode 100644 index 1aa5cf2..c6ce3a3 *** a/contrib/cube/expected/cube_2.out --- b/contrib/cube/expected/cube_2.out *************** SELECT * FROM test_cube WHERE c && '(300 *** 1589,1747 **** (2424, 160),(2424, 81) (5 rows) ! -- kNN with index SELECT *, c <-> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <-> '(100, 100),(500, 500)'::cube LIMIT 5; c | dist -------------------------+------------------ (337, 455),(240, 359) | 0 (759, 187),(662, 163) | 162 (948, 1201),(907, 1156) | 772.000647668122 (1444, 403),(1346, 344) | 846 - (369, 1457),(278, 1409) | 909 (5 rows) SELECT *, c <=> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <=> '(100, 100),(500, 500)'::cube LIMIT 5; c | dist -------------------------+------ (337, 455),(240, 359) | 0 (759, 187),(662, 163) | 162 (948, 1201),(907, 1156) | 656 (1444, 403),(1346, 344) | 846 (369, 1457),(278, 1409) | 909 (5 rows) SELECT *, c <#> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <#> '(100, 100),(500, 500)'::cube LIMIT 5; c | dist -------------------------+------ (337, 455),(240, 359) | 0 (759, 187),(662, 163) | 162 (1444, 403),(1346, 344) | 846 (369, 1457),(278, 1409) | 909 - (948, 1201),(907, 1156) | 1063 (5 rows) ! -- kNN-based sorting ! SELECT * FROM test_cube ORDER BY c~>1 LIMIT 15; -- ascending by 1st coordinate of lower left corner ! c ! --------------------------- ! (54, 38679),(3, 38602) ! (83, 10271),(15, 10265) ! (122, 46832),(64, 46762) ! (167, 17214),(92, 17184) ! (161, 24465),(107, 24374) ! (162, 26040),(120, 25963) ! (154, 4019),(138, 3990) ! (259, 1850),(175, 1820) ! (207, 40886),(179, 40879) ! (288, 49588),(204, 49571) ! (270, 32616),(226, 32607) ! (318, 31489),(235, 31404) ! (337, 455),(240, 359) ! (270, 29508),(264, 29440) ! (369, 1457),(278, 1409) (15 rows) ! SELECT * FROM test_cube ORDER BY c~>4 LIMIT 15; -- ascending by 2nd coordinate or upper right corner ! c ! --------------------------- ! (30333, 50),(30273, 6) ! (43301, 75),(43227, 43) ! (19650, 142),(19630, 51) ! (2424, 160),(2424, 81) ! (3449, 171),(3354, 108) ! (18037, 155),(17941, 109) ! (28511, 208),(28479, 114) ! (19946, 217),(19941, 118) ! (16906, 191),(16816, 139) ! (759, 187),(662, 163) ! (22684, 266),(22656, 181) ! (24423, 255),(24360, 213) ! (45989, 249),(45910, 222) ! (11399, 377),(11360, 294) ! (12162, 389),(12103, 309) (15 rows) ! SELECT * FROM test_cube ORDER BY c~>1 DESC LIMIT 15; -- descending by 1st coordinate of lower left corner ! c ! ------------------------------- ! (50027, 49230),(49951, 49214) ! (49980, 35004),(49937, 34963) ! (49985, 6436),(49927, 6338) ! (49999, 27218),(49908, 27176) ! (49954, 1340),(49905, 1294) ! (49944, 25163),(49902, 25153) ! (49981, 34876),(49898, 34786) ! (49957, 43390),(49897, 43384) ! (49853, 18504),(49848, 18503) ! (49902, 41752),(49818, 41746) ! (49907, 30225),(49810, 30158) ! (49843, 5175),(49808, 5145) ! (49887, 24274),(49805, 24184) ! (49847, 7128),(49798, 7067) ! (49820, 7990),(49771, 7967) (15 rows) ! SELECT * FROM test_cube ORDER BY c~>4 DESC LIMIT 15; -- descending by 2nd coordinate or upper right corner ! c ! ------------------------------- ! (36311, 50073),(36258, 49987) ! (30746, 50040),(30727, 49992) ! (2168, 50012),(2108, 49914) ! (21551, 49983),(21492, 49885) ! (17954, 49975),(17865, 49915) ! (3531, 49962),(3463, 49934) ! (19128, 49932),(19112, 49849) ! (31287, 49923),(31236, 49913) ! (43925, 49912),(43888, 49878) ! (29261, 49910),(29247, 49818) ! (14913, 49873),(14849, 49836) ! (20007, 49858),(19921, 49778) ! (38266, 49852),(38233, 49844) ! (37595, 49849),(37581, 49834) ! (46151, 49848),(46058, 49830) (15 rows) ! -- same thing for index with points ! CREATE TABLE test_point(c cube); ! INSERT INTO test_point(SELECT cube(array[c->1,c->2,c->3,c->4]) FROM test_cube); ! CREATE INDEX ON test_point USING gist(c); ! SELECT * FROM test_point ORDER BY c~>1, c~>2 LIMIT 15; -- ascending by 1st then by 2nd coordinate ! c ! -------------------------- ! (54, 38679, 3, 38602) ! (83, 10271, 15, 10265) ! (122, 46832, 64, 46762) ! (154, 4019, 138, 3990) ! (161, 24465, 107, 24374) ! (162, 26040, 120, 25963) ! (167, 17214, 92, 17184) ! (207, 40886, 179, 40879) ! (259, 1850, 175, 1820) ! (270, 29508, 264, 29440) ! (270, 32616, 226, 32607) ! (288, 49588, 204, 49571) ! (318, 31489, 235, 31404) ! (326, 18837, 285, 18817) ! (337, 455, 240, 359) (15 rows) ! SELECT * FROM test_point ORDER BY c~>4 DESC LIMIT 15; -- descending by 1st coordinate ! c ! ------------------------------ ! (30746, 50040, 30727, 49992) ! (36311, 50073, 36258, 49987) ! (3531, 49962, 3463, 49934) ! (17954, 49975, 17865, 49915) ! (2168, 50012, 2108, 49914) ! (31287, 49923, 31236, 49913) ! (21551, 49983, 21492, 49885) ! (43925, 49912, 43888, 49878) ! (19128, 49932, 19112, 49849) ! (38266, 49852, 38233, 49844) ! (14913, 49873, 14849, 49836) ! (37595, 49849, 37581, 49834) ! (46151, 49848, 46058, 49830) ! (29261, 49910, 29247, 49818) ! (19233, 49824, 19185, 49794) (15 rows) --- 1589,1980 ---- (2424, 160),(2424, 81) (5 rows) ! -- Test kNN ! INSERT INTO test_cube VALUES ('(1,1)'), ('(100000)'), ('(0, 100000)'); -- Some corner cases ! SET enable_seqscan = OFF; ! SET enable_indexscan = ON; ! -- Test different metrics SELECT *, c <-> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <-> '(100, 100),(500, 500)'::cube LIMIT 5; c | dist -------------------------+------------------ (337, 455),(240, 359) | 0 + (1, 1) | 140.007142674936 (759, 187),(662, 163) | 162 (948, 1201),(907, 1156) | 772.000647668122 (1444, 403),(1346, 344) | 846 (5 rows) SELECT *, c <=> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <=> '(100, 100),(500, 500)'::cube LIMIT 5; c | dist -------------------------+------ (337, 455),(240, 359) | 0 + (1, 1) | 99 (759, 187),(662, 163) | 162 (948, 1201),(907, 1156) | 656 (1444, 403),(1346, 344) | 846 + (5 rows) + + SELECT *, c <#> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <#> '(100, 100),(500, 500)'::cube LIMIT 5; + c | dist + -------------------------+------ + (337, 455),(240, 359) | 0 + (759, 187),(662, 163) | 162 + (1, 1) | 198 + (1444, 403),(1346, 344) | 846 (369, 1457),(278, 1409) | 909 (5 rows) + -- Test sorting by coordinates + SELECT c~>1, c FROM test_cube ORDER BY c~>1 LIMIT 15; -- ascending by left bound + ?column? | c + ----------+--------------------------- + 0 | (0, 100000) + 1 | (1, 1) + 3 | (54, 38679),(3, 38602) + 15 | (83, 10271),(15, 10265) + 64 | (122, 46832),(64, 46762) + 92 | (167, 17214),(92, 17184) + 107 | (161, 24465),(107, 24374) + 120 | (162, 26040),(120, 25963) + 138 | (154, 4019),(138, 3990) + 175 | (259, 1850),(175, 1820) + 179 | (207, 40886),(179, 40879) + 204 | (288, 49588),(204, 49571) + 226 | (270, 32616),(226, 32607) + 235 | (318, 31489),(235, 31404) + 240 | (337, 455),(240, 359) + (15 rows) + + SELECT c~>2, c FROM test_cube ORDER BY c~>2 LIMIT 15; -- ascending by right bound + ?column? | c + ----------+--------------------------- + 0 | (0, 100000) + 1 | (1, 1) + 54 | (54, 38679),(3, 38602) + 83 | (83, 10271),(15, 10265) + 122 | (122, 46832),(64, 46762) + 154 | (154, 4019),(138, 3990) + 161 | (161, 24465),(107, 24374) + 162 | (162, 26040),(120, 25963) + 167 | (167, 17214),(92, 17184) + 207 | (207, 40886),(179, 40879) + 259 | (259, 1850),(175, 1820) + 270 | (270, 29508),(264, 29440) + 270 | (270, 32616),(226, 32607) + 288 | (288, 49588),(204, 49571) + 318 | (318, 31489),(235, 31404) + (15 rows) + + SELECT c~>3, c FROM test_cube ORDER BY c~>3 LIMIT 15; -- ascending by lower bound + ?column? | c + ----------+--------------------------- + 0 | (100000) + 1 | (1, 1) + 6 | (30333, 50),(30273, 6) + 43 | (43301, 75),(43227, 43) + 51 | (19650, 142),(19630, 51) + 81 | (2424, 160),(2424, 81) + 108 | (3449, 171),(3354, 108) + 109 | (18037, 155),(17941, 109) + 114 | (28511, 208),(28479, 114) + 118 | (19946, 217),(19941, 118) + 139 | (16906, 191),(16816, 139) + 163 | (759, 187),(662, 163) + 181 | (22684, 266),(22656, 181) + 213 | (24423, 255),(24360, 213) + 222 | (45989, 249),(45910, 222) + (15 rows) + + SELECT c~>4, c FROM test_cube ORDER BY c~>4 LIMIT 15; -- ascending by upper bound + ?column? | c + ----------+--------------------------- + 0 | (100000) + 1 | (1, 1) + 50 | (30333, 50),(30273, 6) + 75 | (43301, 75),(43227, 43) + 142 | (19650, 142),(19630, 51) + 155 | (18037, 155),(17941, 109) + 160 | (2424, 160),(2424, 81) + 171 | (3449, 171),(3354, 108) + 187 | (759, 187),(662, 163) + 191 | (16906, 191),(16816, 139) + 208 | (28511, 208),(28479, 114) + 217 | (19946, 217),(19941, 118) + 249 | (45989, 249),(45910, 222) + 255 | (24423, 255),(24360, 213) + 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) + SET enable_seqscan = ON; + SET enable_indexscan = OFF; + SELECT *, c <-> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <-> '(100, 100),(500, 500)'::cube LIMIT 5; + c | dist + -------------------------+------------------ + (337, 455),(240, 359) | 0 + (1, 1) | 140.007142674936 + (759, 187),(662, 163) | 162 + (948, 1201),(907, 1156) | 772.000647668122 + (1444, 403),(1346, 344) | 846 + (5 rows) + + SELECT *, c <=> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <=> '(100, 100),(500, 500)'::cube LIMIT 5; + c | dist + -------------------------+------ + (337, 455),(240, 359) | 0 + (1, 1) | 99 + (759, 187),(662, 163) | 162 + (948, 1201),(907, 1156) | 656 + (1444, 403),(1346, 344) | 846 + (5 rows) + SELECT *, c <#> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <#> '(100, 100),(500, 500)'::cube LIMIT 5; c | dist -------------------------+------ (337, 455),(240, 359) | 0 (759, 187),(662, 163) | 162 + (1, 1) | 198 (1444, 403),(1346, 344) | 846 (369, 1457),(278, 1409) | 909 (5 rows) ! SELECT c~>1, c FROM test_cube ORDER BY c~>1 LIMIT 15; -- ascending by left bound ! ?column? | c ! ----------+--------------------------- ! 0 | (0, 100000) ! 1 | (1, 1) ! 3 | (54, 38679),(3, 38602) ! 15 | (83, 10271),(15, 10265) ! 64 | (122, 46832),(64, 46762) ! 92 | (167, 17214),(92, 17184) ! 107 | (161, 24465),(107, 24374) ! 120 | (162, 26040),(120, 25963) ! 138 | (154, 4019),(138, 3990) ! 175 | (259, 1850),(175, 1820) ! 179 | (207, 40886),(179, 40879) ! 204 | (288, 49588),(204, 49571) ! 226 | (270, 32616),(226, 32607) ! 235 | (318, 31489),(235, 31404) ! 240 | (337, 455),(240, 359) (15 rows) ! SELECT c~>2, c FROM test_cube ORDER BY c~>2 LIMIT 15; -- ascending by right bound ! ?column? | c ! ----------+--------------------------- ! 0 | (0, 100000) ! 1 | (1, 1) ! 54 | (54, 38679),(3, 38602) ! 83 | (83, 10271),(15, 10265) ! 122 | (122, 46832),(64, 46762) ! 154 | (154, 4019),(138, 3990) ! 161 | (161, 24465),(107, 24374) ! 162 | (162, 26040),(120, 25963) ! 167 | (167, 17214),(92, 17184) ! 207 | (207, 40886),(179, 40879) ! 259 | (259, 1850),(175, 1820) ! 270 | (270, 29508),(264, 29440) ! 270 | (270, 32616),(226, 32607) ! 288 | (288, 49588),(204, 49571) ! 318 | (318, 31489),(235, 31404) (15 rows) ! SELECT c~>3, c FROM test_cube ORDER BY c~>3 LIMIT 15; -- ascending by lower bound ! ?column? | c ! ----------+--------------------------- ! 0 | (100000) ! 1 | (1, 1) ! 6 | (30333, 50),(30273, 6) ! 43 | (43301, 75),(43227, 43) ! 51 | (19650, 142),(19630, 51) ! 81 | (2424, 160),(2424, 81) ! 108 | (3449, 171),(3354, 108) ! 109 | (18037, 155),(17941, 109) ! 114 | (28511, 208),(28479, 114) ! 118 | (19946, 217),(19941, 118) ! 139 | (16906, 191),(16816, 139) ! 163 | (759, 187),(662, 163) ! 181 | (22684, 266),(22656, 181) ! 213 | (24423, 255),(24360, 213) ! 222 | (45989, 249),(45910, 222) (15 rows) ! SELECT c~>4, c FROM test_cube ORDER BY c~>4 LIMIT 15; -- ascending by upper bound ! ?column? | c ! ----------+--------------------------- ! 0 | (100000) ! 1 | (1, 1) ! 50 | (30333, 50),(30273, 6) ! 75 | (43301, 75),(43227, 43) ! 142 | (19650, 142),(19630, 51) ! 155 | (18037, 155),(17941, 109) ! 160 | (2424, 160),(2424, 81) ! 171 | (3449, 171),(3354, 108) ! 187 | (759, 187),(662, 163) ! 191 | (16906, 191),(16816, 139) ! 208 | (28511, 208),(28479, 114) ! 217 | (19946, 217),(19941, 118) ! 249 | (45989, 249),(45910, 222) ! 255 | (24423, 255),(24360, 213) ! 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) diff --git a/contrib/cube/sql/cube.sql b/contrib/cube/sql/cube.sql new file mode 100644 index 58ea3ad..510d5a7 *** a/contrib/cube/sql/cube.sql --- b/contrib/cube/sql/cube.sql *************** SELECT * FROM test_cube WHERE c && '(300 *** 382,401 **** -- Test sorting SELECT * FROM test_cube WHERE c && '(3000,1000),(0,0)' GROUP BY c ORDER BY c; ! -- kNN with index SELECT *, c <-> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <-> '(100, 100),(500, 500)'::cube LIMIT 5; SELECT *, c <=> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <=> '(100, 100),(500, 500)'::cube LIMIT 5; SELECT *, c <#> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <#> '(100, 100),(500, 500)'::cube LIMIT 5; ! -- kNN-based sorting ! SELECT * FROM test_cube ORDER BY c~>1 LIMIT 15; -- ascending by 1st coordinate of lower left corner ! SELECT * FROM test_cube ORDER BY c~>4 LIMIT 15; -- ascending by 2nd coordinate or upper right corner ! SELECT * FROM test_cube ORDER BY c~>1 DESC LIMIT 15; -- descending by 1st coordinate of lower left corner ! SELECT * FROM test_cube ORDER BY c~>4 DESC LIMIT 15; -- descending by 2nd coordinate or upper right corner ! -- same thing for index with points ! CREATE TABLE test_point(c cube); ! INSERT INTO test_point(SELECT cube(array[c->1,c->2,c->3,c->4]) FROM test_cube); ! CREATE INDEX ON test_point USING gist(c); ! SELECT * FROM test_point ORDER BY c~>1, c~>2 LIMIT 15; -- ascending by 1st then by 2nd coordinate ! SELECT * FROM test_point ORDER BY c~>4 DESC LIMIT 15; -- descending by 1st coordinate --- 382,420 ---- -- Test sorting SELECT * FROM test_cube WHERE c && '(3000,1000),(0,0)' GROUP BY c ORDER BY c; ! -- Test kNN ! INSERT INTO test_cube VALUES ('(1,1)'), ('(100000)'), ('(0, 100000)'); -- Some corner cases ! SET enable_seqscan = OFF; ! SET enable_indexscan = ON; ! ! -- Test different metrics SELECT *, c <-> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <-> '(100, 100),(500, 500)'::cube LIMIT 5; SELECT *, c <=> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <=> '(100, 100),(500, 500)'::cube LIMIT 5; SELECT *, c <#> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <#> '(100, 100),(500, 500)'::cube LIMIT 5; ! -- Test sorting by coordinates ! 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) ! SET enable_seqscan = ON; ! SET enable_indexscan = OFF; ! ! SELECT *, c <-> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <-> '(100, 100),(500, 500)'::cube LIMIT 5; ! SELECT *, c <=> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <=> '(100, 100),(500, 500)'::cube LIMIT 5; ! SELECT *, c <#> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <#> '(100, 100),(500, 500)'::cube LIMIT 5; ! ! 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 diff --git a/doc/src/sgml/cube.sgml b/doc/src/sgml/cube.sgml new file mode 100644 index 46d8e4e..65887b1 *** a/doc/src/sgml/cube.sgml --- b/doc/src/sgml/cube.sgml *************** *** 186,195 **** a ~> n float8 ! Get n-th coordinate in normalized cube ! representation, in which the coordinates have been rearranged into ! the form lower left — upper right; that is, the ! smaller endpoint along each dimension appears first. --- 186,197 ---- a ~> n float8 ! Get n-th coordinate of cube in following way: ! n = 2 * k - 1 means lower bound of k-th ! dimension, n = 2 * k means upper bound of ! k-th dimension. Negative ! n denotes inversed value of corresponding ! positive coordinate. This operator is designed for KNN-GiST support.