16 #define RESIZEPRSBUF \
18 if ( state->cur - state->word + 1 >= state->wordlen ) \
20 int4 clen = state->cur - state->word; \
21 state->wordlen *= 2; \
22 state->word = (char*)repalloc( (void*)state->word, state->wordlen ); \
23 state->cur = state->word + clen; \
31 #define GV_WAITESCIN 3
32 #define GV_WAITESCESCIN 4
35 get_val( HSParser *state, bool ignoreeq, bool *escaped ) {
38 state->cur = state->word = palloc( state->wordlen );
42 if ( st == GV_WAITVAL ) {
43 if ( *(state->ptr) == '"' ) {
46 } else if ( *(state->ptr) == '\0' ) {
48 } else if ( *(state->ptr) == '=' && !ignoreeq ) {
49 elog(ERROR,"Syntax error near '%c' at postion %d", *(state->ptr), state->ptr-state->begin);
50 } else if ( *(state->ptr) == '\\' ) {
52 } else if ( !isspace(*(state->ptr)) ) {
53 *(state->cur) = *(state->ptr);
57 } else if ( st == GV_INVAL ) {
58 if ( *(state->ptr) == '\\' ) {
60 } else if ( *(state->ptr) == '=' && !ignoreeq ) {
63 } else if ( *(state->ptr) == ',' && ignoreeq ) {
66 } else if ( isspace(*(state->ptr)) ) {
68 } else if ( *(state->ptr) == '\0' ) {
73 *(state->cur) = *(state->ptr);
76 } else if ( st == GV_INESCVAL ) {
77 if ( *(state->ptr) == '\\' ) {
79 } else if ( *(state->ptr) == '"' ) {
81 } else if ( *(state->ptr) == '\0' ) {
82 elog(ERROR,"Unexpected end of string");
85 *(state->cur) = *(state->ptr);
88 } else if ( st == GV_WAITESCIN ) {
89 if ( *(state->ptr) == '\0' )
90 elog(ERROR,"Unexpected end of string");
92 *(state->cur) = *(state->ptr);
95 } else if ( st == GV_WAITESCESCIN ) {
96 if ( *(state->ptr) == '\0' )
97 elog(ERROR,"Unexpected end of string");
99 *(state->cur) = *(state->ptr);
103 elog(ERROR,"Unknown state %d at postion line %d in file '%s'", st, __LINE__, __FILE__);
119 parse_hstore( HSParser *state ) {
124 state->pairs = (Pairs*)palloc( sizeof(Pairs) * state->plen );
126 state->ptr = state->begin;
131 if ( !get_val(state, false, &escaped) )
133 if ( state->pcur >= state->plen ) {
135 state->pairs = (Pairs*)repalloc( state->pairs, sizeof(Pairs) * state->plen );
137 state->pairs[ state->pcur ].key = state->word;
138 state->pairs[ state->pcur ].keylen = state->cur - state->word;
139 state->pairs[ state->pcur ].val=NULL;
142 } else if ( st == WEQ ) {
143 if ( *(state->ptr) == '=' ) {
145 } else if ( *(state->ptr) == '\0' ) {
146 elog(ERROR,"Unexpectd end of string");
147 } else if (!isspace(*(state->ptr))) {
148 elog(ERROR,"Syntax error near '%c' at postion %d", *(state->ptr), state->ptr-state->begin);
150 } else if ( st == WGT ) {
151 if ( *(state->ptr) == '>' ) {
153 } else if ( *(state->ptr) == '\0' ) {
154 elog(ERROR,"Unexpectd end of string");
156 elog(ERROR,"Syntax error near '%c' at postion %d", *(state->ptr), state->ptr-state->begin);
158 } else if ( st == WVAL ) {
159 if ( !get_val(state, true, &escaped) )
160 elog(ERROR,"Unexpected end of string");
161 state->pairs[ state->pcur ].val = state->word;
162 state->pairs[ state->pcur ].vallen = state->cur - state->word;
163 state->pairs[ state->pcur ].isnull = false;
164 state->pairs[ state->pcur ].needfree = true;
165 if ( state->cur - state->word == 4 && !escaped) {
166 state->word[4] = '\0';
167 if ( 0==strcasecmp(state->word, "null") )
168 state->pairs[ state->pcur ].isnull=true;
173 } else if ( st == WDEL ) {
174 if ( *(state->ptr) == ',' ) {
176 } else if ( *(state->ptr) == '\0' ) {
178 } else if (!isspace(*(state->ptr))) {
179 elog(ERROR,"Syntax error near '%c' at postion %d", *(state->ptr), state->ptr-state->begin);
182 elog(ERROR,"Unknown state %d at line %d in file '%s'", st, __LINE__, __FILE__);
189 comparePairs(const void *a, const void *b) {
190 if ( ((Pairs*)a)->keylen == ((Pairs*)b)->keylen ) {
199 /* guarantee that neddfree willl be later */
200 if ( ((Pairs*)b)->needfree == ((Pairs*)a)->needfree )
202 else if ( ((Pairs*)a)->needfree )
207 return ( ((Pairs*)a)->keylen > ((Pairs*)b)->keylen ) ? 1 : -1;
211 uniquePairs(Pairs * a, int4 l, int4 *buflen) {
217 *buflen = a->keylen + ((a->isnull) ? 0 : a->vallen) ;
221 qsort((void *) a, l, sizeof(Pairs), comparePairs);
224 while( ptr - a < l ) {
225 if ( ptr->keylen == res->keylen && strncmp( ptr->key, res->key, res->keylen )==0 ) {
226 if ( ptr->needfree ) {
231 *buflen += res->keylen + (( res->isnull ) ? 0 : res->vallen);
233 memcpy(res,ptr,sizeof(Pairs));
239 *buflen += res->keylen + (( res->isnull ) ? 0 : res->vallen);
244 freeHSParse(HSParser *state) {
247 if ( state->word ) pfree( state->word );
248 for (i=0;i<state->pcur;i++)
249 if ( state->pairs[i].needfree ) {
250 if (state->pairs[i].key) pfree(state->pairs[i].key);
251 if (state->pairs[i].val) pfree(state->pairs[i].val);
253 pfree( state->pairs );
256 PG_FUNCTION_INFO_V1(hstore_in);
257 Datum hstore_in(PG_FUNCTION_ARGS);
259 hstore_in(PG_FUNCTION_ARGS) {
266 state.begin = PG_GETARG_CSTRING(0);
268 parse_hstore(&state);
270 if ( state.pcur == 0 ) {
272 len = CALCDATASIZE(0,0);
276 PG_RETURN_POINTER(out);
279 state.pcur = uniquePairs(state.pairs, state.pcur, &buflen);
281 len=CALCDATASIZE(state.pcur, buflen);
284 out->size=state.pcur;
289 for(i=0;i<out->size;i++) {
290 entries[i].keylen = state.pairs[i].keylen;
291 entries[i].pos = ptr - STRPTR(out);
292 memcpy(ptr, state.pairs[i].key, state.pairs[i].keylen);
293 ptr+=entries[i].keylen;
295 entries[i].valisnull = state.pairs[i].isnull;
296 if ( entries[i].valisnull )
297 entries[i].vallen=4; /* null */
299 entries[i].vallen = state.pairs[i].vallen;
300 memcpy(ptr, state.pairs[i].val,state.pairs[i].vallen);
301 ptr+=entries[i].vallen;
306 PG_RETURN_POINTER(out);
310 cpw(char *dst, char *src, int len) {
314 if ( *ptr == '"' || *ptr == '\\' )
321 PG_FUNCTION_INFO_V1(hstore_out);
322 Datum hstore_out(PG_FUNCTION_ARGS);
324 hstore_out(PG_FUNCTION_ARGS) {
325 HStore *in = PG_GETARG_HS(0);
328 char *base = STRPTR(in);
329 HEntry *entries = ARRPTR(in);
334 PG_FREE_IF_COPY(in,0);
335 PG_RETURN_CSTRING(out);
338 buflen = ( 4 /* " */ + 2 /* => */ + 2 /*, */ )*in->size +
339 2 /* esc */ * ( in->len - CALCDATASIZE(in->size,0) );
341 out=ptr=palloc(buflen);
342 for(i=0;i<in->size;i++) {
344 ptr = cpw( ptr, base + entries[i].pos, entries[i].keylen );
348 if ( entries[i].valisnull ) {
355 ptr = cpw( ptr, base + entries[i].pos + entries[i].keylen, entries[i].vallen );
359 if ( i+1 != in->size ) {
366 PG_FREE_IF_COPY(in,0);
367 PG_RETURN_CSTRING(out);