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 hstore_slice_to_hstore(PG_FUNCTION_ARGS) { HStore *hs = PG_GETARG_HS(0); HEntry *entries = ARRPTR(hs); char *ptr = STRPTR(hs); ArrayType *key_array = PG_GETARG_ARRAYTYPE_P(1); HStore *out; int nkeys; Pairs *key_pairs = hstoreArrayToPairs(key_array, &nkeys); Pairs *out_pairs; int bufsiz; int lastidx = 0; int i; int out_count = 0; if (nkeys == 0) { out = hstorePairs(NULL, 0, 0); PG_RETURN_POINTER(out); } out_pairs = palloc(sizeof(Pairs) * nkeys); bufsiz = 0; /* * we exploit the fact that the pairs list is already sorted into strictly * increasing order to narrow the hstoreFindKey search; each search can * start one entry past the previous "found" entry, or at the lower bound * of the last search. */ for (i = 0; i < nkeys; ++i) { int idx = hstoreFindKey(hs, &lastidx, key_pairs[i].key, key_pairs[i].keylen); if (idx >= 0) { out_pairs[out_count].key = key_pairs[i].key; bufsiz += (out_pairs[out_count].keylen = key_pairs[i].keylen); out_pairs[out_count].val = HS_VAL(entries, ptr, idx); bufsiz += (out_pairs[out_count].vallen = HS_VALLEN(entries, idx)); out_pairs[out_count].isnull = HS_VALISNULL(entries, idx); out_pairs[out_count].needfree = false; ++out_count; } } /* * we don't use uniquePairs here because we know that the pairs list is * already sorted and uniq'ed. */ out = hstorePairs(out_pairs, out_count, bufsiz); PG_RETURN_POINTER(out); }
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 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_in(PG_FUNCTION_ARGS) { HSParser state; int4 buflen; HStore *out; state.begin = PG_GETARG_CSTRING(0); parse_hstore(&state); state.pcur = hstoreUniquePairs(state.pairs, state.pcur, &buflen); out = hstorePairs(state.pairs, state.pcur, 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); }
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); }
static void apply_changes(lua_State *L, Lua_Hstore *strg){ HStore *hsout; int32 buflen; HStore *in; int i; int count; int pcount; char *base; HEntry *entries; Pairs *pairs; if (strg->issync == 1) return; in = strg->hstore; count = HS_COUNT(in); base = STRPTR(in); entries = ARRPTR(in); lua_pushlightuserdata(L, strg); lua_gettable(L, LUA_REGISTRYINDEX); for (i=0; i < count; i++) { char *key = HS_KEY(entries, base, i); int klen = HS_KEYLEN(entries, i); lua_pushlstring(L, key, klen); lua_rawget(L, -2); if (lua_isnil(L,-1)){ lua_pop(L, 1); lua_pushlstring(L, key, klen); lua_pushinteger(L, i); lua_rawset(L, -3); }else { lua_pop(L, 1); } } pcount = 0; lua_pushnil(L); /* first key */ while (lua_next(L, -2) != 0) { ++pcount; /* removes 'value'; keeps 'key' for next iteration */ lua_pop(L, 1); } MTOLUA(L); pairs = palloc(pcount * sizeof(*pairs)); MTOPG; i = 0; //------------------------------- lua_pushnil(L); while (lua_next(L, -2) != 0) { const char *key = lua_tostring(L, -2); int ltype = lua_type(L, -1); if (ltype == LUA_TNUMBER){ int idx = lua_tointeger(L, -1); set_pair(L, &pairs[i], entries, base, idx); } else { char *mov_value = (char *)lua_touserdata (L, -1); set_pair_from_lv(L, &pairs[i], key, mov_value); } lua_pop(L, 1); ++i; } //------------------------------- lua_pop(L, 1); MTOLUA(L); pcount = hstoreUniquePairs(pairs, pcount, &buflen); hsout = hstorePairs(pairs, pcount, buflen); MTOPG; if (strg->havetodel){ pg_datumFree(strg->datum, hs_type.byval, hs_type.len); } strg->hstore = hsout; strg->datum = PointerGetDatum(hsout); strg->issync = 1; strg->havetodel = 1; lua_pushlightuserdata(L, strg); lua_newtable(L); lua_settable(L, LUA_REGISTRYINDEX); }
HStore * adeven_count_int_array( Datum* i_data, int n, bool * nulls ) { int i, j, biggest = 0; int exp = 1; int * a = palloc0( sizeof( int ) * n ); int * b = palloc0( sizeof( int ) * n ); int * c = palloc0( sizeof( int ) * n ); for( i = 0 ; i < n; ++i ) { a[i] = DatumGetInt32( i_data[i] ); if( a[i] > biggest ) { biggest = a[i]; } } while( biggest / exp > 0 ) { int box[10] = { 0 }; for( i = 0; i < n; i++ ) { box[a[i] / exp % 10]++; } for( i = 1; i < 10; i++ ) { box[i] += box[i - 1]; } for( i = n - 1; i >= 0; i-- ) { b[--box[a[i] / exp % 10]] = a[i]; } for( i = 0; i < n; i++ ) { a[i] = b[i]; } exp *= 10; } int m = 0; for( i = 0; i < n; ++i ) { b[i] = 0; } for( i = 0, j = i + 1; j <= n; j++ ) { if( a[i]==a[j] ) { b[m] = a[i]; if( c[m] == 0 ) { c[m]++; } c[m]++; continue; } if( c[m] == 0 ) { c[m] = 1; } b[m++]=a[i]; i=j; } n = 0; while( c[n] != 0 ) { ++n; } Pairs * pairs = palloc0( n * sizeof( Pairs ) ); int4 buflen = 0; for( i = 0; i < n; ++i ) { int digit_key_num = adeven_count_get_digit_num( b[i] ); int digit_val_num = adeven_count_get_digit_num( c[i] ); char * dig_key_str = palloc0(digit_key_num); char * dig_val_str = palloc0(digit_val_num); sprintf( dig_key_str, "%d", b[i] ); sprintf( dig_val_str, "%d", c[i] ); pairs[i].key = dig_key_str; pairs[i].keylen = digit_key_num; pairs[i].val = dig_val_str; pairs[i].vallen = digit_val_num; pairs[i].isnull = false; pairs[i].needfree = false; buflen += pairs[i].keylen; buflen += pairs[i].vallen; } HStore * out; out = hstorePairs( pairs, n, buflen ); pfree( a ); pfree( b ); pfree( c ); return out; }
HStore * adeven_count_text_array( Datum* i_data, int n, bool * nulls ) { adeven_count_Array a; adeven_count_init_array( &a, 100 ); AvlTree tree = make_empty( NULL ); int i, j; for( i = 0; i < n; ++i ) { if( ! nulls[i] ) { bool found = false; size_t datum_len = VARSIZE( i_data[i] ) - VARHDRSZ; char * current_datum = ( char * ) palloc ( datum_len ); memcpy( current_datum, VARDATA( i_data[i] ), datum_len ); Position position = find( current_datum, datum_len, tree ); if( position == NULL ) { j = a.used; tree = insert( current_datum, datum_len, j, tree ); adeven_count_insert_array( &a, current_datum, datum_len ); } else { j = value( position ); } a.counts[j] += 1; } } // save sort permutation to create pairs in order of ascending keys // we assume that postgres stores the pairs in that order int * perm = ( int * ) palloc ( a.used * sizeof( int ) ); sort_perm( tree, perm ); make_empty( tree ); Pairs * pairs = palloc0( a.used * sizeof( Pairs ) ); int4 buflen = 0; for( i = 0; i < a.used; ++i ) { j = perm[i]; if( a.array[j] != NULL ) { size_t datum_len = a.sizes[j]; int digit_num = adeven_count_get_digit_num( a.counts[j] ); char * dig_str = palloc0(digit_num); sprintf( dig_str, "%d", a.counts[j] ); a.counts_str[j] = dig_str; pairs[i].key = a.array[j]; pairs[i].keylen = datum_len; pairs[i].val = dig_str; pairs[i].vallen = digit_num; pairs[i].isnull = false; pairs[i].needfree = false; buflen += pairs[i].keylen; buflen += pairs[i].vallen; } } HStore * out; out = hstorePairs( pairs, a.used, buflen ); //adeven_count_free_array( &a ); return out; }