Fix contrib/hstore to throw an error for keys or values that don't fit in its

data structure, rather than silently truncating them.  Andrew Gierth
This commit is contained in:
Tom Lane 2009-03-15 22:05:17 +00:00
parent 7a52a8f829
commit f3a72bd40b
4 changed files with 46 additions and 15 deletions

View 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__ #ifndef __HSTORE_H__
#define __HSTORE_H__ #define __HSTORE_H__
@ -16,6 +16,11 @@ typedef struct
pos:31; pos:31;
} HEntry; } 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 typedef struct
{ {
@ -45,6 +50,9 @@ typedef struct
int comparePairs(const void *a, const void *b); int comparePairs(const void *a, const void *b);
int uniquePairs(Pairs * a, int4 l, int4 *buflen); int uniquePairs(Pairs * a, int4 l, int4 *buflen);
size_t hstoreCheckKeyLen(size_t len);
size_t hstoreCheckValLen(size_t len);
#define HStoreContainsStrategyNumber 7 #define HStoreContainsStrategyNumber 7
#define HStoreExistsStrategyNumber 9 #define HStoreExistsStrategyNumber 9

View 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" #include "postgres.h"
@ -188,7 +188,7 @@ parse_hstore(HSParser * state)
state->pairs = (Pairs *) repalloc(state->pairs, sizeof(Pairs) * state->plen); state->pairs = (Pairs *) repalloc(state->pairs, sizeof(Pairs) * state->plen);
} }
state->pairs[state->pcur].key = state->word; 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->pairs[state->pcur].val = NULL;
state->word = NULL; state->word = NULL;
st = WEQ; st = WEQ;
@ -228,7 +228,7 @@ parse_hstore(HSParser * state)
if (!get_val(state, true, &escaped)) if (!get_val(state, true, &escaped))
elog(ERROR, "Unexpected end of string"); elog(ERROR, "Unexpected end of string");
state->pairs[state->pcur].val = state->word; 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].isnull = false;
state->pairs[state->pcur].needfree = true; state->pairs[state->pcur].needfree = true;
if (state->cur - state->word == 4 && !escaped) 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) if (((Pairs *) a)->keylen == ((Pairs *) b)->keylen)
{ {
int res = strncmp( int res = strncmp(((Pairs *) a)->key,
((Pairs *) a)->key,
((Pairs *) b)->key, ((Pairs *) b)->key,
((Pairs *) a)->keylen ((Pairs *) a)->keylen);
);
if (res) if (res)
return res; return res;
@ -347,6 +345,27 @@ freeHSParse(HSParser * state)
pfree(state->pairs); 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); PG_FUNCTION_INFO_V1(hstore_in);
Datum hstore_in(PG_FUNCTION_ARGS); Datum hstore_in(PG_FUNCTION_ARGS);
Datum Datum

View File

@ -295,7 +295,7 @@ tconvert(PG_FUNCTION_ARGS)
SET_VARSIZE(out, len); SET_VARSIZE(out, len);
out->size = 1; out->size = 1;
ARRPTR(out)->keylen = VARSIZE(key) - VARHDRSZ; ARRPTR(out)->keylen = hstoreCheckKeyLen(VARSIZE(key) - VARHDRSZ);
if (PG_ARGISNULL(1)) if (PG_ARGISNULL(1))
{ {
ARRPTR(out)->vallen = 0; ARRPTR(out)->vallen = 0;
@ -303,7 +303,7 @@ tconvert(PG_FUNCTION_ARGS)
} }
else else
{ {
ARRPTR(out)->vallen = VARSIZE(val) - VARHDRSZ; ARRPTR(out)->vallen = hstoreCheckValLen(VARSIZE(val) - VARHDRSZ);
ARRPTR(out)->valisnull = false; ARRPTR(out)->valisnull = false;
} }
ARRPTR(out)->pos = 0; ARRPTR(out)->pos = 0;
@ -540,11 +540,9 @@ hs_contains(PG_FUNCTION_ARGS)
res = false; res = false;
} }
else if (te->vallen != entry->vallen || else if (te->vallen != entry->vallen ||
strncmp( strncmp(vv + entry->pos + entry->keylen,
vv + entry->pos + entry->keylen,
tv + te->pos + te->keylen, tv + te->pos + te->keylen,
te->vallen) te->vallen))
)
res = false; res = false;
} }
else else

View File

@ -1,4 +1,4 @@
<!-- $PostgreSQL: pgsql/doc/src/sgml/hstore.sgml,v 1.2 2007/12/06 04:12:10 tgl Exp $ --> <!-- $PostgreSQL: pgsql/doc/src/sgml/hstore.sgml,v 1.3 2009/03/15 22:05:17 tgl Exp $ -->
<sect1 id="hstore"> <sect1 id="hstore">
<title>hstore</title> <title>hstore</title>
@ -14,6 +14,12 @@
that are rarely examined, or semi-structured data. that are rarely examined, or semi-structured data.
</para> </para>
<para>
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.
</para>
<sect2> <sect2>
<title><type>hstore</> External Representation</title> <title><type>hstore</> External Representation</title>