#include "hstore.h"
 #include "lib/stringinfo.h"
 #include "libpq/pqformat.h"
+#include "nodes/miscnodes.h"
 #include "utils/builtins.h"
 #include "utils/json.h"
 #include "utils/jsonb.h"
    char       *cur;
    char       *word;
    int         wordlen;
+   Node       *escontext;
 
    Pairs      *pairs;
    int         pcur;
    int         plen;
 } HSParser;
 
+static bool hstoreCheckKeyLength(size_t len, HSParser *state);
+static bool hstoreCheckValLength(size_t len, HSParser *state);
+
+
 #define RESIZEPRSBUF \
 do { \
        if ( state->cur - state->word + 1 >= state->wordlen ) \
        } \
 } while (0)
 
+#define PRSSYNTAXERROR return prssyntaxerror(state)
+
+static bool
+prssyntaxerror(HSParser *state)
+{
+   errsave(state->escontext,
+           (errcode(ERRCODE_SYNTAX_ERROR),
+            errmsg("syntax error in hstore, near \"%.*s\" at position %d",
+                   pg_mblen(state->ptr), state->ptr,
+                   (int) (state->ptr - state->begin))));
+   /* In soft error situation, return false as convenience for caller */
+   return false;
+}
+
+#define PRSEOF return prseof(state)
+
+static bool
+prseof(HSParser *state)
+{
+   errsave(state->escontext,
+           (errcode(ERRCODE_SYNTAX_ERROR),
+            errmsg("syntax error in hstore: unexpected end of string")));
+   /* In soft error situation, return false as convenience for caller */
+   return false;
+}
+
 
 #define GV_WAITVAL 0
 #define GV_INVAL 1
            }
            else if (*(state->ptr) == '=' && !ignoreeq)
            {
-               elog(ERROR, "Syntax error near \"%.*s\" at position %d",
-                    pg_mblen(state->ptr), state->ptr,
-                    (int32) (state->ptr - state->begin));
+               PRSSYNTAXERROR;
            }
            else if (*(state->ptr) == '\\')
            {
            }
            else if (*(state->ptr) == '\0')
            {
-               elog(ERROR, "Unexpected end of string");
+               PRSEOF;
            }
            else
            {
        else if (st == GV_WAITESCIN)
        {
            if (*(state->ptr) == '\0')
-               elog(ERROR, "Unexpected end of string");
+               PRSEOF;
            RESIZEPRSBUF;
            *(state->cur) = *(state->ptr);
            state->cur++;
        else if (st == GV_WAITESCESCIN)
        {
            if (*(state->ptr) == '\0')
-               elog(ERROR, "Unexpected end of string");
+               PRSEOF;
            RESIZEPRSBUF;
            *(state->cur) = *(state->ptr);
            state->cur++;
            st = GV_INESCVAL;
        }
        else
-           elog(ERROR, "Unknown state %d at position line %d in file '%s'", st, __LINE__, __FILE__);
+           elog(ERROR, "unrecognized get_val state: %d", st);
 
        state->ptr++;
    }
 #define WDEL   4
 
 
-static void
+static bool
 parse_hstore(HSParser *state)
 {
    int         st = WKEY;
        if (st == WKEY)
        {
            if (!get_val(state, false, &escaped))
-               return;
+           {
+               if (SOFT_ERROR_OCCURRED(state->escontext))
+                   return false;
+               return true;    /* EOF, all okay */
+           }
            if (state->pcur >= state->plen)
            {
                state->plen *= 2;
                state->pairs = (Pairs *) repalloc(state->pairs, sizeof(Pairs) * state->plen);
            }
+           if (!hstoreCheckKeyLength(state->cur - state->word, state))
+               return false;
            state->pairs[state->pcur].key = state->word;
-           state->pairs[state->pcur].keylen = hstoreCheckKeyLen(state->cur - state->word);
+           state->pairs[state->pcur].keylen = state->cur - state->word;
            state->pairs[state->pcur].val = NULL;
            state->word = NULL;
            st = WEQ;
            }
            else if (*(state->ptr) == '\0')
            {
-               elog(ERROR, "Unexpected end of string");
+               PRSEOF;
            }
            else if (!isspace((unsigned char) *(state->ptr)))
            {
-               elog(ERROR, "Syntax error near \"%.*s\" at position %d",
-                    pg_mblen(state->ptr), state->ptr,
-                    (int32) (state->ptr - state->begin));
+               PRSSYNTAXERROR;
            }
        }
        else if (st == WGT)
            }
            else if (*(state->ptr) == '\0')
            {
-               elog(ERROR, "Unexpected end of string");
+               PRSEOF;
            }
            else
            {
-               elog(ERROR, "Syntax error near \"%.*s\" at position %d",
-                    pg_mblen(state->ptr), state->ptr,
-                    (int32) (state->ptr - state->begin));
+               PRSSYNTAXERROR;
            }
        }
        else if (st == WVAL)
        {
            if (!get_val(state, true, &escaped))
-               elog(ERROR, "Unexpected end of string");
+           {
+               if (SOFT_ERROR_OCCURRED(state->escontext))
+                   return false;
+               PRSEOF;
+           }
+           if (!hstoreCheckValLength(state->cur - state->word, state))
+               return false;
            state->pairs[state->pcur].val = state->word;
-           state->pairs[state->pcur].vallen = hstoreCheckValLen(state->cur - state->word);
+           state->pairs[state->pcur].vallen = state->cur - state->word;
            state->pairs[state->pcur].isnull = false;
            state->pairs[state->pcur].needfree = true;
            if (state->cur - state->word == 4 && !escaped)
            {
                state->word[4] = '\0';
-               if (0 == pg_strcasecmp(state->word, "null"))
+               if (pg_strcasecmp(state->word, "null") == 0)
                    state->pairs[state->pcur].isnull = true;
            }
            state->word = NULL;
            }
            else if (*(state->ptr) == '\0')
            {
-               return;
+               return true;
            }
            else if (!isspace((unsigned char) *(state->ptr)))
            {
-               elog(ERROR, "Syntax error near \"%.*s\" at position %d",
-                    pg_mblen(state->ptr), state->ptr,
-                    (int32) (state->ptr - state->begin));
+               PRSSYNTAXERROR;
            }
        }
        else
