示例#1
0
Datum
hstore_to_plpython(PG_FUNCTION_ARGS)
{
	HStore	   *in = PG_GETARG_HS(0);
	int			i;
	int			count = HS_COUNT(in);
	char	   *base = STRPTR(in);
	HEntry	   *entries = ARRPTR(in);
	PyObject   *dict;

	dict = PyDict_New();

	for (i = 0; i < count; i++)
	{
		PyObject   *key;

		key = PyString_FromStringAndSize(HSTORE_KEY(entries, base, i),
										 HSTORE_KEYLEN(entries, i));
		if (HSTORE_VALISNULL(entries, i))
			PyDict_SetItem(dict, key, Py_None);
		else
		{
			PyObject   *value;

			value = PyString_FromStringAndSize(HSTORE_VAL(entries, base, i),
											   HSTORE_VALLEN(entries, i));
			PyDict_SetItem(dict, key, value);
			Py_XDECREF(value);
		}
		Py_XDECREF(key);
	}

	return PointerGetDatum(dict);
}
Datum
hstore_skeys(PG_FUNCTION_ARGS)
{
    FuncCallContext *funcctx;
    HStore	   *hs;
    int			i;

    if (SRF_IS_FIRSTCALL())
    {
        hs = PG_GETARG_HS(0);
        funcctx = SRF_FIRSTCALL_INIT();
        setup_firstcall(funcctx, hs, NULL);
    }

    funcctx = SRF_PERCALL_SETUP();
    hs = (HStore *) funcctx->user_fctx;
    i = funcctx->call_cntr;

    if (i < HS_COUNT(hs))
    {
        HEntry	   *entries = ARRPTR(hs);
        text	   *item;

        item = cstring_to_text_with_len(HS_KEY(entries, STRPTR(hs), i),
                                        HS_KEYLEN(entries, i));

        SRF_RETURN_NEXT(funcctx, PointerGetDatum(item));
    }

    SRF_RETURN_DONE(funcctx);
}
示例#3
0
Datum
ghstore_compress(PG_FUNCTION_ARGS)
{
	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
	GISTENTRY  *retval = entry;

	if (entry->leafkey)
	{
		GISTTYPE   *res = (GISTTYPE *) palloc0(CALCGTSIZE(0));
		HStore	   *val = DatumGetHStoreP(entry->key);
		HEntry	   *hsent = ARRPTR(val);
		char	   *ptr = STRPTR(val);
		int			count = HS_COUNT(val);
		int			i;

		SET_VARSIZE(res, CALCGTSIZE(0));

		for (i = 0; i < count; ++i)
		{
			int			h;

			h = crc32_sz((char *) HSTORE_KEY(hsent, ptr, i),
						 HSTORE_KEYLEN(hsent, i));
			HASH(GETSIGN(res), h);
			if (!HSTORE_VALISNULL(hsent, i))
			{
				h = crc32_sz((char *) HSTORE_VAL(hsent, ptr, i),
							 HSTORE_VALLEN(hsent, i));
				HASH(GETSIGN(res), h);
			}
		}

		retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
		gistentryinit(*retval, PointerGetDatum(res),
					  entry->rel, entry->page,
					  entry->offset,
					  FALSE);
	}
	else if (!ISALLTRUE(DatumGetPointer(entry->key)))
	{
		int32		i;
		GISTTYPE   *res;
		BITVECP		sign = GETSIGN(DatumGetPointer(entry->key));

		LOOPBYTE
		{
			if ((sign[i] & 0xff) != 0xff)
				PG_RETURN_POINTER(retval);
		}

		res = (GISTTYPE *) palloc(CALCGTSIZE(ALLISTRUE));
		SET_VARSIZE(res, CALCGTSIZE(ALLISTRUE));
		res->flag = ALLISTRUE;

		retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
		gistentryinit(*retval, PointerGetDatum(res),
					  entry->rel, entry->page,
					  entry->offset,
					  FALSE);
	}
示例#4
0
Datum
gin_extract_hstore(PG_FUNCTION_ARGS)
{
	HStore	   *hs = PG_GETARG_HS(0);
	int32	   *nentries = (int32 *) PG_GETARG_POINTER(1);
	Datum	   *entries = NULL;
	HEntry	   *hsent = ARRPTR(hs);
	char	   *ptr = STRPTR(hs);
	int			count = HS_COUNT(hs);
	int			i;

	*nentries = 2 * count;
	if (count)
		entries = (Datum *) palloc(sizeof(Datum) * 2 * count);

	for (i = 0; i < count; ++i)
	{
		text	   *item;

		item = makeitem(HS_KEY(hsent, ptr, i), HS_KEYLEN(hsent, i),
						KEYFLAG);
		entries[2 * i] = PointerGetDatum(item);

		if (HS_VALISNULL(hsent, i))
			item = makeitem(NULL, 0, NULLFLAG);
		else
			item = makeitem(HS_VAL(hsent, ptr, i), HS_VALLEN(hsent, i),
							VALFLAG);
		entries[2 * i + 1] = PointerGetDatum(item);
	}

	PG_RETURN_POINTER(entries);
}
示例#5
0
Datum
hstore_to_plperl(PG_FUNCTION_ARGS)
{
	HStore	   *in = PG_GETARG_HS(0);
	int			i;
	int			count = HS_COUNT(in);
	char	   *base = STRPTR(in);
	HEntry	   *entries = ARRPTR(in);
	HV		   *hv;

	hv = newHV();

	for (i = 0; i < count; i++)
	{
		const char *key;
		SV		   *value;

		key = pnstrdup(HS_KEY(entries, base, i), HS_KEYLEN(entries, i));
		value = HS_VALISNULL(entries, i) ? newSV(0) : cstr2sv(pnstrdup(HS_VAL(entries, base, i), HS_VALLEN(entries, i)));

		(void) hv_store(hv, key, strlen(key), value, 0);
	}

	return PointerGetDatum(newRV((SV *) hv));
}
示例#6
0
文件: hstore_io.c 项目: d/gpdb
Datum
hstore_send(PG_FUNCTION_ARGS)
{
	HStore	   *in = PG_GETARG_HS(0);
	int			i;
	int			count = HS_COUNT(in);
	char	   *base = STRPTR(in);
	HEntry	   *entries = ARRPTR(in);
	StringInfoData buf;

	pq_begintypsend(&buf);

	pq_sendint(&buf, count, 4);

	for (i = 0; i < count; i++)
	{
		int32		keylen = HS_KEYLEN(entries, i);

		pq_sendint(&buf, keylen, 4);
		pq_sendtext(&buf, HS_KEY(entries, base, i), keylen);
		if (HS_VALISNULL(entries, i))
		{
			pq_sendint(&buf, -1, 4);
		}
		else
		{
			int32		vallen = HS_VALLEN(entries, i);

			pq_sendint(&buf, vallen, 4);
			pq_sendtext(&buf, HS_VAL(entries, base, i), vallen);
		}
	}

	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
}
Datum
hstore_akeys(PG_FUNCTION_ARGS)
{
    HStore	   *hs = PG_GETARG_HS(0);
    Datum	   *d;
    ArrayType  *a;
    HEntry	   *entries = ARRPTR(hs);
    char	   *base = STRPTR(hs);
    int			count = HS_COUNT(hs);
    int			i;

    if (count == 0)
    {
        a = construct_empty_array(TEXTOID);
        PG_RETURN_POINTER(a);
    }

    d = (Datum *) palloc(sizeof(Datum) * count);

    for (i = 0; i < count; ++i)
    {
        text	   *item = cstring_to_text_with_len(HS_KEY(entries, base, i),
                           HS_KEYLEN(entries, i));

        d[i] = PointerGetDatum(item);
    }

    a = construct_array(d, count,
                        TEXTOID, -1, false, 'i');

    PG_RETURN_POINTER(a);
}
Datum
hstore_hash(PG_FUNCTION_ARGS)
{
    HStore	   *hs = PG_GETARG_HS(0);
    Datum		hval = hash_any((unsigned char *) VARDATA(hs),
                                VARSIZE(hs) - VARHDRSZ);

    /*
     * this is the only place in the code that cares whether the overall
     * varlena size exactly matches the true data size; this assertion should
     * be maintained by all the other code, but we make it explicit here.
     */
    Assert(VARSIZE(hs) ==
           (HS_COUNT(hs) != 0 ?
            CALCDATASIZE(HS_COUNT(hs),
                         HSE_ENDPOS(ARRPTR(hs)[2 * HS_COUNT(hs) - 1])) :
            HSHRDSIZE));

    PG_FREE_IF_COPY(hs, 0);
    PG_RETURN_DATUM(hval);
}
Datum
hstore_each(PG_FUNCTION_ARGS)
{
    FuncCallContext *funcctx;
    HStore	   *hs;
    int			i;

    if (SRF_IS_FIRSTCALL())
    {
        hs = PG_GETARG_HS(0);
        funcctx = SRF_FIRSTCALL_INIT();
        setup_firstcall(funcctx, hs, fcinfo);
    }

    funcctx = SRF_PERCALL_SETUP();
    hs = (HStore *) funcctx->user_fctx;
    i = funcctx->call_cntr;

    if (i < HS_COUNT(hs))
    {
        HEntry	   *entries = ARRPTR(hs);
        char	   *ptr = STRPTR(hs);
        Datum		res,
                    dvalues[2];
        bool		nulls[2] = {false, false};
        text	   *item;
        HeapTuple	tuple;

        item = cstring_to_text_with_len(HS_KEY(entries, ptr, i),
                                        HS_KEYLEN(entries, i));
        dvalues[0] = PointerGetDatum(item);

        if (HS_VALISNULL(entries, i))
        {
            dvalues[1] = (Datum) 0;
            nulls[1] = true;
        }
        else
        {
            item = cstring_to_text_with_len(HS_VAL(entries, ptr, i),
                                            HS_VALLEN(entries, i));
            dvalues[1] = PointerGetDatum(item);
        }

        tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls);
        res = HeapTupleGetDatum(tuple);

        SRF_RETURN_NEXT(funcctx, PointerGetDatum(res));
    }

    SRF_RETURN_DONE(funcctx);
}
示例#10
0
static ArrayType *
hstore_to_array_internal(HStore *hs, int ndims)
{
    HEntry	   *entries = ARRPTR(hs);
    char	   *base = STRPTR(hs);
    int			count = HS_COUNT(hs);
    int			out_size[2] = {0, 2};
    int			lb[2] = {1, 1};
    Datum	   *out_datums;
    bool	   *out_nulls;
    int			i;

    Assert(ndims < 3);

    if (count == 0 || ndims == 0)
        return construct_empty_array(TEXTOID);

    out_size[0] = count * 2 / ndims;
    out_datums = palloc(sizeof(Datum) * count * 2);
    out_nulls = palloc(sizeof(bool) * count * 2);

    for (i = 0; i < count; ++i)
    {
        text	   *key = cstring_to_text_with_len(HS_KEY(entries, base, i),
                          HS_KEYLEN(entries, i));

        out_datums[i * 2] = PointerGetDatum(key);
        out_nulls[i * 2] = false;

        if (HS_VALISNULL(entries, i))
        {
            out_datums[i * 2 + 1] = (Datum) 0;
            out_nulls[i * 2 + 1] = true;
        }
        else
        {
            text	   *item = cstring_to_text_with_len(HS_VAL(entries, base, i),
                               HS_VALLEN(entries, i));

            out_datums[i * 2 + 1] = PointerGetDatum(item);
            out_nulls[i * 2 + 1] = false;
        }
    }

    return construct_md_array(out_datums, out_nulls,
                              ndims, out_size, lb,
                              TEXTOID, -1, false, 'i');
}
示例#11
0
Datum
hstore_to_jsonb(PG_FUNCTION_ARGS)
{
	HStore	   *in = PG_GETARG_HS(0);
	int			i;
	int			count = HS_COUNT(in);
	char	   *base = STRPTR(in);
	HEntry	   *entries = ARRPTR(in);
	JsonbParseState *state = NULL;
	JsonbValue *res;

	res = pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);

	for (i = 0; i < count; i++)
	{
		JsonbValue key, val;

		key.estSize = sizeof(JEntry);
		key.type = jbvString;
		key.val.string.len = HS_KEYLEN(entries, i);
		key.val.string.val = pnstrdup(HS_KEY(entries, base, i), key.val.string.len);
		key.estSize += key.val.string.len;

		res = pushJsonbValue(&state, WJB_KEY, &key);

		if (HS_VALISNULL(entries, i))
		{
			val.estSize = sizeof(JEntry);
			val.type = jbvNull;
		}
		else
		{
			val.estSize = sizeof(JEntry);
			val.type = jbvString;
			val.val.string.len = HS_VALLEN(entries, i);
			val.val.string.val = pnstrdup(HS_VAL(entries, base, i), val.val.string.len);
			val.estSize += val.val.string.len;
		}
		res = pushJsonbValue(&state, WJB_VALUE, &val);
	}

	res = pushJsonbValue(&state, WJB_END_OBJECT, NULL);

	PG_RETURN_POINTER(JsonbValueToJsonb(res));
}
示例#12
0
Datum
hstore_svals(PG_FUNCTION_ARGS)
{
    FuncCallContext *funcctx;
    HStore	   *hs;
    int			i;

    if (SRF_IS_FIRSTCALL())
    {
        hs = PG_GETARG_HS(0);
        funcctx = SRF_FIRSTCALL_INIT();
        setup_firstcall(funcctx, hs, NULL);
    }

    funcctx = SRF_PERCALL_SETUP();
    hs = (HStore *) funcctx->user_fctx;
    i = funcctx->call_cntr;

    if (i < HS_COUNT(hs))
    {
        HEntry	   *entries = ARRPTR(hs);

        if (HS_VALISNULL(entries, i))
        {
            ReturnSetInfo *rsi;

            /* ugly ugly ugly. why no macro for this? */
            (funcctx)->call_cntr++;
            rsi = (ReturnSetInfo *) fcinfo->resultinfo;
            rsi->isDone = ExprMultipleResult;
            PG_RETURN_NULL();
        }
        else
        {
            text	   *item;

            item = cstring_to_text_with_len(HS_VAL(entries, STRPTR(hs), i),
                                            HS_VALLEN(entries, i));

            SRF_RETURN_NEXT(funcctx, PointerGetDatum(item));
        }
    }

    SRF_RETURN_DONE(funcctx);
}
示例#13
0
/*
 * Validity test for a new-format hstore.
 *	0 = not valid
 *	1 = valid but with "slop" in the length
 *	2 = exactly valid
 */
