Datum
hstore_slice_to_array(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);
    ArrayType  *aout;
    Datum	   *key_datums;
    bool	   *key_nulls;
    Datum	   *out_datums;
    bool	   *out_nulls;
    int			key_count;
    int			i;

    deconstruct_array(key_array,
                      TEXTOID, -1, false, 'i',
                      &key_datums, &key_nulls, &key_count);

    if (key_count == 0)
    {
        aout = construct_empty_array(TEXTOID);
        PG_RETURN_POINTER(aout);
    }

    out_datums = palloc(sizeof(Datum) * key_count);
    out_nulls = palloc(sizeof(bool) * key_count);

    for (i = 0; i < key_count; ++i)
    {
        text	   *key = (text *) DatumGetPointer(key_datums[i]);
        int			idx;

        if (key_nulls[i])
            idx = -1;
        else
            idx = hstoreFindKey(hs, NULL, VARDATA(key), VARSIZE(key) - VARHDRSZ);

        if (idx < 0 || HS_VALISNULL(entries, idx))
        {
            out_nulls[i] = true;
            out_datums[i] = (Datum) 0;
        }
        else
        {
            out_datums[i] = PointerGetDatum(
                                cstring_to_text_with_len(HS_VAL(entries, ptr, idx),
                                        HS_VALLEN(entries, idx)));
            out_nulls[i] = false;
        }
    }

    aout = construct_md_array(out_datums, out_nulls,
                              ARR_NDIM(key_array),
                              ARR_DIMS(key_array),
                              ARR_LBOUND(key_array),
                              TEXTOID, -1, false, 'i');

    PG_RETURN_POINTER(aout);
}
Datum
hstore_exists_all(PG_FUNCTION_ARGS)
{
    HStore	   *hs = PG_GETARG_HS(0);
    ArrayType  *keys = PG_GETARG_ARRAYTYPE_P(1);
    int			nkeys;
    Pairs	   *key_pairs = hstoreArrayToPairs(keys, &nkeys);
    int			i;
    int			lowbound = 0;
    bool		res = true;

    /*
     * 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, &lowbound,
                                        key_pairs[i].key, key_pairs[i].keylen);

        if (idx < 0)
        {
            res = false;
            break;
        }
    }

    PG_RETURN_BOOL(res);
}
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_exists(PG_FUNCTION_ARGS)
{
    HStore	   *hs = PG_GETARG_HS(0);
    text	   *key = PG_GETARG_TEXT_PP(1);
    int			idx = hstoreFindKey(hs, NULL,
                                    VARDATA_ANY(key), VARSIZE_ANY_EXHDR(key));

    PG_RETURN_BOOL(idx >= 0);
}
Beispiel #5
0
static int hstore_index(lua_State *L) {

    HStore     *hs;
    char	   *base;
    HEntry	   *entries;
    const char *key;
    char       *k_str;
    int         idx;
    Lua_Hstore *strg;

    BEGINLUA;
    strg = lua_touserdata(L, 1);

    hs = strg->hstore;
    base = STRPTR(hs);
    entries = ARRPTR(hs);

    key = luaL_checkstring(L, 2);

    lua_pushlightuserdata(L, strg);
    lua_gettable(L, LUA_REGISTRYINDEX);
    lua_pushstring(L, key);
    lua_gettable(L, -2);

    if (!lua_isnil(L, -1)) {
        char *data_ptr = lua_touserdata (L, -1);
        lua_pop(L,2);

        if (data_ptr){
            lua_pushstring(L, data_ptr);
        }else {
            lua_pushnil(L);
        }

        ENDLUAV(1);
        return 1;
    }

    lua_pop(L,2);

    k_str = strdup(key);

    idx = hstoreFindKey(hs, NULL, k_str, strlen(k_str));

    free(k_str);
    if (idx<0|| HS_VALISNULL(entries, idx)){
        lua_pushnil(L);
        ENDLUAV(1);
        return 1;
    }

    lua_pushlstring(L, HS_VAL(entries, base, idx),HS_VALLEN(entries, idx));
    ENDLUAV(1);
    return 1;
}
Datum
hstore_defined(PG_FUNCTION_ARGS)
{
    HStore	   *hs = PG_GETARG_HS(0);
    text	   *key = PG_GETARG_TEXT_PP(1);
    HEntry	   *entries = ARRPTR(hs);
    int			idx = hstoreFindKey(hs, NULL,
                                    VARDATA_ANY(key), VARSIZE_ANY_EXHDR(key));
    bool		res = (idx >= 0 && !HS_VALISNULL(entries, idx));

    PG_RETURN_BOOL(res);
}
Datum
hstore_fetchval(PG_FUNCTION_ARGS)
{
    HStore	   *hs = PG_GETARG_HS(0);
    text	   *key = PG_GETARG_TEXT_PP(1);
    HEntry	   *entries = ARRPTR(hs);
    text	   *out;
    int			idx = hstoreFindKey(hs, NULL,
                                    VARDATA_ANY(key), VARSIZE_ANY_EXHDR(key));

    if (idx < 0 || HS_VALISNULL(entries, idx))
        PG_RETURN_NULL();

    out = cstring_to_text_with_len(HS_VAL(entries, STRPTR(hs), idx),
                                   HS_VALLEN(entries, idx));

    PG_RETURN_TEXT_P(out);
}
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);
}
Beispiel #9
0
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));
}