/* * Validity test for a new-format hstore. * 0 = not valid * 1 = valid but with "slop" in the length * 2 = exactly valid */ static int hstoreValidNewFormat(HStore *hs) { int count = HS_COUNT(hs); HEntry *entries = ARRPTR(hs); int buflen = (count) ? HSE_ENDPOS(entries[2 * (count) - 1]) : 0; int vsize = CALCDATASIZE(count, buflen); int i; if (hs->size_ & HS_FLAG_NEWVERSION) return 2; if (count == 0) return 2; if (!HSE_ISFIRST(entries[0])) return 0; if (vsize > VARSIZE(hs)) return 0; /* entry position must be nondecreasing */ for (i = 1; i < 2 * count; ++i) { if (HSE_ISFIRST(entries[i]) || (HSE_ENDPOS(entries[i]) < HSE_ENDPOS(entries[i - 1]))) return 0; } /* key length must be nondecreasing and keys must not be null */ for (i = 1; i < count; ++i) { if (HS_KEYLEN(entries, i) < HS_KEYLEN(entries, i - 1)) return 0; if (HSE_ISNULL(entries[2 * i])) return 0; } if (vsize != VARSIZE(hs)) return 1; return 2; }
Datum hstore_cmp(PG_FUNCTION_ARGS) { HStore *hs1 = PG_GETARG_HS(0); HStore *hs2 = PG_GETARG_HS(1); int hcount1 = HS_COUNT(hs1); int hcount2 = HS_COUNT(hs2); int res = 0; if (hcount1 == 0 || hcount2 == 0) { /* * if either operand is empty, and the other is nonempty, the nonempty * one is larger. If both are empty they are equal. */ if (hcount1 > 0) res = 1; else if (hcount2 > 0) res = -1; } else { /* here we know both operands are nonempty */ char *str1 = STRPTR(hs1); char *str2 = STRPTR(hs2); HEntry *ent1 = ARRPTR(hs1); HEntry *ent2 = ARRPTR(hs2); size_t len1 = HSE_ENDPOS(ent1[2 * hcount1 - 1]); size_t len2 = HSE_ENDPOS(ent2[2 * hcount2 - 1]); res = memcmp(str1, str2, Min(len1, len2)); if (res == 0) { if (len1 > len2) res = 1; else if (len1 < len2) res = -1; else if (hcount1 > hcount2) res = 1; else if (hcount2 > hcount1) res = -1; else { int count = hcount1 * 2; int i; for (i = 0; i < count; ++i) if (HSE_ENDPOS(ent1[i]) != HSE_ENDPOS(ent2[i]) || HSE_ISNULL(ent1[i]) != HSE_ISNULL(ent2[i])) break; if (i < count) { if (HSE_ENDPOS(ent1[i]) < HSE_ENDPOS(ent2[i])) res = -1; else if (HSE_ENDPOS(ent1[i]) > HSE_ENDPOS(ent2[i])) res = 1; else if (HSE_ISNULL(ent1[i])) res = 1; else if (HSE_ISNULL(ent2[i])) res = -1; } } } else { res = (res > 0) ? 1 : -1; } } /* * this is a btree support function; this is one of the few places where * memory needs to be explicitly freed. */ PG_FREE_IF_COPY(hs1, 0); PG_FREE_IF_COPY(hs2, 1); PG_RETURN_INT32(res); }