README
[hstore.git] / hstore_io.c
1 /*
2  * contrib/hstore/hstore_io.c
3  */
4 #include "postgres.h"
5
6 #include <ctype.h>
7
8 #include "access/htup_details.h"
9 #include "catalog/pg_type.h"
10 #include "catalog/pg_cast.h"
11 #include "funcapi.h"
12 #include "libpq/pqformat.h"
13 #include "miscadmin.h"
14 #include "parser/parse_coerce.h"
15 #include "utils/builtins.h"
16 #include "utils/fmgroids.h"
17 #include "utils/json.h"
18 #include "utils/guc.h"
19 #include "utils/lsyscache.h"
20 #include "utils/memutils.h"
21 #include "utils/syscache.h"
22 #include "utils/typcache.h"
23
24 #include "hstore.h"
25
26 PG_MODULE_MAGIC;
27
28 /* old names for C functions */
29 HSTORE_POLLUTE(hstore_from_text, tconvert);
30
31 /* GUC variables */
32 static bool     pretty_print_var = false;
33 #define SET_PRETTY_PRINT_VAR(x)         ((pretty_print_var) ? \
34                                                                          ((x) | PrettyPrint) : (x))
35
36 static void recvHStore(StringInfo buf, HStoreValue *v, uint32 level,
37                                            uint32 header);
38 static Oid searchCast(Oid src, Oid dst, CoercionMethod *method);
39
40 static size_t
41 hstoreCheckKeyLen(size_t len)
42 {
43         if (len > HSTORE_MAX_KEY_LEN)
44                 ereport(ERROR,
45                                 (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
46                                  errmsg("string too long for hstore key")));
47         return len;
48 }
49
50 static size_t
51 hstoreCheckValLen(size_t len)
52 {
53         if (len > HSTORE_MAX_VALUE_LEN)
54                 ereport(ERROR,
55                                 (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
56                                  errmsg("string too long for hstore value")));
57         return len;
58 }
59
60
61 static HStore*
62 hstoreDump(HStoreValue *p)
63 {
64         uint32                  buflen;
65         HStore             *out;
66
67         if (p == NULL || (p->type == hsvArray && p->array.nelems == 0) ||
68                 (p->type == hsvHash && p->hash.npairs == 0))
69         {
70                 buflen = 0;
71                 out = palloc(VARHDRSZ);
72         }
73         else
74         {
75                 buflen = VARHDRSZ + p->size;
76                 out = palloc(buflen);
77                 SET_VARSIZE(out, buflen);
78
79                 buflen = compressHStore(p, VARDATA(out));
80         }
81         SET_VARSIZE(out, buflen + VARHDRSZ);
82
83         return out;
84 }
85
86 PG_FUNCTION_INFO_V1(hstore_in);
87 Datum           hstore_in(PG_FUNCTION_ARGS);
88 Datum
89 hstore_in(PG_FUNCTION_ARGS)
90 {
91         PG_RETURN_POINTER(hstoreDump(parseHStore(PG_GETARG_CSTRING(0), -1, false)));
92 }
93
94 static void
95 recvHStoreValue(StringInfo buf, HStoreValue *v, uint32 level, int c)
96 {
97         uint32  hentry = c & HENTRY_TYPEMASK;
98
99         check_stack_depth();
100
101         if (c == -1 /* compatibility */ || hentry == HENTRY_ISNULL)
102         {
103                 v->type = hsvNull;
104                 v->size = sizeof(HEntry);
105         }
106         else if (hentry == HENTRY_ISHASH || hentry == HENTRY_ISARRAY ||
107                          hentry == HENTRY_ISSCALAR)
108         {
109                 recvHStore(buf, v, level + 1, (uint32)c);
110         }
111         else if (hentry == HENTRY_ISFALSE || hentry == HENTRY_ISTRUE)
112         {
113                 v->type = hsvBool;
114                 v->size = sizeof(HEntry);
115                 v->boolean = (hentry == HENTRY_ISFALSE) ? false : true;
116         }
117         else if (hentry == HENTRY_ISNUMERIC)
118         {
119                 v->type = hsvNumeric;
120                 v->numeric = DatumGetNumeric(DirectFunctionCall3(numeric_recv,
121                                                                                                                  PointerGetDatum(buf),
122                                                                                                                  Int32GetDatum(0),
123                                                                                                                  Int32GetDatum(-1)));
124                 v->size = sizeof(HEntry) * 2 + VARSIZE_ANY(v->numeric);
125         }
126         else if (hentry == HENTRY_ISSTRING)
127         {
128                 v->type = hsvString;
129                 v->string.val = pq_getmsgtext(buf, c & ~HENTRY_TYPEMASK, &c);
130                 v->string.len = hstoreCheckKeyLen(c);
131                 v->size = sizeof(HEntry) + v->string.len;
132         }
133         else
134         {
135                 ereport(ERROR,
136                                 (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
137                                  errmsg("unknown hstore value")));
138         }
139 }
140
141 static void
142 recvHStore(StringInfo buf, HStoreValue *v, uint32 level, uint32 header)
143 {
144         uint32  hentry;
145         uint32  i;
146
147         hentry = header & HENTRY_TYPEMASK;
148
149         if (level == 0 && hentry == 0)
150                 hentry = HENTRY_ISHASH; /* old version */
151
152         check_stack_depth();
153
154         v->size = 3 * sizeof(HEntry);
155         if (hentry == HENTRY_ISHASH)
156         {
157                 v->type = hsvHash;
158                 v->hash.npairs = header & HS_COUNT_MASK;
159
160                 if (v->hash.npairs > (buf->len  - buf->cursor) / (2 * sizeof(uint32)) ||
161                         v->hash.npairs > MaxAllocSize / sizeof(HStorePair))
162                         ereport(ERROR,
163                                         (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
164                                          errmsg("too much elements in hstore hash")));
165
166                 if (v->hash.npairs > 0)
167                 {
168                         v->hash.pairs = palloc(sizeof(*v->hash.pairs) * v->hash.npairs);
169
170                         for(i=0; i<v->hash.npairs; i++)
171                         {
172                                 recvHStoreValue(buf, &v->hash.pairs[i].key, level,
173                                                                 pq_getmsgint(buf, 4));
174                                 if (v->hash.pairs[i].key.type != hsvString)
175                                         ereport(ERROR,
176                                                         (errcode(ERRCODE_DATATYPE_MISMATCH),
177                                                          errmsg("hstore's key could be only a string")));
178
179                                 recvHStoreValue(buf, &v->hash.pairs[i].value, level,
180                                                                 pq_getmsgint(buf, 4));
181
182                                 v->size += v->hash.pairs[i].key.size +
183                                                         v->hash.pairs[i].value.size;
184                         }
185
186                         uniqueHStoreValue(v);
187                 }
188         }
189         else if (hentry == HENTRY_ISARRAY || hentry == HENTRY_ISSCALAR)
190         {
191                 v->type = hsvArray;
192                 v->array.nelems = header & HS_COUNT_MASK;
193                 v->array.scalar = (hentry == HENTRY_ISSCALAR) ? true : false;
194
195                 if (v->array.nelems > (buf->len  - buf->cursor) / sizeof(uint32) ||
196                         v->array.nelems > MaxAllocSize / sizeof(HStoreValue))
197                         ereport(ERROR,
198                                         (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
199                                          errmsg("too much elements in hstore array")));
200
201                 if (v->array.scalar && v->array.nelems != 1)
202                         ereport(ERROR,
203                                         (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
204                                          errmsg("wrong scalar representation")));
205
206                 if (v->array.nelems > 0)
207                 {
208                         v->array.elems = palloc(sizeof(*v->array.elems) * v->array.nelems);
209
210                         for(i=0; i<v->array.nelems; i++)
211                         {
212                                 recvHStoreValue(buf, v->array.elems + i, level,
213                                                                 pq_getmsgint(buf, 4));
214                                 v->size += v->array.elems[i].size;
215                         }
216                 }
217         }
218         else
219         {
220                 ereport(ERROR,
221                                 (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
222                                  errmsg("unknown hstore element")));
223         }
224 }
225
226 PG_FUNCTION_INFO_V1(hstore_recv);
227 Datum           hstore_recv(PG_FUNCTION_ARGS);
228 Datum
229 hstore_recv(PG_FUNCTION_ARGS)
230 {
231         StringInfo      buf = (StringInfo) PG_GETARG_POINTER(0);
232         HStoreValue     v;
233
234         recvHStore(buf, &v, 0, pq_getmsgint(buf, 4));
235
236         PG_RETURN_POINTER(hstoreDump(&v));
237 }
238
239 PG_FUNCTION_INFO_V1(hstore_from_text);
240 Datum           hstore_from_text(PG_FUNCTION_ARGS);
241 Datum
242 hstore_from_text(PG_FUNCTION_ARGS)
243 {
244         text            *key;
245         HStoreValue     v;
246         HStorePair      pair;
247
248         if (PG_ARGISNULL(0))
249                 PG_RETURN_NULL();
250
251         key = PG_GETARG_TEXT_PP(0);
252         pair.key.type = hsvString;
253         pair.key.string.val = VARDATA_ANY(key);
254         pair.key.string.len = hstoreCheckKeyLen(VARSIZE_ANY_EXHDR(key));
255         pair.key.size = pair.key.string.len + sizeof(HEntry);
256
257         if (PG_ARGISNULL(1))
258         {
259                 pair.value.type = hsvNull;
260                 pair.value.size = sizeof(HEntry);
261         }
262         else
263         {
264                 text            *val = NULL;
265
266                 val = PG_GETARG_TEXT_PP(1);
267                 pair.value.type = hsvString;
268                 pair.value.string.val = VARDATA_ANY(val);
269                 pair.value.string.len = hstoreCheckValLen(VARSIZE_ANY_EXHDR(val));
270                 pair.value.size = pair.value.string.len + sizeof(HEntry);
271         }
272
273         v.type = hsvHash;
274         v.size = sizeof(HEntry) + pair.key.size + pair.value.size;
275         v.hash.npairs = 1;
276         v.hash.pairs = &pair;
277
278         PG_RETURN_POINTER(hstoreDump(&v));
279 }
280
281 PG_FUNCTION_INFO_V1(hstore_from_bool);
282 Datum           hstore_from_bool(PG_FUNCTION_ARGS);
283 Datum
284 hstore_from_bool(PG_FUNCTION_ARGS)
285 {
286         text            *key;
287         HStoreValue     v;
288         HStorePair      pair;
289
290         if (PG_ARGISNULL(0))
291                 PG_RETURN_NULL();
292
293         key = PG_GETARG_TEXT_PP(0);
294         pair.key.type = hsvString;
295         pair.key.string.val = VARDATA_ANY(key);
296         pair.key.string.len = hstoreCheckKeyLen(VARSIZE_ANY_EXHDR(key));
297         pair.key.size = pair.key.string.len + sizeof(HEntry);
298
299         if (PG_ARGISNULL(1))
300         {
301                 pair.value.type = hsvNull;
302                 pair.value.size = sizeof(HEntry);
303         }
304         else
305         {
306                 pair.value.type = hsvBool;
307                 pair.value.boolean = PG_GETARG_BOOL(1);
308                 pair.value.size = sizeof(HEntry);
309         }
310
311         v.type = hsvHash;
312         v.size = sizeof(HEntry) + pair.key.size + pair.value.size;
313         v.hash.npairs = 1;
314         v.hash.pairs = &pair;
315
316         PG_RETURN_POINTER(hstoreDump(&v));
317 }
318
319 PG_FUNCTION_INFO_V1(hstore_from_numeric);
320 Datum           hstore_from_numeric(PG_FUNCTION_ARGS);
321 Datum
322 hstore_from_numeric(PG_FUNCTION_ARGS)
323 {
324         text            *key;
325         HStoreValue     v;
326         HStorePair      pair;
327
328         if (PG_ARGISNULL(0))
329                 PG_RETURN_NULL();
330
331         key = PG_GETARG_TEXT_PP(0);
332         pair.key.type = hsvString;
333         pair.key.string.val = VARDATA_ANY(key);
334         pair.key.string.len = hstoreCheckKeyLen(VARSIZE_ANY_EXHDR(key));
335         pair.key.size = pair.key.string.len + sizeof(HEntry);
336
337         if (PG_ARGISNULL(1))
338         {
339                 pair.value.type = hsvNull;
340                 pair.value.size = sizeof(HEntry);
341         }
342         else
343         {
344                 pair.value.type = hsvNumeric;
345                 pair.value.numeric = PG_GETARG_NUMERIC(1);
346                 pair.value.size = sizeof(HEntry) + sizeof(HEntry) +
347                                                         VARSIZE_ANY(pair.value.numeric);
348         }
349
350         v.type = hsvHash;
351         v.size = sizeof(HEntry) + pair.key.size + pair.value.size;
352         v.hash.npairs = 1;
353         v.hash.pairs = &pair;
354
355         PG_RETURN_POINTER(hstoreDump(&v));
356 }
357
358 PG_FUNCTION_INFO_V1(hstore_from_th);
359 Datum           hstore_from_th(PG_FUNCTION_ARGS);
360 Datum
361 hstore_from_th(PG_FUNCTION_ARGS)
362 {
363         text            *key;
364         HStoreValue     v;
365         HStorePair      pair;
366
367         if (PG_ARGISNULL(0))
368                 PG_RETURN_NULL();
369
370         key = PG_GETARG_TEXT_PP(0);
371         pair.key.type = hsvString;
372         pair.key.string.val = VARDATA_ANY(key);
373         pair.key.string.len = hstoreCheckKeyLen(VARSIZE_ANY_EXHDR(key));
374         pair.key.size = pair.key.string.len + sizeof(HEntry);
375
376         if (PG_ARGISNULL(1))
377         {
378                 pair.value.type = hsvNull;
379                 pair.value.size = sizeof(HEntry);
380         }
381         else
382         {
383                 HStore          *val = NULL;
384
385                 val = PG_GETARG_HS(1);
386                 pair.value.type = hsvBinary;
387                 pair.value.binary.data = VARDATA_ANY(val);
388                 pair.value.binary.len = VARSIZE_ANY_EXHDR(val);
389                 pair.value.size = pair.value.binary.len + sizeof(HEntry) * 2;
390         }
391
392         v.type = hsvHash;
393         v.size = sizeof(HEntry) + pair.key.size + pair.value.size;
394         v.hash.npairs = 1;
395         v.hash.pairs = &pair;
396
397         PG_RETURN_POINTER(hstoreDump(&v));
398 }
399
400 PG_FUNCTION_INFO_V1(hstore_from_arrays);
401 PG_FUNCTION_INFO_V1(hstore_scalar_from_text);
402 Datum           hstore_scalar_from_text(PG_FUNCTION_ARGS);
403 Datum
404 hstore_scalar_from_text(PG_FUNCTION_ARGS)
405 {
406         HStoreValue     a, v;
407
408         if (PG_ARGISNULL(0))
409         {
410                 v.type = hsvNull;
411                 v.size = sizeof(HEntry);
412         }
413         else
414         {
415                 text    *scalar;
416
417                 scalar = PG_GETARG_TEXT_PP(0);
418                 v.type = hsvString;
419                 v.string.val = VARDATA_ANY(scalar);
420                 v.string.len = hstoreCheckKeyLen(VARSIZE_ANY_EXHDR(scalar));
421                 v.size = v.string.len + sizeof(HEntry);
422         }
423
424         a.type = hsvArray;
425         a.size = sizeof(HEntry) + v.size;
426         a.array.nelems = 1;
427         a.array.elems = &v;
428         a.array.scalar = true;
429
430         PG_RETURN_POINTER(hstoreDump(&a));
431 }
432
433 PG_FUNCTION_INFO_V1(hstore_scalar_from_bool);
434 Datum           hstore_scalar_from_bool(PG_FUNCTION_ARGS);
435 Datum
436 hstore_scalar_from_bool(PG_FUNCTION_ARGS)
437 {
438         HStoreValue     a, v;
439
440         if (PG_ARGISNULL(0))
441         {
442                 v.type = hsvNull;
443                 v.size = sizeof(HEntry);
444         }
445         else
446         {
447                 v.type = hsvBool;
448                 v.boolean = PG_GETARG_BOOL(0);
449                 v.size = sizeof(HEntry);
450         }
451
452         a.type = hsvArray;
453         a.size = sizeof(HEntry) + v.size;
454         a.array.nelems = 1;
455         a.array.elems = &v;
456         a.array.scalar = true;
457
458         PG_RETURN_POINTER(hstoreDump(&a));
459 }
460
461 PG_FUNCTION_INFO_V1(hstore_scalar_from_numeric);
462 Datum           hstore_scalar_from_numeric(PG_FUNCTION_ARGS);
463 Datum
464 hstore_scalar_from_numeric(PG_FUNCTION_ARGS)
465 {
466         HStoreValue     a, v;
467
468         if (PG_ARGISNULL(0))
469         {
470                 v.type = hsvNull;
471                 v.size = sizeof(HEntry);
472         }
473         else
474         {
475                 v.type = hsvNumeric;
476                 v.numeric = PG_GETARG_NUMERIC(0);
477                 v.size = VARSIZE_ANY(v.numeric) + 2*sizeof(HEntry);
478         }
479
480         a.type = hsvArray;
481         a.size = sizeof(HEntry) + v.size;
482         a.array.nelems = 1;
483         a.array.elems = &v;
484         a.array.scalar = true;
485
486         PG_RETURN_POINTER(hstoreDump(&a));
487 }
488
489 Datum           hstore_from_arrays(PG_FUNCTION_ARGS);
490 Datum
491 hstore_from_arrays(PG_FUNCTION_ARGS)
492 {
493         HStoreValue v;
494         Datum      *key_datums;
495         bool       *key_nulls;
496         int                     key_count;
497         Datum      *value_datums;
498         bool       *value_nulls;
499         int                     value_count;
500         ArrayType  *key_array;
501         ArrayType  *value_array;
502         int                     i;
503
504         if (PG_ARGISNULL(0))
505                 PG_RETURN_NULL();
506
507         key_array = PG_GETARG_ARRAYTYPE_P(0);
508
509         Assert(ARR_ELEMTYPE(key_array) == TEXTOID);
510
511         /*
512          * must check >1 rather than != 1 because empty arrays have 0 dimensions,
513          * not 1
514          */
515
516         if (ARR_NDIM(key_array) > 1)
517                 ereport(ERROR,
518                                 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
519                                  errmsg("wrong number of array subscripts")));
520
521         deconstruct_array(key_array,
522                                           TEXTOID, -1, false, 'i',
523                                           &key_datums, &key_nulls, &key_count);
524
525         /* see discussion in arrayToHStoreSortedArray() */
526         if (key_count > MaxAllocSize / sizeof(HStorePair))
527                 ereport(ERROR,
528                                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
529                           errmsg("number of pairs (%d) exceeds the maximum allowed (%d)",
530                                          key_count, (int) (MaxAllocSize / sizeof(HStorePair)))));
531
532         /* value_array might be NULL */
533
534         if (PG_ARGISNULL(1))
535         {
536                 value_array = NULL;
537                 value_count = key_count;
538                 value_datums = NULL;
539                 value_nulls = NULL;
540         }
541         else
542         {
543                 value_array = PG_GETARG_ARRAYTYPE_P(1);
544
545                 Assert(ARR_ELEMTYPE(value_array) == TEXTOID);
546
547                 if (ARR_NDIM(value_array) > 1)
548                         ereport(ERROR,
549                                         (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
550                                          errmsg("wrong number of array subscripts")));
551
552                 if ((ARR_NDIM(key_array) > 0 || ARR_NDIM(value_array) > 0) &&
553                         (ARR_NDIM(key_array) != ARR_NDIM(value_array) ||
554                          ARR_DIMS(key_array)[0] != ARR_DIMS(value_array)[0] ||
555                          ARR_LBOUND(key_array)[0] != ARR_LBOUND(value_array)[0]))
556                         ereport(ERROR,
557                                         (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
558                                          errmsg("arrays must have same bounds")));
559
560                 deconstruct_array(value_array,
561                                                   TEXTOID, -1, false, 'i',
562                                                   &value_datums, &value_nulls, &value_count);
563
564                 Assert(key_count == value_count);
565         }
566
567         v.type = hsvHash;
568         v.size = 2 * sizeof(HEntry);
569         v.hash.pairs = palloc(key_count * sizeof(*v.hash.pairs));
570         v.hash.npairs = key_count;
571
572         for (i = 0; i < key_count; ++i)
573         {
574                 if (key_nulls[i])
575                         ereport(ERROR,
576                                         (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
577                                          errmsg("null value not allowed for hstore key")));
578
579                 v.hash.pairs[i].key.type = hsvString;
580                 v.hash.pairs[i].key.string.val = VARDATA_ANY(key_datums[i]);
581                 v.hash.pairs[i].key.string.len = hstoreCheckKeyLen(VARSIZE_ANY_EXHDR(key_datums[i]));
582                 v.hash.pairs[i].key.size = sizeof(HEntry) +
583                                                                         v.hash.pairs[i].key.string.len;
584
585                 if (!value_nulls || value_nulls[i])
586                 {
587                         v.hash.pairs[i].value.type = hsvNull;
588                         v.hash.pairs[i].value.size = sizeof(HEntry);
589                 }
590                 else
591                 {
592                         v.hash.pairs[i].value.type = hsvString;
593                         v.hash.pairs[i].value.size = sizeof(HEntry);
594                         v.hash.pairs[i].value.string.val = VARDATA_ANY(value_datums[i]);
595                         v.hash.pairs[i].value.string.len = hstoreCheckKeyLen(VARSIZE_ANY_EXHDR(value_datums[i]));
596                         v.hash.pairs[i].value.size = sizeof(HEntry) +
597                                                                                         v.hash.pairs[i].value.string.len;
598                 }
599
600                 v.size += v.hash.pairs[i].key.size + v.hash.pairs[i].value.size;
601         }
602
603         uniqueHStoreValue(&v);
604
605
606         PG_RETURN_POINTER(hstoreDump(&v));
607 }
608
609
610 PG_FUNCTION_INFO_V1(hstore_from_array);
611 Datum           hstore_from_array(PG_FUNCTION_ARGS);
612 Datum
613 hstore_from_array(PG_FUNCTION_ARGS)
614 {
615         ArrayType  *in_array = PG_GETARG_ARRAYTYPE_P(0);
616         int                     ndims = ARR_NDIM(in_array);
617         int                     count;
618         HStoreValue     v;
619         Datum      *in_datums;
620         bool       *in_nulls;
621         int                     in_count;
622         int                     i;
623
624         Assert(ARR_ELEMTYPE(in_array) == TEXTOID);
625
626         switch (ndims)
627         {
628                 case 0:
629                         PG_RETURN_POINTER(hstoreDump(NULL));
630
631                 case 1:
632                         if ((ARR_DIMS(in_array)[0]) % 2)
633                                 ereport(ERROR,
634                                                 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
635                                                  errmsg("array must have even number of elements")));
636                         break;
637
638                 case 2:
639                         if ((ARR_DIMS(in_array)[1]) != 2)
640                                 ereport(ERROR,
641                                                 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
642                                                  errmsg("array must have two columns")));
643                         break;
644
645                 default:
646                         ereport(ERROR,
647                                         (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
648                                          errmsg("wrong number of array subscripts")));
649         }
650
651         deconstruct_array(in_array,
652                                           TEXTOID, -1, false, 'i',
653                                           &in_datums, &in_nulls, &in_count);
654
655         count = in_count / 2;
656
657         /* see discussion in arrayToHStoreSortedArray() */
658         if (count > MaxAllocSize / sizeof(HStorePair))
659                 ereport(ERROR,
660                                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
661                           errmsg("number of pairs (%d) exceeds the maximum allowed (%d)",
662                                          count, (int) (MaxAllocSize / sizeof(HStorePair)))));
663
664         v.type = hsvHash;
665         v.size = 2*sizeof(HEntry);
666         v.hash.npairs = count;
667         v.hash.pairs = palloc(count * sizeof(HStorePair));
668
669         for (i = 0; i < count; ++i)
670         {
671                 if (in_nulls[i * 2])
672                         ereport(ERROR,
673                                         (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
674                                          errmsg("null value not allowed for hstore key")));
675
676                 v.hash.pairs[i].key.type = hsvString;
677                 v.hash.pairs[i].key.string.val = VARDATA_ANY(in_datums[i * 2]);
678                 v.hash.pairs[i].key.string.len = hstoreCheckKeyLen(VARSIZE_ANY_EXHDR(in_datums[i * 2]));
679                 v.hash.pairs[i].key.size = sizeof(HEntry) +
680                                                                         v.hash.pairs[i].key.string.len;
681
682                 if (in_nulls[i * 2 + 1])
683                 {
684                         v.hash.pairs[i].value.type = hsvNull;
685                         v.hash.pairs[i].value.size = sizeof(HEntry);
686                 }
687                 else
688                 {
689                         v.hash.pairs[i].value.type = hsvString;
690                         v.hash.pairs[i].value.size = sizeof(HEntry);
691                         v.hash.pairs[i].value.string.val = VARDATA_ANY(in_datums[i * 2 + 1]);
692                         v.hash.pairs[i].value.string.len = hstoreCheckKeyLen(VARSIZE_ANY_EXHDR(in_datums[i * 2 + 1]));
693                         v.hash.pairs[i].value.size = sizeof(HEntry) +
694                                                                                         v.hash.pairs[i].value.string.len;
695                 }
696
697                 v.size += v.hash.pairs[i].key.size + v.hash.pairs[i].value.size;
698         }
699
700         uniqueHStoreValue(&v);
701
702         PG_RETURN_POINTER(hstoreDump(&v));
703 }
704
705 /* most of hstore_from_record is shamelessly swiped from record_out */
706
707 /*
708  * structure to cache metadata needed for record I/O
709  */
710 typedef struct ColumnIOData
711 {
712         Oid                     column_type;
713         Oid                     typiofunc;
714         Oid                     typioparam;
715         FmgrInfo        proc;
716 } ColumnIOData;
717
718 typedef struct RecordIOData
719 {
720         Oid                     record_type;
721         int32           record_typmod;
722         int                     ncolumns;
723         ColumnIOData columns[1];        /* VARIABLE LENGTH ARRAY */
724 } RecordIOData;
725
726 PG_FUNCTION_INFO_V1(hstore_from_record);
727 Datum           hstore_from_record(PG_FUNCTION_ARGS);
728 Datum
729 hstore_from_record(PG_FUNCTION_ARGS)
730 {
731         HeapTupleHeader rec;
732         HStore             *out;
733         HStoreValue        v;
734         Oid                             tupType;
735         int32                   tupTypmod;
736         TupleDesc               tupdesc;
737         HeapTupleData   tuple;
738         RecordIOData   *my_extra;
739         int                             ncolumns;
740         int                             i;
741         Datum              *values;
742         bool               *nulls;
743
744         if (PG_ARGISNULL(0))
745         {
746                 Oid                     argtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
747
748                 /*
749                  * have no tuple to look at, so the only source of type info is the
750                  * argtype. The lookup_rowtype_tupdesc call below will error out if we
751                  * don't have a known composite type oid here.
752                  */
753                 tupType = argtype;
754                 tupTypmod = -1;
755
756                 rec = NULL;
757         }
758         else
759         {
760                 rec = PG_GETARG_HEAPTUPLEHEADER(0);
761
762                 /* Extract type info from the tuple itself */
763                 tupType = HeapTupleHeaderGetTypeId(rec);
764                 tupTypmod = HeapTupleHeaderGetTypMod(rec);
765         }
766
767         tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
768         ncolumns = tupdesc->natts;
769
770         /*
771          * We arrange to look up the needed I/O info just once per series of
772          * calls, assuming the record type doesn't change underneath us.
773          */
774         my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra;
775         if (my_extra == NULL ||
776                 my_extra->ncolumns != ncolumns)
777         {
778                 fcinfo->flinfo->fn_extra =
779                         MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
780                                                            sizeof(RecordIOData) - sizeof(ColumnIOData)
781                                                            + ncolumns * sizeof(ColumnIOData));
782                 my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra;
783                 my_extra->record_type = InvalidOid;
784                 my_extra->record_typmod = 0;
785         }
786
787         if (my_extra->record_type != tupType ||
788                 my_extra->record_typmod != tupTypmod)
789         {
790                 MemSet(my_extra, 0,
791                            sizeof(RecordIOData) - sizeof(ColumnIOData)
792                            + ncolumns * sizeof(ColumnIOData));
793                 my_extra->record_type = tupType;
794                 my_extra->record_typmod = tupTypmod;
795                 my_extra->ncolumns = ncolumns;
796         }
797
798         v.type = hsvHash;
799         v.size = 2*sizeof(HEntry);
800         v.hash.npairs = ncolumns;
801         Assert(ncolumns <= MaxTupleAttributeNumber);            /* thus, no overflow */
802         v.hash.pairs = palloc(ncolumns * sizeof(HStorePair));
803
804         if (rec)
805         {
806                 /* Build a temporary HeapTuple control structure */
807                 tuple.t_len = HeapTupleHeaderGetDatumLength(rec);
808                 ItemPointerSetInvalid(&(tuple.t_self));
809                 tuple.t_tableOid = InvalidOid;
810                 tuple.t_data = rec;
811
812                 values = (Datum *) palloc(ncolumns * sizeof(Datum));
813                 nulls = (bool *) palloc(ncolumns * sizeof(bool));
814
815                 /* Break down the tuple into fields */
816                 heap_deform_tuple(&tuple, tupdesc, values, nulls);
817         }
818         else
819         {
820                 values = NULL;
821                 nulls = NULL;
822         }
823
824         for (i = 0; i < ncolumns; ++i)
825         {
826                 ColumnIOData *column_info = &my_extra->columns[i];
827                 Oid                     column_type = tupdesc->attrs[i]->atttypid;
828                 char       *value;
829
830                 /* Ignore dropped columns in datatype */
831                 if (tupdesc->attrs[i]->attisdropped)
832                         continue;
833
834                 v.hash.pairs[i].key.type = hsvString;
835                 v.hash.pairs[i].key.string.val = NameStr(tupdesc->attrs[i]->attname);
836                 v.hash.pairs[i].key.string.len = hstoreCheckKeyLen(strlen(v.hash.pairs[i].key.string.val));
837                 v.hash.pairs[i].key.size = sizeof(HEntry) +
838                                                                         v.hash.pairs[i].key.string.len;
839
840                 if (!nulls || nulls[i])
841                 {
842                         v.hash.pairs[i].value.type = hsvNull;
843                         v.hash.pairs[i].value.size = sizeof(HEntry);
844                 }
845                 else
846                 {
847                         /*
848                          * Convert the column value to hstore's values
849                          */
850                         if (column_type == BOOLOID)
851                         {
852                                 v.hash.pairs[i].value.type = hsvBool;
853                                 v.hash.pairs[i].value.boolean = DatumGetBool(values[i]);
854                                 v.hash.pairs[i].value.size = sizeof(HEntry);
855                         }
856                         else if (TypeCategory(column_type) == TYPCATEGORY_NUMERIC)
857                         {
858                                 Oid                             castOid = InvalidOid;
859                                 CoercionMethod  method;
860
861                                 v.hash.pairs[i].value.type = hsvNumeric;
862
863                                 castOid = searchCast(column_type, NUMERICOID, &method);
864                                 if (castOid == InvalidOid)
865                                 {
866                                         if (method != COERCION_METHOD_BINARY)
867                                                 elog(ERROR, "Could not cast numeric category type to numeric '%c'", (char)method);
868
869                                         v.hash.pairs[i].value.numeric = DatumGetNumeric(values[i]);
870                                 }
871                                 else
872                                 {
873                                         v.hash.pairs[i].value.numeric = 
874                                                 DatumGetNumeric(OidFunctionCall1(castOid, values[i]));
875
876                                 }
877                                 v.hash.pairs[i].value.size = 2*sizeof(HEntry) +
878                                                                 VARSIZE_ANY(v.hash.pairs[i].value.numeric);
879                         }
880                         else
881                         {
882                                 if (column_info->column_type != column_type)
883                                 {
884                                         bool            typIsVarlena;
885
886                                         getTypeOutputInfo(column_type,
887                                                                           &column_info->typiofunc,
888                                                                           &typIsVarlena);
889                                         fmgr_info_cxt(column_info->typiofunc, &column_info->proc,
890                                                                   fcinfo->flinfo->fn_mcxt);
891                                         column_info->column_type = column_type;
892                                 }
893
894                                 value = OutputFunctionCall(&column_info->proc, values[i]);
895
896                                 v.hash.pairs[i].value.type = hsvString;
897                                 v.hash.pairs[i].value.string.val = value;
898                                 v.hash.pairs[i].value.string.len = hstoreCheckValLen(strlen(value));
899                                 v.hash.pairs[i].value.size = sizeof(HEntry) +
900                                                                                 v.hash.pairs[i].value.string.len;
901                         }
902                 }
903
904                 v.size += v.hash.pairs[i].key.size + v.hash.pairs[i].value.size;
905         }
906
907         uniqueHStoreValue(&v);
908
909         out = hstoreDump(&v);
910
911         ReleaseTupleDesc(tupdesc);
912
913         PG_RETURN_POINTER(out);
914 }
915
916
917 PG_FUNCTION_INFO_V1(hstore_populate_record);
918 Datum           hstore_populate_record(PG_FUNCTION_ARGS);
919 Datum
920 hstore_populate_record(PG_FUNCTION_ARGS)
921 {
922         Oid                     argtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
923         HStore     *hs;
924         HeapTupleHeader rec;
925         Oid                     tupType;
926         int32           tupTypmod;
927         TupleDesc       tupdesc;
928         HeapTupleData tuple;
929         HeapTuple       rettuple;
930         RecordIOData *my_extra;
931         int                     ncolumns;
932         int                     i;
933         Datum      *values;
934         bool       *nulls;
935
936         if (!type_is_rowtype(argtype))
937                 ereport(ERROR,
938                                 (errcode(ERRCODE_DATATYPE_MISMATCH),
939                                  errmsg("first argument must be a rowtype")));
940
941         if (PG_ARGISNULL(0))
942         {
943                 if (PG_ARGISNULL(1))
944                         PG_RETURN_NULL();
945
946                 rec = NULL;
947
948                 /*
949                  * have no tuple to look at, so the only source of type info is the
950                  * argtype. The lookup_rowtype_tupdesc call below will error out if we
951                  * don't have a known composite type oid here.
952                  */
953                 tupType = argtype;
954                 tupTypmod = -1;
955         }
956         else
957         {
958                 rec = PG_GETARG_HEAPTUPLEHEADER(0);
959
960                 if (PG_ARGISNULL(1))
961                         PG_RETURN_POINTER(rec);
962
963                 /* Extract type info from the tuple itself */
964                 tupType = HeapTupleHeaderGetTypeId(rec);
965                 tupTypmod = HeapTupleHeaderGetTypMod(rec);
966         }
967
968         hs = PG_GETARG_HS(1);
969
970         /*
971          * if the input hstore is empty, we can only skip the rest if we were
972          * passed in a non-null record, since otherwise there may be issues with
973          * domain nulls.
974          */
975
976         if (HS_ISEMPTY(hs) && rec)
977                 PG_RETURN_POINTER(rec);
978
979         tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
980         ncolumns = tupdesc->natts;
981
982         if (rec)
983         {
984                 /* Build a temporary HeapTuple control structure */
985                 tuple.t_len = HeapTupleHeaderGetDatumLength(rec);
986                 ItemPointerSetInvalid(&(tuple.t_self));
987                 tuple.t_tableOid = InvalidOid;
988                 tuple.t_data = rec;
989         }
990
991         /*
992          * We arrange to look up the needed I/O info just once per series of
993          * calls, assuming the record type doesn't change underneath us.
994          */
995         my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra;
996         if (my_extra == NULL ||
997                 my_extra->ncolumns != ncolumns)
998         {
999                 fcinfo->flinfo->fn_extra =
1000                         MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
1001                                                            sizeof(RecordIOData) - sizeof(ColumnIOData)
1002                                                            + ncolumns * sizeof(ColumnIOData));
1003                 my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra;
1004                 my_extra->record_type = InvalidOid;
1005                 my_extra->record_typmod = 0;
1006         }
1007
1008         if (my_extra->record_type != tupType ||
1009                 my_extra->record_typmod != tupTypmod)
1010         {
1011                 MemSet(my_extra, 0,
1012                            sizeof(RecordIOData) - sizeof(ColumnIOData)
1013                            + ncolumns * sizeof(ColumnIOData));
1014                 my_extra->record_type = tupType;
1015                 my_extra->record_typmod = tupTypmod;
1016                 my_extra->ncolumns = ncolumns;
1017         }
1018
1019         values = (Datum *) palloc(ncolumns * sizeof(Datum));
1020         nulls = (bool *) palloc(ncolumns * sizeof(bool));
1021
1022         if (rec)
1023         {
1024                 /* Break down the tuple into fields */
1025                 heap_deform_tuple(&tuple, tupdesc, values, nulls);
1026         }
1027         else
1028         {
1029                 for (i = 0; i < ncolumns; ++i)
1030                 {
1031                         values[i] = (Datum) 0;
1032                         nulls[i] = true;
1033                 }
1034         }
1035
1036         for (i = 0; i < ncolumns; ++i)
1037         {
1038                 ColumnIOData *column_info = &my_extra->columns[i];
1039                 Oid                     column_type = tupdesc->attrs[i]->atttypid;
1040                 HStoreValue     *v = NULL;
1041
1042                 /* Ignore dropped columns in datatype */
1043                 if (tupdesc->attrs[i]->attisdropped)
1044                 {
1045                         nulls[i] = true;
1046                         continue;
1047                 }
1048
1049                 if (!HS_ISEMPTY(hs))
1050                 {
1051                         char *key = NameStr(tupdesc->attrs[i]->attname);
1052
1053                         v = findUncompressedHStoreValue(VARDATA(hs), HS_FLAG_HSTORE, NULL, key, strlen(key));
1054                 }
1055
1056                 /*
1057                  * we can't just skip here if the key wasn't found since we might have
1058                  * a domain to deal with. If we were passed in a non-null record
1059                  * datum, we assume that the existing values are valid (if they're
1060                  * not, then it's not our fault), but if we were passed in a null,
1061                  * then every field which we don't populate needs to be run through
1062                  * the input function just in case it's a domain type.
1063                  */
1064                 if (v == NULL && rec)
1065                         continue;
1066
1067                 /*
1068                  * Prepare to convert the column value from text
1069                  */
1070                 if (column_info->column_type != column_type)
1071                 {
1072                         getTypeInputInfo(column_type,
1073                                                          &column_info->typiofunc,
1074                                                          &column_info->typioparam);
1075                         fmgr_info_cxt(column_info->typiofunc, &column_info->proc,
1076                                                   fcinfo->flinfo->fn_mcxt);
1077                         column_info->column_type = column_type;
1078                 }
1079
1080                 if (v == NULL || v->type == hsvNull)
1081                 {
1082                         /*
1083                          * need InputFunctionCall to happen even for nulls, so that domain
1084                          * checks are done
1085                          */
1086                         values[i] = InputFunctionCall(&column_info->proc, NULL,
1087                                                                                   column_info->typioparam,
1088                                                                                   tupdesc->attrs[i]->atttypmod);
1089                         nulls[i] = true;
1090                 }
1091                 else
1092                 {
1093                         char *s = NULL;
1094
1095                         if (v->type == hsvString)
1096                                 s = pnstrdup(v->string.val, v->string.len);
1097                         else if (v->type == hsvBool)
1098                                 s = pnstrdup((v->boolean) ? "t" : "f", 1);
1099                         else if (v->type == hsvNumeric)
1100                                 s = DatumGetCString(DirectFunctionCall1(numeric_out,
1101                                                                                                                 PointerGetDatum(v->numeric)));
1102                         else if (v->type == hsvBinary && column_type == JSONOID)
1103                                 s = hstoreToCString(NULL, v->binary.data, v->binary.len,
1104                                                                         SET_PRETTY_PRINT_VAR(JsonOutput | RootHashDecorated));
1105                         else if (v->type == hsvBinary && type_is_array(column_type))
1106                                 s = hstoreToCString(NULL, v->binary.data, v->binary.len,
1107                                                                         SET_PRETTY_PRINT_VAR(ArrayCurlyBraces));
1108                         else if (v->type == hsvBinary)
1109                                 s = hstoreToCString(NULL, v->binary.data, v->binary.len,
1110                                                                         SET_PRETTY_PRINT_VAR(0));
1111                         else
1112                                 elog(PANIC, "Wrong hstore");
1113
1114                         values[i] = InputFunctionCall(&column_info->proc, s,
1115                                                                                   column_info->typioparam,
1116                                                                                   tupdesc->attrs[i]->atttypmod);
1117                         nulls[i] = false;
1118                 }
1119         }
1120
1121         rettuple = heap_form_tuple(tupdesc, values, nulls);
1122
1123         ReleaseTupleDesc(tupdesc);
1124
1125         PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
1126 }
1127
1128 bool
1129 stringIsNumber(char *string, int len, bool jsonNumber) {
1130         enum {
1131                 SIN_FIRSTINT,
1132                 SIN_ZEROINT,
1133                 SIN_INT,
1134                 SIN_SCALE,
1135                 SIN_MSIGN,
1136                 SIN_MANTISSA
1137         } sinState;
1138         char    *c;
1139         bool    r;
1140
1141         if (*string == '-' || *string == '+')
1142         {
1143                 string++;
1144                 len--;
1145         }
1146
1147         c = string;
1148         r = true;
1149         sinState = SIN_FIRSTINT;
1150
1151         while(r && c - string < len)
1152         {
1153                 switch(sinState)
1154                 {
1155                         case SIN_FIRSTINT:
1156                                 if (*c == '0' && jsonNumber)
1157                                         sinState = SIN_ZEROINT;
1158                                 else if (*c == '.')
1159                                         sinState = SIN_SCALE;
1160                                 else if (isdigit(*c))
1161                                         sinState = SIN_INT;
1162                                 else
1163                                         r = false;
1164                                 break;
1165                         case SIN_ZEROINT:
1166                                 if (*c == '.')
1167                                         sinState = SIN_SCALE;
1168                                 else
1169                                         r = false;
1170                                 break;
1171                         case SIN_INT:
1172                                 if (*c == '.')
1173                                         sinState = SIN_SCALE;
1174                                 else if (*c == 'e' || *c == 'E')
1175                                         sinState = SIN_MSIGN;
1176                                 else if (!isdigit(*c))
1177                                         r = false;
1178                                 break;
1179                         case SIN_SCALE:
1180                                 if (*c == 'e' || *c == 'E')
1181                                         sinState = SIN_MSIGN;
1182                                 else if (!isdigit(*c))
1183                                         r = false;
1184                                 break;
1185                         case SIN_MSIGN:
1186                                 if (*c == '-' || *c == '+' || isdigit(*c))
1187                                         sinState = SIN_MANTISSA;
1188                                 else
1189                                         r = false;
1190                                 break;
1191                         case SIN_MANTISSA:
1192                                 if (!isdigit(*c))
1193                                         r = false;
1194                                 break;
1195                         default:
1196                                 abort();
1197                 }
1198
1199                 c++;
1200         }
1201
1202         if (sinState == SIN_MSIGN)
1203                 r = false;
1204
1205         return r;
1206 }
1207
1208 static void
1209 printIndent(StringInfo out, bool isRootHash, HStoreOutputKind kind, int level)
1210 {
1211         if (kind & PrettyPrint)
1212         {
1213                 int i;
1214
1215                 if (isRootHash && (kind & RootHashDecorated) == 0)
1216                         level--;
1217                 for(i=0; i<4*level; i++)
1218                         appendStringInfoCharMacro(out, ' ');
1219         }
1220 }
1221
1222 static void
1223 printCR(StringInfo out, HStoreOutputKind kind)
1224 {
1225         if (kind & PrettyPrint)
1226                 appendStringInfoCharMacro(out, '\n');
1227 }
1228
1229 static void
1230 escape_hstore(StringInfo out, char *string, uint32 len)
1231 {
1232         char       *ptr = string;
1233
1234         appendStringInfoCharMacro(out, '"');
1235         while (ptr - string < len)
1236         {
1237                 if (*ptr == '"' || *ptr == '\\')
1238                         appendStringInfoCharMacro(out, '\\');
1239                 appendStringInfoCharMacro(out, *ptr);
1240                 ptr++;
1241         }
1242         appendStringInfoCharMacro(out, '"');
1243 }
1244
1245 static void
1246 putEscapedString(StringInfo out, HStoreOutputKind kind,
1247                                  char *string, uint32 len)
1248 {
1249         if (kind & LooseOutput)
1250         {
1251                 if (len == 1 && *string == 't')
1252                         appendStringInfoString(out, (kind & JsonOutput) ? "true" : "t" );
1253                 else if (len == 1 && *string == 'f')
1254                         appendStringInfoString(out, (kind & JsonOutput) ? "false" : "f");
1255                 else if (len > 0 && stringIsNumber(string, len, true))
1256                         appendBinaryStringInfo(out, string, len);
1257                 else if (kind & JsonOutput)
1258                         escape_json(out, pnstrdup(string, len));
1259                 else
1260                         escape_hstore(out, string, len);
1261         }
1262         else
1263         {
1264                 if (kind & JsonOutput)
1265                         escape_json(out, pnstrdup(string, len));
1266                 else
1267                         escape_hstore(out, string, len);
1268         }
1269 }
1270
1271 static void
1272 putEscapedValue(StringInfo out, HStoreOutputKind kind, HStoreValue *v)
1273 {
1274         switch(v->type)
1275         {
1276                 case hsvNull:
1277                         appendBinaryStringInfo(out,
1278                                                                    (kind & JsonOutput) ? "null" : "NULL", 4);
1279                         break;
1280                 case hsvString:
1281                         putEscapedString(out, kind, v->string.val, v->string.len);
1282                         break;
1283                 case hsvBool:
1284                         if ((kind & JsonOutput) == 0)
1285                                 appendBinaryStringInfo(out, (v->boolean) ? "t" : "f", 1);
1286                         else if (v->boolean)
1287                                 appendBinaryStringInfo(out, "true", 4);
1288                         else
1289                                 appendBinaryStringInfo(out, "false", 5);
1290                         break;
1291                 case hsvNumeric:
1292                         appendStringInfoString(out, DatumGetCString(DirectFunctionCall1(numeric_out, PointerGetDatum(v->numeric))));
1293                         break;
1294                 default:
1295                         elog(PANIC, "Unknown type");
1296         }
1297 }
1298
1299 static bool
1300 needBrackets(int level, bool isArray, HStoreOutputKind kind, bool isScalar)
1301 {
1302         bool res;
1303
1304         if (isArray && isScalar)
1305                 res = false;
1306         else if (level == 0)
1307                 res = (isArray || (kind & RootHashDecorated)) ? true : false;
1308         else
1309                 res = true;
1310
1311         return res;
1312 }
1313
1314 static bool
1315 isArrayBrackets(HStoreOutputKind kind)
1316 {
1317         return ((kind & ArrayCurlyBraces) == 0) ? true : false;
1318 }
1319
1320
1321 char*
1322 hstoreToCString(StringInfo out, char *in, int len /* just estimation */,
1323                   HStoreOutputKind kind)
1324 {
1325         bool                    first = true;
1326         HStoreIterator  *it;
1327         int                             type;
1328         HStoreValue             v;
1329         int                             level = 0;
1330         bool                    isRootHash = false;
1331
1332         if (out == NULL)
1333                 out = makeStringInfo();
1334
1335         if (in == NULL)
1336         {
1337                 appendStringInfoString(out, "");
1338                 return out->data;
1339         }
1340
1341         enlargeStringInfo(out, (len >= 0) ? len : 64);
1342
1343         it = HStoreIteratorInit(in);
1344
1345         while((type = HStoreIteratorGet(&it, &v, false)) != 0)
1346         {
1347 reout:
1348                 switch(type)
1349                 {
1350                         case WHS_BEGIN_ARRAY:
1351                                 if (first == false)
1352                                 {
1353                                         appendBinaryStringInfo(out, ", ", 2);
1354                                         printCR(out, kind);
1355                                 }
1356                                 first = true;
1357
1358                                 if (needBrackets(level, true, kind, v.array.scalar))
1359                                 {
1360                                         printIndent(out, isRootHash, kind, level);
1361                                         appendStringInfoChar(out, isArrayBrackets(kind) ? '[' : '{');
1362                                         printCR(out, kind);
1363                                 }
1364                                 level++;
1365                                 break;
1366                         case WHS_BEGIN_HASH:
1367                                 if (first == false)
1368                                 {
1369                                         appendBinaryStringInfo(out, ", ", 2);
1370                                         printCR(out, kind);
1371                                 }
1372                                 first = true;
1373
1374                                 if (level == 0)
1375                                         isRootHash = true;
1376
1377                                 if (needBrackets(level, false, kind, false))
1378                                 {
1379                                         printIndent(out, isRootHash, kind, level);
1380                                         appendStringInfoCharMacro(out, '{');
1381                                         printCR(out, kind);
1382                                 }
1383
1384                                 level++;
1385                                 break;
1386                         case WHS_KEY:
1387                                 if (first == false)
1388                                 {
1389                                         appendBinaryStringInfo(out, ", ", 2);
1390                                         printCR(out, kind);
1391                                 }
1392                                 first = true;
1393
1394                                 printIndent(out, isRootHash, kind, level);
1395                                 /* key should not be loose */
1396                                 putEscapedValue(out, kind & ~LooseOutput, &v);
1397                                 appendBinaryStringInfo(out,
1398                                                                            (kind & JsonOutput) ? ": " : "=>", 2);
1399
1400                                 type = HStoreIteratorGet(&it, &v, false);
1401                                 if (type == WHS_VALUE)
1402                                 {
1403                                         first = false;
1404                                         putEscapedValue(out, kind, &v);
1405                                 }
1406                                 else
1407                                 {
1408                                         Assert(type == WHS_BEGIN_HASH || type == WHS_BEGIN_ARRAY);
1409                                         printCR(out, kind);
1410                                         /*
1411                                          * We need to rerun current switch() due to put
1412                                          * in current place object which we just got
1413                                          * from iterator.
1414                                          */
1415                                         goto reout;
1416                                 }
1417                                 break;
1418                         case WHS_ELEM:
1419                                 if (first == false)
1420                                 {
1421                                         appendBinaryStringInfo(out, ", ", 2);
1422                                         printCR(out, kind);
1423                                 }
1424                                 else
1425                                 {
1426                                         first = false;
1427                                 }
1428
1429                                 printIndent(out, isRootHash, kind, level);
1430                                 putEscapedValue(out, kind, &v);
1431                                 break;
1432                         case WHS_END_ARRAY:
1433                                 level--;
1434                                 if (needBrackets(level, true, kind, v.array.scalar))
1435                                 {
1436                                         printCR(out, kind);
1437                                         printIndent(out, isRootHash, kind, level);
1438                                         appendStringInfoChar(out, isArrayBrackets(kind) ? ']' : '}');
1439                                 }
1440                                 first = false;
1441                                 break;
1442                         case WHS_END_HASH:
1443                                 level--;
1444                                 if (needBrackets(level, false, kind, false))
1445                                 {
1446                                         printCR(out, kind);
1447                                         printIndent(out, isRootHash, kind, level);
1448                                         appendStringInfoCharMacro(out, '}');
1449                                 }
1450                                 first = false;
1451                                 break;
1452                         default:
1453                                 elog(PANIC, "Wrong flags");
1454                 }
1455         }
1456
1457         Assert(level == 0);
1458
1459         return out->data;
1460 }
1461
1462 text*
1463 HStoreValueToText(HStoreValue *v)
1464 {
1465         text            *out;
1466
1467         if (v == NULL || v->type == hsvNull)
1468         {
1469                 out = NULL;
1470         }
1471         else if (v->type == hsvString)
1472         {
1473                 out = cstring_to_text_with_len(v->string.val, v->string.len);
1474         }
1475         else if (v->type == hsvBool)
1476         {
1477                 out = cstring_to_text_with_len((v->boolean) ? "t" : "f", 1);
1478         }
1479         else if (v->type == hsvNumeric)
1480         {
1481                 out = cstring_to_text(DatumGetCString(
1482                                 DirectFunctionCall1(numeric_out, PointerGetDatum(v->numeric))
1483                 ));
1484         }
1485         else
1486         {
1487                 StringInfo      str;
1488
1489                 str = makeStringInfo();
1490                 appendBinaryStringInfo(str, "    ", 4); /* VARHDRSZ */
1491
1492                 hstoreToCString(str, v->binary.data, v->binary.len,
1493                                                 SET_PRETTY_PRINT_VAR(0));
1494
1495                 out = (text*)str->data;
1496                 SET_VARSIZE(out, str->len);
1497         }
1498
1499         return out;
1500 }
1501
1502 PG_FUNCTION_INFO_V1(hstore_out);
1503 Datum           hstore_out(PG_FUNCTION_ARGS);
1504 Datum
1505 hstore_out(PG_FUNCTION_ARGS)
1506 {
1507         HStore  *hs = PG_GETARG_HS(0);
1508         char    *out;
1509
1510         out = hstoreToCString(NULL, (HS_ISEMPTY(hs)) ? NULL : VARDATA(hs),
1511                                                   VARSIZE(hs), SET_PRETTY_PRINT_VAR(0));
1512
1513         PG_RETURN_CSTRING(out);
1514 }
1515
1516 PG_FUNCTION_INFO_V1(hstore_send);
1517 Datum           hstore_send(PG_FUNCTION_ARGS);
1518 Datum
1519 hstore_send(PG_FUNCTION_ARGS)
1520 {
1521         HStore                  *in = PG_GETARG_HS(0);
1522         StringInfoData  buf;
1523
1524         pq_begintypsend(&buf);
1525
1526         if (HS_ISEMPTY(in))
1527         {
1528                 pq_sendint(&buf, 0, 4);
1529         }
1530         else
1531         {
1532                 HStoreIterator  *it;
1533                 int                             type;
1534                 HStoreValue             v;
1535                 uint32                  flag;
1536                 bytea                   *nbuf;
1537
1538                 enlargeStringInfo(&buf, VARSIZE_ANY(in) /* just estimation */);
1539
1540                 it = HStoreIteratorInit(VARDATA_ANY(in));
1541
1542                 while((type = HStoreIteratorGet(&it, &v, false)) != 0)
1543                 {
1544                         switch(type)
1545                         {
1546                                 case WHS_BEGIN_ARRAY:
1547                                         flag = (v.array.scalar) ? HENTRY_ISSCALAR : HENTRY_ISARRAY;
1548                                         pq_sendint(&buf, v.array.nelems | flag, 4);
1549                                         break;
1550                                 case WHS_BEGIN_HASH:
1551                                         pq_sendint(&buf, v.hash.npairs | HENTRY_ISHASH, 4);
1552                                         break;
1553                                 case WHS_KEY:
1554                                         pq_sendint(&buf, v.string.len | HENTRY_ISSTRING, 4);
1555                                         pq_sendtext(&buf, v.string.val, v.string.len);
1556                                         break;
1557                                 case WHS_ELEM:
1558                                 case WHS_VALUE:
1559                                         switch(v.type)
1560                                         {
1561                                                 case hsvNull:
1562                                                         pq_sendint(&buf, HENTRY_ISNULL, 4);
1563                                                         break;
1564                                                 case hsvString:
1565                                                         pq_sendint(&buf, v.string.len | HENTRY_ISSTRING, 4);
1566                                                         pq_sendtext(&buf, v.string.val, v.string.len);
1567                                                         break;
1568                                                 case hsvBool:
1569                                                         pq_sendint(&buf, (v.boolean) ? HENTRY_ISTRUE : HENTRY_ISFALSE, 4);
1570                                                         break;
1571                                                 case hsvNumeric:
1572                                                         nbuf = DatumGetByteaP(DirectFunctionCall1(numeric_send, NumericGetDatum(v.numeric)));
1573                                                         pq_sendint(&buf, ((int)VARSIZE_ANY_EXHDR(nbuf)) | HENTRY_ISNUMERIC, 4);
1574                                                         pq_sendbytes(&buf, VARDATA(nbuf), (int)VARSIZE_ANY_EXHDR(nbuf));
1575                                                         break;
1576                                                 default:
1577                                                         elog(PANIC, "Wrong type: %u", v.type);
1578                                         }
1579                                         break;
1580                                 case WHS_END_ARRAY:
1581                                 case WHS_END_HASH:
1582                                         break;
1583                                 default:
1584                                         elog(PANIC, "Wrong flags");
1585                         }
1586                 }
1587         }
1588
1589         PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
1590 }
1591
1592
1593 /*
1594  * hstore_to_json_loose
1595  *
1596  * This is a heuristic conversion to json which treats
1597  * 't' and 'f' as booleans and strings that look like numbers as numbers,
1598  * as long as they don't start with a leading zero followed by another digit
1599  * (think zip codes or phone numbers starting with 0).
1600  */
1601 PG_FUNCTION_INFO_V1(hstore_to_json_loose);
1602 Datum           hstore_to_json_loose(PG_FUNCTION_ARGS);
1603 Datum
1604 hstore_to_json_loose(PG_FUNCTION_ARGS)
1605 {
1606         HStore     *in = PG_GETARG_HS(0);
1607         text       *out;
1608
1609         if (HS_ISEMPTY(in))
1610         {
1611                 out = cstring_to_text_with_len("{}",2);
1612         }
1613         else
1614         {
1615                 StringInfo      str;
1616
1617                 str = makeStringInfo();
1618                 appendBinaryStringInfo(str, "    ", 4); /* VARHDRSZ */
1619
1620                 hstoreToCString(str, VARDATA_ANY(in), VARSIZE_ANY(in),
1621                                                 SET_PRETTY_PRINT_VAR(JsonOutput | RootHashDecorated | LooseOutput));
1622
1623                 out = (text*)str->data;
1624
1625                 SET_VARSIZE(out, str->len);
1626         }
1627
1628         PG_RETURN_TEXT_P(out);
1629 }
1630
1631 PG_FUNCTION_INFO_V1(hstore_to_json);
1632 Datum           hstore_to_json(PG_FUNCTION_ARGS);
1633 Datum
1634 hstore_to_json(PG_FUNCTION_ARGS)
1635 {
1636         HStore     *in = PG_GETARG_HS(0);
1637         text       *out;
1638
1639         if (HS_ISEMPTY(in))
1640         {
1641                 out = cstring_to_text_with_len("{}",2);
1642         }
1643         else
1644         {
1645                 StringInfo      str;
1646
1647                 str = makeStringInfo();
1648                 appendBinaryStringInfo(str, "    ", 4); /* VARHDRSZ */
1649
1650                 hstoreToCString(str,
1651                                                 HS_ISEMPTY(in) ? NULL : VARDATA_ANY(in),
1652                                                 VARSIZE_ANY(in),
1653                                                 SET_PRETTY_PRINT_VAR(JsonOutput | RootHashDecorated));
1654
1655                 out = (text*)str->data;
1656
1657                 SET_VARSIZE(out, str->len);
1658         }
1659
1660         PG_RETURN_TEXT_P(out);
1661 }
1662
1663 PG_FUNCTION_INFO_V1(json_to_hstore);
1664 Datum           json_to_hstore(PG_FUNCTION_ARGS);
1665 Datum
1666 json_to_hstore(PG_FUNCTION_ARGS)
1667 {
1668         text    *json = PG_GETARG_TEXT_PP(0);
1669
1670         PG_RETURN_POINTER(hstoreDump(parseHStore(VARDATA_ANY(json),
1671                                                                                          VARSIZE_ANY_EXHDR(json), true)));
1672 }
1673
1674 static Oid
1675 searchCast(Oid src, Oid dst, CoercionMethod *method)
1676 {
1677         Oid                             funcOid = InvalidOid,
1678                                         baseSrc;
1679         HeapTuple       tuple;
1680
1681         if (src == dst)
1682         {
1683                 *method = COERCION_METHOD_BINARY;
1684                 return InvalidOid;
1685         }
1686
1687         tuple = SearchSysCache2(CASTSOURCETARGET,
1688                                                         ObjectIdGetDatum(src),
1689                                                         ObjectIdGetDatum(dst));
1690
1691         *method = 0;
1692
1693         if (HeapTupleIsValid(tuple))
1694         {
1695                 Form_pg_cast    castForm = (Form_pg_cast) GETSTRUCT(tuple);
1696
1697                 if (castForm->castmethod == COERCION_METHOD_FUNCTION)
1698                         funcOid = castForm->castfunc;
1699
1700                 *method = castForm->castmethod;
1701
1702                 ReleaseSysCache(tuple);
1703         }
1704         else if ((baseSrc = getBaseType(src)) != src && OidIsValid(baseSrc))
1705         {       
1706                 /* domain type */
1707                 funcOid = searchCast(baseSrc, dst, method);
1708         }
1709
1710         return funcOid;
1711 }
1712
1713 PG_FUNCTION_INFO_V1(array_to_hstore);
1714 Datum           array_to_hstore(PG_FUNCTION_ARGS);
1715 Datum
1716 array_to_hstore(PG_FUNCTION_ARGS)
1717 {
1718         ArrayType               *array = PG_GETARG_ARRAYTYPE_P(0);
1719         ArrayIterator   iterator;
1720         int                             i = 0;
1721         Datum                   datum;
1722         bool                    isnull;
1723         int                             ncounters = ARR_NDIM(array),
1724                                         *counters = palloc0(sizeof(*counters) * ncounters),
1725                                         *dims = ARR_DIMS(array);
1726         ToHStoreState   *state = NULL;
1727         HStoreValue             value, *result;
1728         Oid                             castOid = InvalidOid;
1729         int                             valueType = hsvString;
1730         FmgrInfo                castInfo;
1731         CoercionMethod  method;
1732
1733         if (ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array)) == 0)
1734                 PG_RETURN_POINTER(hstoreDump(NULL));
1735
1736         switch(ARR_ELEMTYPE(array))
1737         {
1738                 case BOOLOID:
1739                         valueType = hsvBool;
1740                         break;
1741                 case NUMERICOID:
1742                         valueType = hsvNumeric;
1743                         break;
1744                 case TEXTOID:
1745                         valueType = hsvString;
1746                         break;
1747                 default:
1748                         if (TypeCategory(ARR_ELEMTYPE(array)) == TYPCATEGORY_NUMERIC)
1749                         {
1750                                 castOid = searchCast(ARR_ELEMTYPE(array), NUMERICOID, &method);
1751
1752                                 if (castOid == InvalidOid && method != COERCION_METHOD_BINARY)
1753                                         elog(ERROR, "Could not cast array's element type to numeric");
1754
1755                                 valueType = hsvNumeric;
1756                                 break;
1757                         }
1758                         else
1759                         {
1760                                 castOid = searchCast(ARR_ELEMTYPE(array), TEXTOID, &method);
1761
1762                                 if (castOid == InvalidOid && method != COERCION_METHOD_BINARY)
1763                                         elog(ERROR, "Could not cast array's element type to text");
1764
1765                                 valueType = hsvString;
1766                                 break;
1767                         }
1768         }
1769
1770         if (castOid != InvalidOid)
1771                 fmgr_info(castOid, &castInfo);
1772
1773         iterator = array_create_iterator(array, 0);
1774
1775         value.type = hsvArray;
1776         value.array.scalar = false;
1777         for(i=0; i<ncounters; i++)
1778         {
1779                 value.array.nelems = dims[i];
1780                 result = pushHStoreValue(&state, WHS_BEGIN_ARRAY, &value);
1781         }
1782
1783         while(array_iterate(iterator, &datum, &isnull))
1784         {
1785                 i = ncounters - 1;
1786
1787                 if (counters[i] >= dims[i])
1788                 {
1789                         while(i>=0 && counters[i] >= dims[i])
1790                         {
1791                                 counters[i] = 0;
1792                                 result = pushHStoreValue(&state, WHS_END_ARRAY, NULL);
1793                                 i--;
1794                         }
1795
1796                         Assert(i>=0);
1797
1798                         counters[i]++;
1799
1800                         value.type = hsvArray;
1801                         value.array.scalar = false;
1802                         for(i = i + 1; i<ncounters; i++)
1803                         {
1804                                 counters[i] = 1;
1805                                 value.array.nelems = dims[i];
1806                                 result = pushHStoreValue(&state, WHS_BEGIN_ARRAY, &value);
1807                         }
1808                 }
1809                 else
1810                 {
1811                         counters[i]++;
1812                 }
1813
1814                 if (isnull)
1815                 {
1816                         value.type = hsvNull;
1817                         value.size = sizeof(HEntry);
1818                 }
1819                 else
1820                 {
1821                         value.type = valueType;
1822                         switch(valueType)
1823                         {
1824                                 case hsvBool:
1825                                         value.boolean = DatumGetBool(datum);
1826                                         value.size = sizeof(HEntry);
1827                                         break;
1828                                 case hsvString:
1829                                         if (castOid != InvalidOid)
1830                                                 datum = FunctionCall1(&castInfo, datum);
1831                                         value.string.val = VARDATA_ANY(datum);
1832                                         value.string.len = VARSIZE_ANY_EXHDR(datum);
1833                                         value.size = sizeof(HEntry) + value.string.len;
1834                                         break;
1835                                 case hsvNumeric:
1836                                         if (castOid != InvalidOid)
1837                                                 datum = FunctionCall1(&castInfo, datum);
1838                                         value.numeric = DatumGetNumeric(datum);
1839                                         value.size = sizeof(HEntry)*2 + VARSIZE_ANY(value.numeric);
1840                                         break;
1841                                 default:
1842                                         elog(ERROR, "Impossible state: %d", valueType);
1843                         }
1844                 }
1845
1846                 result = pushHStoreValue(&state, WHS_ELEM, &value);
1847         }
1848
1849         for(i=0; i<ncounters; i++)
1850                 result = pushHStoreValue(&state, WHS_END_ARRAY, NULL);
1851
1852         PG_RETURN_POINTER(hstoreDump(result));
1853 }
1854
1855 PG_FUNCTION_INFO_V1(hstore_print);
1856 Datum           hstore_print(PG_FUNCTION_ARGS);
1857 Datum
1858 hstore_print(PG_FUNCTION_ARGS)
1859 {
1860         HStore          *hs = PG_GETARG_HS(0);
1861         int             flags = 0;
1862         text            *out;
1863         StringInfo      str;
1864
1865         if (PG_GETARG_BOOL(1))
1866                 flags |= PrettyPrint;
1867         if (PG_GETARG_BOOL(2))
1868                 flags |= ArrayCurlyBraces;
1869         if (PG_GETARG_BOOL(3))
1870                 flags |= RootHashDecorated;
1871         if (PG_GETARG_BOOL(4))
1872                 flags |= JsonOutput;
1873         if (PG_GETARG_BOOL(5))
1874                 flags |= LooseOutput;
1875
1876         str = makeStringInfo();
1877         appendBinaryStringInfo(str, "    ", 4); /* VARHDRSZ */
1878
1879         hstoreToCString(str, (HS_ISEMPTY(hs)) ? NULL : VARDATA(hs),
1880                                         VARSIZE(hs), flags);
1881
1882         out = (text*)str->data;
1883         SET_VARSIZE(out, str->len);
1884
1885         PG_RETURN_TEXT_P(out);
1886 }
1887
1888 void _PG_init(void);
1889 void
1890 _PG_init(void)
1891 {
1892         DefineCustomBoolVariable(
1893                 "hstore.pretty_print",
1894                 "Enable pretty print",
1895                 "Enable pretty print of hstore type",
1896                 &pretty_print_var,
1897                 pretty_print_var,
1898                 PGC_USERSET,
1899                 GUC_NOT_IN_SAMPLE,
1900                 NULL,
1901                 NULL,
1902                 NULL
1903         );
1904
1905         EmitWarningsOnPlaceholders("hstore");
1906 }