diff --git a/src/backend/access/gist/gistproc.c b/src/backend/access/gist/gistproc.c new file mode 100644 index 3a45781..d10477e *** a/src/backend/access/gist/gistproc.c --- b/src/backend/access/gist/gistproc.c *************** static bool rtree_internal_consistent(BO *** 37,54 **** **************************************************/ /* - * Calculates union of two boxes, a and b. The result is stored in *n. - */ - static void - rt_box_union(BOX *n, BOX *a, BOX *b) - { - n->high.x = Max(a->high.x, b->high.x); - n->high.y = Max(a->high.y, b->high.y); - n->low.x = Min(a->low.x, b->low.x); - n->low.y = Min(a->low.y, b->low.y); - } - - /* * The GiST Consistent method for boxes * * Should return false if for all data items x below entry, --- 37,42 ---- *************** gist_box_consistent(PG_FUNCTION_ARGS) *** 85,100 **** strategy)); } static void adjustBox(BOX *b, BOX *addon) { ! if (b->high.x < addon->high.x) b->high.x = addon->high.x; ! if (b->low.x > addon->low.x) b->low.x = addon->low.x; ! if (b->high.y < addon->high.y) b->high.y = addon->high.y; ! if (b->low.y > addon->low.y) b->low.y = addon->low.y; } --- 73,93 ---- strategy)); } + /* + * Extend box with addon value. NaN bound never satisfy any condition in + * consistent function. That's why NaN bound value has lesser priority than + * any other value. + */ static void adjustBox(BOX *b, BOX *addon) { ! if (b->high.x < addon->high.x || isnan(b->high.x)) b->high.x = addon->high.x; ! if (b->low.x > addon->low.x || isnan(b->low.x)) b->low.x = addon->low.x; ! if (b->high.y < addon->high.y || isnan(b->high.y)) b->high.y = addon->high.y; ! if (b->low.y > addon->low.y || isnan(b->low.y)) b->low.y = addon->low.y; } *************** gist_box_penalty(PG_FUNCTION_ARGS) *** 164,172 **** float *result = (float *) PG_GETARG_POINTER(2); BOX *origbox = DatumGetBoxP(origentry->key); BOX *newbox = DatumGetBoxP(newentry->key); ! BOX unionbox; ! rt_box_union(&unionbox, origbox, newbox); *result = (float) (size_box(&unionbox) - size_box(origbox)); PG_RETURN_POINTER(result); } --- 157,165 ---- float *result = (float *) PG_GETARG_POINTER(2); BOX *origbox = DatumGetBoxP(origentry->key); BOX *newbox = DatumGetBoxP(newentry->key); ! BOX unionbox = *origbox; ! adjustBox(&unionbox, newbox); *result = (float) (size_box(&unionbox) - size_box(origbox)); PG_RETURN_POINTER(result); } *************** typedef struct *** 272,278 **** } SplitInterval; /* ! * Interval comparison function by lower bound of the interval; */ static int interval_cmp_lower(const void *i1, const void *i2) --- 265,272 ---- } SplitInterval; /* ! * Interval comparison function by lower bound of the interval which puts ! * NaNs to the end. */ static int interval_cmp_lower(const void *i1, const void *i2) *************** interval_cmp_lower(const void *i1, const *** 280,295 **** double lower1 = ((const SplitInterval *) i1)->lower, lower2 = ((const SplitInterval *) i2)->lower; ! if (lower1 < lower2) return -1; ! else if (lower1 > lower2) ! return 1; else ! return 0; } /* ! * Interval comparison function by upper bound of the interval; */ static int interval_cmp_upper(const void *i1, const void *i2) --- 274,304 ---- double lower1 = ((const SplitInterval *) i1)->lower, lower2 = ((const SplitInterval *) i2)->lower; ! if (isnan(lower1)) ! { ! if (isnan(lower2)) ! return 0; ! else ! return 1; ! } ! else if (isnan(lower2)) ! { return -1; ! } else ! { ! if (lower1 < lower2) ! return -1; ! else if (lower1 > lower2) ! return 1; ! else ! return 0; ! } } /* ! * Interval comparison function by upper bound of the interval which puts ! * NaNs to the beginning. */ static int interval_cmp_upper(const void *i1, const void *i2) *************** interval_cmp_upper(const void *i1, const *** 297,308 **** double upper1 = ((const SplitInterval *) i1)->upper, upper2 = ((const SplitInterval *) i2)->upper; ! if (upper1 < upper2) ! return -1; ! else if (upper1 > upper2) return 1; else ! return 0; } /* --- 306,331 ---- double upper1 = ((const SplitInterval *) i1)->upper, upper2 = ((const SplitInterval *) i2)->upper; ! if (isnan(upper1)) ! { ! if (isnan(upper2)) ! return 0; ! else ! return -1; ! } ! else if (isnan(upper2)) ! { return 1; + } else ! { ! if (upper1 < upper2) ! return -1; ! else if (upper1 > upper2) ! return 1; ! else ! return 0; ! } } /* *************** common_entry_cmp(const void *i1, const v *** 480,485 **** --- 503,511 ---- * * The common entries are distributed by minimizing penalty. * + * NaN bounds never satisfy any conditions in consistent function. That's why + * NaN bound doesn't restrict box join to any group. + * * For details see: * "A new double sorting-based node splitting algorithm for R-tree", A. Korotkov * http://syrcose.ispras.ru/2011/files/SYRCoSE2011_Proceedings.pdf#page=36 *************** gist_box_picksplit(PG_FUNCTION_ARGS) *** 605,613 **** /* * Find next lower bound of right group. */ ! while (i1 < nentries && rightLower == intervalsLower[i1].lower) { ! leftUpper = Max(leftUpper, intervalsLower[i1].upper); i1++; } if (i1 >= nentries) --- 631,641 ---- /* * Find next lower bound of right group. */ ! while (i1 < nentries && (rightLower == intervalsLower[i1].lower || ! isnan(intervalsLower[i1].lower))) { ! if (leftUpper < intervalsLower[i1].upper || isnan(leftUpper)) ! leftUpper = intervalsLower[i1].upper; i1++; } if (i1 >= nentries) *************** gist_box_picksplit(PG_FUNCTION_ARGS) *** 640,648 **** /* * Find next upper bound of left group. */ ! while (i2 >= 0 && leftUpper == intervalsUpper[i2].upper) { ! rightLower = Min(rightLower, intervalsUpper[i2].lower); i2--; } if (i2 < 0) --- 668,678 ---- /* * Find next upper bound of left group. */ ! while (i2 >= 0 && (leftUpper == intervalsUpper[i2].upper || ! isnan(intervalsUpper[i2].upper))) { ! if (rightLower > intervalsUpper[i2].lower || isnan(rightLower)) ! rightLower = intervalsUpper[i2].lower; i2--; } if (i2 < 0) *************** gist_box_picksplit(PG_FUNCTION_ARGS) *** 741,750 **** upper = box->high.y; } ! if (upper <= context.leftUpper) { /* Fits to the left group */ ! if (lower >= context.rightLower) { /* Fits also to the right group, so "common entry" */ commonEntries[commonEntriesCount++].index = i; --- 771,780 ---- upper = box->high.y; } ! if (upper <= context.leftUpper || isnan(upper)) { /* Fits to the left group */ ! if (lower >= context.rightLower || isnan(lower)) { /* Fits also to the right group, so "common entry" */ commonEntries[commonEntriesCount++].index = i;