Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Extend cube on-disk format to pack points more tightly.
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>
Mon, 21 Oct 2013 17:59:42 +0000 (20:59 +0300)
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>
Mon, 21 Oct 2013 19:00:15 +0000 (22:00 +0300)
If the lower left and upper right corners of a cube are the same, set a
flag in the cube header, and only store one copy of the coordinates. That
cuts the on-disk size into half for the common case that the cube datatype
is used to represent points rather than boxes.

The new format is backwards-compatible with the old one, so pg_upgrade
still works. However, to get the space savings, the data needs to be
rewritten. A simple VACUUM FULL or REINDEX is not enough, as the old
Datums will just be moved to the new heap/index as is. A pg_dump and
reload, or something similar like casting to text and back, will do the
trick.

This patch deliberately doesn't update all the alternative expected output
files, as I don't have access to machines that produce those outputs. I'm
not sure if they are still relevant, but if they are, the buildfarm will
tell us and produce the diff required to fix it. If none of the buildfarm
animals need them, they should be removed altogether.

Patch by Stas Kelvich.

contrib/cube/cube.c
contrib/cube/cubedata.h
contrib/cube/cubeparse.y
contrib/cube/expected/cube_1.out
contrib/cube/expected/cube_2.out
contrib/cube/sql/cube.sql

index dab0e6e7586e306ecfabb6537789a91f95d656e8..dadda133b91bbf90aff71d0023b36ef8b2fac22b 100644 (file)
@@ -144,6 +144,7 @@ bool        g_cube_internal_consistent(NDBOX *key, NDBOX *query, StrategyNumber strate
 ** Auxiliary funxtions
 */
 static double distance_1D(double a1, double a2, double b1, double b2);
+static bool    cube_is_point_internal(NDBOX *cube);
 
 
 /*****************************************************************************
@@ -181,6 +182,7 @@ cube_a_f8_f8(PG_FUNCTION_ARGS)
    int         i;
    int         dim;
    int         size;
+   bool        point;
    double     *dur,
               *dll;
 
@@ -198,16 +200,32 @@ cube_a_f8_f8(PG_FUNCTION_ARGS)
    dur = ARRPTR(ur);
    dll = ARRPTR(ll);
 
-   size = offsetof(NDBOX, x[0]) +sizeof(double) * 2 * dim;
+   /* Check if it's a point */
+   point = true;
+   for (i = 0; i < dim; i++)
+   {
+       if (dur[i] != dll[i])
+       {
+           point = false;
+           break;
+       }
+   }
+
+   size = point ? POINT_SIZE(dim) : CUBE_SIZE(dim);
    result = (NDBOX *) palloc0(size);
    SET_VARSIZE(result, size);
-   result->dim = dim;
+   SET_DIM(result, dim);
 
    for (i = 0; i < dim; i++)
-   {
        result->x[i] = dur[i];
-       result->x[i + dim] = dll[i];
+
+   if (!point)
+   {
+       for (i = 0; i < dim; i++)
+           result->x[i + dim] = dll[i];
    }
+   else
+       SET_POINT_BIT(result);
 
    PG_RETURN_NDBOX(result);
 }
@@ -234,16 +252,14 @@ cube_a_f8(PG_FUNCTION_ARGS)
 
    dur = ARRPTR(ur);
 
-   size = offsetof(NDBOX, x[0]) +sizeof(double) * 2 * dim;
+   size = POINT_SIZE(dim);
    result = (NDBOX *) palloc0(size);
    SET_VARSIZE(result, size);
-   result->dim = dim;
+   SET_DIM(result, dim);
+   SET_POINT_BIT(result);
 
    for (i = 0; i < dim; i++)
-   {
        result->x[i] = dur[i];
-       result->x[i + dim] = dur[i];
-   }
 
    PG_RETURN_NDBOX(result);
 }
@@ -267,14 +283,17 @@ cube_subset(PG_FUNCTION_ARGS)
    dx = (int32 *) ARR_DATA_PTR(idx);
 
    dim = ARRNELEMS(idx);
-   size = offsetof(NDBOX, x[0]) +sizeof(double) * 2 * dim;
+   size = IS_POINT(c) ? POINT_SIZE(dim) : CUBE_SIZE(dim);
    result = (NDBOX *) palloc0(size);
    SET_VARSIZE(result, size);
-   result->dim = dim;
+   SET_DIM(result, dim);
+
+   if (IS_POINT(c))
+       SET_POINT_BIT(result);
 
    for (i = 0; i < dim; i++)
    {
-       if ((dx[i] <= 0) || (dx[i] > c->dim))
+       if ((dx[i] <= 0) || (dx[i] > DIM(c)))
        {
            pfree(result);
            ereport(ERROR,
@@ -282,7 +301,8 @@ cube_subset(PG_FUNCTION_ARGS)
                     errmsg("Index out of bounds")));
        }
        result->x[i] = c->x[dx[i] - 1];
-       result->x[i + dim] = c->x[dx[i] + c->dim - 1];
+       if (!IS_POINT(c))
+           result->x[i + dim] = c->x[dx[i] + DIM(c) - 1];
    }
 
    PG_FREE_IF_COPY(c, 0);