static int
hstoreValidNewFormat(HStore *hs)
{
    int			count = HS_COUNT(hs);
    HEntry	   *entries = ARRPTR(hs);
    int			buflen = (count) ? HSE_ENDPOS(entries[2 * (count) - 1]) : 0;
    int			vsize = CALCDATASIZE(count, buflen);
    int			i;

    if (hs->size_ & HS_FLAG_NEWVERSION)
        return 2;

    if (count == 0)
        return 2;

    if (!HSE_ISFIRST(entries[0]))
        return 0;

    if (vsize > VARSIZE(hs))
        return 0;

    /* entry position must be nondecreasing */

    for (i = 1; i < 2 * count; ++i)
    {
        if (HSE_ISFIRST(entries[i])
                || (HSE_ENDPOS(entries[i]) < HSE_ENDPOS(entries[i - 1])))
            return 0;
    }

    /* key length must be nondecreasing and keys must not be null */

    for (i = 1; i < count; ++i)
    {
        if (HS_KEYLEN(entries, i) < HS_KEYLEN(entries, i - 1))
            return 0;
        if (HSE_ISNULL(entries[2 * i]))
            return 0;
    }

    if (vsize != VARSIZE(hs))
        return 1;

    return 2;
}
示例#14
0
Datum
hstore_avals(PG_FUNCTION_ARGS)
{
    HStore	   *hs = PG_GETARG_HS(0);
    Datum	   *d;
    bool	   *nulls;
    ArrayType  *a;
    HEntry	   *entries = ARRPTR(hs);
    char	   *base = STRPTR(hs);
    int			count = HS_COUNT(hs);
    int			lb = 1;
    int			i;

    if (count == 0)
    {
        a = construct_empty_array(TEXTOID);
        PG_RETURN_POINTER(a);
    }

    d = (Datum *) palloc(sizeof(Datum) * count);
    nulls = (bool *) palloc(sizeof(bool) * count);

    for (i = 0; i < count; ++i)
    {
        if (HS_VALISNULL(entries, i))
        {
            d[i] = (Datum) 0;
            nulls[i] = true;
        }
        else
        {
            text	   *item = cstring_to_text_with_len(HS_VAL(entries, base, i),
                               HS_VALLEN(entries, i));

            d[i] = PointerGetDatum(item);
            nulls[i] = false;
        }
    }

    a = construct_md_array(d, nulls, 1, &count, &lb,
                           TEXTOID, -1, false, 'i');

    PG_RETURN_POINTER(a);
}
示例#15
0
Datum
hstore_delete(PG_FUNCTION_ARGS)
{
    HStore	   *hs = PG_GETARG_HS(0);
    text	   *key = PG_GETARG_TEXT_PP(1);
    char	   *keyptr = VARDATA_ANY(key);
    int			keylen = VARSIZE_ANY_EXHDR(key);
    HStore	   *out = palloc(VARSIZE(hs));
    char	   *bufs,
               *bufd,
               *ptrd;
    HEntry	   *es,
               *ed;
    int			i;
    int			count = HS_COUNT(hs);
    int			outcount = 0;

    SET_VARSIZE(out, VARSIZE(hs));
    HS_SETCOUNT(out, count);	/* temporary! */

    bufs = STRPTR(hs);
    es = ARRPTR(hs);
    bufd = ptrd = STRPTR(out);
    ed = ARRPTR(out);

    for (i = 0; i < count; ++i)
    {
        int			len = HS_KEYLEN(es, i);
        char	   *ptrs = HS_KEY(es, bufs, i);

        if (!(len == keylen && memcmp(ptrs, keyptr, keylen) == 0))
        {
            int			vallen = HS_VALLEN(es, i);

            HS_COPYITEM(ed, bufd, ptrd, ptrs, len, vallen, HS_VALISNULL(es, i));
            ++outcount;
        }
    }

    HS_FINALIZE(out, outcount, bufd, ptrd);

    PG_RETURN_POINTER(out);
}
示例#16
0
Datum
hstore_contains(PG_FUNCTION_ARGS)
{
    HStore	   *val = PG_GETARG_HS(0);
    HStore	   *tmpl = PG_GETARG_HS(1);
    bool		res = true;
    HEntry	   *te = ARRPTR(tmpl);
    char	   *tstr = STRPTR(tmpl);
    HEntry	   *ve = ARRPTR(val);
    char	   *vstr = STRPTR(val);
    int			tcount = HS_COUNT(tmpl);
    int			lastidx = 0;
    int			i;

    /*
     * we exploit the fact that keys in "tmpl" are in 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
     * search
     */

    for (i = 0; res && i < tcount; ++i)
    {
        int			idx = hstoreFindKey(val, &lastidx,
                                        HS_KEY(te, tstr, i), HS_KEYLEN(te, i));

        if (idx >= 0)
        {
            bool		nullval = HS_VALISNULL(te, i);
            int			vallen = HS_VALLEN(te, i);

            if (nullval != HS_VALISNULL(ve, idx)
                    || (!nullval
                        && (vallen != HS_VALLEN(ve, idx)
                            || memcmp(HS_VAL(te, tstr, i), HS_VAL(ve, vstr, idx), vallen))))
                res = false;
        }
        else
            res = false;
    }

    PG_RETURN_BOOL(res);
}
示例#17
0
Datum
hstore_to_json(PG_FUNCTION_ARGS)
{
	HStore	   *in = PG_GETARG_HS(0);
	int			i;
	int			count = HS_COUNT(in);
	char	   *base = STRPTR(in);
	HEntry	   *entries = ARRPTR(in);
	StringInfoData tmp,
				dst;

	if (count == 0)
		PG_RETURN_TEXT_P(cstring_to_text_with_len("{}",2));

	initStringInfo(&tmp);
	initStringInfo(&dst);

	appendStringInfoChar(&dst, '{');

	for (i = 0; i < count; i++)
	{
		resetStringInfo(&tmp);
		appendBinaryStringInfo(&tmp, HS_KEY(entries, base, i), HS_KEYLEN(entries, i));
		escape_json(&dst, tmp.data);
		appendStringInfoString(&dst, ": ");
		if (HS_VALISNULL(entries, i))
			appendStringInfoString(&dst, "null");
		else
		{
			resetStringInfo(&tmp);
			appendBinaryStringInfo(&tmp, HS_VAL(entries, base, i), HS_VALLEN(entries, i));
			escape_json(&dst, tmp.data);
		}

		if (i + 1 != count)
			appendStringInfoString(&dst, ", ");
	}
	appendStringInfoChar(&dst, '}');

	PG_RETURN_TEXT_P(cstring_to_text(dst.data));
}
示例#18
0
/*
 * We're often finding a sequence of keys in ascending order. The
 * "lowbound" parameter is used to cache lower bounds of searches
 * between calls, based on this assumption. Pass NULL for it for
 * one-off or unordered searches.
 */
