20 #define RESIZEPRSBUF \
22 if ( state->cur - state->word + 1 >= state->wordlen ) \
24 int4 clen = state->cur - state->word; \
25 state->wordlen *= 2; \
26 state->word = (char*)repalloc( (void*)state->word, state->wordlen ); \
27 state->cur = state->word + clen; \
35 #define GV_WAITESCIN 3
36 #define GV_WAITESCESCIN 4
39 get_val( HSParser *state, bool ignoreeq, bool *escaped ) {
42 state->cur = state->word = palloc( state->wordlen );
46 if ( st == GV_WAITVAL ) {
47 if ( *(state->ptr) == '"' ) {
50 } else if ( *(state->ptr) == '\0' ) {
52 } else if ( *(state->ptr) == '=' && !ignoreeq ) {
53 elog(ERROR,"Syntax error near '%c' at postion %d", *(state->ptr), state->ptr-state->begin);
54 } else if ( *(state->ptr) == '\\' ) {
56 } else if ( !isspace(*(state->ptr)) ) {
57 *(state->cur) = *(state->ptr);
61 } else if ( st == GV_INVAL ) {
62 if ( *(state->ptr) == '\\' ) {
64 } else if ( *(state->ptr) == '=' && !ignoreeq ) {
67 } else if ( *(state->ptr) == ',' && ignoreeq ) {
70 } else if ( isspace(*(state->ptr)) ) {
72 } else if ( *(state->ptr) == '\0' ) {
77 *(state->cur) = *(state->ptr);
80 } else if ( st == GV_INESCVAL ) {
81 if ( *(state->ptr) == '\\' ) {
83 } else if ( *(state->ptr) == '"' ) {
85 } else if ( *(state->ptr) == '\0' ) {
86 elog(ERROR,"Unexpected end of string");
89 *(state->cur) = *(state->ptr);
92 } else if ( st == GV_WAITESCIN ) {
93 if ( *(state->ptr) == '\0' )
94 elog(ERROR,"Unexpected end of string");
96 *(state->cur) = *(state->ptr);
99 } else if ( st == GV_WAITESCESCIN ) {
100 if ( *(state->ptr) == '\0' )
101 elog(ERROR,"Unexpected end of string");
103 *(state->cur) = *(state->ptr);
107 elog(ERROR,"Unknown state %d at postion line %d in file '%s'", st, __LINE__, __FILE__);
123 parse_hstore( HSParser *state ) {
128 state->pairs = (Pairs*)palloc( sizeof(Pairs) * state->plen );
130 state->ptr = state->begin;
135 if ( !get_val(state, false, &escaped) )
137 if ( state->pcur >= state->plen ) {
139 state->pairs = (Pairs*)repalloc( state->pairs, sizeof(Pairs) * state->plen );
141 state->pairs[ state->pcur ].key = state->word;
142 state->pairs[ state->pcur ].keylen = state->cur - state->word;
143 state->pairs[ state->pcur ].val=NULL;
146 } else if ( st == WEQ ) {
147 if ( *(state->ptr) == '=' ) {
149 } else if ( *(state->ptr) == '\0' ) {
150 elog(ERROR,"Unexpectd end of string");
151 } else if (!isspace(*(state->ptr))) {
152 elog(ERROR,"Syntax error near '%c' at postion %d", *(state->ptr), state->ptr-state->begin);
154 } else if ( st == WGT ) {
155 if ( *(state->ptr) == '>' ) {
157 } else if ( *(state->ptr) == '\0' ) {
158 elog(ERROR,"Unexpectd end of string");
160 elog(ERROR,"Syntax error near '%c' at postion %d", *(state->ptr), state->ptr-state->begin);
162 } else if ( st == WVAL ) {
163 if ( !get_val(state, true, &escaped) )
164 elog(ERROR,"Unexpected end of string");
165 state->pairs[ state->pcur ].val = state->word;
166 state->pairs[ state->pcur ].vallen = state->cur - state->word;
167 state->pairs[ state->pcur ].isnull = false;
168 state->pairs[ state->pcur ].needfree = true;
169 if ( state->cur - state->word == 4 && !escaped) {
170 state->word[4] = '\0';
171 if ( 0==strcasecmp(state->word, "null") )
172 state->pairs[ state->pcur ].isnull=true;
177 } else if ( st == WDEL ) {
178 if ( *(state->ptr) == ',' ) {
180 } else if ( *(state->ptr) == '\0' ) {
182 } else if (!isspace(*(state->ptr))) {
183 elog(ERROR,"Syntax error near '%c' at postion %d", *(state->ptr), state->ptr-state->begin);
186 elog(ERROR,"Unknown state %d at line %d in file '%s'", st, __LINE__, __FILE__);
193 comparePairs(const void *a, const void *b) {
194 if ( ((Pairs*)a)->keylen == ((Pairs*)b)->keylen ) {
203 /* guarantee that neddfree willl be later */
204 if ( ((Pairs*)b)->needfree == ((Pairs*)a)->needfree )
206 else if ( ((Pairs*)a)->needfree )
211 return ( ((Pairs*)a)->keylen > ((Pairs*)b)->keylen ) ? 1 : -1;
215 uniquePairs(Pairs * a, int4 l, int4 *buflen) {
221 *buflen = a->keylen + ((a->isnull) ? 0 : a->vallen) ;
225 qsort((void *) a, l, sizeof(Pairs), comparePairs);
228 while( ptr - a < l ) {
229 if ( ptr->keylen == res->keylen && strncmp( ptr->key, res->key, res->keylen )==0 ) {
230 if ( ptr->needfree ) {
235 *buflen += res->keylen + (( res->isnull ) ? 0 : res->vallen);
237 memcpy(res,ptr,sizeof(Pairs));
243 *buflen += res->keylen + (( res->isnull ) ? 0 : res->vallen);
248 freeHSParse(HSParser *state) {
251 if ( state->word ) pfree( state->word );
252 for (i=0;i<state->pcur;i++)
253 if ( state->pairs[i].needfree ) {
254 if (state->pairs[i].key) pfree(state->pairs[i].key);
255 if (state->pairs[i].val) pfree(state->pairs[i].val);
257 pfree( state->pairs );
260 PG_FUNCTION_INFO_V1(hstore_in);
261 Datum hstore_in(PG_FUNCTION_ARGS);
263 hstore_in(PG_FUNCTION_ARGS) {
270 state.begin = PG_GETARG_CSTRING(0);
272 parse_hstore(&state);
274 if ( state.pcur == 0 ) {
276 len = CALCDATASIZE(0,0);
280 PG_RETURN_POINTER(out);
283 state.pcur = uniquePairs(state.pairs, state.pcur, &buflen);
285 len=CALCDATASIZE(state.pcur, buflen);
288 out->size=state.pcur;
293 for(i=0;i<out->size;i++) {
294 entries[i].keylen = state.pairs[i].keylen;
295 entries[i].pos = ptr - STRPTR(out);
296 memcpy(ptr, state.pairs[i].key, state.pairs[i].keylen);
297 ptr+=entries[i].keylen;
299 entries[i].valisnull = state.pairs[i].isnull;
300 if ( entries[i].valisnull )
301 entries[i].vallen=4; /* null */
303 entries[i].vallen = state.pairs[i].vallen;
304 memcpy(ptr, state.pairs[i].val,state.pairs[i].vallen);
305 ptr+=entries[i].vallen;
310 PG_RETURN_POINTER(out);
314 cpw(char *dst, char *src, int len) {
318 if ( *ptr == '"' || *ptr == '\\' )
325 PG_FUNCTION_INFO_V1(hstore_out);
326 Datum hstore_out(PG_FUNCTION_ARGS);
328 hstore_out(PG_FUNCTION_ARGS) {
329 HStore *in = PG_GETARG_HS(0);
332 char *base = STRPTR(in);
333 HEntry *entries = ARRPTR(in);
338 PG_FREE_IF_COPY(in,0);
339 PG_RETURN_CSTRING(out);
342 buflen = ( 4 /* " */ + 2 /* => */ + 2 /*, */ )*in->size +
343 2 /* esc */ * ( in->len - CALCDATASIZE(in->size,0) );
345 out=ptr=palloc(buflen);
346 for(i=0;i<in->size;i++) {
348 ptr = cpw( ptr, base + entries[i].pos, entries[i].keylen );
352 if ( entries[i].valisnull ) {
359 ptr = cpw( ptr, base + entries[i].pos + entries[i].keylen, entries[i].vallen );
363 if ( i+1 != in->size ) {
370 PG_FREE_IF_COPY(in,0);
371 PG_RETURN_CSTRING(out);