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
3233 char * cur ;
3334 char * word ;
3435 int wordlen ;
36+ Node * escontext ;
3537
3638 Pairs * pairs ;
3739 int pcur ;
3840 int 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 { \
4349 if ( 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 }
81113 else 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 }
87117 else if (* (state -> ptr ) == '\\' )
88118 {
@@ -139,7 +169,7 @@ get_val(HSParser *state, bool ignoreeq, bool *escaped)
139169 }
140170 else if (* (state -> ptr ) == '\0' )
141171 {
142- elog ( ERROR , "Unexpected end of string" ) ;
172+ PRSEOF ;
143173 }
144174 else
145175 {
@@ -151,7 +181,7 @@ get_val(HSParser *state, bool ignoreeq, bool *escaped)
151181 else if (st == GV_WAITESCIN )
152182 {
153183 if (* (state -> ptr ) == '\0' )
154- elog ( ERROR , "Unexpected end of string" ) ;
184+ PRSEOF ;
155185 RESIZEPRSBUF ;
156186 * (state -> cur ) = * (state -> ptr );
157187 state -> cur ++ ;
@@ -160,14 +190,14 @@ get_val(HSParser *state, bool ignoreeq, bool *escaped)
160190 else if (st == GV_WAITESCESCIN )
161191 {
162192 if (* (state -> ptr ) == '\0' )
163- elog ( ERROR , "Unexpected end of string" ) ;
193+ PRSEOF ;
164194 RESIZEPRSBUF ;
165195 * (state -> cur ) = * (state -> ptr );
166196 state -> cur ++ ;
167197 st = GV_INESCVAL ;
168198 }
169199 else
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
172202 state -> 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{
186216 int st = WKEY ;
@@ -197,14 +227,20 @@ parse_hstore(HSParser *state)
197227 if (st == WKEY )
198228 {
199229 if (!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+ }
201235 if (state -> pcur >= state -> plen )
202236 {
203237 state -> plen *= 2 ;
204238 state -> pairs = (Pairs * ) repalloc (state -> pairs , sizeof (Pairs ) * state -> plen );
205239 }
240+ if (!hstoreCheckKeyLength (state -> cur - state -> word , state ))
241+ return false;
206242 state -> 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 ;
208244 state -> pairs [state -> pcur ].val = NULL ;
209245 state -> word = NULL ;
210246 st = WEQ ;
@@ -217,13 +253,11 @@ parse_hstore(HSParser *state)
217253 }
218254 else if (* (state -> ptr ) == '\0' )
219255 {
220- elog ( ERROR , "Unexpected end of string" ) ;
256+ PRSEOF ;
221257 }
222258 else if (!isspace ((unsigned char ) * (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 }
229263 else if (st == WGT )
@@ -234,27 +268,31 @@ parse_hstore(HSParser *state)
234268 }
235269 else if (* (state -> ptr ) == '\0' )
236270 {
237- elog ( ERROR , "Unexpected end of string" ) ;
271+ PRSEOF ;
238272 }
239273 else
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 }
246278 else if (st == WVAL )
247279 {
248280 if (!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;
250288 state -> 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 ;
252290 state -> pairs [state -> pcur ].isnull = false;
253291 state -> pairs [state -> pcur ].needfree = true;
254292 if (state -> cur - state -> word == 4 && !escaped )
255293 {
256294 state -> word [4 ] = '\0' ;
257- if (0 == pg_strcasecmp (state -> word , "null" ))
295+ if (pg_strcasecmp (state -> word , "null" ) == 0 )
258296 state -> pairs [state -> pcur ].isnull = true;
259297 }
260298 state -> word = NULL ;
@@ -269,17 +307,15 @@ parse_hstore(HSParser *state)
269307 }
270308 else if (* (state -> ptr ) == '\0' )
271309 {
272- return ;
310+ return true ;
273311 }
274312 else if (!isspace ((unsigned char ) * (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 }
281317 else
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
284320 state -> ptr ++ ;
285321 }
@@ -373,6 +409,16 @@ hstoreCheckKeyLen(size_t len)
373409 return 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)
383429 return 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 ;
421479 HSParser state ;
422480 int32 buflen ;
423481 HStore * 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
429489 state .pcur = hstoreUniquePairs (state .pairs , state .pcur , & buflen );
430490
0 commit comments