int
hstoreFindKey(HStore *hs, int *lowbound, char *key, int keylen)
{
    HEntry	   *entries = ARRPTR(hs);
    int			stopLow = lowbound ? *lowbound : 0;
    int			stopHigh = HS_COUNT(hs);
    int			stopMiddle;
    char	   *base = STRPTR(hs);

    while (stopLow < stopHigh)
    {
        int			difference;

        stopMiddle = stopLow + (stopHigh - stopLow) / 2;

        if (HS_KEYLEN(entries, stopMiddle) == keylen)
            difference = memcmp(HS_KEY(entries, base, stopMiddle), key, keylen);
        else
            difference = (HS_KEYLEN(entries, stopMiddle) > keylen) ? 1 : -1;

        if (difference == 0)
        {
            if (lowbound)
                *lowbound = stopMiddle + 1;
            return stopMiddle;
        }
        else if (difference < 0)
            stopLow = stopMiddle + 1;
        else
            stopHigh = stopMiddle;
    }

    if (lowbound)
        *lowbound = stopLow;
    return -1;
}
示例#19
0
文件: hstore_io.c 项目: d/gpdb
Datum
hstore_out(PG_FUNCTION_ARGS)
{
	HStore	   *in = PG_GETARG_HS(0);
	int			buflen,
				i;
	int			count = HS_COUNT(in);
	char	   *out,
			   *ptr;
	char	   *base = STRPTR(in);
	HEntry	   *entries = ARRPTR(in);

	if (count == 0)
	{
		out = palloc(1);
		*out = '\0';
		PG_RETURN_CSTRING(out);
	}

	buflen = 0;

	/*
	 * this loop overestimates due to pessimistic assumptions about escaping,
	 * so very large hstore values can't be output. this could be fixed, but
	 * many other data types probably have the same issue. This replaced code
	 * that used the original varlena size for calculations, which was wrong
	 * in some subtle ways.
	 */

	for (i = 0; i < count; i++)
	{
		/* include "" and => and comma-space */
		buflen += 6 + 2 * HS_KEYLEN(entries, i);
		/* include "" only if nonnull */
		buflen += 2 + (HS_VALISNULL(entries, i)
					   ? 2
					   : 2 * HS_VALLEN(entries, i));
	}

	out = ptr = palloc(buflen);

	for (i = 0; i < count; i++)
	{
		*ptr++ = '"';
		ptr = cpw(ptr, HS_KEY(entries, base, i), HS_KEYLEN(entries, i));
		*ptr++ = '"';
		*ptr++ = '=';
		*ptr++ = '>';
		if (HS_VALISNULL(entries, i))
		{
			*ptr++ = 'N';
			*ptr++ = 'U';
			*ptr++ = 'L';
			*ptr++ = 'L';
		}
		else
		{
			*ptr++ = '"';
			ptr = cpw(ptr, HS_VAL(entries, base, i), HS_VALLEN(entries, i));
			*ptr++ = '"';
		}

		if (i + 1 != count)
		{
			*ptr++ = ',';
			*ptr++ = ' ';
		}
	}
	*ptr = '\0';

	PG_RETURN_CSTRING(out);
}
示例#20
0
Datum
hstore_to_json_loose(PG_FUNCTION_ARGS)
{
	HStore	   *in = PG_GETARG_HS(0);
	int			i;
	int			count = HS_COUNT(in);
	char	   *base = STRPTR(in);
	HEntry	   *entries = ARRPTR(in);
	bool		is_number;
	StringInfoData tmp,
				dst;

	if (count == 0)
		PG_RETURN_TEXT_P(cstring_to_text_with_len("{}",2));

	initStringInfo(&tmp);
	initStringInfo(&dst);

	appendStringInfoChar(&dst, '{');

	for (i = 0; i < count; i++)
	{
		resetStringInfo(&tmp);
		appendBinaryStringInfo(&tmp, HS_KEY(entries, base, i), HS_KEYLEN(entries, i));
		escape_json(&dst, tmp.data);
		appendStringInfoString(&dst, ": ");
		if (HS_VALISNULL(entries, i))
			appendStringInfoString(&dst, "null");
		/* guess that values of 't' or 'f' are booleans */
		else if (HS_VALLEN(entries, i) == 1 && *(HS_VAL(entries, base, i)) == 't')
			appendStringInfoString(&dst, "true");
		else if (HS_VALLEN(entries, i) == 1 && *(HS_VAL(entries, base, i)) == 'f')
			appendStringInfoString(&dst, "false");
		else
		{
			is_number = false;
			resetStringInfo(&tmp);
			appendBinaryStringInfo(&tmp, HS_VAL(entries, base, i), HS_VALLEN(entries, i));

			/*
			 * don't treat something with a leading zero followed by another
			 * digit as numeric - could be a zip code or similar
			 */
			if (tmp.len > 0 &&
				!(tmp.data[0] == '0' &&
				  isdigit((unsigned char) tmp.data[1])) &&
				strspn(tmp.data, "+-0123456789Ee.") == tmp.len)
			{
				/*
				 * might be a number. See if we can input it as a numeric
				 * value. Ignore any actual parsed value.
				 */
				char	   *endptr = "junk";
				long		lval;

				lval = strtol(tmp.data, &endptr, 10);
				(void) lval;
				if (*endptr == '\0')
				{
					/*
					 * strol man page says this means the whole string is
					 * valid
					 */
					is_number = true;
				}
				else
				{
					/* not an int - try a double */
					double		dval;

					dval = strtod(tmp.data, &endptr);
					(void) dval;
					if (*endptr == '\0')
						is_number = true;
				}
			}
			if (is_number)
				appendBinaryStringInfo(&dst, tmp.data, tmp.len);
			else
				escape_json(&dst, tmp.data);
		}

		if (i + 1 != count)
			appendStringInfoString(&dst, ", ");
	}
	appendStringInfoChar(&dst, '}');

	PG_RETURN_TEXT_P(cstring_to_text(dst.data));
}
示例#21
0
Datum
hstore_to_jsonb_loose(PG_FUNCTION_ARGS)
{
	HStore	   *in = PG_GETARG_HS(0);
	int			i;
	int			count = HS_COUNT(in);
	char	   *base = STRPTR(in);
	HEntry	   *entries = ARRPTR(in);
	JsonbParseState *state = NULL;
	JsonbValue *res;
	StringInfoData tmp;
	bool        is_number;

	initStringInfo(&tmp);

	res = pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);

	for (i = 0; i < count; i++)
	{
		JsonbValue key, val;

		key.estSize = sizeof(JEntry);
		key.type = jbvString;
		key.val.string.len = HS_KEYLEN(entries, i);
		key.val.string.val = pnstrdup(HS_KEY(entries, base, i), key.val.string.len);
		key.estSize += key.val.string.len;

		res = pushJsonbValue(&state, WJB_KEY, &key);

		val.estSize = sizeof(JEntry);

		if (HS_VALISNULL(entries, i))
		{
			val.type = jbvNull;
		}
		/* guess that values of 't' or 'f' are booleans */
		else if (HS_VALLEN(entries, i) == 1 && *(HS_VAL(entries, base, i)) == 't')
		{
			val.type = jbvBool;
			val.val.boolean = true;
		}
		else if (HS_VALLEN(entries, i) == 1 && *(HS_VAL(entries, base, i)) == 'f')
		{
			val.type = jbvBool;
			val.val.boolean = false;
		}
		else
		{
			is_number = false;
			resetStringInfo(&tmp);

			appendBinaryStringInfo(&tmp, HS_VAL(entries, base, i), HS_VALLEN(entries, i));

			/*
			 * don't treat something with a leading zero followed by another
			 * digit as numeric - could be a zip code or similar
			 */
			if (tmp.len > 0 &&
				!(tmp.data[0] == '0' &&
				  isdigit((unsigned char) tmp.data[1])) &&
				strspn(tmp.data, "+-0123456789Ee.") == tmp.len)
			{
				/*
				 * might be a number. See if we can input it as a numeric
				 * value. Ignore any actual parsed value.
				 */
				char	   *endptr = "junk";
				long		lval;

				lval = strtol(tmp.data, &endptr, 10);
				(void) lval;
				if (*endptr == '\0')
				{
					/*
					 * strol man page says this means the whole string is
					 * valid
					 */
					is_number = true;
				}
				else
				{
					/* not an int - try a double */
					double		dval;

					dval = strtod(tmp.data, &endptr);
					(void) dval;
					if (*endptr == '\0')
						is_number = true;
				}
			}
			if (is_number)
			{
				val.type = jbvNumeric;
				val.val.numeric = DatumGetNumeric(
					DirectFunctionCall3(numeric_in, CStringGetDatum(tmp.data), 0, -1));
				val.estSize += VARSIZE_ANY(val.val.numeric) +sizeof(JEntry);
			}
			else
			{
				val.estSize = sizeof(JEntry);
				val.type = jbvString;
				val.val.string.len = HS_VALLEN(entries, i);
				val.val.string.val = pnstrdup(HS_VAL(entries, base, i), val.val.string.len);
				val.estSize += val.val.string.len;
			}
		}
		res = pushJsonbValue(&state, WJB_VALUE, &val);
	}

	res = pushJsonbValue(&state, WJB_END_OBJECT, NULL);

	PG_RETURN_POINTER(JsonbValueToJsonb(res));
}
示例#22
0
/*
 * hstoreUpgrade: PG_DETOAST_DATUM plus support for conversion of old hstores
 */
