Fix contrib/hstore to throw an error for keys or values that don't fit in its
authorTom Lane
Sun, 15 Mar 2009 22:05:17 +0000 (22:05 +0000)
committerTom Lane
Sun, 15 Mar 2009 22:05:17 +0000 (22:05 +0000)
data structure, rather than silently truncating them.  Andrew Gierth

contrib/hstore/hstore.h
contrib/hstore/hstore_io.c
contrib/hstore/hstore_op.c
doc/src/sgml/hstore.sgml

index e66f72a139068f5d86ed6841c1532bc1f3694d51..2a2c3bad58a4f769ec8a3453d2c441f9a20e327a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $PostgreSQL: pgsql/contrib/hstore/hstore.h,v 1.6 2008/05/12 00:00:42 alvherre Exp $
+ * $PostgreSQL: pgsql/contrib/hstore/hstore.h,v 1.7 2009/03/15 22:05:17 tgl Exp $
  */
 #ifndef __HSTORE_H__
 #define __HSTORE_H__
@@ -16,6 +16,11 @@ typedef struct
                pos:31;
 }  HEntry;
 
+/* these are determined by the sizes of the keylen and vallen fields */
+/* in struct HEntry and struct Pairs */
+#define HSTORE_MAX_KEY_LEN 65535
+#define HSTORE_MAX_VALUE_LEN 65535
+
 
 typedef struct
 {
@@ -45,6 +50,9 @@ typedef struct
 int            comparePairs(const void *a, const void *b);
 int            uniquePairs(Pairs * a, int4 l, int4 *buflen);
 
+size_t      hstoreCheckKeyLen(size_t len);
+size_t      hstoreCheckValLen(size_t len);
+
 #define HStoreContainsStrategyNumber   7
 #define HStoreExistsStrategyNumber     9
 
index d1ecc48fad05a5c5eee7dd8a43426e3613cfd27c..4786d7b4476d1f509d7047a20bba20f88efda4b2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $PostgreSQL: pgsql/contrib/hstore/hstore_io.c,v 1.8 2008/05/12 00:00:42 alvherre Exp $
+ * $PostgreSQL: pgsql/contrib/hstore/hstore_io.c,v 1.9 2009/03/15 22:05:17 tgl Exp $
  */
 #include "postgres.h"
 
@@ -188,7 +188,7 @@ parse_hstore(HSParser * state)
                state->pairs = (Pairs *) repalloc(state->pairs, sizeof(Pairs) * state->plen);
            }
            state->pairs[state->pcur].key = state->word;
-           state->pairs[state->pcur].keylen = state->cur - state->word;
+           state->pairs[state->pcur].keylen = hstoreCheckKeyLen(state->cur - state->word);
            state->pairs[state->pcur].val = NULL;
            state->word = NULL;
            st = WEQ;
@@ -228,7 +228,7 @@ parse_hstore(HSParser * state)
            if (!get_val(state, true, &escaped))
                elog(ERROR, "Unexpected end of string");
            state->pairs[state->pcur].val = state->word;
-           state->pairs[state->pcur].vallen = state->cur - state->word;
+           state->pairs[state->pcur].vallen = hstoreCheckValLen(state->cur - state->word);
            state->pairs[state->pcur].isnull = false;
            state->pairs[state->pcur].needfree = true;
            if (state->cur - state->word == 4 && !escaped)
@@ -268,11 +268,9 @@ comparePairs(const void *a, const void *b)
 {
    if (((Pairs *) a)->keylen == ((Pairs *) b)->keylen)
    {
-       int         res = strncmp(
-                                 ((Pairs *) a)->key,
+       int         res = strncmp(((Pairs *) a)->key,
                                  ((Pairs *) b)->key,
-                                 ((Pairs *) a)->keylen
-       );
+                                 ((Pairs *) a)->keylen);
 
        if (res)
            return res;
@@ -347,6 +345,27 @@ freeHSParse(HSParser * state)
    pfree(state->pairs);
 }
 
+size_t
+hstoreCheckKeyLen(size_t len)
+{
+   if (len > HSTORE_MAX_KEY_LEN)
+       ereport(ERROR,
+               (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
+                errmsg("string too long for hstore key")));
+   return len;
+}
+
+size_t
+hstoreCheckValLen(size_t len)
+{
+   if (len > HSTORE_MAX_VALUE_LEN)
+       ereport(ERROR,
+               (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
+                errmsg("string too long for hstore value")));
+   return len;
+}
+
+
 PG_FUNCTION_INFO_V1(hstore_in);
 Datum      hstore_in(PG_FUNCTION_ARGS);
 Datum
index bb1ebe4055f1a9e11d3e726c91ab53734ac47af1..dfd762b029b26a9302a4a76219be63821a582bbd 100644 (file)
@@ -295,7 +295,7 @@ tconvert(PG_FUNCTION_ARGS)
    SET_VARSIZE(out, len);
    out->size = 1;
 
-   ARRPTR(out)->keylen = VARSIZE(key) - VARHDRSZ;
+   ARRPTR(out)->keylen = hstoreCheckKeyLen(VARSIZE(key) - VARHDRSZ);
    if (PG_ARGISNULL(1))
    {
        ARRPTR(out)->vallen = 0;
@@ -303,7 +303,7 @@ tconvert(PG_FUNCTION_ARGS)
    }
    else
    {
-       ARRPTR(out)->vallen = VARSIZE(val) - VARHDRSZ;
+       ARRPTR(out)->vallen = hstoreCheckValLen(VARSIZE(val) - VARHDRSZ);
        ARRPTR(out)->valisnull = false;
    }
    ARRPTR(out)->pos = 0;
@@ -540,11 +540,9 @@ hs_contains(PG_FUNCTION_ARGS)
                    res = false;
            }
            else if (te->vallen != entry->vallen ||
-                    strncmp(
-                            vv + entry->pos + entry->keylen,
+                    strncmp(vv + entry->pos + entry->keylen,
                             tv + te->pos + te->keylen,
-                            te->vallen)
-               )
+                            te->vallen))
                res = false;
        }
        else
index 4418d5209e3687de3c97fe73c229c2c8de2382e5..48664b2b25b0143d849b62277101d408a0dfb3bc 100644 (file)
@@ -1,4 +1,4 @@
-
+
 
 
  hstore
   that are rarely examined, or semi-structured data.
  
 
+  In the current implementation, neither the key nor the value
+  string can exceed 65535 bytes in length; an error will be thrown if this
+  limit is exceeded. These maximum lengths may change in future releases.
+
  
   <type>hstore</> External Representation