1212#include "hstore.h"
1313#include "lib/stringinfo.h"
1414#include "libpq/pqformat.h"
15+ #include "nodes/miscnodes.h"
1516#include "utils/builtins.h"
1617#include "utils/json.h"
1718#include "utils/jsonb.h"
@@ -32,12 +33,17 @@ typedef struct
3233char * cur ;
3334char * word ;
3435int wordlen ;
36+ Node * escontext ;
3537
3638Pairs * pairs ;
3739int pcur ;
3840int plen ;
3941}HSParser ;
4042
43+ static bool hstoreCheckKeyLength (size_t len ,HSParser * state );
44+ static bool hstoreCheckValLength (size_t len ,HSParser * state );
45+
46+
4147#define RESIZEPRSBUF \
4248do { \
4349if ( state->cur - state->word + 1 >= state->wordlen ) \
@@ -49,6 +55,32 @@ do { \
4955} \
5056} while (0)
5157
58+ #define PRSSYNTAXERROR return prssyntaxerror(state)
59+
60+ static bool
61+ prssyntaxerror (HSParser * state )
62+ {
63+ errsave (state -> escontext ,
64+ (errcode (ERRCODE_SYNTAX_ERROR ),
65+ errmsg ("syntax error in hstore, near \"%.*s\" at position %d" ,
66+ pg_mblen (state -> ptr ),state -> ptr ,
67+ (int ) (state -> ptr - state -> begin ))));
68+ /* In soft error situation, return false as convenience for caller */
69+ return false;
70+ }
71+
72+ #define PRSEOF return prseof(state)
73+
74+ static bool
75+ prseof (HSParser * state )
76+ {
77+ errsave (state -> escontext ,
78+ (errcode (ERRCODE_SYNTAX_ERROR ),
79+ errmsg ("syntax error in hstore: unexpected end of string" )));
80+ /* In soft error situation, return false as convenience for caller */
81+ return false;
82+ }
83+
5284
5385#define GV_WAITVAL 0
5486#define GV_INVAL 1
@@ -80,9 +112,7 @@ get_val(HSParser *state, bool ignoreeq, bool *escaped)
80112}
81113else if (* (state -> ptr )== '=' && !ignoreeq )
82114{
83- elog (ERROR ,"Syntax error near \"%.*s\" at position %d" ,
84- pg_mblen (state -> ptr ),state -> ptr ,
85- (int32 ) (state -> ptr - state -> begin ));
115+ PRSSYNTAXERROR ;
86116}
87117else if (* (state -> ptr )== '\\' )
88118{
@@ -139,7 +169,7 @@ get_val(HSParser *state, bool ignoreeq, bool *escaped)
139169}
140170else if (* (state -> ptr )== '\0' )
141171{
142- elog ( ERROR , "Unexpected end of string" ) ;
172+ PRSEOF ;
143173}
144174else
145175{
@@ -151,7 +181,7 @@ get_val(HSParser *state, bool ignoreeq, bool *escaped)
151181else if (st == GV_WAITESCIN )
152182{
153183if (* (state -> ptr )== '\0' )
154- elog ( ERROR , "Unexpected end of string" ) ;
184+ PRSEOF ;
155185RESIZEPRSBUF ;
156186* (state -> cur )= * (state -> ptr );
157187state -> cur ++ ;
@@ -160,14 +190,14 @@ get_val(HSParser *state, bool ignoreeq, bool *escaped)
160190else if (st == GV_WAITESCESCIN )
161191{
162192if (* (state -> ptr )== '\0' )
163- elog ( ERROR , "Unexpected end of string" ) ;
193+ PRSEOF ;
164194RESIZEPRSBUF ;
165195* (state -> cur )= * (state -> ptr );
166196state -> cur ++ ;
167197st = GV_INESCVAL ;
168198}
169199else
170- elog (ERROR ,"Unknown state %d at position line %d in file '%s' " ,st , __LINE__ , __FILE__ );
200+ elog (ERROR ,"unrecognized get_val state: %d" ,st );
171201
172202state -> ptr ++ ;
173203}
@@ -180,7 +210,7 @@ get_val(HSParser *state, bool ignoreeq, bool *escaped)
180210#define WDEL 4
181211
182212
183- static void
213+ static bool
184214parse_hstore (HSParser * state )
185215{
186216int st = WKEY ;
@@ -197,14 +227,20 @@ parse_hstore(HSParser *state)
197227if (st == WKEY )
198228{
199229if (!get_val (state , false,& escaped ))
200- return ;
230+ {
231+ if (SOFT_ERROR_OCCURRED (state -> escontext ))
232+ return false;
233+ return true;/* EOF, all okay */
234+ }
201235if (state -> pcur >=state -> plen )
202236{
203237state -> plen *=2 ;
204238state -> pairs = (Pairs * )repalloc (state -> pairs ,sizeof (Pairs )* state -> plen );
205239}
240+ if (!hstoreCheckKeyLength (state -> cur - state -> word ,state ))
241+ return false;
206242state -> pairs [state -> pcur ].key = state -> word ;
207- state -> pairs [state -> pcur ].keylen = hstoreCheckKeyLen ( state -> cur - state -> word ) ;
243+ state -> pairs [state -> pcur ].keylen = state -> cur - state -> word ;
208244state -> pairs [state -> pcur ].val = NULL ;
209245state -> word = NULL ;
210246st = WEQ ;
@@ -217,13 +253,11 @@ parse_hstore(HSParser *state)
217253}
218254else if (* (state -> ptr )== '\0' )
219255{
220- elog ( ERROR , "Unexpected end of string" ) ;
256+ PRSEOF ;
221257}
222258else if (!isspace ((unsignedchar )* (state -> ptr )))
223259{
224- elog (ERROR ,"Syntax error near \"%.*s\" at position %d" ,
225- pg_mblen (state -> ptr ),state -> ptr ,
226- (int32 ) (state -> ptr - state -> begin ));
260+ PRSSYNTAXERROR ;
227261}
228262}
229263else if (st == WGT )
@@ -234,27 +268,31 @@ parse_hstore(HSParser *state)
234268}
235269else if (* (state -> ptr )== '\0' )
236270{
237- elog ( ERROR , "Unexpected end of string" ) ;
271+ PRSEOF ;
238272}
239273else
240274{
241- elog (ERROR ,"Syntax error near \"%.*s\" at position %d" ,
242- pg_mblen (state -> ptr ),state -> ptr ,
243- (int32 ) (state -> ptr - state -> begin ));
275+ PRSSYNTAXERROR ;
244276}
245277}
246278else if (st == WVAL )
247279{
248280if (!get_val (state , true,& escaped ))
249- elog (ERROR ,"Unexpected end of string" );
281+ {
282+ if (SOFT_ERROR_OCCURRED (state -> escontext ))
283+ return false;
284+ PRSEOF ;
285+ }
286+ if (!hstoreCheckValLength (state -> cur - state -> word ,state ))
287+ return false;
250288state -> pairs [state -> pcur ].val = state -> word ;
251- state -> pairs [state -> pcur ].vallen = hstoreCheckValLen ( state -> cur - state -> word ) ;
289+ state -> pairs [state -> pcur ].vallen = state -> cur - state -> word ;
252290state -> pairs [state -> pcur ].isnull = false;
253291state -> pairs [state -> pcur ].needfree = true;
254292if (state -> cur - state -> word == 4 && !escaped )
255293{
256294state -> word [4 ]= '\0' ;
257- if (0 == pg_strcasecmp (state -> word ,"null" ))
295+ if (pg_strcasecmp (state -> word ,"null" )== 0 )
258296state -> pairs [state -> pcur ].isnull = true;
259297}
260298state -> word = NULL ;
@@ -269,17 +307,15 @@ parse_hstore(HSParser *state)
269307}
270308else if (* (state -> ptr )== '\0' )
271309{
272- return ;
310+ return true ;
273311}
274312else if (!isspace ((unsignedchar )* (state -> ptr )))
275313{
276- elog (ERROR ,"Syntax error near \"%.*s\" at position %d" ,
277- pg_mblen (state -> ptr ),state -> ptr ,
278- (int32 ) (state -> ptr - state -> begin ));
314+ PRSSYNTAXERROR ;
279315}
280316}
281317else
282- elog (ERROR ,"Unknown state %d at line %d in file '%s' " ,st , __LINE__ , __FILE__ );
318+ elog (ERROR ,"unrecognized parse_hstore state: %d" ,st );
283319
284320state -> ptr ++ ;
285321}
@@ -373,6 +409,16 @@ hstoreCheckKeyLen(size_t len)
373409return len ;
374410}
375411
412+ static bool
413+ hstoreCheckKeyLength (size_t len ,HSParser * state )
414+ {
415+ if (len > HSTORE_MAX_KEY_LEN )
416+ ereturn (state -> escontext , false,
417+ (errcode (ERRCODE_STRING_DATA_RIGHT_TRUNCATION ),
418+ errmsg ("string too long for hstore key" )));
419+ return true;
420+ }
421+
376422size_t
377423hstoreCheckValLen (size_t len )
378424{
@@ -383,6 +429,16 @@ hstoreCheckValLen(size_t len)
383429return len ;
384430}
385431
432+ static bool
433+ hstoreCheckValLength (size_t len ,HSParser * state )
434+ {
435+ if (len > HSTORE_MAX_VALUE_LEN )
436+ ereturn (state -> escontext , false,
437+ (errcode (ERRCODE_STRING_DATA_RIGHT_TRUNCATION ),
438+ errmsg ("string too long for hstore value" )));
439+ return true;
440+ }
441+
386442
387443HStore *
388444hstorePairs (Pairs * pairs ,int32 pcount ,int32 buflen )
@@ -418,13 +474,17 @@ PG_FUNCTION_INFO_V1(hstore_in);
418474Datum
419475hstore_in (PG_FUNCTION_ARGS )
420476{
477+ char * str = PG_GETARG_CSTRING (0 );
478+ Node * escontext = fcinfo -> context ;
421479HSParser state ;
422480int32 buflen ;
423481HStore * out ;
424482
425- state .begin = PG_GETARG_CSTRING (0 );
483+ state .begin = str ;
484+ state .escontext = escontext ;
426485
427- parse_hstore (& state );
486+ if (!parse_hstore (& state ))
487+ PG_RETURN_NULL ();
428488
429489state .pcur = hstoreUniquePairs (state .pairs ,state .pcur ,& buflen );
430490