2 * contrib/hstore/hstore_io.c
8 #include "access/htup_details.h"
9 #include "catalog/pg_type.h"
10 #include "catalog/pg_cast.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"
28 /* old names for C functions */
29 HSTORE_POLLUTE(hstore_from_text, tconvert);
32 static bool pretty_print_var = false;
33 #define SET_PRETTY_PRINT_VAR(x) ((pretty_print_var) ? \
34 ((x) | PrettyPrint) : (x))
36 static void recvHStore(StringInfo buf, HStoreValue *v, uint32 level,
38 static Oid searchCast(Oid src, Oid dst, CoercionMethod *method);
41 hstoreCheckKeyLen(size_t len)
43 if (len > HSTORE_MAX_KEY_LEN)
45 (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
46 errmsg("string too long for hstore key")));
51 hstoreCheckValLen(size_t len)
53 if (len > HSTORE_MAX_VALUE_LEN)
55 (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
56 errmsg("string too long for hstore value")));
62 hstoreDump(HStoreValue *p)
67 if (p == NULL || (p->type == hsvArray && p->array.nelems == 0) ||
68 (p->type == hsvHash && p->hash.npairs == 0))
71 out = palloc(VARHDRSZ);
75 buflen = VARHDRSZ + p->size;
77 SET_VARSIZE(out, buflen);
79 buflen = compressHStore(p, VARDATA(out));
81 SET_VARSIZE(out, buflen + VARHDRSZ);
86 PG_FUNCTION_INFO_V1(hstore_in);
87 Datum hstore_in(PG_FUNCTION_ARGS);
89 hstore_in(PG_FUNCTION_ARGS)
91 PG_RETURN_POINTER(hstoreDump(parseHStore(PG_GETARG_CSTRING(0), -1, false)));
95 recvHStoreValue(StringInfo buf, HStoreValue *v, uint32 level, int c)
97 uint32 hentry = c & HENTRY_TYPEMASK;
101 if (c == -1 /* compatibility */ || hentry == HENTRY_ISNULL)
104 v->size = sizeof(HEntry);
106 else if (hentry == HENTRY_ISHASH || hentry == HENTRY_ISARRAY ||
107 hentry == HENTRY_ISSCALAR)
109 recvHStore(buf, v, level + 1, (uint32)c);
111 else if (hentry == HENTRY_ISFALSE || hentry == HENTRY_ISTRUE)
114 v->size = sizeof(HEntry);
115 v->boolean = (hentry == HENTRY_ISFALSE) ? false : true;
117 else if (hentry == HENTRY_ISNUMERIC)
119 v->type = hsvNumeric;
120 v->numeric = DatumGetNumeric(DirectFunctionCall3(numeric_recv,
121 PointerGetDatum(buf),
124 v->size = sizeof(HEntry) * 2 + VARSIZE_ANY(v->numeric);
126 else if (hentry == HENTRY_ISSTRING)
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;
136 (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
137 errmsg("unknown hstore value")));
142 recvHStore(StringInfo buf, HStoreValue *v, uint32 level, uint32 header)
147 hentry = header & HENTRY_TYPEMASK;
149 if (level == 0 && hentry == 0)
150 hentry = HENTRY_ISHASH; /* old version */
154 v->size = 3 * sizeof(HEntry);
155 if (hentry == HENTRY_ISHASH)
158 v->hash.npairs = header & HS_COUNT_MASK;
160 if (v->hash.npairs > (buf->len - buf->cursor) / (2 * sizeof(uint32)) ||
161 v->hash.npairs > MaxAllocSize / sizeof(HStorePair))
163 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
164 errmsg("too much elements in hstore hash")));
166 if (v->hash.npairs > 0)
168 v->hash.pairs = palloc(sizeof(*v->hash.pairs) * v->hash.npairs);
170 for(i=0; i<v->hash.npairs; i++)
172 recvHStoreValue(buf, &v->hash.pairs[i].key, level,
173 pq_getmsgint(buf, 4));
174 if (v->hash.pairs[i].key.type != hsvString)
176 (errcode(ERRCODE_DATATYPE_MISMATCH),
177 errmsg("hstore's key could be only a string")));
179 recvHStoreValue(buf, &v->hash.pairs[i].value, level,
180 pq_getmsgint(buf, 4));
182 v->size += v->hash.pairs[i].key.size +
183 v->hash.pairs[i].value.size;
186 uniqueHStoreValue(v);
189 else if (hentry == HENTRY_ISARRAY || hentry == HENTRY_ISSCALAR)
192 v->array.nelems = header & HS_COUNT_MASK;
193 v->array.scalar = (hentry == HENTRY_ISSCALAR) ? true : false;
195 if (v->array.nelems > (buf->len - buf->cursor) / sizeof(uint32) ||
196 v->array.nelems > MaxAllocSize / sizeof(HStoreValue))
198 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
199 errmsg("too much elements in hstore array")));
201 if (v->array.scalar && v->array.nelems != 1)
203 (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
204 errmsg("wrong scalar representation")));
206 if (v->array.nelems > 0)
208 v->array.elems = palloc(sizeof(*v->array.elems) * v->array.nelems);
210 for(i=0; i<v->array.nelems; i++)
212 recvHStoreValue(buf, v->array.elems + i, level,
213 pq_getmsgint(buf, 4));
214 v->size += v->array.elems[i].size;
221 (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
222 errmsg("unknown hstore element")));
226 PG_FUNCTION_INFO_V1(hstore_recv);
227 Datum hstore_recv(PG_FUNCTION_ARGS);
229 hstore_recv(PG_FUNCTION_ARGS)
231 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
234 recvHStore(buf, &v, 0, pq_getmsgint(buf, 4));
236 PG_RETURN_POINTER(hstoreDump(&v));
239 PG_FUNCTION_INFO_V1(hstore_from_text);
240 Datum hstore_from_text(PG_FUNCTION_ARGS);
242 hstore_from_text(PG_FUNCTION_ARGS)
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);
259 pair.value.type = hsvNull;
260 pair.value.size = sizeof(HEntry);
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);
274 v.size = sizeof(HEntry) + pair.key.size + pair.value.size;
276 v.hash.pairs = &pair;
278 PG_RETURN_POINTER(hstoreDump(&v));
281 PG_FUNCTION_INFO_V1(hstore_from_bool);
282 Datum hstore_from_bool(PG_FUNCTION_ARGS);
284 hstore_from_bool(PG_FUNCTION_ARGS)
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);
301 pair.value.type = hsvNull;
302 pair.value.size = sizeof(HEntry);
306 pair.value.type = hsvBool;
307 pair.value.boolean = PG_GETARG_BOOL(1);
308 pair.value.size = sizeof(HEntry);
312 v.size = sizeof(HEntry) + pair.key.size + pair.value.size;
314 v.hash.pairs = &pair;
316 PG_RETURN_POINTER(hstoreDump(&v));
319 PG_FUNCTION_INFO_V1(hstore_from_numeric);
320 Datum hstore_from_numeric(PG_FUNCTION_ARGS);
322 hstore_from_numeric(PG_FUNCTION_ARGS)
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);
339 pair.value.type = hsvNull;
340 pair.value.size = sizeof(HEntry);
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);
351 v.size = sizeof(HEntry) + pair.key.size + pair.value.size;
353 v.hash.pairs = &pair;
355 PG_RETURN_POINTER(hstoreDump(&v));
358 PG_FUNCTION_INFO_V1(hstore_from_th);
359 Datum hstore_from_th(PG_FUNCTION_ARGS);
361 hstore_from_th(PG_FUNCTION_ARGS)
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);
378 pair.value.type = hsvNull;
379 pair.value.size = sizeof(HEntry);
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;
393 v.size = sizeof(HEntry) + pair.key.size + pair.value.size;
395 v.hash.pairs = &pair;
397 PG_RETURN_POINTER(hstoreDump(&v));
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);
404 hstore_scalar_from_text(PG_FUNCTION_ARGS)
411 v.size = sizeof(HEntry);
417 scalar = PG_GETARG_TEXT_PP(0);
419 v.string.val = VARDATA_ANY(scalar);
420 v.string.len = hstoreCheckKeyLen(VARSIZE_ANY_EXHDR(scalar));
421 v.size = v.string.len + sizeof(HEntry);
425 a.size = sizeof(HEntry) + v.size;
428 a.array.scalar = true;
430 PG_RETURN_POINTER(hstoreDump(&a));
433 PG_FUNCTION_INFO_V1(hstore_scalar_from_bool);
434 Datum hstore_scalar_from_bool(PG_FUNCTION_ARGS);
436 hstore_scalar_from_bool(PG_FUNCTION_ARGS)
443 v.size = sizeof(HEntry);
448 v.boolean = PG_GETARG_BOOL(0);
449 v.size = sizeof(HEntry);
453 a.size = sizeof(HEntry) + v.size;
456 a.array.scalar = true;
458 PG_RETURN_POINTER(hstoreDump(&a));
461 PG_FUNCTION_INFO_V1(hstore_scalar_from_numeric);
462 Datum hstore_scalar_from_numeric(PG_FUNCTION_ARGS);
464 hstore_scalar_from_numeric(PG_FUNCTION_ARGS)
471 v.size = sizeof(HEntry);
476 v.numeric = PG_GETARG_NUMERIC(0);
477 v.size = VARSIZE_ANY(v.numeric) + 2*sizeof(HEntry);
481 a.size = sizeof(HEntry) + v.size;
484 a.array.scalar = true;
486 PG_RETURN_POINTER(hstoreDump(&a));
489 Datum hstore_from_arrays(PG_FUNCTION_ARGS);
491 hstore_from_arrays(PG_FUNCTION_ARGS)
500 ArrayType *key_array;
501 ArrayType *value_array;
507 key_array = PG_GETARG_ARRAYTYPE_P(0);
509 Assert(ARR_ELEMTYPE(key_array) == TEXTOID);
512 * must check >1 rather than != 1 because empty arrays have 0 dimensions,
516 if (ARR_NDIM(key_array) > 1)
518 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
519 errmsg("wrong number of array subscripts")));
521 deconstruct_array(key_array,
522 TEXTOID, -1, false, 'i',
523 &key_datums, &key_nulls, &key_count);
525 /* see discussion in arrayToHStoreSortedArray() */
526 if (key_count > MaxAllocSize / sizeof(HStorePair))
528 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
529 errmsg("number of pairs (%d) exceeds the maximum allowed (%d)",
530 key_count, (int) (MaxAllocSize / sizeof(HStorePair)))));
532 /* value_array might be NULL */
537 value_count = key_count;
543 value_array = PG_GETARG_ARRAYTYPE_P(1);
545 Assert(ARR_ELEMTYPE(value_array) == TEXTOID);
547 if (ARR_NDIM(value_array) > 1)
549 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
550 errmsg("wrong number of array subscripts")));
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]))
557 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
558 errmsg("arrays must have same bounds")));
560 deconstruct_array(value_array,
561 TEXTOID, -1, false, 'i',
562 &value_datums, &value_nulls, &value_count);
564 Assert(key_count == value_count);
568 v.size = 2 * sizeof(HEntry);
569 v.hash.pairs = palloc(key_count * sizeof(*v.hash.pairs));
570 v.hash.npairs = key_count;
572 for (i = 0; i < key_count; ++i)
576 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
577 errmsg("null value not allowed for hstore key")));
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;
585 if (!value_nulls || value_nulls[i])
587 v.hash.pairs[i].value.type = hsvNull;
588 v.hash.pairs[i].value.size = sizeof(HEntry);
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;
600 v.size += v.hash.pairs[i].key.size + v.hash.pairs[i].value.size;
603 uniqueHStoreValue(&v);
606 PG_RETURN_POINTER(hstoreDump(&v));
610 PG_FUNCTION_INFO_V1(hstore_from_array);
611 Datum hstore_from_array(PG_FUNCTION_ARGS);
613 hstore_from_array(PG_FUNCTION_ARGS)
615 ArrayType *in_array = PG_GETARG_ARRAYTYPE_P(0);
616 int ndims = ARR_NDIM(in_array);
624 Assert(ARR_ELEMTYPE(in_array) == TEXTOID);
629 PG_RETURN_POINTER(hstoreDump(NULL));
632 if ((ARR_DIMS(in_array)[0]) % 2)
634 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
635 errmsg("array must have even number of elements")));
639 if ((ARR_DIMS(in_array)[1]) != 2)
641 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
642 errmsg("array must have two columns")));
647 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
648 errmsg("wrong number of array subscripts")));
651 deconstruct_array(in_array,
652 TEXTOID, -1, false, 'i',
653 &in_datums, &in_nulls, &in_count);
655 count = in_count / 2;
657 /* see discussion in arrayToHStoreSortedArray() */
658 if (count > MaxAllocSize / sizeof(HStorePair))
660 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
661 errmsg("number of pairs (%d) exceeds the maximum allowed (%d)",
662 count, (int) (MaxAllocSize / sizeof(HStorePair)))));
665 v.size = 2*sizeof(HEntry);
666 v.hash.npairs = count;
667 v.hash.pairs = palloc(count * sizeof(HStorePair));
669 for (i = 0; i < count; ++i)
673 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
674 errmsg("null value not allowed for hstore key")));
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;
682 if (in_nulls[i * 2 + 1])
684 v.hash.pairs[i].value.type = hsvNull;
685 v.hash.pairs[i].value.size = sizeof(HEntry);
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;
697 v.size += v.hash.pairs[i].key.size + v.hash.pairs[i].value.size;
700 uniqueHStoreValue(&v);
702 PG_RETURN_POINTER(hstoreDump(&v));
705 /* most of hstore_from_record is shamelessly swiped from record_out */
708 * structure to cache metadata needed for record I/O
710 typedef struct ColumnIOData
718 typedef struct RecordIOData
723 ColumnIOData columns[1]; /* VARIABLE LENGTH ARRAY */
726 PG_FUNCTION_INFO_V1(hstore_from_record);
727 Datum hstore_from_record(PG_FUNCTION_ARGS);
729 hstore_from_record(PG_FUNCTION_ARGS)
738 RecordIOData *my_extra;
746 Oid argtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
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.
760 rec = PG_GETARG_HEAPTUPLEHEADER(0);
762 /* Extract type info from the tuple itself */
763 tupType = HeapTupleHeaderGetTypeId(rec);
764 tupTypmod = HeapTupleHeaderGetTypMod(rec);
767 tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
768 ncolumns = tupdesc->natts;
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.
774 my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra;
775 if (my_extra == NULL ||
776 my_extra->ncolumns != ncolumns)
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;
787 if (my_extra->record_type != tupType ||
788 my_extra->record_typmod != tupTypmod)
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;
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));
806 /* Build a temporary HeapTuple control structure */
807 tuple.t_len = HeapTupleHeaderGetDatumLength(rec);
808 ItemPointerSetInvalid(&(tuple.t_self));
809 tuple.t_tableOid = InvalidOid;
812 values = (Datum *) palloc(ncolumns * sizeof(Datum));
813 nulls = (bool *) palloc(ncolumns * sizeof(bool));
815 /* Break down the tuple into fields */
816 heap_deform_tuple(&tuple, tupdesc, values, nulls);
824 for (i = 0; i < ncolumns; ++i)
826 ColumnIOData *column_info = &my_extra->columns[i];
827 Oid column_type = tupdesc->attrs[i]->atttypid;
830 /* Ignore dropped columns in datatype */
831 if (tupdesc->attrs[i]->attisdropped)
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;
840 if (!nulls || nulls[i])
842 v.hash.pairs[i].value.type = hsvNull;
843 v.hash.pairs[i].value.size = sizeof(HEntry);
848 * Convert the column value to hstore's values
850 if (column_type == BOOLOID)
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);
856 else if (TypeCategory(column_type) == TYPCATEGORY_NUMERIC)
858 Oid castOid = InvalidOid;
859 CoercionMethod method;
861 v.hash.pairs[i].value.type = hsvNumeric;
863 castOid = searchCast(column_type, NUMERICOID, &method);
864 if (castOid == InvalidOid)
866 if (method != COERCION_METHOD_BINARY)
867 elog(ERROR, "Could not cast numeric category type to numeric '%c'", (char)method);
869 v.hash.pairs[i].value.numeric = DatumGetNumeric(values[i]);
873 v.hash.pairs[i].value.numeric =
874 DatumGetNumeric(OidFunctionCall1(castOid, values[i]));
877 v.hash.pairs[i].value.size = 2*sizeof(HEntry) +
878 VARSIZE_ANY(v.hash.pairs[i].value.numeric);
882 if (column_info->column_type != column_type)
886 getTypeOutputInfo(column_type,
887 &column_info->typiofunc,
889 fmgr_info_cxt(column_info->typiofunc, &column_info->proc,
890 fcinfo->flinfo->fn_mcxt);
891 column_info->column_type = column_type;
894 value = OutputFunctionCall(&column_info->proc, values[i]);
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;
904 v.size += v.hash.pairs[i].key.size + v.hash.pairs[i].value.size;
907 uniqueHStoreValue(&v);
909 out = hstoreDump(&v);
911 ReleaseTupleDesc(tupdesc);
913 PG_RETURN_POINTER(out);
917 PG_FUNCTION_INFO_V1(hstore_populate_record);
918 Datum hstore_populate_record(PG_FUNCTION_ARGS);
920 hstore_populate_record(PG_FUNCTION_ARGS)
922 Oid argtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
930 RecordIOData *my_extra;
936 if (!type_is_rowtype(argtype))
938 (errcode(ERRCODE_DATATYPE_MISMATCH),
939 errmsg("first argument must be a rowtype")));
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.
958 rec = PG_GETARG_HEAPTUPLEHEADER(0);
961 PG_RETURN_POINTER(rec);
963 /* Extract type info from the tuple itself */
964 tupType = HeapTupleHeaderGetTypeId(rec);
965 tupTypmod = HeapTupleHeaderGetTypMod(rec);
968 hs = PG_GETARG_HS(1);
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
976 if (HS_ISEMPTY(hs) && rec)
977 PG_RETURN_POINTER(rec);
979 tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
980 ncolumns = tupdesc->natts;
984 /* Build a temporary HeapTuple control structure */
985 tuple.t_len = HeapTupleHeaderGetDatumLength(rec);
986 ItemPointerSetInvalid(&(tuple.t_self));
987 tuple.t_tableOid = InvalidOid;
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.
995 my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra;
996 if (my_extra == NULL ||
997 my_extra->ncolumns != ncolumns)
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;
1008 if (my_extra->record_type != tupType ||
1009 my_extra->record_typmod != tupTypmod)
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;
1019 values = (Datum *) palloc(ncolumns * sizeof(Datum));
1020 nulls = (bool *) palloc(ncolumns * sizeof(bool));
1024 /* Break down the tuple into fields */
1025 heap_deform_tuple(&tuple, tupdesc, values, nulls);
1029 for (i = 0; i < ncolumns; ++i)
1031 values[i] = (Datum) 0;
1036 for (i = 0; i < ncolumns; ++i)
1038 ColumnIOData *column_info = &my_extra->columns[i];
1039 Oid column_type = tupdesc->attrs[i]->atttypid;
1040 HStoreValue *v = NULL;
1042 /* Ignore dropped columns in datatype */
1043 if (tupdesc->attrs[i]->attisdropped)
1049 if (!HS_ISEMPTY(hs))
1051 char *key = NameStr(tupdesc->attrs[i]->attname);
1053 v = findUncompressedHStoreValue(VARDATA(hs), HS_FLAG_HSTORE, NULL, key, strlen(key));
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.
1064 if (v == NULL && rec)
1068 * Prepare to convert the column value from text
1070 if (column_info->column_type != column_type)
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;
1080 if (v == NULL || v->type == hsvNull)
1083 * need InputFunctionCall to happen even for nulls, so that domain
1086 values[i] = InputFunctionCall(&column_info->proc, NULL,
1087 column_info->typioparam,
1088 tupdesc->attrs[i]->atttypmod);
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));
1112 elog(PANIC, "Wrong hstore");
1114 values[i] = InputFunctionCall(&column_info->proc, s,
1115 column_info->typioparam,
1116 tupdesc->attrs[i]->atttypmod);
1121 rettuple = heap_form_tuple(tupdesc, values, nulls);
1123 ReleaseTupleDesc(tupdesc);
1125 PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
1129 stringIsNumber(char *string, int len, bool jsonNumber) {
1141 if (*string == '-' || *string == '+')
1149 sinState = SIN_FIRSTINT;
1151 while(r && c - string < len)
1156 if (*c == '0' && jsonNumber)
1157 sinState = SIN_ZEROINT;
1159 sinState = SIN_SCALE;
1160 else if (isdigit(*c))
1167 sinState = SIN_SCALE;
1173 sinState = SIN_SCALE;
1174 else if (*c == 'e' || *c == 'E')
1175 sinState = SIN_MSIGN;
1176 else if (!isdigit(*c))
1180 if (*c == 'e' || *c == 'E')
1181 sinState = SIN_MSIGN;
1182 else if (!isdigit(*c))
1186 if (*c == '-' || *c == '+' || isdigit(*c))
1187 sinState = SIN_MANTISSA;
1202 if (sinState == SIN_MSIGN)
1209 printIndent(StringInfo out, bool isRootHash, HStoreOutputKind kind, int level)
1211 if (kind & PrettyPrint)
1215 if (isRootHash && (kind & RootHashDecorated) == 0)
1217 for(i=0; i<4*level; i++)
1218 appendStringInfoCharMacro(out, ' ');
1223 printCR(StringInfo out, HStoreOutputKind kind)
1225 if (kind & PrettyPrint)
1226 appendStringInfoCharMacro(out, '\n');
1230 escape_hstore(StringInfo out, char *string, uint32 len)
1234 appendStringInfoCharMacro(out, '"');
1235 while (ptr - string < len)
1237 if (*ptr == '"' || *ptr == '\\')
1238 appendStringInfoCharMacro(out, '\\');
1239 appendStringInfoCharMacro(out, *ptr);
1242 appendStringInfoCharMacro(out, '"');
1246 putEscapedString(StringInfo out, HStoreOutputKind kind,
1247 char *string, uint32 len)
1249 if (kind & LooseOutput)
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));
1260 escape_hstore(out, string, len);
1264 if (kind & JsonOutput)
1265 escape_json(out, pnstrdup(string, len));
1267 escape_hstore(out, string, len);
1272 putEscapedValue(StringInfo out, HStoreOutputKind kind, HStoreValue *v)
1277 appendBinaryStringInfo(out,
1278 (kind & JsonOutput) ? "null" : "NULL", 4);
1281 putEscapedString(out, kind, v->string.val, v->string.len);
1284 if ((kind & JsonOutput) == 0)
1285 appendBinaryStringInfo(out, (v->boolean) ? "t" : "f", 1);
1286 else if (v->boolean)
1287 appendBinaryStringInfo(out, "true", 4);
1289 appendBinaryStringInfo(out, "false", 5);
1292 appendStringInfoString(out, DatumGetCString(DirectFunctionCall1(numeric_out, PointerGetDatum(v->numeric))));
1295 elog(PANIC, "Unknown type");
1300 needBrackets(int level, bool isArray, HStoreOutputKind kind, bool isScalar)
1304 if (isArray && isScalar)
1306 else if (level == 0)
1307 res = (isArray || (kind & RootHashDecorated)) ? true : false;
1315 isArrayBrackets(HStoreOutputKind kind)
1317 return ((kind & ArrayCurlyBraces) == 0) ? true : false;
1322 hstoreToCString(StringInfo out, char *in, int len /* just estimation */,
1323 HStoreOutputKind kind)
1330 bool isRootHash = false;
1333 out = makeStringInfo();
1337 appendStringInfoString(out, "");
1341 enlargeStringInfo(out, (len >= 0) ? len : 64);
1343 it = HStoreIteratorInit(in);
1345 while((type = HStoreIteratorGet(&it, &v, false)) != 0)
1350 case WHS_BEGIN_ARRAY:
1353 appendBinaryStringInfo(out, ", ", 2);
1358 if (needBrackets(level, true, kind, v.array.scalar))
1360 printIndent(out, isRootHash, kind, level);
1361 appendStringInfoChar(out, isArrayBrackets(kind) ? '[' : '{');
1366 case WHS_BEGIN_HASH:
1369 appendBinaryStringInfo(out, ", ", 2);
1377 if (needBrackets(level, false, kind, false))
1379 printIndent(out, isRootHash, kind, level);
1380 appendStringInfoCharMacro(out, '{');
1389 appendBinaryStringInfo(out, ", ", 2);
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);
1400 type = HStoreIteratorGet(&it, &v, false);
1401 if (type == WHS_VALUE)
1404 putEscapedValue(out, kind, &v);
1408 Assert(type == WHS_BEGIN_HASH || type == WHS_BEGIN_ARRAY);
1411 * We need to rerun current switch() due to put
1412 * in current place object which we just got
1421 appendBinaryStringInfo(out, ", ", 2);
1429 printIndent(out, isRootHash, kind, level);
1430 putEscapedValue(out, kind, &v);
1434 if (needBrackets(level, true, kind, v.array.scalar))
1437 printIndent(out, isRootHash, kind, level);
1438 appendStringInfoChar(out, isArrayBrackets(kind) ? ']' : '}');
1444 if (needBrackets(level, false, kind, false))
1447 printIndent(out, isRootHash, kind, level);
1448 appendStringInfoCharMacro(out, '}');
1453 elog(PANIC, "Wrong flags");
1463 HStoreValueToText(HStoreValue *v)
1467 if (v == NULL || v->type == hsvNull)
1471 else if (v->type == hsvString)
1473 out = cstring_to_text_with_len(v->string.val, v->string.len);
1475 else if (v->type == hsvBool)
1477 out = cstring_to_text_with_len((v->boolean) ? "t" : "f", 1);
1479 else if (v->type == hsvNumeric)
1481 out = cstring_to_text(DatumGetCString(
1482 DirectFunctionCall1(numeric_out, PointerGetDatum(v->numeric))
1489 str = makeStringInfo();
1490 appendBinaryStringInfo(str, " ", 4); /* VARHDRSZ */
1492 hstoreToCString(str, v->binary.data, v->binary.len,
1493 SET_PRETTY_PRINT_VAR(0));
1495 out = (text*)str->data;
1496 SET_VARSIZE(out, str->len);
1502 PG_FUNCTION_INFO_V1(hstore_out);
1503 Datum hstore_out(PG_FUNCTION_ARGS);
1505 hstore_out(PG_FUNCTION_ARGS)
1507 HStore *hs = PG_GETARG_HS(0);
1510 out = hstoreToCString(NULL, (HS_ISEMPTY(hs)) ? NULL : VARDATA(hs),
1511 VARSIZE(hs), SET_PRETTY_PRINT_VAR(0));
1513 PG_RETURN_CSTRING(out);
1516 PG_FUNCTION_INFO_V1(hstore_send);
1517 Datum hstore_send(PG_FUNCTION_ARGS);
1519 hstore_send(PG_FUNCTION_ARGS)
1521 HStore *in = PG_GETARG_HS(0);
1524 pq_begintypsend(&buf);
1528 pq_sendint(&buf, 0, 4);
1538 enlargeStringInfo(&buf, VARSIZE_ANY(in) /* just estimation */);
1540 it = HStoreIteratorInit(VARDATA_ANY(in));
1542 while((type = HStoreIteratorGet(&it, &v, false)) != 0)
1546 case WHS_BEGIN_ARRAY:
1547 flag = (v.array.scalar) ? HENTRY_ISSCALAR : HENTRY_ISARRAY;
1548 pq_sendint(&buf, v.array.nelems | flag, 4);
1550 case WHS_BEGIN_HASH:
1551 pq_sendint(&buf, v.hash.npairs | HENTRY_ISHASH, 4);
1554 pq_sendint(&buf, v.string.len | HENTRY_ISSTRING, 4);
1555 pq_sendtext(&buf, v.string.val, v.string.len);
1562 pq_sendint(&buf, HENTRY_ISNULL, 4);
1565 pq_sendint(&buf, v.string.len | HENTRY_ISSTRING, 4);
1566 pq_sendtext(&buf, v.string.val, v.string.len);
1569 pq_sendint(&buf, (v.boolean) ? HENTRY_ISTRUE : HENTRY_ISFALSE, 4);
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));
1577 elog(PANIC, "Wrong type: %u", v.type);
1584 elog(PANIC, "Wrong flags");
1589 PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
1594 * hstore_to_json_loose
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).
1601 PG_FUNCTION_INFO_V1(hstore_to_json_loose);
1602 Datum hstore_to_json_loose(PG_FUNCTION_ARGS);
1604 hstore_to_json_loose(PG_FUNCTION_ARGS)
1606 HStore *in = PG_GETARG_HS(0);
1611 out = cstring_to_text_with_len("{}",2);
1617 str = makeStringInfo();
1618 appendBinaryStringInfo(str, " ", 4); /* VARHDRSZ */
1620 hstoreToCString(str, VARDATA_ANY(in), VARSIZE_ANY(in),
1621 SET_PRETTY_PRINT_VAR(JsonOutput | RootHashDecorated | LooseOutput));
1623 out = (text*)str->data;
1625 SET_VARSIZE(out, str->len);
1628 PG_RETURN_TEXT_P(out);
1631 PG_FUNCTION_INFO_V1(hstore_to_json);
1632 Datum hstore_to_json(PG_FUNCTION_ARGS);
1634 hstore_to_json(PG_FUNCTION_ARGS)
1636 HStore *in = PG_GETARG_HS(0);
1641 out = cstring_to_text_with_len("{}",2);
1647 str = makeStringInfo();
1648 appendBinaryStringInfo(str, " ", 4); /* VARHDRSZ */
1650 hstoreToCString(str,
1651 HS_ISEMPTY(in) ? NULL : VARDATA_ANY(in),
1653 SET_PRETTY_PRINT_VAR(JsonOutput | RootHashDecorated));
1655 out = (text*)str->data;
1657 SET_VARSIZE(out, str->len);
1660 PG_RETURN_TEXT_P(out);
1663 PG_FUNCTION_INFO_V1(json_to_hstore);
1664 Datum json_to_hstore(PG_FUNCTION_ARGS);
1666 json_to_hstore(PG_FUNCTION_ARGS)
1668 text *json = PG_GETARG_TEXT_PP(0);
1670 PG_RETURN_POINTER(hstoreDump(parseHStore(VARDATA_ANY(json),
1671 VARSIZE_ANY_EXHDR(json), true)));
1675 searchCast(Oid src, Oid dst, CoercionMethod *method)
1677 Oid funcOid = InvalidOid,
1683 *method = COERCION_METHOD_BINARY;
1687 tuple = SearchSysCache2(CASTSOURCETARGET,
1688 ObjectIdGetDatum(src),
1689 ObjectIdGetDatum(dst));
1693 if (HeapTupleIsValid(tuple))
1695 Form_pg_cast castForm = (Form_pg_cast) GETSTRUCT(tuple);
1697 if (castForm->castmethod == COERCION_METHOD_FUNCTION)
1698 funcOid = castForm->castfunc;
1700 *method = castForm->castmethod;
1702 ReleaseSysCache(tuple);
1704 else if ((baseSrc = getBaseType(src)) != src && OidIsValid(baseSrc))
1707 funcOid = searchCast(baseSrc, dst, method);
1713 PG_FUNCTION_INFO_V1(array_to_hstore);
1714 Datum array_to_hstore(PG_FUNCTION_ARGS);
1716 array_to_hstore(PG_FUNCTION_ARGS)
1718 ArrayType *array = PG_GETARG_ARRAYTYPE_P(0);
1719 ArrayIterator iterator;
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;
1731 CoercionMethod method;
1733 if (ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array)) == 0)
1734 PG_RETURN_POINTER(hstoreDump(NULL));
1736 switch(ARR_ELEMTYPE(array))
1739 valueType = hsvBool;
1742 valueType = hsvNumeric;
1745 valueType = hsvString;
1748 if (TypeCategory(ARR_ELEMTYPE(array)) == TYPCATEGORY_NUMERIC)
1750 castOid = searchCast(ARR_ELEMTYPE(array), NUMERICOID, &method);
1752 if (castOid == InvalidOid && method != COERCION_METHOD_BINARY)
1753 elog(ERROR, "Could not cast array's element type to numeric");
1755 valueType = hsvNumeric;
1760 castOid = searchCast(ARR_ELEMTYPE(array), TEXTOID, &method);
1762 if (castOid == InvalidOid && method != COERCION_METHOD_BINARY)
1763 elog(ERROR, "Could not cast array's element type to text");
1765 valueType = hsvString;
1770 if (castOid != InvalidOid)
1771 fmgr_info(castOid, &castInfo);
1773 iterator = array_create_iterator(array, 0);
1775 value.type = hsvArray;
1776 value.array.scalar = false;
1777 for(i=0; i<ncounters; i++)
1779 value.array.nelems = dims[i];
1780 result = pushHStoreValue(&state, WHS_BEGIN_ARRAY, &value);
1783 while(array_iterate(iterator, &datum, &isnull))
1787 if (counters[i] >= dims[i])
1789 while(i>=0 && counters[i] >= dims[i])
1792 result = pushHStoreValue(&state, WHS_END_ARRAY, NULL);
1800 value.type = hsvArray;
1801 value.array.scalar = false;
1802 for(i = i + 1; i<ncounters; i++)
1805 value.array.nelems = dims[i];
1806 result = pushHStoreValue(&state, WHS_BEGIN_ARRAY, &value);
1816 value.type = hsvNull;
1817 value.size = sizeof(HEntry);
1821 value.type = valueType;
1825 value.boolean = DatumGetBool(datum);
1826 value.size = sizeof(HEntry);
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;
1836 if (castOid != InvalidOid)
1837 datum = FunctionCall1(&castInfo, datum);
1838 value.numeric = DatumGetNumeric(datum);
1839 value.size = sizeof(HEntry)*2 + VARSIZE_ANY(value.numeric);
1842 elog(ERROR, "Impossible state: %d", valueType);
1846 result = pushHStoreValue(&state, WHS_ELEM, &value);
1849 for(i=0; i<ncounters; i++)
1850 result = pushHStoreValue(&state, WHS_END_ARRAY, NULL);
1852 PG_RETURN_POINTER(hstoreDump(result));
1855 PG_FUNCTION_INFO_V1(hstore_print);
1856 Datum hstore_print(PG_FUNCTION_ARGS);
1858 hstore_print(PG_FUNCTION_ARGS)
1860 HStore *hs = PG_GETARG_HS(0);
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;
1876 str = makeStringInfo();
1877 appendBinaryStringInfo(str, " ", 4); /* VARHDRSZ */
1879 hstoreToCString(str, (HS_ISEMPTY(hs)) ? NULL : VARDATA(hs),
1880 VARSIZE(hs), flags);
1882 out = (text*)str->data;
1883 SET_VARSIZE(out, str->len);
1885 PG_RETURN_TEXT_P(out);
1888 void _PG_init(void);
1892 DefineCustomBoolVariable(
1893 "hstore.pretty_print",
1894 "Enable pretty print",
1895 "Enable pretty print of hstore type",
1905 EmitWarningsOnPlaceholders("hstore");