12
12
#include "hstore.h"
13
13
#include "lib/stringinfo.h"
14
14
#include "libpq/pqformat.h"
15
+ #include "nodes/miscnodes.h"
15
16
#include "utils/builtins.h"
16
17
#include "utils/json.h"
17
18
#include "utils/jsonb.h"
@@ -32,12 +33,17 @@ typedef struct
32
33
char * cur ;
33
34
char * word ;
34
35
int wordlen ;
36
+ Node * escontext ;
35
37
36
38
Pairs * pairs ;
37
39
int pcur ;
38
40
int plen ;
39
41
} HSParser ;
40
42
43
+ static bool hstoreCheckKeyLength (size_t len , HSParser * state );
44
+ static bool hstoreCheckValLength (size_t len , HSParser * state );
45
+
46
+
41
47
#define RESIZEPRSBUF \
42
48
do { \
43
49
if ( state->cur - state->word + 1 >= state->wordlen ) \
@@ -49,6 +55,32 @@ do { \
49
55
} \
50
56
} while (0)
51
57
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
+
52
84
53
85
#define GV_WAITVAL 0
54
86
#define GV_INVAL 1
@@ -80,9 +112,7 @@ get_val(HSParser *state, bool ignoreeq, bool *escaped)
80
112
}
81
113
else if (* (state -> ptr ) == '=' && !ignoreeq )
82
114
{
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 ;
86
116
}
87
117
else if (* (state -> ptr ) == '\\' )
88
118
{
@@ -139,7 +169,7 @@ get_val(HSParser *state, bool ignoreeq, bool *escaped)
139
169
}
140
170
else if (* (state -> ptr ) == '\0' )
141
171
{
142
- elog ( ERROR , "Unexpected end of string" ) ;
172
+ PRSEOF ;
143
173
}
144
174
else
145
175
{
@@ -151,7 +181,7 @@ get_val(HSParser *state, bool ignoreeq, bool *escaped)
151
181
else if (st == GV_WAITESCIN )
152
182
{
153
183
if (* (state -> ptr ) == '\0' )
154
- elog ( ERROR , "Unexpected end of string" ) ;
184
+ PRSEOF ;
155
185
RESIZEPRSBUF ;
156
186
* (state -> cur ) = * (state -> ptr );
157
187
state -> cur ++ ;
@@ -160,14 +190,14 @@ get_val(HSParser *state, bool ignoreeq, bool *escaped)
160
190
else if (st == GV_WAITESCESCIN )
161
191
{
162
192
if (* (state -> ptr ) == '\0' )
163
- elog ( ERROR , "Unexpected end of string" ) ;
193
+ PRSEOF ;
164
194
RESIZEPRSBUF ;
165
195
* (state -> cur ) = * (state -> ptr );
166
196
state -> cur ++ ;
167
197
st = GV_INESCVAL ;
168
198
}
169
199
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 );
171
201
172
202
state -> ptr ++ ;
173
203
}
@@ -180,7 +210,7 @@ get_val(HSParser *state, bool ignoreeq, bool *escaped)
180
210
#define WDEL 4
181
211
182
212
183
- static void
213
+ static bool
184
214
parse_hstore (HSParser * state )
185
215
{
186
216
int st = WKEY ;
@@ -197,14 +227,20 @@ parse_hstore(HSParser *state)
197
227
if (st == WKEY )
198
228
{
199
229
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
+ }
201
235
if (state -> pcur >= state -> plen )
202
236
{
203
237
state -> plen *= 2 ;
204
238
state -> pairs = (Pairs * ) repalloc (state -> pairs , sizeof (Pairs ) * state -> plen );
205
239
}
240
+ if (!hstoreCheckKeyLength (state -> cur - state -> word , state ))
241
+ return false;
206
242
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 ;
208
244
state -> pairs [state -> pcur ].val = NULL ;
209
245
state -> word = NULL ;
210
246
st = WEQ ;
@@ -217,13 +253,11 @@ parse_hstore(HSParser *state)
217
253
}
218
254
else if (* (state -> ptr ) == '\0' )
219
255
{
220
- elog ( ERROR , "Unexpected end of string" ) ;
256
+ PRSEOF ;
221
257
}
222
258
else if (!isspace ((unsigned char ) * (state -> ptr )))
223
259
{
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 ;
227
261
}
228
262
}
229
263
else if (st == WGT )
@@ -234,27 +268,31 @@ parse_hstore(HSParser *state)
234
268
}
235
269
else if (* (state -> ptr ) == '\0' )
236
270
{
237
- elog ( ERROR , "Unexpected end of string" ) ;
271
+ PRSEOF ;
238
272
}
239
273
else
240
274
{
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 ;
244
276
}
245
277
}
246
278
else if (st == WVAL )
247
279
{
248
280
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;
250
288
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 ;
252
290
state -> pairs [state -> pcur ].isnull = false;
253
291
state -> pairs [state -> pcur ].needfree = true;
254
292
if (state -> cur - state -> word == 4 && !escaped )
255
293
{
256
294
state -> word [4 ] = '\0' ;
257
- if (0 == pg_strcasecmp (state -> word , "null" ))
295
+ if (pg_strcasecmp (state -> word , "null" ) == 0 )
258
296
state -> pairs [state -> pcur ].isnull = true;
259
297
}
260
298
state -> word = NULL ;
@@ -269,17 +307,15 @@ parse_hstore(HSParser *state)
269
307
}
270
308
else if (* (state -> ptr ) == '\0' )
271
309
{
272
- return ;
310
+ return true ;
273
311
}
274
312
else if (!isspace ((unsigned char ) * (state -> ptr )))
275
313
{
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 ;
279
315
}
280
316
}
281
317
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 );
283
319
284
320
state -> ptr ++ ;
285
321
}
@@ -373,6 +409,16 @@ hstoreCheckKeyLen(size_t len)
373
409
return len ;
374
410
}
375
411
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
+
376
422
size_t
377
423
hstoreCheckValLen (size_t len )
378
424
{
@@ -383,6 +429,16 @@ hstoreCheckValLen(size_t len)
383
429
return len ;
384
430
}
385
431
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
+
386
442
387
443
HStore *
388
444
hstorePairs (Pairs * pairs , int32 pcount , int32 buflen )
@@ -418,13 +474,17 @@ PG_FUNCTION_INFO_V1(hstore_in);
418
474
Datum
419
475
hstore_in (PG_FUNCTION_ARGS )
420
476
{
477
+ char * str = PG_GETARG_CSTRING (0 );
478
+ Node * escontext = fcinfo -> context ;
421
479
HSParser state ;
422
480
int32 buflen ;
423
481
HStore * out ;
424
482
425
- state .begin = PG_GETARG_CSTRING (0 );
483
+ state .begin = str ;
484
+ state .escontext = escontext ;
426
485
427
- parse_hstore (& state );
486
+ if (!parse_hstore (& state ))
487
+ PG_RETURN_NULL ();
428
488
429
489
state .pcur = hstoreUniquePairs (state .pairs , state .pcur , & buflen );
430
490
0 commit comments