@@ -294,8 +314,7 @@ cube_out(PG_FUNCTION_ARGS)
 {
    NDBOX      *cube = PG_GETARG_NDBOX(0);
    StringInfoData buf;
-   int         dim = cube->dim;
-   bool        equal = true;
+   int         dim = DIM(cube);
    int         i;
    int         ndig;
 
@@ -317,20 +336,18 @@ cube_out(PG_FUNCTION_ARGS)
    {
        if (i > 0)
            appendStringInfo(&buf, ", ");
-       appendStringInfo(&buf, "%.*g", ndig, cube->x[i]);
-       if (cube->x[i] != cube->x[i + dim])
-           equal = false;
+       appendStringInfo(&buf, "%.*g", ndig, LL_COORD(cube, i));
    }
    appendStringInfoChar(&buf, ')');
 
-   if (!equal)
+   if (!cube_is_point_internal(cube))
    {
        appendStringInfo(&buf, ",(");
        for (i = 0; i < dim; i++)
        {
            if (i > 0)
                appendStringInfo(&buf, ", ");
-           appendStringInfo(&buf, "%.*g", ndig, cube->x[i + dim]);
+           appendStringInfo(&buf, "%.*g", ndig, UR_COORD(cube, i));
        }
        appendStringInfoChar(&buf, ')');
    }
@@ -729,51 +746,60 @@ cube_union_v0(NDBOX *a, NDBOX *b)
 {
    int         i;
    NDBOX      *result;
+   int         dim;
+   int         size;
 
-   if (a->dim >= b->dim)
-   {
-       result = palloc0(VARSIZE(a));
-       SET_VARSIZE(result, VARSIZE(a));
-       result->dim = a->dim;
-   }
-   else
-   {
-       result = palloc0(VARSIZE(b));
-       SET_VARSIZE(result, VARSIZE(b));
-       result->dim = b->dim;
-   }
+   /* trivial case */
+   if (a == b)
+       return a;
 
-   /* swap the box pointers if needed */
-   if (a->dim < b->dim)
+   /* swap the arguments if needed, so that 'a' is always larger than 'b' */
+   if (DIM(a) < DIM(b))
    {
        NDBOX      *tmp = b;
 
        b = a;
        a = tmp;
    }
+   dim = DIM(a);
 
-   /*
-    * use the potentially smaller of the two boxes (b) to fill in the result,
-    * padding absent dimensions with zeroes
-    */
-   for (i = 0; i < b->dim; i++)
+   size = CUBE_SIZE(dim);
+   result = palloc0(size);
+   SET_VARSIZE(result, size);
+   SET_DIM(result, dim);
+
+    /* First compute the union of the dimensions present in both args */
+   for (i = 0; i < DIM(b); i++)
    {
-       result->x[i] = Min(b->x[i], b->x[i + b->dim]);
-       result->x[i + a->dim] = Max(b->x[i], b->x[i + b->dim]);
+       result->x[i] = Min(
+           Min(LL_COORD(a, i), UR_COORD(a, i)),
+           Min(LL_COORD(b, i), UR_COORD(b, i))
+       );
+       result->x[i + DIM(a)] = Max(
+           Max(LL_COORD(a, i), UR_COORD(a, i)),
+           Max(LL_COORD(b, i), UR_COORD(b, i))
+       );
    }
-   for (i = b->dim; i < a->dim; i++)
+   /* continue on the higher dimensions only present in 'a' */
+   for (; i < DIM(a); i++)
    {
-       result->x[i] = 0;
-       result->x[i + a->dim] = 0;
+       result->x[i] = Min(0,
+           Min(LL_COORD(a, i), UR_COORD(a, i))
+       );
+       result->x[i + dim] = Max(0,
+           Max(LL_COORD(a, i), UR_COORD(a, i))
+       );
    }
 
-   /* compute the union */
-   for (i = 0; i < a->dim; i++)
+   /*
+    * Check if the result was in fact a point, and set the flag in the datum
+    * accordingly. (we don't bother to repalloc it smaller)
+    */
+   if (cube_is_point_internal(result))
    {
-       result->x[i] =
-           Min(Min(a->x[i], a->x[i + a->dim]), result->x[i]);
-       result->x[i + a->dim] = Max(Max(a->x[i],
-                                  a->x[i + a->dim]), result->x[i + a->dim]);
+       size = POINT_SIZE(dim);
+       SET_VARSIZE(result, size);
+       SET_POINT_BIT(result);
    }
 
    return (result);
@@ -802,52 +828,57 @@ cube_inter(PG_FUNCTION_ARGS)
    NDBOX      *result;
    bool        swapped = false;
    int         i;
+   int         dim;
+   int         size;
 
-   if (a->dim >= b->dim)
-   {
-       result = palloc0(VARSIZE(a));
-       SET_VARSIZE(result, VARSIZE(a));
-       result->dim = a->dim;
-   }
-   else
-   {
-       result = palloc0(VARSIZE(b));
-       SET_VARSIZE(result, VARSIZE(b));
-       result->dim = b->dim;
-   }
-
-   /* swap the box pointers if needed */
-   if (a->dim < b->dim)
+   /* swap the arguments if needed, so that 'a' is always larger than 'b' */
+   if (DIM(a) < DIM(b))
    {
        NDBOX      *tmp = b;
-
        b = a;
        a = tmp;
        swapped = true;
    }
+   dim = DIM(a);
 
-   /*
-    * use the potentially  smaller of the two boxes (b) to fill in the
-    * result, padding absent dimensions with zeroes
-    */
-   for (i = 0; i < b->dim; i++)
+   size = CUBE_SIZE(dim);
+   result = (NDBOX *) palloc0(size);
+   SET_VARSIZE(result, size);
+   SET_DIM(result, dim);
+
+    /* First compute intersection of the dimensions present in both args */
+   for (i = 0; i < DIM(b); i++)
    {
-       result->x[i] = Min(b->x[i], b->x[i + b->dim]);
-       result->x[i + a->dim] = Max(b->x[i], b->x[i + b->dim]);
+       result->x[i] = Max(
+           Min(LL_COORD(a, i), UR_COORD(a, i)),
+           Min(LL_COORD(b, i), UR_COORD(b, i))
+       );
+       result->x[i + DIM(a)] = Min(
+           Max(LL_COORD(a, i), UR_COORD(a, i)),
+           Max(LL_COORD(b, i), UR_COORD(b, i))
+       );
    }
-   for (i = b->dim; i < a->dim; i++)
+   /* continue on the higher dimemsions only present in 'a' */
+   for (; i < DIM(a); i++)
    {
-       result->x[i] = 0;
-       result->x[i + a->dim] = 0;
+       result->x[i] = Max(0,
+           Min(LL_COORD(a, i), UR_COORD(a, i))
+       );
+       result->x[i + DIM(a)] = Min(0,
+           Max(LL_COORD(a, i), UR_COORD(a, i))
+       );
    }
 
-   /* compute the intersection */
-   for (i = 0; i < a->dim; i++)
+   /*
+    * Check if the result was in fact a point, and set the flag in the datum
+    * accordingly. (we don't bother to repalloc it smaller)
+    */
+   if (cube_is_point_internal(result))
    {
-       result->x[i] =
-           Max(Min(a->x[i], a->x[i + a->dim]), result->x[i]);
-       result->x[i + a->dim] = Min(Max(a->x[i],
-                                  a->x[i + a->dim]), result->x[i + a->dim]);
+       size = POINT_SIZE(dim);
+       result = repalloc(result, size);
+       SET_VARSIZE(result, size);
+       SET_POINT_BIT(result);
    }
 
    if (swapped)
@@ -873,12 +904,11 @@ cube_size(PG_FUNCTION_ARGS)
 {
    NDBOX      *a = PG_GETARG_NDBOX(0);
    double      result;
-   int         i,
-               j;
+   int         i;
 
    result = 1.0;
-   for (i = 0, j = a->dim; i < a->dim; i++, j++)
-       result = result * Abs((a->x[j] - a->x[i]));
+   for (i = 0; i < DIM(a); i++)
+       result = result * Abs((LL_COORD(a, i) - UR_COORD(a, i)));
 
    PG_FREE_IF_COPY(a, 0);
    PG_RETURN_FLOAT8(result);
@@ -887,16 +917,15 @@ cube_size(PG_FUNCTION_ARGS)
 void
 rt_cube_size(NDBOX *a, double *size)
 {
-   int         i,
-               j;
+   int         i;
 
    if (a == (NDBOX *) NULL)
        *size = 0.0;
    else
    {
        *size = 1.0;
-       for (i = 0, j = a->dim; i < a->dim; i++, j++)
-           *size = (*size) * Abs((a->x[j] - a->x[i]));
+       for (i = 0; i < DIM(a); i++)
+           *size = (*size) * Abs(UR_COORD(a, i) - LL_COORD(a, i));
    }
    return;
 }
@@ -909,43 +938,43 @@ cube_cmp_v0(NDBOX *a, NDBOX *b)
    int         i;
    int         dim;
 
-   dim = Min(a->dim, b->dim);
+   dim = Min(DIM(a), DIM(b));
 
    /* compare the common dimensions */
    for (i = 0; i < dim; i++)
    {
-       if (Min(a->x[i], a->x[a->dim + i]) >
-           Min(b->x[i], b->x[b->dim + i]))
+       if (Min(LL_COORD(a, i), UR_COORD(a, i)) >
+           Min(LL_COORD(b, i), UR_COORD(b, i)))
            return 1;
-       if (Min(a->x[i], a->x[a->dim + i]) <
-           Min(b->x[i], b->x[b->dim + i]))
+       if (Min(LL_COORD(a, i), UR_COORD(a, i)) <
+           Min(LL_COORD(b, i), UR_COORD(b, i)))
            return -1;
    }
    for (i = 0; i < dim; i++)
    {
-       if (Max(a->x[i], a->x[a->dim + i]) >
-           Max(b->x[i], b->x[b->dim + i]))
+       if (Max(LL_COORD(a, i), UR_COORD(a, i)) >
+           Max(LL_COORD(b, i), UR_COORD(b, i)))
            return 1;
-       if (Max(a->x[i], a->x[a->dim + i]) <
-           Max(b->x[i], b->x[b->dim + i]))
+       if (Max(LL_COORD(a, i), UR_COORD(a, i)) <
+           Max(LL_COORD(b, i), UR_COORD(b, i)))
            return -1;
    }
 
    /* compare extra dimensions to zero */
-   if (a->dim > b->dim)
+   if (DIM(a) > DIM(b))
    {
-       for (i = dim; i < a->dim; i++)
+       for (i = dim; i < DIM(a); i++)
        {
-           if (Min(a->x[i], a->x[a->dim + i]) > 0)
+           if (Min(LL_COORD(a, i), UR_COORD(a, i)) > 0)
                return 1;
-           if (Min(a->x[i], a->x[a->dim + i]) < 0)
+           if (Min(LL_COORD(a, i), UR_COORD(a, i)) < 0)
                return -1;
        }
-       for (i = dim; i < a->dim; i++)
+       for (i = dim; i < DIM(a); i++)
        {
-           if (Max(a->x[i], a->x[a->dim + i]) > 0)
+           if (Max(LL_COORD(a, i), UR_COORD(a, i)) > 0)
                return 1;
-           if (Max(a->x[i], a->x[a->dim + i]) < 0)
+           if (Max(LL_COORD(a, i), UR_COORD(a, i)) < 0)
                return -1;
        }
 
@@ -955,20 +984,20 @@ cube_cmp_v0(NDBOX *a, NDBOX *b)
         */
        return 1;
    }
-   if (a->dim < b->dim)
+   if (DIM(a) < DIM(b))
    {
-       for (i = dim; i < b->dim; i++)
+       for (i = dim; i < DIM(b); i++)
        {
-           if (Min(b->x[i], b->x[b->dim + i]) > 0)
+           if (Min(LL_COORD(b, i), UR_COORD(b, i)) > 0)
                return -1;
-           if (Min(b->x[i], b->x[b->dim + i]) < 0)
+           if (Min(LL_COORD(b, i), UR_COORD(b, i)) < 0)
                return 1;
        }
-       for (i = dim; i < b->dim; i++)
+       for (i = dim; i < DIM(b); i++)
        {
-           if (Max(b->x[i], b->x[b->dim + i]) > 0)
+           if (Max(LL_COORD(b, i), UR_COORD(b, i)) > 0)
                return -1;
-           if (Max(b->x[i], b->x[b->dim + i]) < 0)
+           if (Max(LL_COORD(b, i), UR_COORD(b, i)) < 0)
                return 1;
        }
 
@@ -1098,30 +1127,30 @@ cube_contains_v0(NDBOX *a, NDBOX *b)
    if ((a == NULL) || (b == NULL))
        return (FALSE);
 
-   if (a->dim < b->dim)
+   if (DIM(a) < DIM(b))
    {
        /*
         * the further comparisons will make sense if the excess dimensions of
         * (b) were zeroes Since both UL and UR coordinates must be zero, we
         * can check them all without worrying about which is which.
         */
-       for (i = a->dim; i < b->dim; i++)
+       for (i = DIM(a); i < DIM(b); i++)
        {
-           if (b->x[i] != 0)
+           if (LL_COORD(b, i) != 0)
                return (FALSE);
-           if (b->x[i + b->dim] != 0)
+           if (UR_COORD(b, i) != 0)
                return (FALSE);
        }
    }
 
    /* Can't care less about the excess dimensions of (a), if any */
-   for (i = 0; i < Min(a->dim, b->dim); i++)
+   for (i = 0; i < Min(DIM(a), DIM(b)); i++)
    {
-       if (Min(a->x[i], a->x[a->dim + i]) >
-           Min(b->x[i], b->x[b->dim + i]))
+       if (Min(LL_COORD(a, i), UR_COORD(a, i)) >
+           Min(LL_COORD(b, i), UR_COORD(b, i)))
            return (FALSE);
-       if (Max(a->x[i], a->x[a->dim + i]) <
-           Max(b->x[i], b->x[b->dim + i]))
+       if (Max(LL_COORD(a, i), UR_COORD(a, i)) <
+           Max(LL_COORD(b, i), UR_COORD(b, i)))
            return (FALSE);
    }
 
@@ -1173,7 +1202,7 @@ cube_overlap_v0(NDBOX *a, NDBOX *b)
        return (FALSE);
 
    /* swap the box pointers if needed */
-   if (a->dim < b->dim)
+   if (DIM(a) < DIM(b))
    {
        NDBOX      *tmp = b;
 
@@ -1182,22 +1211,20 @@ cube_overlap_v0(NDBOX *a, NDBOX *b)
    }
 
    /* compare within the dimensions of (b) */
-   for (i = 0; i < b->dim; i++)
+   for (i = 0; i < DIM(b); i++)
    {
-       if (Min(a->x[i], a->x[a->dim + i]) >
-           Max(b->x[i], b->x[b->dim + i]))
+       if (Min(LL_COORD(a, i), UR_COORD(a, i)) > Max(LL_COORD(b, i), UR_COORD(b, i)))
            return (FALSE);
-       if (Max(a->x[i], a->x[a->dim + i]) <
-           Min(b->x[i], b->x[b->dim + i]))
+       if (Max(LL_COORD(a, i), UR_COORD(a, i)) < Min(LL_COORD(b, i), UR_COORD(b, i)))
            return (FALSE);
    }
 
    /* compare to zero those dimensions in (a) absent in (b) */
-   for (i = b->dim; i < a->dim; i++)
+   for (i = DIM(b); i < DIM(a); i++)
    {
-       if (Min(a->x[i], a->x[a->dim + i]) > 0)
+       if (Min(LL_COORD(a, i), UR_COORD(a, i)) > 0)
            return (FALSE);
-       if (Max(a->x[i], a->x[a->dim + i]) < 0)
+       if (Max(LL_COORD(a, i), UR_COORD(a, i)) < 0)
            return (FALSE);
    }
 
@@ -1236,7 +1263,7 @@ cube_distance(PG_FUNCTION_ARGS)
    int         i;
 
    /* swap the box pointers if needed */
-   if (a->dim < b->dim)
+   if (DIM(a) < DIM(b))
    {
        NDBOX      *tmp = b;
 
@@ -1247,16 +1274,16 @@ cube_distance(PG_FUNCTION_ARGS)
 
    distance = 0.0;
    /* compute within the dimensions of (b) */
-   for (i = 0; i < b->dim; i++)
+   for (i = 0; i < DIM(b); i++)
    {
-       d = distance_1D(a->x[i], a->x[i + a->dim], b->x[i], b->x[i + b->dim]);
+       d = distance_1D(LL_COORD(a,i), UR_COORD(a,i), LL_COORD(b,i), UR_COORD(b,i));
        distance += d * d;
    }
 
    /* compute distance to zero for those dimensions in (a) absent in (b) */
-   for (i = b->dim; i < a->dim; i++)
+   for (i = DIM(b); i < DIM(a); i++)
    {
-       d = distance_1D(a->x[i], a->x[i + a->dim], 0.0, 0.0);
+       d = distance_1D(LL_COORD(a,i), UR_COORD(a,i), 0.0, 0.0);
        distance += d * d;
    }
 
@@ -1293,18 +1320,35 @@ distance_1D(double a1, double a2, double b1, double b2)
 Datum
 cube_is_point(PG_FUNCTION_ARGS)
 {
-   NDBOX      *a = PG_GETARG_NDBOX(0);
-   int         i,
-               j;
+   NDBOX      *cube = PG_GETARG_NDBOX(0);
+   bool        result;
+
+   result = cube_is_point_internal(cube);
+   PG_FREE_IF_COPY(cube, 0);
+   PG_RETURN_BOOL(result);
+}
 
-   for (i = 0, j = a->dim; i < a->dim; i++, j++)
+static bool
+cube_is_point_internal(NDBOX *cube)
+{
+   int         i;
+
+   if (IS_POINT(cube))
+       return true;
+
+   /*
+    * Even if the point-flag is not set, all the lower-left coordinates
+    * might match the upper-right coordinates, so that the value is in
+    * fact a point. Such values don't arise with current code - the point
+    * flag is always set if appropriate - but they might be present on-disk
+    * in clusters upgraded from pre-9.4 versions.
+    */
+   for (i = 0; i < DIM(cube); i++)
    {
-       if (a->x[i] != a->x[j])
-           PG_RETURN_BOOL(FALSE);
+       if (LL_COORD(cube, i) != UR_COORD(cube, i))
+           return false;
    }
-
-   PG_FREE_IF_COPY(a, 0);
-   PG_RETURN_BOOL(TRUE);
+   return true;
 }
 
 /* Return dimensions in use in the data structure */
@@ -1312,8 +1356,7 @@ Datum
 cube_dim(PG_FUNCTION_ARGS)
 {
    NDBOX      *c = PG_GETARG_NDBOX(0);
-   int         dim = c->dim;
-
+   int         dim = DIM(c);
    PG_FREE_IF_COPY(c, 0);
    PG_RETURN_INT32(dim);
 }
@@ -1326,8 +1369,8 @@ cube_ll_coord(PG_FUNCTION_ARGS)
    int         n = PG_GETARG_INT16(1);
    double      result;
 
-   if (c->dim >= n && n > 0)
-       result = Min(c->x[n - 1], c->x[c->dim + n - 1]);
+   if (DIM(c) >= n && n > 0)
+       result = Min(LL_COORD(c, n-1), UR_COORD(c, n-1));
    else
        result = 0;
 
@@ -1343,8 +1386,8 @@ cube_ur_coord(PG_FUNCTION_ARGS)
    int         n = PG_GETARG_INT16(1);
    double      result;
 
-   if (c->dim >= n && n > 0)
-       result = Max(c->x[n - 1], c->x[c->dim + n - 1]);
+   if (DIM(c) >= n && n > 0)
+       result = Max(LL_COORD(c, n-1), UR_COORD(c, n-1));
    else
        result = 0;
 
@@ -1363,30 +1406,31 @@ cube_enlarge(PG_FUNCTION_ARGS)
    int         dim = 0;
    int         size;
    int         i,
-               j,
-               k;
+               j;
 
    if (n > CUBE_MAX_DIM)
        n = CUBE_MAX_DIM;
    if (r > 0 && n > 0)
        dim = n;
-   if (a->dim > dim)
-       dim = a->dim;
-   size = offsetof(NDBOX, x[0]) +sizeof(double) * dim * 2;
+   if (DIM(a) > dim)
+       dim = DIM(a);
+
+   size = CUBE_SIZE(dim);
    result = (NDBOX *) palloc0(size);
    SET_VARSIZE(result, size);
-   result->dim = dim;
-   for (i = 0, j = dim, k = a->dim; i < a->dim; i++, j++, k++)
+   SET_DIM(result, dim);
+
+   for (i = 0, j = dim; i < DIM(a); i++, j++)
    {
-       if (a->x[i] >= a->x[k])
+       if (LL_COORD(a,i) >= UR_COORD(a,i))
        {
-           result->x[i] = a->x[k] - r;
-           result->x[j] = a->x[i] + r;
+           result->x[i] = UR_COORD(a,i) - r;
+           result->x[j] = LL_COORD(a,i) + r;
        }
        else
        {
-           result->x[i] = a->x[i] - r;
-           result->x[j] = a->x[k] + r;
+           result->x[i] = LL_COORD(a,i) - r;
+           result->x[j] = UR_COORD(a,i) + r;
        }
        if (result->x[i] > result->x[j])
        {
@@ -1401,6 +1445,17 @@ cube_enlarge(PG_FUNCTION_ARGS)
        result->x[j] = r;
    }
 
+   /*
+    * Check if the result was in fact a point, and set the flag in the datum
+    * accordingly. (we don't bother to repalloc it smaller)
+    */
+   if (cube_is_point_internal(result))
+   {
+       size = POINT_SIZE(dim);
+       SET_VARSIZE(result, size);
+       SET_POINT_BIT(result);
+   }
+
    PG_FREE_IF_COPY(a, 0);
    PG_RETURN_NDBOX(result);
 }
@@ -1413,11 +1468,12 @@ cube_f8(PG_FUNCTION_ARGS)
    NDBOX      *result;
    int         size;
 
-   size = offsetof(NDBOX, x[0]) +sizeof(double) * 2;
+   size = POINT_SIZE(1);
    result = (NDBOX *) palloc0(size);
    SET_VARSIZE(result, size);
-   result->dim = 1;
-   result->x[0] = result->x[1] = x;
+   SET_DIM(result, 1);
+   SET_POINT_BIT(result);
+   result->x[0] = x;
 
    PG_RETURN_NDBOX(result);
 }
@@ -1431,12 +1487,24 @@ cube_f8_f8(PG_FUNCTION_ARGS)
    NDBOX      *result;
    int         size;
 
-   size = offsetof(NDBOX, x[0]) +sizeof(double) * 2;
-   result = (NDBOX *) palloc0(size);
-   SET_VARSIZE(result, size);
-   result->dim = 1;
-   result->x[0] = x0;
-   result->x[1] = x1;
+   if (x0 == x1)
+   {
+       size = POINT_SIZE(1);
+       result = (NDBOX *) palloc0(size);
+       SET_VARSIZE(result, size);
+       SET_DIM(result, 1);
+       SET_POINT_BIT(result);
+       result->x[0] = x0;
+   }
+   else
+   {
+       size = CUBE_SIZE(1);
+       result = (NDBOX *) palloc0(size);
+       SET_VARSIZE(result, size);
+       SET_DIM(result, 1);
+       result->x[0] = x0;
+       result->x[1] = x1;
+   }
 
    PG_RETURN_NDBOX(result);
 }
@@ -1446,25 +1514,39 @@ cube_f8_f8(PG_FUNCTION_ARGS)
 Datum
 cube_c_f8(PG_FUNCTION_ARGS)
 {
-   NDBOX      *c = PG_GETARG_NDBOX(0);
+   NDBOX      *cube = PG_GETARG_NDBOX(0);
    double      x = PG_GETARG_FLOAT8(1);
    NDBOX      *result;
    int         size;
    int         i;
 
-   size = offsetof(NDBOX, x[0]) +sizeof(double) * (c->dim + 1) *2;
-   result = (NDBOX *) palloc0(size);
-   SET_VARSIZE(result, size);
-   result->dim = c->dim + 1;
-   for (i = 0; i < c->dim; i++)
+   if (IS_POINT(cube))
+   {
+       size = POINT_SIZE((DIM(cube) + 1));
+       result = (NDBOX *) palloc0(size);
+       SET_VARSIZE(result, size);
+       SET_DIM(result, DIM(cube) + 1);
+       SET_POINT_BIT(result);
+       for (i = 0; i < DIM(cube); i++)
+           result->x[i] = cube->x[i];
+       result->x[DIM(result) - 1] = x;
+   }
+   else
    {
-       result->x[i] = c->x[i];
-       result->x[result->dim + i] = c->x[c->dim + i];
+       size = CUBE_SIZE((DIM(cube) + 1));
+       result = (NDBOX *) palloc0(size);
+       SET_VARSIZE(result, size);
+       SET_DIM(result, DIM(cube) + 1);
+       for (i = 0; i < DIM(cube); i++)
+       {
+           result->x[i] = cube->x[i];
+           result->x[DIM(result) + i] = cube->x[DIM(cube) + i];
+       }
+       result->x[DIM(result) - 1] = x;
+       result->x[2*DIM(result) - 1] = x;
    }
-   result->x[result->dim - 1] = x;
-   result->x[2 * result->dim - 1] = x;
 
-   PG_FREE_IF_COPY(c, 0);
+   PG_FREE_IF_COPY(cube, 0);
    PG_RETURN_NDBOX(result);
 }
 
@@ -1472,25 +1554,38 @@ cube_c_f8(PG_FUNCTION_ARGS)
 Datum
 cube_c_f8_f8(PG_FUNCTION_ARGS)
 {
-   NDBOX      *c = PG_GETARG_NDBOX(0);
+   NDBOX      *cube = PG_GETARG_NDBOX(0);
    double      x1 = PG_GETARG_FLOAT8(1);
    double      x2 = PG_GETARG_FLOAT8(2);
    NDBOX      *result;
    int         size;
    int         i;
 
-   size = offsetof(NDBOX, x[0]) +sizeof(double) * (c->dim + 1) *2;
-   result = (NDBOX *) palloc0(size);
-   SET_VARSIZE(result, size);
-   result->dim = c->dim + 1;
-   for (i = 0; i < c->dim; i++)
+   if (IS_POINT(cube) && (x1 == x2)){
+       size = POINT_SIZE((DIM(cube) + 1));
+       result = (NDBOX *) palloc0(size);
+       SET_VARSIZE(result, size);
+       SET_DIM(result, DIM(cube) + 1);
+       SET_POINT_BIT(result);
+       for (i = 0; i < DIM(cube); i++)
+           result->x[i] = cube->x[i];
+       result->x[DIM(result) - 1] = x1;
+   }
+   else
    {
-       result->x[i] = c->x[i];
-       result->x[result->dim + i] = c->x[c->dim + i];
+       size = CUBE_SIZE((DIM(cube) + 1));
+       result = (NDBOX *) palloc0(size);
+       SET_VARSIZE(result, size);
+       SET_DIM(result, DIM(cube) + 1);
+       for (i = 0; i < DIM(cube); i++)
+       {
+           result->x[i] = LL_COORD(cube, i);
+           result->x[DIM(result) + i] = UR_COORD(cube, i);
+       }
+       result->x[DIM(result) - 1] = x1;
+       result->x[2 * DIM(result) - 1] = x2;
    }
-   result->x[result->dim - 1] = x1;
-   result->x[2 * result->dim - 1] = x2;
 
-   PG_FREE_IF_COPY(c, 0);
+   PG_FREE_IF_COPY(cube, 0);
    PG_RETURN_NDBOX(result);
 }
index fd0c26a381655eed175804e43c68f429d11864e6..6c825b98ea735b89506755dd290b5ce0e67e92a6 100644 (file)
@@ -4,11 +4,46 @@
 
 typedef struct NDBOX
 {
-   int32       vl_len_;        /* varlena header (do not touch directly!) */
-   unsigned int dim;
+   /* varlena header (do not touch directly!) */
+   int32       vl_len_;
+
+   /*----------
+    * Header contains info about NDBOX. For binary compatibility with old
+    * versions, it is defined as "unsigned int".
+    *
+    * Following information is stored:
+    *
+    *  bits 0-7  : number of cube dimensions;
+    *  bits 8-30 : unused, initialize to zero;
+    *  bit  31   : point flag. If set, the upper right coordinates are not
+    *              stored, and are implicitly the same as the lower left
+    *              coordinates.
+    *----------
+    */
+   unsigned int header;
+
+   /*
+    * Variable length array. The lower left coordinates for each dimension
+    * come first, followed by upper right coordinates unless the point flag
+    * is set.
+    */
    double      x[1];
 } NDBOX;
 
+#define POINT_BIT          0x80000000
+#define    DIM_MASK            0x7fffffff
+
+#define IS_POINT(cube)     ( ((cube)->header & POINT_BIT) != 0 )
+#define SET_POINT_BIT(cube)    ( (cube)->header |= POINT_BIT )
+#define DIM(cube)          ( (cube)->header & DIM_MASK )
+#define SET_DIM(cube, _dim)    ( (cube)->header = ((cube)->header & ~DIM_MASK) | (_dim) )
+
+#define LL_COORD(cube, i) ( (cube)->x[i] )
+#define UR_COORD(cube, i) ( IS_POINT(cube) ? (cube)->x[i] : (cube)->x[(i) + DIM(cube)] )
+
+#define POINT_SIZE(_dim) (offsetof(NDBOX, x[0]) + sizeof(double)*(_dim))
+#define CUBE_SIZE(_dim) (offsetof(NDBOX, x[0]) + sizeof(double)*(_dim)*2)
+
 #define DatumGetNDBOX(x)   ((NDBOX*)DatumGetPointer(x))
 #define PG_GETARG_NDBOX(x) DatumGetNDBOX( PG_DETOAST_DATUM(PG_GETARG_DATUM(x)) )
 #define PG_RETURN_NDBOX(x) PG_RETURN_POINTER(x)
index d7205b824cb5c0f21c913b5746552898d8590327..0baee8e13245a930c0b1e6a1285a59eded71aac2 100644 (file)
@@ -175,11 +175,12 @@ write_box(unsigned int dim, char *str1, char *str2)
    NDBOX      *bp;
    char       *s;
    int         i;
-   int         size = offsetof(NDBOX, x[0]) + sizeof(double) * dim * 2;
+   int         size = CUBE_SIZE(dim);
+   bool        point = true;
 
    bp = palloc0(size);
    SET_VARSIZE(bp, size);
-   bp->dim = dim;
+   SET_DIM(bp, dim);
 
    s = str1;
    bp->x[i=0] = strtod(s, NULL);
@@ -191,10 +192,28 @@ write_box(unsigned int dim, char *str1, char *str2)
 
    s = str2;
    bp->x[i=dim] = strtod(s, NULL);
+   if (bp->x[dim] != bp->x[0])
+       point = false;
    while ((s = strchr(s, ',')) != NULL)
    {
        s++; i++;
        bp->x[i] = strtod(s, NULL);
+       if (bp->x[i] != bp->x[i-dim])
+           point = false;
+   }
+
+   if (point)
+   {
+       /*
+        * The value turned out to be a point, ie. all the upper-right
+        * coordinates were equal to the lower-left coordinates. Resize the
+        * the cube we constructed. Note: we don't bother to repalloc() it
+        * smaller, it's unlikely that the tiny amount of memory free'd that
+        * way would be useful.
+        */
+       size = POINT_SIZE(dim);
+       SET_VARSIZE(bp, size);
+       SET_POINT_BIT(bp);
    }
 
    return(bp);
@@ -203,31 +222,29 @@ write_box(unsigned int dim, char *str1, char *str2)
 static NDBOX *
 write_point_as_box(char *str, int dim)
 {
-  NDBOX           *bp;
-  int          i,
+   NDBOX       *bp;
+   int         i,
                size;
-  double       x;
-  char        *s = str;
-
-  size = offsetof(NDBOX, x[0]) + sizeof(double) * dim * 2;
-
-  bp = palloc0(size);
-  SET_VARSIZE(bp, size);
-  bp->dim = dim;
-
-  i = 0;
-  x = strtod(s, NULL);
-  bp->x[0] = x;
-  bp->x[dim] = x;
-  while ((s = strchr(s, ',')) != NULL)
-  {
-     s++; i++;
-     x = strtod(s, NULL);
-     bp->x[i] = x;
-     bp->x[i+dim] = x;
-  }
-
-  return(bp);
+   double      x;
+   char        *s = str;
+
+   size = POINT_SIZE(dim);
+   bp = palloc0(size);
+   SET_VARSIZE(bp, size);
+   SET_DIM(bp, dim);
+   SET_POINT_BIT(bp);
+
+   i = 0;
+   x = strtod(s, NULL);
+   bp->x[0] = x;
+   while ((s = strchr(s, ',')) != NULL)
+   {
+       s++; i++;
+       x = strtod(s, NULL);
+       bp->x[i] = x;
+   }
+
+   return(bp);
 }
 
 #include "cubescan.c"
index fefebf5fb943e761ac907af42f2177cbf1e16a72..c07d61d0b0af9cc478fde07ca006d0c616283db7 100644 (file)
@@ -473,8 +473,85 @@ SELECT cube_subset(cube('(1,3,5),(6,7,8)'), ARRAY[3,2,1,1]);
  (5, 3, 1, 1),(8, 7, 6, 6)
 (1 row)
 
+SELECT cube_subset(cube('(1,3,5),(1,3,5)'), ARRAY[3,2,1,1]);
+ cube_subset  
+--------------
+ (5, 3, 1, 1)
+(1 row)
+
 SELECT cube_subset(cube('(1,3,5),(6,7,8)'), ARRAY[4,0]);
 ERROR:  Index out of bounds
+SELECT cube_subset(cube('(6,7,8),(6,7,8)'), ARRAY[4,0]);
+ERROR:  Index out of bounds
+--
+-- Test point processing
+--
+SELECT cube('(1,2),(1,2)'); -- cube_in
+  cube  
+--------
+ (1, 2)
+(1 row)
+
+SELECT cube('{0,1,2}'::float[], '{0,1,2}'::float[]); -- cube_a_f8_f8
+   cube    
+-----------
+ (0, 1, 2)
+(1 row)
+
+SELECT cube('{5,6,7,8}'::float[]); -- cube_a_f8
+     cube     
+--------------
+ (5, 6, 7, 8)
+(1 row)
+
+SELECT cube(1.37); -- cube_f8
+  cube  
+--------
+ (1.37)
+(1 row)
+
+SELECT cube(1.37, 1.37); -- cube_f8_f8
+  cube  
+--------
+ (1.37)
+(1 row)
+
+SELECT cube(cube(1,1), 42); -- cube_c_f8
+  cube   
+---------
+ (1, 42)
+(1 row)
+
+SELECT cube(cube(1,2), 42); -- cube_c_f8
+      cube       
+-----------------
+ (1, 42),(2, 42)
+(1 row)
+
+SELECT cube(cube(1,1), 42, 42); -- cube_c_f8_f8
+  cube   
+---------
+ (1, 42)
+(1 row)
+
+SELECT cube(cube(1,1), 42, 24); -- cube_c_f8_f8
+      cube       
+-----------------
+ (1, 42),(1, 24)
+(1 row)
+
+SELECT cube(cube(1,2), 42, 42); -- cube_c_f8_f8
+      cube       
+-----------------
+ (1, 42),(2, 42)
+(1 row)
+
+SELECT cube(cube(1,2), 42, 24); -- cube_c_f8_f8
+      cube       
+-----------------
+ (1, 42),(2, 24)
+(1 row)
+
 --
 -- Testing limit of CUBE_MAX_DIM dimensions check in cube_in.
 --
@@ -878,6 +955,24 @@ SELECT cube_distance('(0)'::cube,'(.3,.4)'::cube);
            0.5
 (1 row)
 
+SELECT cube_distance('(2,3,4)'::cube,'(2,3,4)'::cube);
+ cube_distance 
+---------------
+             0
+(1 row)
+
+SELECT cube_distance('(42,42,42,42)'::cube,'(137,137,137,137)'::cube);
+ cube_distance 
+---------------
+           190
+(1 row)
+
+SELECT cube_distance('(42,42,42)'::cube,'(137,137)'::cube);
+  cube_distance   
+------------------
+ 140.762210837994
+(1 row)
+
 -- Test of cube function (text to cube)
 --
 SELECT cube('(1,1.2)'::text);
@@ -912,6 +1007,18 @@ SELECT cube_dim('(0,0,0)'::cube);
         3
 (1 row)
 
+SELECT cube_dim('(42,42,42),(42,42,42)'::cube);
+ cube_dim 
+----------
+        3
+(1 row)
+
+SELECT cube_dim('(4,8,15,16,23),(4,8,15,16,23)'::cube);
+ cube_dim 
+----------
+        5
+(1 row)
+
 -- Test of cube_ll_coord function (retrieves LL coodinate values)
 --
 SELECT cube_ll_coord('(-1,1),(2,-2)'::cube, 1);
@@ -932,6 +1039,42 @@ SELECT cube_ll_coord('(-1,1),(2,-2)'::cube, 3);
              0
 (1 row)
 
+SELECT cube_ll_coord('(1,2),(1,2)'::cube, 1);
+ cube_ll_coord 
+---------------
+             1
+(1 row)
+
+SELECT cube_ll_coord('(1,2),(1,2)'::cube, 2);
+ cube_ll_coord 
+---------------
+             2
+(1 row)
+
+SELECT cube_ll_coord('(1,2),(1,2)'::cube, 3);
+ cube_ll_coord 
+---------------
+             0
+(1 row)
+
+SELECT cube_ll_coord('(42,137)'::cube, 1);
+ cube_ll_coord 
+---------------
+            42
+(1 row)
+
+SELECT cube_ll_coord('(42,137)'::cube, 2);
+ cube_ll_coord 
+---------------
+           137
+(1 row)
+
+SELECT cube_ll_coord('(42,137)'::cube, 3);
+ cube_ll_coord 
+---------------
+             0
+(1 row)
+
 -- Test of cube_ur_coord function (retrieves UR coodinate values)
 --
 SELECT cube_ur_coord('(-1,1),(2,-2)'::cube, 1);
@@ -952,6 +1095,42 @@ SELECT cube_ur_coord('(-1,1),(2,-2)'::cube, 3);
              0
 (1 row)
 
+SELECT cube_ur_coord('(1,2),(1,2)'::cube, 1);
+ cube_ur_coord 
+---------------
+             1
+(1 row)
+
+SELECT cube_ur_coord('(1,2),(1,2)'::cube, 2);
+ cube_ur_coord 
+---------------
+             2
+(1 row)
+
+SELECT cube_ur_coord('(1,2),(1,2)'::cube, 3);
+ cube_ur_coord 
+---------------
+             0
+(1 row)
+
+SELECT cube_ur_coord('(42,137)'::cube, 1);
+ cube_ur_coord 
+---------------
+            42
+(1 row)
+
+SELECT cube_ur_coord('(42,137)'::cube, 2);
+ cube_ur_coord 
+---------------
+           137
+(1 row)
+
+SELECT cube_ur_coord('(42,137)'::cube, 3);
+ cube_ur_coord 
+---------------
+             0
+(1 row)
+
 -- Test of cube_is_point
 --
 SELECT cube_is_point('(0)'::cube);
@@ -1100,6 +1279,108 @@ SELECT cube_enlarge('(2,-2),(-3,7)'::cube, -3, 2);
  (-0.5, 1),(-0.5, 4)
 (1 row)
 
+SELECT cube_enlarge('(42,-23,-23),(42,23,23)'::cube, -23, 5);
+ cube_enlarge 
+--------------
+ (42, 0, 0)
+(1 row)
+
+SELECT cube_enlarge('(42,-23,-23),(42,23,23)'::cube, -24, 5);
+ cube_enlarge 
+--------------
+ (42, 0, 0)
+(1 row)
+
+-- Test of cube_union (MBR for two cubes)
+--
+SELECT cube_union('(1,2),(3,4)'::cube, '(5,6,7),(8,9,10)'::cube);
+      cube_union      
+----------------------
+ (1, 2, 0),(8, 9, 10)
+(1 row)
+
+SELECT cube_union('(1,2)'::cube, '(4,2,0,0)'::cube);
+        cube_union         
+---------------------------
+ (1, 2, 0, 0),(4, 2, 0, 0)
+(1 row)
+
+SELECT cube_union('(1,2),(1,2)'::cube, '(4,2),(4,2)'::cube);
+  cube_union   
+---------------
+ (1, 2),(4, 2)
+(1 row)
+
+SELECT cube_union('(1,2),(1,2)'::cube, '(1,2),(1,2)'::cube);
+ cube_union 
+------------
+ (1, 2)
+(1 row)
+
+SELECT cube_union('(1,2),(1,2)'::cube, '(1,2,0),(1,2,0)'::cube);
+ cube_union 
+------------
+ (1, 2, 0)
+(1 row)
+
+-- Test of cube_inter
+--
+SELECT cube_inter('(1,2),(10,11)'::cube, '(3,4), (16,15)'::cube); -- intersects
+   cube_inter    
+-----------------
+ (3, 4),(10, 11)
+(1 row)
+
+SELECT cube_inter('(1,2),(10,11)'::cube, '(3,4), (6,5)'::cube); -- includes
+  cube_inter   
+---------------
+ (3, 4),(6, 5)
+(1 row)
+
+SELECT cube_inter('(1,2),(10,11)'::cube, '(13,14), (16,15)'::cube); -- no intersection
+    cube_inter     
+-------------------
+ (13, 14),(10, 11)
+(1 row)
+
+SELECT cube_inter('(1,2),(10,11)'::cube, '(3,14), (16,15)'::cube); -- no intersection, but one dimension intersects
+    cube_inter    
+------------------
+ (3, 14),(10, 11)
+(1 row)
+
+SELECT cube_inter('(1,2),(10,11)'::cube, '(10,11), (16,15)'::cube); -- point intersection
+ cube_inter 
+------------
+ (10, 11)
+(1 row)
+
+SELECT cube_inter('(1,2,3)'::cube, '(1,2,3)'::cube); -- point args
+ cube_inter 
+------------
+ (1, 2, 3)
+(1 row)
+
+SELECT cube_inter('(1,2,3)'::cube, '(5,6,3)'::cube); -- point args
+     cube_inter      
+---------------------
+ (5, 6, 3),(1, 2, 3)
+(1 row)
+
+-- Test of cube_size
+--
+SELECT cube_size('(4,8),(15,16)'::cube);
+ cube_size 
+-----------
+        88
+(1 row)
+
+SELECT cube_size('(42,137)'::cube);
+ cube_size 
+-----------
+         0
+(1 row)
+
 -- Load some example data and build the index
 --
 CREATE TABLE test_cube (c cube);
index 6d15d635700bc9ca141073026e4cc68c1761a5cf..3767d0ef9bc7928933413fcbf545b11602cc0c67 100644 (file)
@@ -473,8 +473,85 @@ SELECT cube_subset(cube('(1,3,5),(6,7,8)'), ARRAY[3,2,1,1]);
  (5, 3, 1, 1),(8, 7, 6, 6)
 (1 row)
 
+SELECT cube_subset(cube('(1,3,5),(1,3,5)'), ARRAY[3,2,1,1]);
+ cube_subset  
+--------------
+ (5, 3, 1, 1)
+(1 row)
+
 SELECT cube_subset(cube('(1,3,5),(6,7,8)'), ARRAY[4,0]);
 ERROR:  Index out of bounds
+SELECT cube_subset(cube('(6,7,8),(6,7,8)'), ARRAY[4,0]);
+ERROR:  Index out of bounds
+--
+-- Test point processing
+--
+SELECT cube('(1,2),(1,2)'); -- cube_in
+  cube  
+--------
+ (1, 2)
+(1 row)
+
+SELECT cube('{0,1,2}'::float[], '{0,1,2}'::float[]); -- cube_a_f8_f8
+   cube    
+-----------
+ (0, 1, 2)
+(1 row)
+
+SELECT cube('{5,6,7,8}'::float[]); -- cube_a_f8
+     cube     
+--------------
+ (5, 6, 7, 8)
+(1 row)
+
+SELECT cube(1.37); -- cube_f8
+  cube  
+--------
+ (1.37)
+(1 row)
+
+SELECT cube(1.37, 1.37); -- cube_f8_f8
+  cube  
+--------
+ (1.37)
+(1 row)
+
+SELECT cube(cube(1,1), 42); -- cube_c_f8
+  cube   
+---------
+ (1, 42)
+(1 row)
+
+SELECT cube(cube(1,2), 42); -- cube_c_f8
+      cube       
+-----------------
+ (1, 42),(2, 42)
+(1 row)
+
+SELECT cube(cube(1,1), 42, 42); -- cube_c_f8_f8
+  cube   
+---------
+ (1, 42)
+(1 row)
+
+SELECT cube(cube(1,1), 42, 24); -- cube_c_f8_f8
+      cube       
+-----------------
+ (1, 42),(1, 24)
+(1 row)
+
+SELECT cube(cube(1,2), 42, 42); -- cube_c_f8_f8
+      cube       
+-----------------
+ (1, 42),(2, 42)
+(1 row)
+
+SELECT cube(cube(1,2), 42, 24); -- cube_c_f8_f8
+      cube       
+-----------------
+ (1, 42),(2, 24)
+(1 row)
+
 --
 -- Testing limit of CUBE_MAX_DIM dimensions check in cube_in.
 --
@@ -878,6 +955,24 @@ SELECT cube_distance('(0)'::cube,'(.3,.4)'::cube);
            0.5
 (1 row)
 
+SELECT cube_distance('(2,3,4)'::cube,'(2,3,4)'::cube);
+ cube_distance 
+---------------
+             0
+(1 row)
+
+SELECT cube_distance('(42,42,42,42)'::cube,'(137,137,137,137)'::cube);
+ cube_distance 
+---------------
+           190
+(1 row)
+
+SELECT cube_distance('(42,42,42)'::cube,'(137,137)'::cube);
+  cube_distance   
+------------------
+ 140.762210837994
+(1 row)
+
 -- Test of cube function (text to cube)
 --
 SELECT cube('(1,1.2)'::text);
@@ -912,6 +1007,18 @@ SELECT cube_dim('(0,0,0)'::cube);
         3
 (1 row)
 
+SELECT cube_dim('(42,42,42),(42,42,42)'::cube);
+ cube_dim 
+----------
+        3
+(1 row)
+
+SELECT cube_dim('(4,8,15,16,23),(4,8,15,16,23)'::cube);
+ cube_dim 
+----------
+        5
+(1 row)
+
 -- Test of cube_ll_coord function (retrieves LL coodinate values)
 --
 SELECT cube_ll_coord('(-1,1),(2,-2)'::cube, 1);
@@ -932,6 +1039,42 @@ SELECT cube_ll_coord('(-1,1),(2,-2)'::cube, 3);
              0
 (1 row)
 
+SELECT cube_ll_coord('(1,2),(1,2)'::cube, 1);
+ cube_ll_coord 
+---------------
+             1
+(1 row)
+
+SELECT cube_ll_coord('(1,2),(1,2)'::cube, 2);
+ cube_ll_coord 
+---------------
+             2
+(1 row)
+
+SELECT cube_ll_coord('(1,2),(1,2)'::cube, 3);
+ cube_ll_coord 
+---------------
+             0
+(1 row)
+
+SELECT cube_ll_coord('(42,137)'::cube, 1);
+ cube_ll_coord 
+---------------
+            42
+(1 row)
+
+SELECT cube_ll_coord('(42,137)'::cube, 2);
+ cube_ll_coord 
+---------------
+           137
+(1 row)
+
+SELECT cube_ll_coord('(42,137)'::cube, 3);
+ cube_ll_coord 
+---------------
+             0
+(1 row)
+
 -- Test of cube_ur_coord function (retrieves UR coodinate values)
 --
 SELECT cube_ur_coord('(-1,1),(2,-2)'::cube, 1);
@@ -952,6 +1095,42 @@ SELECT cube_ur_coord('(-1,1),(2,-2)'::cube, 3);
              0
 (1 row)
 
+SELECT cube_ur_coord('(1,2),(1,2)'::cube, 1);
+ cube_ur_coord 
+---------------
+             1
+(1 row)
+
+SELECT cube_ur_coord('(1,2),(1,2)'::cube, 2);
+ cube_ur_coord 
+---------------
+             2
+(1 row)
+
+SELECT cube_ur_coord('(1,2),(1,2)'::cube, 3);
+ cube_ur_coord 
+---------------
+             0
+(1 row)
+
+SELECT cube_ur_coord('(42,137)'::cube, 1);
+ cube_ur_coord 
+---------------
+            42
+(1 row)
+
+SELECT cube_ur_coord('(42,137)'::cube, 2);
+ cube_ur_coord 
+---------------
+           137
+(1 row)
+
+SELECT cube_ur_coord('(42,137)'::cube, 3);
+ cube_ur_coord 
+---------------
+             0
+(1 row)
+
 -- Test of cube_is_point
 --
 SELECT cube_is_point('(0)'::cube);
@@ -1100,6 +1279,108 @@ SELECT cube_enlarge('(2,-2),(-3,7)'::cube, -3, 2);
  (-0.5, 1),(-0.5, 4)
 (1 row)
 
+SELECT cube_enlarge('(42,-23,-23),(42,23,23)'::cube, -23, 5);
+ cube_enlarge 
+--------------
+ (42, 0, 0)
+(1 row)
+
+SELECT cube_enlarge('(42,-23,-23),(42,23,23)'::cube, -24, 5);
+ cube_enlarge 
+--------------
+ (42, 0, 0)
+(1 row)
+
+-- Test of cube_union (MBR for two cubes)
+--
+SELECT cube_union('(1,2),(3,4)'::cube, '(5,6,7),(8,9,10)'::cube);
+      cube_union      
+----------------------
+ (1, 2, 0),(8, 9, 10)
+(1 row)
+
+SELECT cube_union('(1,2)'::cube, '(4,2,0,0)'::cube);
+        cube_union         
+---------------------------
+ (1, 2, 0, 0),(4, 2, 0, 0)
+(1 row)
+
+SELECT cube_union('(1,2),(1,2)'::cube, '(4,2),(4,2)'::cube);
+  cube_union   
+---------------
+ (1, 2),(4, 2)
+(1 row)
+
+SELECT cube_union('(1,2),(1,2)'::cube, '(1,2),(1,2)'::cube);
+ cube_union 
+------------
+ (1, 2)
+(1 row)
+
+SELECT cube_union('(1,2),(1,2)'::cube, '(1,2,0),(1,2,0)'::cube);
+ cube_union 
+------------
+ (1, 2, 0)
+(1 row)
+
+-- Test of cube_inter
+--
+SELECT cube_inter('(1,2),(10,11)'::cube, '(3,4), (16,15)'::cube); -- intersects
+   cube_inter    
+-----------------
+ (3, 4),(10, 11)
+(1 row)
+
+SELECT cube_inter('(1,2),(10,11)'::cube, '(3,4), (6,5)'::cube); -- includes
+  cube_inter   
+---------------
+ (3, 4),(6, 5)
+(1 row)
+
+SELECT cube_inter('(1,2),(10,11)'::cube, '(13,14), (16,15)'::cube); -- no intersection
+    cube_inter     
+-------------------
+ (13, 14),(10, 11)
+(1 row)
+
+SELECT cube_inter('(1,2),(10,11)'::cube, '(3,14), (16,15)'::cube); -- no intersection, but one dimension intersects
+    cube_inter    
+------------------
+ (3, 14),(10, 11)
+(1 row)
+
+SELECT cube_inter('(1,2),(10,11)'::cube, '(10,11), (16,15)'::cube); -- point intersection
+ cube_inter 
+------------
+ (10, 11)
+(1 row)
+
+SELECT cube_inter('(1,2,3)'::cube, '(1,2,3)'::cube); -- point args
+ cube_inter 
+------------
+ (1, 2, 3)
+(1 row)
+
+SELECT cube_inter('(1,2,3)'::cube, '(5,6,3)'::cube); -- point args
+     cube_inter      
+---------------------
+ (5, 6, 3),(1, 2, 3)
+(1 row)
+
+-- Test of cube_size
+--
+SELECT cube_size('(4,8),(15,16)'::cube);
+ cube_size 
+-----------
+        88
+(1 row)
+
+SELECT cube_size('(42,137)'::cube);
+ cube_size 
+-----------
+         0
+(1 row)
+
 -- Load some example data and build the index
 --
 CREATE TABLE test_cube (c cube);
index 02e068edf4df1cb7c3f26ead232b8816a141649b..d58974c408e1560f03c9acb8e2d1180c3cf21ec5 100644 (file)
@@ -112,7 +112,24 @@ SELECT cube('{0,1,2}'::float[], '{3}'::float[]);
 SELECT cube(NULL::float[], '{3}'::float[]);
 SELECT cube('{0,1,2}'::float[]);
 SELECT cube_subset(cube('(1,3,5),(6,7,8)'), ARRAY[3,2,1,1]);
+SELECT cube_subset(cube('(1,3,5),(1,3,5)'), ARRAY[3,2,1,1]);
 SELECT cube_subset(cube('(1,3,5),(6,7,8)'), ARRAY[4,0]);
+SELECT cube_subset(cube('(6,7,8),(6,7,8)'), ARRAY[4,0]);
+
+--
+-- Test point processing
+--
+SELECT cube('(1,2),(1,2)'); -- cube_in
+SELECT cube('{0,1,2}'::float[], '{0,1,2}'::float[]); -- cube_a_f8_f8
+SELECT cube('{5,6,7,8}'::float[]); -- cube_a_f8
+SELECT cube(1.37); -- cube_f8
+SELECT cube(1.37, 1.37); -- cube_f8_f8
+SELECT cube(cube(1,1), 42); -- cube_c_f8
+SELECT cube(cube(1,2), 42); -- cube_c_f8
+SELECT cube(cube(1,1), 42, 42); -- cube_c_f8_f8
+SELECT cube(cube(1,1), 42, 24); -- cube_c_f8_f8
+SELECT cube(cube(1,2), 42, 42); -- cube_c_f8_f8
+SELECT cube(cube(1,2), 42, 24); -- cube_c_f8_f8
 
 --
 -- Testing limit of CUBE_MAX_DIM dimensions check in cube_in.
@@ -212,6 +229,9 @@ SELECT '(-1,-1),(1,1)'::cube            @> '(-2),(1)'::cube          AS bool;
 --
 SELECT cube_distance('(0)'::cube,'(2,2,2,2)'::cube);
 SELECT cube_distance('(0)'::cube,'(.3,.4)'::cube);
+SELECT cube_distance('(2,3,4)'::cube,'(2,3,4)'::cube);
+SELECT cube_distance('(42,42,42,42)'::cube,'(137,137,137,137)'::cube);
+SELECT cube_distance('(42,42,42)'::cube,'(137,137)'::cube);
 
 -- Test of cube function (text to cube)
 --
@@ -223,18 +243,32 @@ SELECT cube(NULL);
 SELECT cube_dim('(0)'::cube);
 SELECT cube_dim('(0,0)'::cube);
 SELECT cube_dim('(0,0,0)'::cube);
+SELECT cube_dim('(42,42,42),(42,42,42)'::cube);
+SELECT cube_dim('(4,8,15,16,23),(4,8,15,16,23)'::cube);
 
 -- Test of cube_ll_coord function (retrieves LL coodinate values)
 --
 SELECT cube_ll_coord('(-1,1),(2,-2)'::cube, 1);
 SELECT cube_ll_coord('(-1,1),(2,-2)'::cube, 2);
 SELECT cube_ll_coord('(-1,1),(2,-2)'::cube, 3);
+SELECT cube_ll_coord('(1,2),(1,2)'::cube, 1);
+SELECT cube_ll_coord('(1,2),(1,2)'::cube, 2);
+SELECT cube_ll_coord('(1,2),(1,2)'::cube, 3);
+SELECT cube_ll_coord('(42,137)'::cube, 1);
+SELECT cube_ll_coord('(42,137)'::cube, 2);
+SELECT cube_ll_coord('(42,137)'::cube, 3);
 
 -- Test of cube_ur_coord function (retrieves UR coodinate values)
 --
 SELECT cube_ur_coord('(-1,1),(2,-2)'::cube, 1);
 SELECT cube_ur_coord('(-1,1),(2,-2)'::cube, 2);
 SELECT cube_ur_coord('(-1,1),(2,-2)'::cube, 3);
+SELECT cube_ur_coord('(1,2),(1,2)'::cube, 1);
+SELECT cube_ur_coord('(1,2),(1,2)'::cube, 2);
+SELECT cube_ur_coord('(1,2),(1,2)'::cube, 3);
+SELECT cube_ur_coord('(42,137)'::cube, 1);
+SELECT cube_ur_coord('(42,137)'::cube, 2);
+SELECT cube_ur_coord('(42,137)'::cube, 3);
 
 -- Test of cube_is_point
 --
@@ -265,6 +299,31 @@ SELECT cube_enlarge('(2,-2),(-3,7)'::cube, 1, 2);
 SELECT cube_enlarge('(2,-2),(-3,7)'::cube, 3, 2);
 SELECT cube_enlarge('(2,-2),(-3,7)'::cube, -1, 2);
 SELECT cube_enlarge('(2,-2),(-3,7)'::cube, -3, 2);
+SELECT cube_enlarge('(42,-23,-23),(42,23,23)'::cube, -23, 5);
+SELECT cube_enlarge('(42,-23,-23),(42,23,23)'::cube, -24, 5);
+
+-- Test of cube_union (MBR for two cubes)
+--
+SELECT cube_union('(1,2),(3,4)'::cube, '(5,6,7),(8,9,10)'::cube);
+SELECT cube_union('(1,2)'::cube, '(4,2,0,0)'::cube);
+SELECT cube_union('(1,2),(1,2)'::cube, '(4,2),(4,2)'::cube);
+SELECT cube_union('(1,2),(1,2)'::cube, '(1,2),(1,2)'::cube);
+SELECT cube_union('(1,2),(1,2)'::cube, '(1,2,0),(1,2,0)'::cube);
+
+-- Test of cube_inter
+--
+SELECT cube_inter('(1,2),(10,11)'::cube, '(3,4), (16,15)'::cube); -- intersects
+SELECT cube_inter('(1,2),(10,11)'::cube, '(3,4), (6,5)'::cube); -- includes
+SELECT cube_inter('(1,2),(10,11)'::cube, '(13,14), (16,15)'::cube); -- no intersection
+SELECT cube_inter('(1,2),(10,11)'::cube, '(3,14), (16,15)'::cube); -- no intersection, but one dimension intersects
+SELECT cube_inter('(1,2),(10,11)'::cube, '(10,11), (16,15)'::cube); -- point intersection
+SELECT cube_inter('(1,2,3)'::cube, '(1,2,3)'::cube); -- point args
+SELECT cube_inter('(1,2,3)'::cube, '(5,6,3)'::cube); -- point args
+
+-- Test of cube_size
+--
+SELECT cube_size('(4,8),(15,16)'::cube);
+SELECT cube_size('(42,137)'::cube);
 
 -- Load some example data and build the index
 --