Datum hstore_from_text(PG_FUNCTION_ARGS) { text *key; text *val = NULL; Pairs p; HStore *out; if (PG_ARGISNULL(0)) PG_RETURN_NULL(); p.needfree = false; key = PG_GETARG_TEXT_PP(0); p.key = VARDATA_ANY(key); p.keylen = hstoreCheckKeyLen(VARSIZE_ANY_EXHDR(key)); if (PG_ARGISNULL(1)) { p.vallen = 0; p.isnull = true; } else { val = PG_GETARG_TEXT_PP(1); p.val = VARDATA_ANY(val); p.vallen = hstoreCheckValLen(VARSIZE_ANY_EXHDR(val)); p.isnull = false; } out = hstorePairs(&p, 1, p.keylen + p.vallen); PG_RETURN_POINTER(out); }
Datum hstore_recv(PG_FUNCTION_ARGS) { int32 buflen; HStore *out; Pairs *pairs; int32 i; int32 pcount; StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); pcount = pq_getmsgint(buf, 4); if (pcount == 0) { out = hstorePairs(NULL, 0, 0); PG_RETURN_POINTER(out); } if (pcount < 0 || pcount > MaxAllocSize / sizeof(Pairs)) ereport(ERROR, (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("number of pairs (%d) exceeds the maximum allowed (%d)", pcount, (int) (MaxAllocSize / sizeof(Pairs))))); pairs = palloc(pcount * sizeof(Pairs)); for (i = 0; i < pcount; ++i) { int rawlen = pq_getmsgint(buf, 4); int len; if (rawlen < 0) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("null value not allowed for hstore key"))); pairs[i].key = pq_getmsgtext(buf, rawlen, &len); pairs[i].keylen = hstoreCheckKeyLen(len); pairs[i].needfree = true; rawlen = pq_getmsgint(buf, 4); if (rawlen < 0) { pairs[i].val = NULL; pairs[i].vallen = 0; pairs[i].isnull = true; } else { pairs[i].val = pq_getmsgtext(buf, rawlen, &len); pairs[i].vallen = hstoreCheckValLen(len); pairs[i].isnull = false; } } pcount = hstoreUniquePairs(pairs, pcount, &buflen); out = hstorePairs(pairs, pcount, buflen); PG_RETURN_POINTER(out); }
Datum tconvert(PG_FUNCTION_ARGS) { text *key; text *val = NULL; int len; HStore *out; if (PG_ARGISNULL(0)) PG_RETURN_NULL(); key = PG_GETARG_TEXT_P(0); if (PG_ARGISNULL(1)) len = CALCDATASIZE(1, VARSIZE(key)); else { val = PG_GETARG_TEXT_P(1); len = CALCDATASIZE(1, VARSIZE(key) + VARSIZE(val) - 2 * VARHDRSZ); } out = palloc(len); SET_VARSIZE(out, len); out->size = 1; ARRPTR(out)->keylen = hstoreCheckKeyLen(VARSIZE(key) - VARHDRSZ); if (PG_ARGISNULL(1)) { ARRPTR(out)->vallen = 0; ARRPTR(out)->valisnull = true; } else { ARRPTR(out)->vallen = hstoreCheckValLen(VARSIZE(val) - VARHDRSZ); ARRPTR(out)->valisnull = false; } ARRPTR(out)->pos = 0; memcpy(STRPTR(out), VARDATA(key), ARRPTR(out)->keylen); if (!PG_ARGISNULL(1)) { memcpy(STRPTR(out) + ARRPTR(out)->keylen, VARDATA(val), ARRPTR(out)->vallen); PG_FREE_IF_COPY(val, 1); } PG_FREE_IF_COPY(key, 0); PG_RETURN_POINTER(out); }
Datum plperl_to_hstore(PG_FUNCTION_ARGS) { HV *hv; HE *he; int32 buflen; int32 i; int32 pcount; HStore *out; Pairs *pairs; hv = (HV *) SvRV((SV *) PG_GETARG_POINTER(0)); pcount = hv_iterinit(hv); pairs = palloc(pcount * sizeof(Pairs)); i = 0; while ((he = hv_iternext(hv))) { char *key = sv2cstr(HeSVKEY_force(he)); SV *value = HeVAL(he); pairs[i].key = pstrdup(key); pairs[i].keylen = hstoreCheckKeyLen(strlen(pairs[i].key)); pairs[i].needfree = true; if (!SvOK(value)) { pairs[i].val = NULL; pairs[i].vallen = 0; pairs[i].isnull = true; } else { pairs[i].val = pstrdup(sv2cstr(value)); pairs[i].vallen = hstoreCheckValLen(strlen(pairs[i].val)); pairs[i].isnull = false; } i++; } pcount = hstoreUniquePairs(pairs, pcount, &buflen); out = hstorePairs(pairs, pcount, buflen); PG_RETURN_POINTER(out); }
Datum hstore_from_record(PG_FUNCTION_ARGS) { HeapTupleHeader rec; int4 buflen; HStore *out; Pairs *pairs; Oid tupType; int32 tupTypmod; TupleDesc tupdesc; HeapTupleData tuple; RecordIOData *my_extra; int ncolumns; int i, j; Datum *values; bool *nulls; if (PG_ARGISNULL(0)) { Oid argtype = get_fn_expr_argtype(fcinfo->flinfo, 0); /* * have no tuple to look at, so the only source of type info is the * argtype. The lookup_rowtype_tupdesc call below will error out if we * don't have a known composite type oid here. */ tupType = argtype; tupTypmod = -1; rec = NULL; } else { rec = PG_GETARG_HEAPTUPLEHEADER(0); /* Extract type info from the tuple itself */ tupType = HeapTupleHeaderGetTypeId(rec); tupTypmod = HeapTupleHeaderGetTypMod(rec); } tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod); ncolumns = tupdesc->natts; /* * We arrange to look up the needed I/O info just once per series of * calls, assuming the record type doesn't change underneath us. */ my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra; if (my_extra == NULL || my_extra->ncolumns != ncolumns) { fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt, sizeof(RecordIOData) - sizeof(ColumnIOData) + ncolumns * sizeof(ColumnIOData)); my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra; my_extra->record_type = InvalidOid; my_extra->record_typmod = 0; } if (my_extra->record_type != tupType || my_extra->record_typmod != tupTypmod) { MemSet(my_extra, 0, sizeof(RecordIOData) - sizeof(ColumnIOData) + ncolumns * sizeof(ColumnIOData)); my_extra->record_type = tupType; my_extra->record_typmod = tupTypmod; my_extra->ncolumns = ncolumns; } pairs = palloc(ncolumns * sizeof(Pairs)); if (rec) { /* Build a temporary HeapTuple control structure */ tuple.t_len = HeapTupleHeaderGetDatumLength(rec); ItemPointerSetInvalid(&(tuple.t_self)); //tuple.t_tableOid = InvalidOid; tuple.t_data = rec; values = (Datum *) palloc(ncolumns * sizeof(Datum)); nulls = (bool *) palloc(ncolumns * sizeof(bool)); /* Break down the tuple into fields */ heap_deform_tuple(&tuple, tupdesc, values, nulls); } else { values = NULL; nulls = NULL; } for (i = 0, j = 0; i < ncolumns; ++i) { ColumnIOData *column_info = &my_extra->columns[i]; Oid column_type = tupdesc->attrs[i]->atttypid; char *value; /* Ignore dropped columns in datatype */ if (tupdesc->attrs[i]->attisdropped) continue; pairs[j].key = NameStr(tupdesc->attrs[i]->attname); pairs[j].keylen = hstoreCheckKeyLen(strlen(NameStr(tupdesc->attrs[i]->attname))); if (!nulls || nulls[i]) { pairs[j].val = NULL; pairs[j].vallen = 4; pairs[j].isnull = true; pairs[j].needfree = false; ++j; continue; } /* * Convert the column value to text */ if (column_info->column_type != column_type) { bool typIsVarlena; getTypeOutputInfo(column_type, &column_info->typiofunc, &typIsVarlena); fmgr_info_cxt(column_info->typiofunc, &column_info->proc, fcinfo->flinfo->fn_mcxt); column_info->column_type = column_type; } value = OutputFunctionCall(&column_info->proc, values[i]); pairs[j].val = value; pairs[j].vallen = hstoreCheckValLen(strlen(value)); pairs[j].isnull = false; pairs[j].needfree = false; ++j; } ncolumns = hstoreUniquePairs(pairs, j, &buflen); out = hstorePairs(pairs, ncolumns, buflen); ReleaseTupleDesc(tupdesc); PG_RETURN_POINTER(out); }
Datum hstore_from_array(PG_FUNCTION_ARGS) { ArrayType *in_array = PG_GETARG_ARRAYTYPE_P(0); int ndims = ARR_NDIM(in_array); int count; int4 buflen; HStore *out; Pairs *pairs; Datum *in_datums; bool *in_nulls; int in_count; int i; Assert(ARR_ELEMTYPE(in_array) == TEXTOID); switch (ndims) { case 0: out = hstorePairs(NULL, 0, 0); PG_RETURN_POINTER(out); case 1: if ((ARR_DIMS(in_array)[0]) % 2) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("array must have even number of elements"))); break; case 2: if ((ARR_DIMS(in_array)[1]) != 2) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("array must have two columns"))); break; default: ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("wrong number of array subscripts"))); } deconstruct_array(in_array, TEXTOID, -1, false, 'i', &in_datums, &in_nulls, &in_count); count = in_count / 2; pairs = palloc(count * sizeof(Pairs)); for (i = 0; i < count; ++i) { if (in_nulls[i * 2]) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("null value not allowed for hstore key"))); if (in_nulls[i * 2 + 1]) { pairs[i].key = VARDATA_ANY(in_datums[i * 2]); pairs[i].val = NULL; pairs[i].keylen = hstoreCheckKeyLen(VARSIZE_ANY_EXHDR(in_datums[i * 2])); pairs[i].vallen = 4; pairs[i].isnull = true; pairs[i].needfree = false; } else { pairs[i].key = VARDATA_ANY(in_datums[i * 2]); pairs[i].val = VARDATA_ANY(in_datums[i * 2 + 1]); pairs[i].keylen = hstoreCheckKeyLen(VARSIZE_ANY_EXHDR(in_datums[i * 2])); pairs[i].vallen = hstoreCheckValLen(VARSIZE_ANY_EXHDR(in_datums[i * 2 + 1])); pairs[i].isnull = false; pairs[i].needfree = false; } } count = hstoreUniquePairs(pairs, count, &buflen); out = hstorePairs(pairs, count, buflen); PG_RETURN_POINTER(out); }
Datum hstore_from_arrays(PG_FUNCTION_ARGS) { int4 buflen; HStore *out; Pairs *pairs; Datum *key_datums; bool *key_nulls; int key_count; Datum *value_datums; bool *value_nulls; int value_count; ArrayType *key_array; ArrayType *value_array; int i; if (PG_ARGISNULL(0)) PG_RETURN_NULL(); key_array = PG_GETARG_ARRAYTYPE_P(0); Assert(ARR_ELEMTYPE(key_array) == TEXTOID); /* * must check >1 rather than != 1 because empty arrays have 0 dimensions, * not 1 */ if (ARR_NDIM(key_array) > 1) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("wrong number of array subscripts"))); deconstruct_array(key_array, TEXTOID, -1, false, 'i', &key_datums, &key_nulls, &key_count); /* value_array might be NULL */ if (PG_ARGISNULL(1)) { value_array = NULL; value_count = key_count; value_datums = NULL; value_nulls = NULL; } else { value_array = PG_GETARG_ARRAYTYPE_P(1); Assert(ARR_ELEMTYPE(value_array) == TEXTOID); if (ARR_NDIM(value_array) > 1) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("wrong number of array subscripts"))); if ((ARR_NDIM(key_array) > 0 || ARR_NDIM(value_array) > 0) && (ARR_NDIM(key_array) != ARR_NDIM(value_array) || ARR_DIMS(key_array)[0] != ARR_DIMS(value_array)[0] || ARR_LBOUND(key_array)[0] != ARR_LBOUND(value_array)[0])) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("arrays must have same bounds"))); deconstruct_array(value_array, TEXTOID, -1, false, 'i', &value_datums, &value_nulls, &value_count); Assert(key_count == value_count); } pairs = palloc(key_count * sizeof(Pairs)); for (i = 0; i < key_count; ++i) { if (key_nulls[i]) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("null value not allowed for hstore key"))); if (!value_nulls || value_nulls[i]) { pairs[i].key = VARDATA_ANY(key_datums[i]); pairs[i].val = NULL; pairs[i].keylen = hstoreCheckKeyLen(VARSIZE_ANY_EXHDR(key_datums[i])); pairs[i].vallen = 4; pairs[i].isnull = true; pairs[i].needfree = false; } else { pairs[i].key = VARDATA_ANY(key_datums[i]); pairs[i].val = VARDATA_ANY(value_datums[i]); pairs[i].keylen = hstoreCheckKeyLen(VARSIZE_ANY_EXHDR(key_datums[i])); pairs[i].vallen = hstoreCheckValLen(VARSIZE_ANY_EXHDR(value_datums[i])); pairs[i].isnull = false; pairs[i].needfree = false; } } key_count = hstoreUniquePairs(pairs, key_count, &buflen); out = hstorePairs(pairs, key_count, buflen); PG_RETURN_POINTER(out); }
static void parse_hstore(HSParser *state) { int st = WKEY; bool escaped = false; state->plen = 16; state->pairs = (Pairs *) palloc(sizeof(Pairs) * state->plen); state->pcur = 0; state->ptr = state->begin; state->word = NULL; while (1) { if (st == WKEY) { if (!get_val(state, false, &escaped)) return; if (state->pcur >= state->plen) { state->plen *= 2; state->pairs = (Pairs *) repalloc(state->pairs, sizeof(Pairs) * state->plen); } state->pairs[state->pcur].key = state->word; state->pairs[state->pcur].keylen = hstoreCheckKeyLen(state->cur - state->word); state->pairs[state->pcur].val = NULL; state->word = NULL; st = WEQ; } else if (st == WEQ) { if (*(state->ptr) == '=') { st = WGT; } else if (*(state->ptr) == '\0') { elog(ERROR, "Unexpected end of string"); } else if (!isspace((unsigned char) *(state->ptr))) { elog(ERROR, "Syntax error near '%c' at position %d", *(state->ptr), (int4) (state->ptr - state->begin)); } } else if (st == WGT) { if (*(state->ptr) == '>') { st = WVAL; } else if (*(state->ptr) == '\0') { elog(ERROR, "Unexpected end of string"); } else { elog(ERROR, "Syntax error near '%c' at position %d", *(state->ptr), (int4) (state->ptr - state->begin)); } } else if (st == WVAL) { if (!get_val(state, true, &escaped)) elog(ERROR, "Unexpected end of string"); state->pairs[state->pcur].val = state->word; state->pairs[state->pcur].vallen = hstoreCheckValLen(state->cur - state->word); state->pairs[state->pcur].isnull = false; state->pairs[state->pcur].needfree = true; if (state->cur - state->word == 4 && !escaped) { state->word[4] = '\0'; if (0 == pg_strcasecmp(state->word, "null")) state->pairs[state->pcur].isnull = true; } state->word = NULL; state->pcur++; st = WDEL; } else if (st == WDEL) { if (*(state->ptr) == ',') { st = WKEY; } else if (*(state->ptr) == '\0') { return; } else if (!isspace((unsigned char) *(state->ptr))) { elog(ERROR, "Syntax error near '%c' at position %d", *(state->ptr), (int4) (state->ptr - state->begin)); } } else elog(ERROR, "Unknown state %d at line %d in file '%s'", st, __LINE__, __FILE__); state->ptr++; } }
Datum plpython_to_hstore(PG_FUNCTION_ARGS) { PyObject *dict; volatile PyObject *items_v = NULL; int32 pcount; HStore *out; dict = (PyObject *) PG_GETARG_POINTER(0); if (!PyMapping_Check(dict)) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("not a Python mapping"))); pcount = PyMapping_Size(dict); items_v = PyMapping_Items(dict); PG_TRY(); { int32 buflen; int32 i; Pairs *pairs; PyObject *items = (PyObject *) items_v; pairs = palloc(pcount * sizeof(*pairs)); for (i = 0; i < pcount; i++) { PyObject *tuple; PyObject *key; PyObject *value; tuple = PyList_GetItem(items, i); key = PyTuple_GetItem(tuple, 0); value = PyTuple_GetItem(tuple, 1); pairs[i].key = PLyObject_AsString(key); pairs[i].keylen = hstoreCheckKeyLen(strlen(pairs[i].key)); pairs[i].needfree = true; if (value == Py_None) { pairs[i].val = NULL; pairs[i].vallen = 0; pairs[i].isnull = true; } else { pairs[i].val = PLyObject_AsString(value); pairs[i].vallen = hstoreCheckValLen(strlen(pairs[i].val)); pairs[i].isnull = false; } } Py_DECREF(items_v); pcount = hstoreUniquePairs(pairs, pcount, &buflen); out = hstorePairs(pairs, pcount, buflen); } PG_CATCH(); { Py_DECREF(items_v); PG_RE_THROW(); } PG_END_TRY(); PG_RETURN_POINTER(out); }