Exemple #1
0
/*
 * Returns a pointer to a WordEntry's array corresponding to 'item' from
 * tsvector 't'. 'q' is the TSQuery containing 'item'.
 * Returns NULL if not found.
 */
static WordEntry *
find_wordentry(TSVector t, TSQuery q, QueryOperand *item, int32 *nitem)
{
	WordEntry  *StopLow = ARRPTR(t);
	WordEntry  *StopHigh = (WordEntry *) STRPTR(t);
	WordEntry  *StopMiddle = StopHigh;
	int			difference;

	*nitem = 0;

	/* Loop invariant: StopLow <= item < StopHigh */
	while (StopLow < StopHigh)
	{
		StopMiddle = StopLow + (StopHigh - StopLow) / 2;
		difference = WordECompareQueryItem(STRPTR(t), GETOPERAND(q), StopMiddle, item, false);
		if (difference == 0)
		{
			StopHigh = StopMiddle;
			*nitem = 1;
			break;
		}
		else if (difference > 0)
			StopLow = StopMiddle + 1;
		else
			StopHigh = StopMiddle;
	}

	if (item->prefix)
	{
		if (StopLow >= StopHigh)
			StopMiddle = StopHigh;

		*nitem = 0;

		while (StopMiddle < (WordEntry *) STRPTR(t) &&
			   WordECompareQueryItem(STRPTR(t), GETOPERAND(q), StopMiddle, item, true) == 0)
		{
			(*nitem)++;
			StopMiddle++;
		}
	}

	return (*nitem > 0) ? StopHigh : NULL;
}
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);
}
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);
}
Exemple #4
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_out(PG_FUNCTION_ARGS)
{
	HStore	   *in = PG_GETARG_HS(0);
	int			buflen,
				i;
	char	   *out,
			   *ptr;
	char	   *base = STRPTR(in);
	HEntry	   *entries = ARRPTR(in);

	if (in->size == 0)
	{
		out = palloc(1);
		*out = '\0';
		PG_FREE_IF_COPY(in, 0);
		PG_RETURN_CSTRING(out);
	}

	buflen = (4 /* " */ + 2 /* => */ + 2 /* , */ ) * in->size +
		2 /* esc */ * (in->len - CALCDATASIZE(in->size, 0));

	out = ptr = palloc(buflen);
	for (i = 0; i < in->size; i++)
	{
		*ptr++ = '"';
		ptr = cpw(ptr, base + entries[i].pos, entries[i].keylen);
		*ptr++ = '"';
		*ptr++ = '=';
		*ptr++ = '>';
		if (entries[i].valisnull)
		{
			*ptr++ = 'N';
			*ptr++ = 'U';
			*ptr++ = 'L';
			*ptr++ = 'L';
		}
		else
		{
			*ptr++ = '"';
			ptr = cpw(ptr, base + entries[i].pos + entries[i].keylen, entries[i].vallen);
			*ptr++ = '"';
		}

		if (i + 1 != in->size)
		{
			*ptr++ = ',';
			*ptr++ = ' ';
		}
	}
	*ptr = '\0';

	PG_FREE_IF_COPY(in, 0);
	PG_RETURN_CSTRING(out);
}
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);
}
Exemple #7
0
Datum
svals(PG_FUNCTION_ARGS)
{
	FuncCallContext *funcctx;
	AKStore    *st;

	if (SRF_IS_FIRSTCALL())
	{
		HStore	   *hs = PG_GETARG_HS(0);

		funcctx = SRF_FIRSTCALL_INIT();
		setup_firstcall(funcctx, hs);
		PG_FREE_IF_COPY(hs, 0);
	}

	funcctx = SRF_PERCALL_SETUP();
	st = (AKStore *) funcctx->user_fctx;

	if (st->i < st->hs->size)
	{
		HEntry	   *ptr = &(ARRPTR(st->hs)[st->i]);

		if (ptr->valisnull)
		{
			ReturnSetInfo *rsi;

			st->i++;
			(funcctx)->call_cntr++;
			rsi = (ReturnSetInfo *) fcinfo->resultinfo;
			rsi->isDone = ExprMultipleResult;
			PG_RETURN_NULL();
		}
		else
		{
			int			vallen = ptr->vallen;
			text	   *item = (text *) palloc(VARHDRSZ + vallen);

			SET_VARSIZE(item, VARHDRSZ + vallen);
			memcpy(VARDATA(item), STRPTR(st->hs) + ptr->pos + ptr->keylen, vallen);
			st->i++;

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

	pfree(st->hs);
	pfree(st);

	SRF_RETURN_DONE(funcctx);
}
Exemple #8
0
Datum
hs_contains(PG_FUNCTION_ARGS)
{
	HStore	   *val = PG_GETARG_HS(0);
	HStore	   *tmpl = PG_GETARG_HS(1);
	bool		res = true;
	HEntry	   *te = ARRPTR(tmpl);
	char	   *vv = STRPTR(val);
	char	   *tv = STRPTR(tmpl);

	while (res && te - ARRPTR(tmpl) < tmpl->size)
	{
		HEntry	   *entry = findkey(val, tv + te->pos, te->keylen);

		if (entry)
		{
			if (te->valisnull || entry->valisnull)
			{
				if (!(te->valisnull && entry->valisnull))
					res = false;
			}
			else if (te->vallen != entry->vallen ||
					 strncmp(vv + entry->pos + entry->keylen,
							 tv + te->pos + te->keylen,
							 te->vallen))
				res = false;
		}
		else
			res = false;
		te++;
	}

	PG_FREE_IF_COPY(val, 0);
	PG_FREE_IF_COPY(tmpl, 1);

	PG_RETURN_BOOL(res);
}
Exemple #9
0
static WordEntry *
find_wordentry(tsvector * t, QUERYTYPE * q, ITEM * item)
{
	WordEntry  *StopLow = ARRPTR(t);
	WordEntry  *StopHigh = (WordEntry *) STRPTR(t);
	WordEntry  *StopMiddle;
	int			difference;

	/* Loop invariant: StopLow <= item < StopHigh */

	while (StopLow < StopHigh)
	{
		StopMiddle = StopLow + (StopHigh - StopLow) / 2;
		difference = WordECompareITEM(STRPTR(t), GETOPERAND(q), StopMiddle, item);
		if (difference == 0)
			return StopMiddle;
		else if (difference < 0)
			StopLow = StopMiddle + 1;
		else
			StopHigh = StopMiddle;
	}

	return NULL;
}
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');
}
Exemple #11
0
Datum
gin_extract_hstore(PG_FUNCTION_ARGS)
{
	HStore	   *hs = PG_GETARG_HS(0);
	int32	   *nentries = (int32 *) PG_GETARG_POINTER(1);
	Datum	   *entries = NULL;

	*nentries = 2 * hs->size;

	if (hs->size > 0)
	{
		HEntry	   *ptr = ARRPTR(hs);
		char	   *words = STRPTR(hs);
		int			i = 0;

		entries = (Datum *) palloc(sizeof(Datum) * 2 * hs->size);

		while (ptr - ARRPTR(hs) < hs->size)
		{
			text	   *item;

			item = makeitem(words + ptr->pos, ptr->keylen);
			*VARDATA(item) = KEYFLAG;
			entries[i++] = PointerGetDatum(item);

			if (ptr->valisnull)
			{
				item = makeitem(NULL, 0);
				*VARDATA(item) = NULLFLAG;

			}
			else
			{
				item = makeitem(words + ptr->pos + ptr->keylen, ptr->vallen);
				*VARDATA(item) = VALFLAG;
			}
			entries[i++] = PointerGetDatum(item);

			ptr++;
		}
	}

	PG_FREE_IF_COPY(hs, 0);
	PG_RETURN_POINTER(entries);
}
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);
}
Exemple #13
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));
}
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_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);
}
Exemple #16
0
static int
cnt_length(tsvector * t)
{
	WordEntry  *ptr = ARRPTR(t),
			   *end = (WordEntry *) STRPTR(t);
	int			len = 0,
				clen;

	while (ptr < end)
	{
		if ((clen = POSDATALEN(t, ptr)) == 0)
			len += 1;
		else
			len += clen;
		ptr++;
	}

	return len;
}
Exemple #17
0
Datum
avals(PG_FUNCTION_ARGS)
{
	HStore	   *hs = PG_GETARG_HS(0);
	Datum	   *d;
	ArrayType  *a;
	HEntry	   *ptr = ARRPTR(hs);
	char	   *base = STRPTR(hs);

	d = (Datum *) palloc(sizeof(Datum) * (hs->size + 1));
	while (ptr - ARRPTR(hs) < hs->size)
	{
		int			vallen = (ptr->valisnull) ? 0 : ptr->vallen;
		text	   *item = (text *) palloc(VARHDRSZ + vallen);

		SET_VARSIZE(item, VARHDRSZ + vallen);
		memcpy(VARDATA(item), base + ptr->pos + ptr->keylen, vallen);
		d[ptr - ARRPTR(hs)] = PointerGetDatum(item);
		ptr++;
	}

	a = construct_array(
						d,
						hs->size,
						TEXTOID,
						-1,
						false,
						'i'
		);

	ptr = ARRPTR(hs);
	while (ptr - ARRPTR(hs) < hs->size)
	{
		pfree(DatumGetPointer(d[ptr - ARRPTR(hs)]));
		ptr++;
	}

	pfree(d);
	PG_FREE_IF_COPY(hs, 0);

	PG_RETURN_POINTER(a);
}
Exemple #18
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));
}
Exemple #19
0
static int
cnt_length(TSVector t)
{
	WordEntry  *ptr = ARRPTR(t),
			   *end = (WordEntry *) STRPTR(t);
	int			len = 0;

	while (ptr < end)
	{
		int			clen = POSDATALEN(t, ptr);

		if (clen == 0)
			len += 1;
		else
			len += clen;

		ptr++;
	}

	return len;
}
Exemple #20
0
static void write_exec(ioent_t *io, event_t *evt) {
    DWORD error;
    int len;

    aio_count++;
    len = STRLEN(evt->val) - io->offset;
    if (len > io->bufsz) {
        len = io->bufsz;
    }
    /* 新規に書き込みIO発行 */
    memcpy(io->buf, STRPTR(evt->val)+io->offset, len);
    if (!WriteFileEx(io->handle, io->buf, len, &io->ctlblk, write_completion_handler)) {
        error = GetLastError();
        switch (error) {
        case ERROR_IO_PENDING:
            break;
        default:
            perr(PERR_SYSTEM, "WriteFile", error, __FILE__, __LINE__);
            return;
        }
    }
}
Exemple #21
0
Datum
tsvectorsend(PG_FUNCTION_ARGS)
{
	TSVector	vec = PG_GETARG_TSVECTOR(0);
	StringInfoData buf;
	int			i,
				j;
	WordEntry  *weptr = ARRPTR(vec);

	pq_begintypsend(&buf);

	pq_sendint(&buf, vec->size, sizeof(int32));
	for (i = 0; i < vec->size; i++)
	{
		uint16		npos;

		/*
		 * the strings in the TSVector array are not null-terminated, so we
		 * have to send the null-terminator separately
		 */
		pq_sendtext(&buf, STRPTR(vec) + weptr->pos, weptr->len);
		pq_sendbyte(&buf, '\0');

		npos = POSDATALEN(vec, weptr);
		pq_sendint(&buf, npos, sizeof(uint16));

		if (npos > 0)
		{
			WordEntryPos *wepptr = POSDATAPTR(vec, weptr);

			for (j = 0; j < npos; j++)
				pq_sendint(&buf, wepptr[j], sizeof(WordEntryPos));
		}
		weptr++;
	}

	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
}
Exemple #22
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));
		*VARDATA(item) = KEYFLAG;
		entries[2 * i] = PointerGetDatum(item);

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

	PG_RETURN_POINTER(entries);
}
Exemple #23
0
Datum
fetchval(PG_FUNCTION_ARGS)
{
	HStore	   *hs = PG_GETARG_HS(0);
	text	   *key = PG_GETARG_TEXT_P(1);
	HEntry	   *entry;
	text	   *out;

	if ((entry = findkey(hs, VARDATA(key), VARSIZE(key) - VARHDRSZ)) == NULL || entry->valisnull)
	{
		PG_FREE_IF_COPY(hs, 0);
		PG_FREE_IF_COPY(key, 1);
		PG_RETURN_NULL();
	}

	out = palloc(VARHDRSZ + entry->vallen);
	memcpy(VARDATA(out), STRPTR(hs) + entry->pos + entry->keylen, entry->vallen);
	SET_VARSIZE(out, VARHDRSZ + entry->vallen);

	PG_FREE_IF_COPY(hs, 0);
	PG_FREE_IF_COPY(key, 1);
	PG_RETURN_POINTER(out);
}
Exemple #24
0
datum_t gin_extract_tsvector(PG_FUNC_ARGS)
{
	TSVector vector = ARG_TSVECTOR(0);
	int32 *nentries = (int32 *) ARG_POINTER(1);
	datum_t *entries = NULL;

	*nentries = vector->size;
	if (vector->size > 0) {
		int i;
		WordEntry *we = ARRPTR(vector);

		entries = (datum_t *) palloc(sizeof(datum_t) * vector->size);
		for (i = 0; i < vector->size; i++) {
			text *txt;

			txt = cstring_to_text_with_len(STRPTR(vector) + we->pos, we->len);
			entries[i] = PTR_TO_D(txt);
			we++;
		}
	}

	PG_FREE_IF_COPY(vector, 0);
	RET_POINTER(entries);
}
/*
 * 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;
}
Exemple #26
0
static void
insertStatEntry(MemoryContext persistentContext, TSVectorStat *stat, TSVector txt, uint32 off)
{
	WordEntry  *we = ARRPTR(txt) + off;
	StatEntry  *node = stat->root,
			   *pnode = NULL;
	int			n,
				res = 0;
	uint32		depth = 1;

	if (stat->weight == 0)
		n = (we->haspos) ? POSDATALEN(txt, we) : 1;
	else
		n = (we->haspos) ? check_weight(txt, we, stat->weight) : 0;

	if (n == 0)
		return;					/* nothing to insert */

	while (node)
	{
		res = compareStatWord(node, we, txt);

		if (res == 0)
		{
			break;
		}
		else
		{
			pnode = node;
			node = (res < 0) ? node->left : node->right;
		}
		depth++;
	}

	if (depth > stat->maxdepth)
		stat->maxdepth = depth;

	if (node == NULL)
	{
		node = MemoryContextAlloc(persistentContext, STATENTRYHDRSZ + we->len);
		node->left = node->right = NULL;
		node->ndoc = 1;
		node->nentry = n;
		node->lenlexeme = we->len;
		memcpy(node->lexeme, STRPTR(txt) + we->pos, node->lenlexeme);

		if (pnode == NULL)
		{
			stat->root = node;
		}
		else
		{
			if (res < 0)
				pnode->left = node;
			else
				pnode->right = node;
		}

	}
	else
	{
		node->ndoc++;
		node->nentry += n;
	}
}
Exemple #27
0
Datum
tsvector_concat(PG_FUNCTION_ARGS)
{
	TSVector	in1 = PG_GETARG_TSVECTOR(0);
	TSVector	in2 = PG_GETARG_TSVECTOR(1);
	TSVector	out;
	WordEntry  *ptr;
	WordEntry  *ptr1,
			   *ptr2;
	WordEntryPos *p;
	int			maxpos = 0,
				i,
				j,
				i1,
				i2,
				dataoff,
				output_bytes,
				output_size;
	char	   *data,
			   *data1,
			   *data2;

	/* Get max position in in1; we'll need this to offset in2's positions */
	ptr = ARRPTR(in1);
	i = in1->size;
	while (i--)
	{
		if ((j = POSDATALEN(in1, ptr)) != 0)
		{
			p = POSDATAPTR(in1, ptr);
			while (j--)
			{
				if (WEP_GETPOS(*p) > maxpos)
					maxpos = WEP_GETPOS(*p);
				p++;
			}
		}
		ptr++;
	}

	ptr1 = ARRPTR(in1);
	ptr2 = ARRPTR(in2);
	data1 = STRPTR(in1);
	data2 = STRPTR(in2);
	i1 = in1->size;
	i2 = in2->size;

	/*
	 * Conservative estimate of space needed.  We might need all the data in
	 * both inputs, and conceivably add a pad byte before position data for
	 * each item where there was none before.
	 */
	output_bytes = VARSIZE(in1) + VARSIZE(in2) + i1 + i2;

	out = (TSVector) palloc0(output_bytes);
	SET_VARSIZE(out, output_bytes);

	/*
	 * We must make out->size valid so that STRPTR(out) is sensible.  We'll
	 * collapse out any unused space at the end.
	 */
	out->size = in1->size + in2->size;

	ptr = ARRPTR(out);
	data = STRPTR(out);
	dataoff = 0;
	while (i1 && i2)
	{
		int			cmp = compareEntry(data1, ptr1, data2, ptr2);

		if (cmp < 0)
		{						/* in1 first */
			ptr->haspos = ptr1->haspos;
			ptr->len = ptr1->len;
			memcpy(data + dataoff, data1 + ptr1->pos, ptr1->len);
			ptr->pos = dataoff;
			dataoff += ptr1->len;
			if (ptr->haspos)
			{
				dataoff = SHORTALIGN(dataoff);
				memcpy(data + dataoff, _POSVECPTR(in1, ptr1), POSDATALEN(in1, ptr1) * sizeof(WordEntryPos) + sizeof(uint16));
				dataoff += POSDATALEN(in1, ptr1) * sizeof(WordEntryPos) + sizeof(uint16);
			}

			ptr++;
			ptr1++;
			i1--;
		}
		else if (cmp > 0)
		{						/* in2 first */
			ptr->haspos = ptr2->haspos;
			ptr->len = ptr2->len;
			memcpy(data + dataoff, data2 + ptr2->pos, ptr2->len);
			ptr->pos = dataoff;
			dataoff += ptr2->len;
			if (ptr->haspos)
			{
				int			addlen = add_pos(in2, ptr2, out, ptr, maxpos);

				if (addlen == 0)
					ptr->haspos = 0;
				else
				{
					dataoff = SHORTALIGN(dataoff);
					dataoff += addlen * sizeof(WordEntryPos) + sizeof(uint16);
				}
			}

			ptr++;
			ptr2++;
			i2--;
		}
		else
		{
			ptr->haspos = ptr1->haspos | ptr2->haspos;
			ptr->len = ptr1->len;
			memcpy(data + dataoff, data1 + ptr1->pos, ptr1->len);
			ptr->pos = dataoff;
			dataoff += ptr1->len;
			if (ptr->haspos)
			{
				if (ptr1->haspos)
				{
					dataoff = SHORTALIGN(dataoff);
					memcpy(data + dataoff, _POSVECPTR(in1, ptr1), POSDATALEN(in1, ptr1) * sizeof(WordEntryPos) + sizeof(uint16));
					dataoff += POSDATALEN(in1, ptr1) * sizeof(WordEntryPos) + sizeof(uint16);
					if (ptr2->haspos)
						dataoff += add_pos(in2, ptr2, out, ptr, maxpos) * sizeof(WordEntryPos);
				}
				else	/* must have ptr2->haspos */
				{
					int			addlen = add_pos(in2, ptr2, out, ptr, maxpos);

					if (addlen == 0)
						ptr->haspos = 0;
					else
					{
						dataoff = SHORTALIGN(dataoff);
						dataoff += addlen * sizeof(WordEntryPos) + sizeof(uint16);
					}
				}
			}

			ptr++;
			ptr1++;
			ptr2++;
			i1--;
			i2--;
		}
	}

	while (i1)
	{
		ptr->haspos = ptr1->haspos;
		ptr->len = ptr1->len;
		memcpy(data + dataoff, data1 + ptr1->pos, ptr1->len);
		ptr->pos = dataoff;
		dataoff += ptr1->len;
		if (ptr->haspos)
		{
			dataoff = SHORTALIGN(dataoff);
			memcpy(data + dataoff, _POSVECPTR(in1, ptr1), POSDATALEN(in1, ptr1) * sizeof(WordEntryPos) + sizeof(uint16));
			dataoff += POSDATALEN(in1, ptr1) * sizeof(WordEntryPos) + sizeof(uint16);
		}

		ptr++;
		ptr1++;
		i1--;
	}

	while (i2)
	{
		ptr->haspos = ptr2->haspos;
		ptr->len = ptr2->len;
		memcpy(data + dataoff, data2 + ptr2->pos, ptr2->len);
		ptr->pos = dataoff;
		dataoff += ptr2->len;
		if (ptr->haspos)
		{
			int			addlen = add_pos(in2, ptr2, out, ptr, maxpos);

			if (addlen == 0)
				ptr->haspos = 0;
			else
			{
				dataoff = SHORTALIGN(dataoff);
				dataoff += addlen * sizeof(WordEntryPos) + sizeof(uint16);
			}
		}

		ptr++;
		ptr2++;
		i2--;
	}

	/*
	 * Instead of checking each offset individually, we check for overflow of
	 * pos fields once at the end.
	 */
	if (dataoff > MAXSTRPOS)
		ereport(ERROR,
				(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
				 errmsg("string is too long for tsvector (%d bytes, max %d bytes)", dataoff, MAXSTRPOS)));

	/*
	 * Adjust sizes (asserting that we didn't overrun the original estimates)
	 * and collapse out any unused array entries.
	 */
	output_size = ptr - ARRPTR(out);
	Assert(output_size <= out->size);
	out->size = output_size;
	if (data != STRPTR(out))
		memmove(STRPTR(out), data, dataoff);
	output_bytes = CALCDATASIZE(out->size, dataoff);
	Assert(output_bytes <= VARSIZE(out));
	SET_VARSIZE(out, output_bytes);

	PG_FREE_IF_COPY(in1, 0);
	PG_FREE_IF_COPY(in2, 1);
	PG_RETURN_POINTER(out);
}
Exemple #28
0
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);
}
Exemple #29
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));
}
Exemple #30
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));
}