HStore *
hstoreUpgrade(Datum orig)
{
    HStore	   *hs = (HStore *) PG_DETOAST_DATUM(orig);
    int			valid_new;
    int			valid_old;
    bool		writable;

    /* Return immediately if no conversion needed */
    if ((hs->size_ & HS_FLAG_NEWVERSION) ||
            hs->size_ == 0 ||
            (VARSIZE(hs) < 32768 && HSE_ISFIRST((ARRPTR(hs)[0]))))
        return hs;

    valid_new = hstoreValidNewFormat(hs);
    valid_old = hstoreValidOldFormat(hs);
    /* Do we have a writable copy? */
    writable = ((void *) hs != (void *) DatumGetPointer(orig));

    if (!valid_old || hs->size_ == 0)
    {
        if (valid_new)
        {
            /*
             * force the "new version" flag and the correct varlena length,
             * but only if we have a writable copy already (which we almost
             * always will, since short new-format values won't come through
             * here)
             */
            if (writable)
            {
                HS_SETCOUNT(hs, HS_COUNT(hs));
                HS_FIXSIZE(hs, HS_COUNT(hs));
            }
            return hs;
        }
        else
        {
            elog(ERROR, "invalid hstore value found");
        }
    }

    /*
     * this is the tricky edge case. It is only possible in some quite extreme
     * cases (the hstore must have had a lot of wasted padding space at the
     * end). But the only way a "new" hstore value could get here is if we're
     * upgrading in place from a pre-release version of hstore-new (NOT
     * contrib/hstore), so we work off the following assumptions: 1. If you're
     * moving from old contrib/hstore to hstore-new, you're required to fix up
     * any potential conflicts first, e.g. by running ALTER TABLE ... USING
     * col::text::hstore; on all hstore columns before upgrading. 2. If you're
     * moving from old contrib/hstore to new contrib/hstore, then "new" values
     * are impossible here 3. If you're moving from pre-release hstore-new to
     * hstore-new, then "old" values are impossible here 4. If you're moving
     * from pre-release hstore-new to new contrib/hstore, you're not doing so
     * as an in-place upgrade, so there is no issue So the upshot of all this
     * is that we can treat all the edge cases as "new" if we're being built
     * as hstore-new, and "old" if we're being built as contrib/hstore.
     *
     * XXX the WARNING can probably be downgraded to DEBUG1 once this has been
     * beta-tested. But for now, it would be very useful to know if anyone can
     * actually reach this case in a non-contrived setting.
     */

    if (valid_new)
    {
#if HSTORE_IS_HSTORE_NEW
        elog(WARNING, "ambiguous hstore value resolved as hstore-new");

        /*
         * force the "new version" flag and the correct varlena length, but
         * only if we have a writable copy already (which we almost always
         * will, since short new-format values won't come through here)
         */
        if (writable)
        {
            HS_SETCOUNT(hs, HS_COUNT(hs));
            HS_FIXSIZE(hs, HS_COUNT(hs));
        }
        return hs;
#else
        elog(WARNING, "ambiguous hstore value resolved as hstore-old");
#endif
    }

    /*
     * must have an old-style value. Overwrite it in place as a new-style one,
     * making sure we have a writable copy first.
     */

    if (!writable)
        hs = (HStore *) PG_DETOAST_DATUM_COPY(orig);

    {
        int			count = hs->size_;
        HEntry	   *new_entries = ARRPTR(hs);
        HOldEntry  *old_entries = (HOldEntry *) ARRPTR(hs);
        int			i;

        for (i = 0; i < count; ++i)
        {
            uint32		pos = old_entries[i].pos;
            uint32		keylen = old_entries[i].keylen;
            uint32		vallen = old_entries[i].vallen;
            bool		isnull = old_entries[i].valisnull;

            if (isnull)
                vallen = 0;

            new_entries[2 * i].entry = (pos + keylen) & HENTRY_POSMASK;
            new_entries[2 * i + 1].entry = (((pos + keylen + vallen) & HENTRY_POSMASK)
                                            | ((isnull) ? HENTRY_ISNULL : 0));
        }

        if (count)
            new_entries[0].entry |= HENTRY_ISFIRST;
        HS_SETCOUNT(hs, count);
        HS_FIXSIZE(hs, count);
    }

    return hs;
}
示例#23
0
Datum
hstore_cmp(PG_FUNCTION_ARGS)
{
    HStore	   *hs1 = PG_GETARG_HS(0);
    HStore	   *hs2 = PG_GETARG_HS(1);
    int			hcount1 = HS_COUNT(hs1);
    int			hcount2 = HS_COUNT(hs2);
    int			res = 0;

    if (hcount1 == 0 || hcount2 == 0)
    {
        /*
         * if either operand is empty, and the other is nonempty, the nonempty
         * one is larger. If both are empty they are equal.
         */
        if (hcount1 > 0)
            res = 1;
        else if (hcount2 > 0)
            res = -1;
    }
    else
    {
        /* here we know both operands are nonempty */
        char	   *str1 = STRPTR(hs1);
        char	   *str2 = STRPTR(hs2);
        HEntry	   *ent1 = ARRPTR(hs1);
        HEntry	   *ent2 = ARRPTR(hs2);
        size_t		len1 = HSE_ENDPOS(ent1[2 * hcount1 - 1]);
        size_t		len2 = HSE_ENDPOS(ent2[2 * hcount2 - 1]);

        res = memcmp(str1, str2, Min(len1, len2));

        if (res == 0)
        {
            if (len1 > len2)
                res = 1;
            else if (len1 < len2)
                res = -1;
            else if (hcount1 > hcount2)
                res = 1;
            else if (hcount2 > hcount1)
                res = -1;
            else
            {
                int			count = hcount1 * 2;
                int			i;

                for (i = 0; i < count; ++i)
                    if (HSE_ENDPOS(ent1[i]) != HSE_ENDPOS(ent2[i]) ||
                            HSE_ISNULL(ent1[i]) != HSE_ISNULL(ent2[i]))
                        break;
                if (i < count)
                {
                    if (HSE_ENDPOS(ent1[i]) < HSE_ENDPOS(ent2[i]))
                        res = -1;
                    else if (HSE_ENDPOS(ent1[i]) > HSE_ENDPOS(ent2[i]))
                        res = 1;
                    else if (HSE_ISNULL(ent1[i]))
                        res = 1;
                    else if (HSE_ISNULL(ent2[i]))
                        res = -1;
                }
            }
        }
        else
        {
            res = (res > 0) ? 1 : -1;
        }
    }

    /*
     * this is a btree support function; this is one of the few places where
     * memory needs to be explicitly freed.
     */
    PG_FREE_IF_COPY(hs1, 0);
    PG_FREE_IF_COPY(hs2, 1);
    PG_RETURN_INT32(res);
}
示例#24
0
Datum
hstore_delete_array(PG_FUNCTION_ARGS)
{
    HStore	   *hs = PG_GETARG_HS(0);
    HStore	   *out = palloc(VARSIZE(hs));
    int			hs_count = HS_COUNT(hs);
    char	   *ps,
               *bufd,
               *pd;
    HEntry	   *es,
               *ed;
    int			i,
                j;
    int			outcount = 0;
    ArrayType  *key_array = PG_GETARG_ARRAYTYPE_P(1);
    int			nkeys;
    Pairs	   *key_pairs = hstoreArrayToPairs(key_array, &nkeys);

    SET_VARSIZE(out, VARSIZE(hs));
    HS_SETCOUNT(out, hs_count); /* temporary! */

    ps = STRPTR(hs);
    es = ARRPTR(hs);
    bufd = pd = STRPTR(out);
    ed = ARRPTR(out);

    if (nkeys == 0)
    {
        /* return a copy of the input, unchanged */
        memcpy(out, hs, VARSIZE(hs));
        HS_FIXSIZE(out, hs_count);
        HS_SETCOUNT(out, hs_count);
        PG_RETURN_POINTER(out);
    }

    /*
     * this is in effect a merge between hs and key_pairs, both of which are
     * already sorted by (keylen,key); we take keys from hs only
     */

    for (i = j = 0; i < hs_count;)
    {
        int			difference;

        if (j >= nkeys)
            difference = -1;
        else
        {
            int			skeylen = HS_KEYLEN(es, i);

            if (skeylen == key_pairs[j].keylen)
                difference = memcmp(HS_KEY(es, ps, i),
                                    key_pairs[j].key,
                                    key_pairs[j].keylen);
            else
                difference = (skeylen > key_pairs[j].keylen) ? 1 : -1;
        }

        if (difference > 0)
            ++j;
        else if (difference == 0)
            ++i, ++j;
        else
        {
            HS_COPYITEM(ed, bufd, pd,
                        HS_KEY(es, ps, i), HS_KEYLEN(es, i),
                        HS_VALLEN(es, i), HS_VALISNULL(es, i));
            ++outcount;
            ++i;
        }
    }

    HS_FINALIZE(out, outcount, bufd, pd);

    PG_RETURN_POINTER(out);
}
示例#25
0
Datum
hstore_delete_hstore(PG_FUNCTION_ARGS)
{
    HStore	   *hs = PG_GETARG_HS(0);
    HStore	   *hs2 = PG_GETARG_HS(1);
    HStore	   *out = palloc(VARSIZE(hs));
    int			hs_count = HS_COUNT(hs);
    int			hs2_count = HS_COUNT(hs2);
    char	   *ps,
               *ps2,
               *bufd,
               *pd;
    HEntry	   *es,
               *es2,
               *ed;
    int			i,
                j;
    int			outcount = 0;

    SET_VARSIZE(out, VARSIZE(hs));
    HS_SETCOUNT(out, hs_count); /* temporary! */

    ps = STRPTR(hs);
    es = ARRPTR(hs);
    ps2 = STRPTR(hs2);
    es2 = ARRPTR(hs2);
    bufd = pd = STRPTR(out);
    ed = ARRPTR(out);

    if (hs2_count == 0)
    {
        /* return a copy of the input, unchanged */
        memcpy(out, hs, VARSIZE(hs));
        HS_FIXSIZE(out, hs_count);
        HS_SETCOUNT(out, hs_count);
        PG_RETURN_POINTER(out);
    }

    /*
     * this is in effect a merge between hs and hs2, both of which are already
     * sorted by (keylen,key); we take keys from hs only; for equal keys, we
     * take the value from hs unless the values are equal
     */

    for (i = j = 0; i < hs_count;)
    {
        int			difference;

        if (j >= hs2_count)
            difference = -1;
        else
        {
            int			skeylen = HS_KEYLEN(es, i);
            int			s2keylen = HS_KEYLEN(es2, j);

            if (skeylen == s2keylen)
                difference = memcmp(HS_KEY(es, ps, i),
                                    HS_KEY(es2, ps2, j),
                                    skeylen);
            else
                difference = (skeylen > s2keylen) ? 1 : -1;
        }

        if (difference > 0)
            ++j;
        else if (difference == 0)
        {
            int			svallen = HS_VALLEN(es, i);
            int			snullval = HS_VALISNULL(es, i);

            if (snullval != HS_VALISNULL(es2, j)
                    || (!snullval
                        && (svallen != HS_VALLEN(es2, j)
                            || memcmp(HS_VAL(es, ps, i), HS_VAL(es2, ps2, j), svallen) != 0)))
            {
                HS_COPYITEM(ed, bufd, pd,
                            HS_KEY(es, ps, i), HS_KEYLEN(es, i),
                            svallen, snullval);
                ++outcount;
            }
            ++i, ++j;
        }
        else
        {
            HS_COPYITEM(ed, bufd, pd,
                        HS_KEY(es, ps, i), HS_KEYLEN(es, i),
                        HS_VALLEN(es, i), HS_VALISNULL(es, i));
            ++outcount;
            ++i;
        }
    }

    HS_FINALIZE(out, outcount, bufd, pd);

    PG_RETURN_POINTER(out);
}
示例#26
0
Datum
hstore_concat(PG_FUNCTION_ARGS)
{
    HStore	   *s1 = PG_GETARG_HS(0);
    HStore	   *s2 = PG_GETARG_HS(1);
    HStore	   *out = palloc(VARSIZE(s1) + VARSIZE(s2));
    char	   *ps1,
               *ps2,
               *bufd,
               *pd;
    HEntry	   *es1,
               *es2,
               *ed;
    int			s1idx;
    int			s2idx;
    int			s1count = HS_COUNT(s1);
    int			s2count = HS_COUNT(s2);
    int			outcount = 0;

    SET_VARSIZE(out, VARSIZE(s1) + VARSIZE(s2) - HSHRDSIZE);
    HS_SETCOUNT(out, s1count + s2count);

    if (s1count == 0)
    {
        /* return a copy of the input, unchanged */
        memcpy(out, s2, VARSIZE(s2));
        HS_FIXSIZE(out, s2count);
        HS_SETCOUNT(out, s2count);
        PG_RETURN_POINTER(out);
    }

    if (s2count == 0)
    {
        /* return a copy of the input, unchanged */
        memcpy(out, s1, VARSIZE(s1));
        HS_FIXSIZE(out, s1count);
        HS_SETCOUNT(out, s1count);
        PG_RETURN_POINTER(out);
    }

    ps1 = STRPTR(s1);
    ps2 = STRPTR(s2);
    bufd = pd = STRPTR(out);
    es1 = ARRPTR(s1);
    es2 = ARRPTR(s2);
    ed = ARRPTR(out);

    /*
     * this is in effect a merge between s1 and s2, both of which are already
     * sorted by (keylen,key); we take s2 for equal keys
     */

    for (s1idx = s2idx = 0; s1idx < s1count || s2idx < s2count; ++outcount)
    {
        int			difference;

        if (s1idx >= s1count)
            difference = 1;
        else if (s2idx >= s2count)
            difference = -1;
        else
        {
            int			s1keylen = HS_KEYLEN(es1, s1idx);
            int			s2keylen = HS_KEYLEN(es2, s2idx);

            if (s1keylen == s2keylen)
                difference = memcmp(HS_KEY(es1, ps1, s1idx),
                                    HS_KEY(es2, ps2, s2idx),
                                    s1keylen);
            else
                difference = (s1keylen > s2keylen) ? 1 : -1;
        }

        if (difference >= 0)
        {
            HS_COPYITEM(ed, bufd, pd,
                        HS_KEY(es2, ps2, s2idx), HS_KEYLEN(es2, s2idx),
                        HS_VALLEN(es2, s2idx), HS_VALISNULL(es2, s2idx));
            ++s2idx;
            if (difference == 0)
                ++s1idx;
        }
        else
        {
            HS_COPYITEM(ed, bufd, pd,
                        HS_KEY(es1, ps1, s1idx), HS_KEYLEN(es1, s1idx),
                        HS_VALLEN(es1, s1idx), HS_VALISNULL(es1, s1idx));
            ++s1idx;
        }
    }

    HS_FINALIZE(out, outcount, bufd, pd);

    PG_RETURN_POINTER(out);
}
示例#27
0
文件: hstore_io.c 项目: d/gpdb
Datum
hstore_populate_record(PG_FUNCTION_ARGS)
{
	Oid			argtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
	HStore	   *hs;
	HEntry	   *entries;
	char	   *ptr;
	HeapTupleHeader rec;
	Oid			tupType;
	int32		tupTypmod;
	TupleDesc	tupdesc;
	HeapTupleData tuple;
	HeapTuple	rettuple;
	RecordIOData *my_extra;
	int			ncolumns;
	int			i;
	Datum	   *values;
	bool	   *nulls;

	if (!type_is_rowtype(argtype))
		ereport(ERROR,
				(errcode(ERRCODE_DATATYPE_MISMATCH),
				 errmsg("first argument must be a rowtype")));

	if (PG_ARGISNULL(0))
	{
		if (PG_ARGISNULL(1))
			PG_RETURN_NULL();

		rec = NULL;

		/*
		 * 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;
	}
	else
	{
		rec = PG_GETARG_HEAPTUPLEHEADER(0);

		if (PG_ARGISNULL(1))
			PG_RETURN_POINTER(rec);

		/* Extract type info from the tuple itself */
		tupType = HeapTupleHeaderGetTypeId(rec);
		tupTypmod = HeapTupleHeaderGetTypMod(rec);
	}

	hs = PG_GETARG_HS(1);
	entries = ARRPTR(hs);
	ptr = STRPTR(hs);

	/*
	 * if the input hstore is empty, we can only skip the rest if we were
	 * passed in a non-null record, since otherwise there may be issues with
	 * domain nulls.
	 */

	if (HS_COUNT(hs) == 0 && rec)
		PG_RETURN_POINTER(rec);

	tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
	ncolumns = tupdesc->natts;

	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;
	}

	/*
	 * 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;
	}

	values = (Datum *) palloc(ncolumns * sizeof(Datum));
	nulls = (bool *) palloc(ncolumns * sizeof(bool));

	if (rec)
	{
		/* Break down the tuple into fields */
		heap_deform_tuple(&tuple, tupdesc, values, nulls);
	}
	else
	{
		for (i = 0; i < ncolumns; ++i)
		{
			values[i] = (Datum) 0;
			nulls[i] = true;
		}
	}

	for (i = 0; i < ncolumns; ++i)
	{
		ColumnIOData *column_info = &my_extra->columns[i];
		Oid			column_type = tupdesc->attrs[i]->atttypid;
		char	   *value;
		int			idx;
		int			vallen;

		/* Ignore dropped columns in datatype */
		if (tupdesc->attrs[i]->attisdropped)
		{
			nulls[i] = true;
			continue;
		}

		idx = hstoreFindKey(hs, 0,
							NameStr(tupdesc->attrs[i]->attname),
							strlen(NameStr(tupdesc->attrs[i]->attname)));

		/*
		 * we can't just skip here if the key wasn't found since we might have
		 * a domain to deal with. If we were passed in a non-null record
		 * datum, we assume that the existing values are valid (if they're
		 * not, then it's not our fault), but if we were passed in a null,
		 * then every field which we don't populate needs to be run through
		 * the input function just in case it's a domain type.
		 */
		if (idx < 0 && rec)
			continue;

		/*
		 * Prepare to convert the column value from text
		 */
		if (column_info->column_type != column_type)
		{
			getTypeInputInfo(column_type,
							 &column_info->typiofunc,
							 &column_info->typioparam);
			fmgr_info_cxt(column_info->typiofunc, &column_info->proc,
						  fcinfo->flinfo->fn_mcxt);
			column_info->column_type = column_type;
		}

		if (idx < 0 || HS_VALISNULL(entries, idx))
		{
			/*
			 * need InputFunctionCall to happen even for nulls, so that domain
			 * checks are done
			 */
			values[i] = InputFunctionCall(&column_info->proc, NULL,
										  column_info->typioparam,
										  tupdesc->attrs[i]->atttypmod);
			nulls[i] = true;
		}
		else
		{
			vallen = HS_VALLEN(entries, idx);
			value = palloc(1 + vallen);
			memcpy(value, HS_VAL(entries, ptr, idx), vallen);
			value[vallen] = 0;

			values[i] = InputFunctionCall(&column_info->proc, value,
										  column_info->typioparam,
										  tupdesc->attrs[i]->atttypmod);
			nulls[i] = false;
		}
	}

	rettuple = heap_form_tuple(tupdesc, values, nulls);

	ReleaseTupleDesc(tupdesc);

	PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
}
示例#28
0
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);
}