25 #define RESIZEPRSBUF \
27 if ( state->cur - state->word + 1 >= state->wordlen ) \
29 int4 clen = state->cur - state->word; \
30 state->wordlen *= 2; \
31 state->word = (char*)repalloc( (void*)state->word, state->wordlen ); \
32 state->cur = state->word + clen; \
40 #define GV_WAITESCIN 3
41 #define GV_WAITESCESCIN 4
44 get_val(HSParser
* state
, bool ignoreeq
, bool *escaped
)
49 state
->cur
= state
->word
= palloc(state
->wordlen
);
56 if (*(state
->ptr
) == '"')
61 else if (*(state
->ptr
) == '\0')
65 else if (*(state
->ptr
) == '=' && !ignoreeq
)
67 elog(ERROR
, "Syntax error near '%c' at postion %d", *(state
->ptr
), (int4
) (state
->ptr
- state
->begin
));
69 else if (*(state
->ptr
) == '\\')
73 else if (!isspace((unsigned char) *(state
->ptr
)))
75 *(state
->cur
) = *(state
->ptr
);
80 else if (st
== GV_INVAL
)
82 if (*(state
->ptr
) == '\\')
86 else if (*(state
->ptr
) == '=' && !ignoreeq
)
91 else if (*(state
->ptr
) == ',' && ignoreeq
)
96 else if (isspace((unsigned char) *(state
->ptr
)))
100 else if (*(state
->ptr
) == '\0')
108 *(state
->cur
) = *(state
->ptr
);
112 else if (st
== GV_INESCVAL
)
114 if (*(state
->ptr
) == '\\')
116 st
= GV_WAITESCESCIN
;
118 else if (*(state
->ptr
) == '"')
122 else if (*(state
->ptr
) == '\0')
124 elog(ERROR
, "Unexpected end of string");
129 *(state
->cur
) = *(state
->ptr
);
133 else if (st
== GV_WAITESCIN
)
135 if (*(state
->ptr
) == '\0')
136 elog(ERROR
, "Unexpected end of string");
138 *(state
->cur
) = *(state
->ptr
);
142 else if (st
== GV_WAITESCESCIN
)
144 if (*(state
->ptr
) == '\0')
145 elog(ERROR
, "Unexpected end of string");
147 *(state
->cur
) = *(state
->ptr
);
152 elog(ERROR
, "Unknown state %d at position line %d in file '%s'", st
, __LINE__
, __FILE__
);
168 parse_hstore(HSParser
* state
)
171 bool escaped
= false;
174 state
->pairs
= (Pairs
*) palloc(sizeof(Pairs
) * state
->plen
);
176 state
->ptr
= state
->begin
;
183 if (!get_val(state
, false, &escaped
))
185 if (state
->pcur
>= state
->plen
)
188 state
->pairs
= (Pairs
*) repalloc(state
->pairs
, sizeof(Pairs
) * state
->plen
);
190 state
->pairs
[state
->pcur
].key
= state
->word
;
191 state
->pairs
[state
->pcur
].keylen
= state
->cur
- state
->word
;
192 state
->pairs
[state
->pcur
].val
= NULL
;
198 if (*(state
->ptr
) == '=')
202 else if (*(state
->ptr
) == '\0')
204 elog(ERROR
, "Unexpected end of string");
206 else if (!isspace((unsigned char) *(state
->ptr
)))
208 elog(ERROR
, "Syntax error near '%c' at position %d", *(state
->ptr
), (int4
) (state
->ptr
- state
->begin
));
213 if (*(state
->ptr
) == '>')
217 else if (*(state
->ptr
) == '\0')
219 elog(ERROR
, "Unexpected end of string");
223 elog(ERROR
, "Syntax error near '%c' at position %d", *(state
->ptr
), (int4
) (state
->ptr
- state
->begin
));
228 if (!get_val(state
, true, &escaped
))
229 elog(ERROR
, "Unexpected end of string");
230 state
->pairs
[state
->pcur
].val
= state
->word
;
231 state
->pairs
[state
->pcur
].vallen
= state
->cur
- state
->word
;
232 state
->pairs
[state
->pcur
].isnull
= false;
233 state
->pairs
[state
->pcur
].needfree
= true;
234 if (state
->cur
- state
->word
== 4 && !escaped
)
236 state
->word
[4] = '\0';
237 if (0 == pg_strcasecmp(state
->word
, "null"))
238 state
->pairs
[state
->pcur
].isnull
= true;
246 if (*(state
->ptr
) == ',')
250 else if (*(state
->ptr
) == '\0')
254 else if (!isspace((unsigned char) *(state
->ptr
)))
256 elog(ERROR
, "Syntax error near '%c' at position %d", *(state
->ptr
), (int4
) (state
->ptr
- state
->begin
));
260 elog(ERROR
, "Unknown state %d at line %d in file '%s'", st
, __LINE__
, __FILE__
);
267 comparePairs(const void *a
, const void *b
)
269 if (((Pairs
*) a
)->keylen
== ((Pairs
*) b
)->keylen
)
274 ((Pairs
*) a
)->keylen
280 /* guarantee that needfree will be later */
281 if (((Pairs
*) b
)->needfree
== ((Pairs
*) a
)->needfree
)
283 else if (((Pairs
*) a
)->needfree
)
288 return (((Pairs
*) a
)->keylen
> ((Pairs
*) b
)->keylen
) ? 1 : -1;
292 uniquePairs(Pairs
* a
, int4 l
, int4
*buflen
)
301 *buflen
= a
->keylen
+ ((a
->isnull
) ? 0 : a
->vallen
);
305 qsort((void *) a
, l
, sizeof(Pairs
), comparePairs
);
310 if (ptr
->keylen
== res
->keylen
&& strncmp(ptr
->key
, res
->key
, res
->keylen
) == 0)
320 *buflen
+= res
->keylen
+ ((res
->isnull
) ? 0 : res
->vallen
);
322 memcpy(res
, ptr
, sizeof(Pairs
));
328 *buflen
+= res
->keylen
+ ((res
->isnull
) ? 0 : res
->vallen
);
333 freeHSParse(HSParser
* state
)
339 for (i
= 0; i
< state
->pcur
; i
++)
340 if (state
->pairs
[i
].needfree
)
342 if (state
->pairs
[i
].key
)
343 pfree(state
->pairs
[i
].key
);
344 if (state
->pairs
[i
].val
)
345 pfree(state
->pairs
[i
].val
);
350 PG_FUNCTION_INFO_V1(hstore_in
);
351 Datum
hstore_in(PG_FUNCTION_ARGS
);
353 hstore_in(PG_FUNCTION_ARGS
)
363 state
.begin
= PG_GETARG_CSTRING(0);
365 parse_hstore(&state
);
370 len
= CALCDATASIZE(0, 0);
372 SET_VARSIZE(out
, len
);
374 PG_RETURN_POINTER(out
);
377 state
.pcur
= uniquePairs(state
.pairs
, state
.pcur
, &buflen
);
379 len
= CALCDATASIZE(state
.pcur
, buflen
);
381 SET_VARSIZE(out
, len
);
382 out
->size
= state
.pcur
;
384 entries
= ARRPTR(out
);
387 for (i
= 0; i
< out
->size
; i
++)
389 entries
[i
].keylen
= state
.pairs
[i
].keylen
;
390 entries
[i
].pos
= ptr
- STRPTR(out
);
391 memcpy(ptr
, state
.pairs
[i
].key
, state
.pairs
[i
].keylen
);
392 ptr
+= entries
[i
].keylen
;
394 entries
[i
].valisnull
= state
.pairs
[i
].isnull
;
395 if (entries
[i
].valisnull
)
396 entries
[i
].vallen
= 4; /* null */
399 entries
[i
].vallen
= state
.pairs
[i
].vallen
;
400 memcpy(ptr
, state
.pairs
[i
].val
, state
.pairs
[i
].vallen
);
401 ptr
+= entries
[i
].vallen
;
406 PG_RETURN_POINTER(out
);
410 cpw(char *dst
, char *src
, int len
)
414 while (ptr
- src
< len
)
416 if (*ptr
== '"' || *ptr
== '\\')
423 PG_FUNCTION_INFO_V1(hstore_out
);
424 Datum
hstore_out(PG_FUNCTION_ARGS
);
426 hstore_out(PG_FUNCTION_ARGS
)
428 HStore
*in
= PG_GETARG_HS(0);
433 char *base
= STRPTR(in
);
434 HEntry
*entries
= ARRPTR(in
);
440 PG_FREE_IF_COPY(in
, 0);
441 PG_RETURN_CSTRING(out
);
444 buflen
= (4 /* " */ + 2 /* => */ + 2 /* , */ ) * in
->size
+
445 2 /* esc */ * (VARSIZE(in
) - CALCDATASIZE(in
->size
, 0));
447 out
= ptr
= palloc(buflen
);
448 for (i
= 0; i
< in
->size
; i
++)
451 ptr
= cpw(ptr
, base
+ entries
[i
].pos
, entries
[i
].keylen
);
455 if (entries
[i
].valisnull
)
465 ptr
= cpw(ptr
, base
+ entries
[i
].pos
+ entries
[i
].keylen
, entries
[i
].vallen
);
469 if (i
+ 1 != in
->size
)
477 PG_FREE_IF_COPY(in
, 0);
478 PG_RETURN_CSTRING(out
);