-           elog(ERROR, "Unknown state %d at line %d in file '%s'", st, __LINE__, __FILE__);
+           elog(ERROR, "unrecognized parse_hstore state: %d", st);
 
        state->ptr++;
    }
    return len;
 }
 
+static bool
+hstoreCheckKeyLength(size_t len, HSParser *state)
+{
+   if (len > HSTORE_MAX_KEY_LEN)
+       ereturn(state->escontext, false,
+               (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
+                errmsg("string too long for hstore key")));
+   return true;
+}
+
 size_t
 hstoreCheckValLen(size_t len)
 {
    return len;
 }
 
+static bool
+hstoreCheckValLength(size_t len, HSParser *state)
+{
+   if (len > HSTORE_MAX_VALUE_LEN)
+       ereturn(state->escontext, false,
+               (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
+                errmsg("string too long for hstore value")));
+   return true;
+}
+
 
 HStore *
 hstorePairs(Pairs *pairs, int32 pcount, int32 buflen)
 Datum
 hstore_in(PG_FUNCTION_ARGS)
 {
+   char       *str = PG_GETARG_CSTRING(0);
+   Node       *escontext = fcinfo->context;
    HSParser    state;
    int32       buflen;
    HStore     *out;
 
-   state.begin = PG_GETARG_CSTRING(0);
+   state.begin = str;
+   state.escontext = escontext;
 
-   parse_hstore(&state);
+   if (!parse_hstore(&state))
+       PG_RETURN_NULL();
 
    state.pcur = hstoreUniquePairs(state.pairs, state.pcur, &buflen);