예제 #1
0
char *ConvertToText( Datum value, Oid column_type, MemoryContext fn_mcxt, char** pbuf )
{
	bool typIsVarlena;
	Oid typiofunc;
	FmgrInfo	proc;
	char*		result;
//	FILE* log;

//	log = fopen("/var/lib/postgresql/serializer.log", "a");

	getTypeOutputInfo(column_type, &typiofunc, &typIsVarlena);
	fmgr_info_cxt( typiofunc, &proc, fn_mcxt );

//	fprintf(log, "Oid of function: %i\n", proc.fn_oid);

	result =  OutputFunctionCall( &proc, value );

	if((column_type != INT8OID) && (column_type != BOOLOID) &&
           (column_type != INT4OID) && (column_type != FLOAT8OID) &&
           (column_type != INT2OID) && (column_type != FLOAT4OID)) {
//		fprintf(log, "WELL WELL\n");
		result = json_escape_str(pbuf, result);
//		fprintf(log, "result: %s\n", result);
//		fclose(log);
		return result;
	}
//	fclose(log);
	return result;
}
예제 #2
0
void
tf_write_one_row(StringInfo msgbuf,
			  FmgrInfo *out_funcs,
			  List *attnumlist,
			  Datum *values,
			  bool *nulls)
{
	ListCell   *cur;
	char	   *string;

	bool need_delim = false;

	foreach(cur, attnumlist)
	{
		int			attnum = lfirst_int(cur);
		Datum		value = values[attnum - 1];
		bool		isnull = nulls[attnum - 1];

		if (need_delim)
			tf_write_char(msgbuf, '\t');

		need_delim = true;

		if (isnull)
		{
			tf_write_string(msgbuf, "\\N");
		}
		else
		{
			string = OutputFunctionCall(&out_funcs[attnum - 1],
										value);

			tf_write_attribute_out_text(msgbuf,'\t',string);
		}
	}
예제 #3
0
static PyObject *
PLyString_FromDatum(PLyDatumToOb *arg, Datum d)
{
	char	   *x = OutputFunctionCall(&arg->typfunc, d);
	PyObject   *r = PyString_FromString(x);

	pfree(x);
	return r;
}
예제 #4
0
static int tostring(lua_State *L) {
    Lua_Hstore *strg = lua_touserdata(L, 1);
    apply_changes(L, strg);
    if (strg->issync){
        lua_pushstring(L, OutputFunctionCall(&hs_type.output, PointerGetDatum(strg->hstore)));
    }else{
        return luaL_error(L, "hstore apply changes failed");
    }
    return 1;
}
예제 #5
0
파일: execute.c 프로젝트: comagic/plexor
static void
create_fn_args(PlxFn*              plx_fn,
               FunctionCallInfo    fcinfo,
               char             ***args,
               int               **arg_lens,
               int               **arg_fmts)
{
    PlxQuery  *plx_q = plx_fn->run_query;
    int        i;

    (* args)     = palloc0(sizeof(char *) * plx_q->nargs);
    (* arg_lens) = palloc0(sizeof(int)    * plx_q->nargs);
    (* arg_fmts) = palloc0(sizeof(int)    * plx_q->nargs);

    if (plx_fn->is_binary)
    {
        bytea *bin;
        for (i = 0; i < plx_q->nargs; i++)
        {
            int idx = plx_q->plx_fn_arg_indexes[i];

            bin = SendFunctionCall(&plx_fn->arg_types[idx]->send_fn, PG_GETARG_DATUM(idx));
            (* args)[i]     = VARDATA(bin);
            (* arg_lens)[i] = VARSIZE(bin) - VARHDRSZ;
            (* arg_fmts)[i] = 1;
        }
    }
    else
    {
        for (i = 0; i < plx_q->nargs; i++)
        {
            int idx = plx_q->plx_fn_arg_indexes[i];

            if (PG_ARGISNULL(idx))
                (* args)[i] = NULL;
            else
                (* args)[i] = OutputFunctionCall(
                    &plx_fn->arg_types[idx]->output_fn,
                    PG_GETARG_DATUM(idx));
            (* arg_lens)[i] = 0;
            (* arg_fmts)[i] = 0;
        }
    }
}
예제 #6
0
파일: pl_bf.c 프로젝트: jeltz/pl-bf
size_t append_datum(char* buf, Datum val, bool isnull, Oid typeoid)
{
    HeapTuple typeTup;
    Form_pg_type typeStruct;
    FmgrInfo tmp_flinfo;
    char *str;
    size_t len;

    typeTup = SearchSysCache(TYPEOID, ObjectIdGetDatum(typeoid), 0, 0, 0);
    if (!HeapTupleIsValid(typeTup)) {
        elog(ERROR, "Cache lookup failed for %u", typeoid);
    }
    typeStruct = (Form_pg_type)GETSTRUCT(typeTup);

    if (typeStruct->typtype != 'b') {
        // Non-basic type
        elog(ERROR, "Don't support non-basic types (%s)",
             format_type_be(typeoid));
    }

    fmgr_info_cxt(typeStruct->typoutput, &tmp_flinfo, CurTransactionContext);

    ReleaseSysCache(typeTup);
    
    if (!isnull) {
        if (typeoid == INT4OID) {
            *((int*)buf) = DatumGetInt32(val);
            return 4;
        }
        
        SPI_push();
        str = OutputFunctionCall(&tmp_flinfo, val);
        SPI_pop();
        len = strlen(str);
        strncpy(buf, str, len);
        return len;
    }

    return 0;
}
예제 #7
0
파일: type.c 프로젝트: plproxy/plproxy
/* Convert a Datum to parameter for libpq */
char *
plproxy_send_type(ProxyType *type, Datum val, bool allow_bin, int *len, int *fmt)
{
	bytea	   *bin;
	char	   *res;

	Assert(type->for_send == 1);

	if (allow_bin && type->has_send)
	{
		bin = SendFunctionCall(&type->io.out.send_func, val);
		res = VARDATA(bin);
		*len = VARSIZE(bin) - VARHDRSZ;
		*fmt = 1;
	}
	else
	{
		res = OutputFunctionCall(&type->io.out.output_func, val);
		*len = 0;
		*fmt = 0;
	}
	return res;
}
예제 #8
0
파일: hstore_io.c 프로젝트: d/gpdb
Datum
hstore_from_record(PG_FUNCTION_ARGS)
{
	HeapTupleHeader rec;
	int4		buflen;
	HStore	   *out;
	Pairs	   *pairs;
	Oid			tupType;
	int32		tupTypmod;
	TupleDesc	tupdesc;
	HeapTupleData tuple;
	RecordIOData *my_extra;
	int			ncolumns;
	int			i,
				j;
	Datum	   *values;
	bool	   *nulls;

	if (PG_ARGISNULL(0))
	{
		Oid			argtype = get_fn_expr_argtype(fcinfo->flinfo, 0);

		/*
		 * have no tuple to look at, so the only source of type info is the
		 * argtype. The lookup_rowtype_tupdesc call below will error out if we
		 * don't have a known composite type oid here.
		 */
		tupType = argtype;
		tupTypmod = -1;

		rec = NULL;
	}
	else
	{
		rec = PG_GETARG_HEAPTUPLEHEADER(0);

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

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

	/*
	 * We arrange to look up the needed I/O info just once per series of
	 * calls, assuming the record type doesn't change underneath us.
	 */
	my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra;
	if (my_extra == NULL ||
		my_extra->ncolumns != ncolumns)
	{
		fcinfo->flinfo->fn_extra =
			MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
							   sizeof(RecordIOData) - sizeof(ColumnIOData)
							   + ncolumns * sizeof(ColumnIOData));
		my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra;
		my_extra->record_type = InvalidOid;
		my_extra->record_typmod = 0;
	}

	if (my_extra->record_type != tupType ||
		my_extra->record_typmod != tupTypmod)
	{
		MemSet(my_extra, 0,
			   sizeof(RecordIOData) - sizeof(ColumnIOData)
			   + ncolumns * sizeof(ColumnIOData));
		my_extra->record_type = tupType;
		my_extra->record_typmod = tupTypmod;
		my_extra->ncolumns = ncolumns;
	}

	pairs = palloc(ncolumns * sizeof(Pairs));

	if (rec)
	{
		/* Build a temporary HeapTuple control structure */
		tuple.t_len = HeapTupleHeaderGetDatumLength(rec);
		ItemPointerSetInvalid(&(tuple.t_self));
		//tuple.t_tableOid = InvalidOid;
		tuple.t_data = rec;

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

		/* Break down the tuple into fields */
		heap_deform_tuple(&tuple, tupdesc, values, nulls);
	}
	else
	{
		values = NULL;
		nulls = NULL;
	}

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

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

		pairs[j].key = NameStr(tupdesc->attrs[i]->attname);
		pairs[j].keylen = hstoreCheckKeyLen(strlen(NameStr(tupdesc->attrs[i]->attname)));

		if (!nulls || nulls[i])
		{
			pairs[j].val = NULL;
			pairs[j].vallen = 4;
			pairs[j].isnull = true;
			pairs[j].needfree = false;
			++j;
			continue;
		}

		/*
		 * Convert the column value to text
		 */
		if (column_info->column_type != column_type)
		{
			bool		typIsVarlena;

			getTypeOutputInfo(column_type,
							  &column_info->typiofunc,
							  &typIsVarlena);
			fmgr_info_cxt(column_info->typiofunc, &column_info->proc,
						  fcinfo->flinfo->fn_mcxt);
			column_info->column_type = column_type;
		}

		value = OutputFunctionCall(&column_info->proc, values[i]);

		pairs[j].val = value;
		pairs[j].vallen = hstoreCheckValLen(strlen(value));
		pairs[j].isnull = false;
		pairs[j].needfree = false;
		++j;
	}

	ncolumns = hstoreUniquePairs(pairs, j, &buflen);

	out = hstorePairs(pairs, ncolumns, buflen);

	ReleaseTupleDesc(tupdesc);

	PG_RETURN_POINTER(out);
}
예제 #9
0
/* ----------------
 *		printtup --- print a tuple in protocol 3.0
 * ----------------
 */
static void
printtup(TupleTableSlot *slot, DestReceiver *self)
{
	TupleDesc	typeinfo = slot->tts_tupleDescriptor;
	DR_printtup *myState = (DR_printtup *) self;
	StringInfoData buf;
	int			natts = typeinfo->natts;
	int			i;

	/* Set or update my derived attribute info, if needed */
	if (myState->attrinfo != typeinfo || myState->nattrs != natts)
		printtup_prepare_info(myState, typeinfo, natts);

	/* Make sure the tuple is fully deconstructed */
	slot_getallattrs(slot);

	/*
	 * Prepare a DataRow message
	 */
	pq_beginmessage(&buf, 'D');

	pq_sendint(&buf, natts, 2);

	/*
	 * send the attributes of this tuple
	 */
	for (i = 0; i < natts; ++i)
	{
		PrinttupAttrInfo *thisState = myState->myinfo + i;
		Datum		origattr = slot->tts_values[i],
					attr;

		if (slot->tts_isnull[i])
		{
			pq_sendint(&buf, -1, 4);
			continue;
		}

		/*
		 * If we have a toasted datum, forcibly detoast it here to avoid
		 * memory leakage inside the type's output routine.
		 */
		if (thisState->typisvarlena)
			attr = PointerGetDatum(PG_DETOAST_DATUM(origattr));
		else
			attr = origattr;

		if (thisState->format == 0)
		{
			/* Text output */
			char	   *outputstr;

			outputstr = OutputFunctionCall(&thisState->finfo, attr);
			pq_sendcountedtext(&buf, outputstr, strlen(outputstr), false);
			pfree(outputstr);
		}
		else
		{
			/* Binary output */
			bytea	   *outputbytes;

			outputbytes = SendFunctionCall(&thisState->finfo, attr);
			pq_sendint(&buf, VARSIZE(outputbytes) - VARHDRSZ, 4);
			pq_sendbytes(&buf, VARDATA(outputbytes),
						 VARSIZE(outputbytes) - VARHDRSZ);
			pfree(outputbytes);
		}

		/* Clean up detoasted copy, if any */
		if (DatumGetPointer(attr) != DatumGetPointer(origattr))
			pfree(DatumGetPointer(attr));
	}

	pq_endmessage(&buf);
}
예제 #10
0
/* ----------------
 *		printtup_20 --- print a tuple in protocol 2.0
 * ----------------
 */
static void
printtup_20(TupleTableSlot *slot, DestReceiver *self)
{
	TupleDesc	typeinfo = slot->tts_tupleDescriptor;
	DR_printtup *myState = (DR_printtup *) self;
	StringInfoData buf;
	int			natts = typeinfo->natts;
	int			i,
				j,
				k;

	/* Set or update my derived attribute info, if needed */
	if (myState->attrinfo != typeinfo || myState->nattrs != natts)
		printtup_prepare_info(myState, typeinfo, natts);

	/* Make sure the tuple is fully deconstructed */
	slot_getallattrs(slot);

	/*
	 * tell the frontend to expect new tuple data (in ASCII style)
	 */
	pq_beginmessage(&buf, 'D');

	/*
	 * send a bitmap of which attributes are not null
	 */
	j = 0;
	k = 1 << 7;
	for (i = 0; i < natts; ++i)
	{
		if (!slot->tts_isnull[i])
			j |= k;				/* set bit if not null */
		k >>= 1;
		if (k == 0)				/* end of byte? */
		{
			pq_sendint(&buf, j, 1);
			j = 0;
			k = 1 << 7;
		}
	}
	if (k != (1 << 7))			/* flush last partial byte */
		pq_sendint(&buf, j, 1);

	/*
	 * send the attributes of this tuple
	 */
	for (i = 0; i < natts; ++i)
	{
		PrinttupAttrInfo *thisState = myState->myinfo + i;
		Datum		origattr = slot->tts_values[i],
					attr;
		char	   *outputstr;

		if (slot->tts_isnull[i])
			continue;

		Assert(thisState->format == 0);

		/*
		 * If we have a toasted datum, forcibly detoast it here to avoid
		 * memory leakage inside the type's output routine.
		 */
		if (thisState->typisvarlena)
			attr = PointerGetDatum(PG_DETOAST_DATUM(origattr));
		else
			attr = origattr;

		outputstr = OutputFunctionCall(&thisState->finfo, attr);
		pq_sendcountedtext(&buf, outputstr, strlen(outputstr), true);
		pfree(outputstr);

		/* Clean up detoasted copy, if any */
		if (DatumGetPointer(attr) != DatumGetPointer(origattr))
			pfree(DatumGetPointer(attr));
	}

	pq_endmessage(&buf);
}
static void
grab_ExecutorEnd(QueryDesc * queryDesc)
{
	Datum           values[10];
	bool            nulls[10] = {false, false, false, false, false, false, false, false, false, false};
	Relation        dump_heap;
	RangeVar       *dump_table_rv;
	HeapTuple       tuple;
	Oid             namespaceId;

	/* lookup schema */
	namespaceId = GetSysCacheOid1(NAMESPACENAME, CStringGetDatum(EXTENSION_SCHEMA));
	if (OidIsValid(namespaceId)) {
		/* lookup table */
		if (OidIsValid(get_relname_relid(EXTENSION_LOG_TABLE, namespaceId))) {

			/* get table heap */
			dump_table_rv = makeRangeVar(EXTENSION_SCHEMA, EXTENSION_LOG_TABLE, -1);
			dump_heap = heap_openrv(dump_table_rv, RowExclusiveLock);

			/* transaction info */
			values[0] = Int32GetDatum(GetCurrentTransactionId());
			values[1] = Int32GetDatum(GetCurrentCommandId(false));
			values[2] = Int32GetDatum(MyProcPid);
			values[3] = Int32GetDatum(GetUserId());

			/* query timing */
			if (queryDesc->totaltime != NULL) {
				InstrEndLoop(queryDesc->totaltime);
				values[4] = TimestampGetDatum(
							      TimestampTzPlusMilliseconds(GetCurrentTimestamp(),
				  (queryDesc->totaltime->total * -1000.0)));
				values[5] = Float8GetDatum(queryDesc->totaltime->total);
			} else {
				nulls[4] = true;
				nulls[5] = true;
			}

			/* query command type */
			values[6] = Int32GetDatum(queryDesc->operation);

			/* query text */
			values[7] = CStringGetDatum(
				    cstring_to_text(queryDesc->sourceText));

			/* query params */
			if (queryDesc->params != NULL) {
				int             numParams = queryDesc->params->numParams;
				Oid             out_func_oid, ptype;
				Datum           pvalue;
				bool            isvarlena;
				FmgrInfo       *out_functions;

				bool            arr_nulls[numParams];
				size_t          arr_nelems = (size_t) numParams;
				Datum          *arr_val_elems = palloc(sizeof(Datum) * arr_nelems);
				Datum          *arr_typ_elems = palloc(sizeof(Datum) * arr_nelems);
				char            elem_val_byval, elem_val_align, elem_typ_byval,
				                elem_typ_align;
				int16           elem_val_len, elem_typ_len;
				int             elem_dims[1], elem_lbs[1];

				int paramno;

				/* init */
				out_functions = (FmgrInfo *) palloc(
					    (numParams) * sizeof(FmgrInfo));
				get_typlenbyvalalign(TEXTOID, &elem_val_len, &elem_val_byval, &elem_val_align);
				get_typlenbyvalalign(REGTYPEOID, &elem_typ_len, &elem_typ_byval, &elem_typ_align);
				elem_dims[0] = arr_nelems;
				elem_lbs[0] = 1;

				for (paramno = 0; paramno < numParams; paramno++) {
					pvalue = queryDesc->params->params[paramno].value;
					ptype = queryDesc->params->params[paramno].ptype;
					getTypeOutputInfo(ptype, &out_func_oid, &isvarlena);
					fmgr_info(out_func_oid, &out_functions[paramno]);

					arr_typ_elems[paramno] = ptype;

					arr_nulls[paramno] = true;
					if (!queryDesc->params->params[paramno].isnull) {
						arr_nulls[paramno] = false;
						arr_val_elems[paramno] = PointerGetDatum(
							    cstring_to_text(
									    OutputFunctionCall(&out_functions[paramno], pvalue)));
					}
				}
				values[8] = PointerGetDatum(
							 construct_md_array(
							      arr_val_elems,
								  arr_nulls,
									  1,
								  elem_dims,
								   elem_lbs,
								    TEXTOID,
							       elem_val_len,
							     elem_val_byval,
							   elem_val_align));
				values[9] = PointerGetDatum(
							    construct_array(
							      arr_typ_elems,
								 arr_nelems,
								 REGTYPEOID,
							       elem_typ_len,
							     elem_typ_byval,
							   elem_typ_align));

				pfree(out_functions);
				pfree(arr_val_elems);

			} else {
				nulls[8] = true;
				nulls[9] = true;
			}

			/* insert */
			tuple = heap_form_tuple(dump_heap->rd_att, values, nulls);
			simple_heap_insert(dump_heap, tuple);
			heap_close(dump_heap, RowExclusiveLock);
		}
	}
	if (prev_ExecutorEnd)
		prev_ExecutorEnd(queryDesc);
	else
		standard_ExecutorEnd(queryDesc);
}
예제 #12
0
파일: variant.c 프로젝트: decibel/variant
static char *
variant_out_int(FunctionCallInfo fcinfo, Variant input)
{
    VariantCache	*cache;
    bool					need_quote;
    char					*tmp;
    char					*org_cstring;
    StringInfoData	outd;
    StringInfo		out = &outd;
    VariantInt		vi;

    Assert(fcinfo->flinfo->fn_strict); /* Must be strict */

    vi = make_variant_int(input, fcinfo, IOFunc_output);
    cache = GetCache(fcinfo);
    Assert(cache->formatted_name);

    /* Start building string */
    initStringInfo(out);
    appendStringInfoChar(out, '(');

    need_quote = false;
    for (tmp = cache->formatted_name; *tmp; tmp++)
    {
        char		ch = *tmp;

        if (ch == '"' || ch == '\\' ||
                ch == '(' || ch == ')' || ch == ',' ||
                isspace((unsigned char) ch))
        {
            need_quote = true;
            break;
        }
    }
    if(!need_quote)
        appendStringInfoString(out, cache->formatted_name);
    else
    {
        appendStringInfoChar(out, '"');
        for (tmp = cache->formatted_name; *tmp; tmp++)
        {
            char		ch = *tmp;

            if (ch == '"' || ch == '\\')
                appendStringInfoCharMacro(out, ch);
            appendStringInfoCharMacro(out, ch);
        }
        appendStringInfoChar(out, '"');
    }
    appendStringInfoChar(out, ',');

    if(!vi->isnull)
    {
        org_cstring = OutputFunctionCall(&cache->proc, vi->data);

        /*
         * Detect whether we need double quotes for this value
         *
         * Stolen then modified from record_out.
         */
        need_quote = (org_cstring[0] == '\0' ); /* force quotes for empty string */
        if( !need_quote )
        {
            for (tmp = org_cstring; *tmp; tmp++)
            {
                char		ch = *tmp;

                if (ch == '"' || ch == '\\' ||
                        ch == '(' || ch == ')' || ch == ',' ||
                        isspace((unsigned char) ch))
                {
                    need_quote = true;
                    break;
                }
            }
        }

        if (!need_quote)
            appendStringInfoString(out, org_cstring);
        else
        {
            appendStringInfoChar(out, '"');
            for (tmp = org_cstring; *tmp; tmp++)
            {
                char		ch = *tmp;

                if (ch == '"' || ch == '\\')
                    appendStringInfoCharMacro(out, ch);
                appendStringInfoCharMacro(out, ch);
            }
            appendStringInfoChar(out, '"');
        }
    }

    appendStringInfoChar(out, ')');

    return out->data;
}
예제 #13
0
/* ----------------
 *		printtup --- print a tuple in protocol 3.0
 * ----------------
 */
static void
printtup(TupleTableSlot *slot, DestReceiver *self)
{
	TupleDesc	typeinfo = slot->tts_tupleDescriptor;
	DR_printtup *myState = (DR_printtup *) self;
	StringInfoData buf;
	int			natts = typeinfo->natts;
	int			i;

	/* Set or update my derived attribute info, if needed */
	if (myState->attrinfo != typeinfo || myState->nattrs != natts)
		printtup_prepare_info(myState, typeinfo, natts);

	/* Make sure the tuple is fully deconstructed */
	slot_getallattrs(slot);

	/*
	 * Prepare a DataRow message
	 */
	pq_beginmessage(&buf, 'D');

	pq_sendint(&buf, natts, 2);

	/*
	 * send the attributes of this tuple
	 */
	for (i = 0; i < natts; ++i)
	{
		PrinttupAttrInfo *thisState = myState->myinfo + i;
		Datum		origattr = slot->tts_values[i],
					attr;

		if (slot->tts_isnull[i])
		{
			pq_sendint(&buf, -1, 4);
			continue;
		}

		/*
		 * If we have a toasted datum, forcibly detoast it here to avoid
		 * memory leakage inside the type's output routine.
		 *
		 * Here we catch undefined bytes in tuples that are returned to the
		 * client without hitting disk; see comments at the related check in
		 * PageAddItem().  Whether to test before or after detoast is somewhat
		 * arbitrary, as is whether to test external/compressed data at all.
		 * Undefined bytes in the pre-toast datum will have triggered Valgrind
		 * errors in the compressor or toaster; any error detected here for
		 * such datums would indicate an (unlikely) bug in a type-independent
		 * facility.  Therefore, this test is most useful for uncompressed,
		 * non-external datums.
		 *
		 * We don't presently bother checking non-varlena datums for undefined
		 * data.  PageAddItem() does check them.
		 */
		if (thisState->typisvarlena)
		{
			VALGRIND_CHECK_MEM_IS_DEFINED(origattr, VARSIZE_ANY(origattr));

			attr = PointerGetDatum(PG_DETOAST_DATUM(origattr));
		}
		else
			attr = origattr;

		if (thisState->format == 0)
		{
			/* Text output */
			char	   *outputstr;

			outputstr = OutputFunctionCall(&thisState->finfo, attr);
			pq_sendcountedtext(&buf, outputstr, strlen(outputstr), false);
			pfree(outputstr);
		}
		else
		{
			/* Binary output */
			bytea	   *outputbytes;

			outputbytes = SendFunctionCall(&thisState->finfo, attr);
			pq_sendint(&buf, VARSIZE(outputbytes) - VARHDRSZ, 4);
			pq_sendbytes(&buf, VARDATA(outputbytes),
						 VARSIZE(outputbytes) - VARHDRSZ);
			pfree(outputbytes);
		}

		/* Clean up detoasted copy, if any */
		if (DatumGetPointer(attr) != DatumGetPointer(origattr))
			pfree(DatumGetPointer(attr));
	}

	pq_endmessage(&buf);
}
예제 #14
0
/*
 * TupleToBytes
 *
 * Serialize a tuple to bytes
 */
StringInfo
TupleToBytes(BufferPrinterState *self, TupleTableSlot *slot)
{
	StringInfo buf = makeStringInfo();
	TupleDesc	typeinfo = slot->tts_tupleDescriptor;
	int			natts = typeinfo->natts;
	int			i;
	int			len = 0;

	/* Make sure the tuple is fully deconstructed */
	slot_getallattrs(slot);

	/*
	 * Prepare a DataRow message
	 */
	pq_beginmessage(buf, 'D');
	len += 1;

	pq_sendint(buf, natts, 2);
	len+= 2;

	/*
	 * send the attributes of this tuple
	 */
	for (i = 0; i < natts; ++i)
	{
		BufferPrinterAttrInfo *thisState = self->typeinfo + i;
		Datum		origattr = slot->tts_values[i],
					attr;

		if (slot->tts_isnull[i])
		{
			pq_sendint(buf, -1, 4);
			len += 4;
			continue;
		}

		/*
		 * If we have a toasted datum, forcibly detoast it here to avoid
		 * memory leakage inside the type's output routine.
		 */
		if (thisState->typisvarlena)
			attr = PointerGetDatum(PG_DETOAST_DATUM(origattr));
		else
			attr = origattr;

		if (thisState->format == 0)
		{
			/* Text output */
			char	   *outputstr;

			outputstr = OutputFunctionCall(&thisState->finfo, attr);
			pq_sendcountedtext(buf, outputstr, strlen(outputstr), false);
			len += strlen(outputstr);
			pfree(outputstr);
		}
		else
		{
			/* Binary output */
			bytea	   *outputbytes;
			int size;
			outputbytes = SendFunctionCall(&thisState->finfo, attr);
			pq_sendint(buf, VARSIZE(outputbytes) - VARHDRSZ, 4);
			len += 4;

			size = VARSIZE(outputbytes) - VARHDRSZ;
			pq_sendbytes(buf, VARDATA(outputbytes), size);
			len += size;

			pfree(outputbytes);
		}

		/* Clean up detoasted copy, if any */
		if (DatumGetPointer(attr) != DatumGetPointer(origattr))
			pfree(DatumGetPointer(attr));
	}

	return buf;
}
예제 #15
0
파일: printtup.c 프로젝트: 0x0FFF/postgres
/* ----------------
 *		printtup_20 --- print a tuple in protocol 2.0
 * ----------------
 */
static bool
printtup_20(TupleTableSlot *slot, DestReceiver *self)
{
	TupleDesc	typeinfo = slot->tts_tupleDescriptor;
	DR_printtup *myState = (DR_printtup *) self;
	MemoryContext oldcontext;
	StringInfoData buf;
	int			natts = typeinfo->natts;
	int			i,
				j,
				k;

	/* Set or update my derived attribute info, if needed */
	if (myState->attrinfo != typeinfo || myState->nattrs != natts)
		printtup_prepare_info(myState, typeinfo, natts);

	/* Make sure the tuple is fully deconstructed */
	slot_getallattrs(slot);

	/* Switch into per-row context so we can recover memory below */
	oldcontext = MemoryContextSwitchTo(myState->tmpcontext);

	/*
	 * tell the frontend to expect new tuple data (in ASCII style)
	 */
	pq_beginmessage(&buf, 'D');

	/*
	 * send a bitmap of which attributes are not null
	 */
	j = 0;
	k = 1 << 7;
	for (i = 0; i < natts; ++i)
	{
		if (!slot->tts_isnull[i])
			j |= k;				/* set bit if not null */
		k >>= 1;
		if (k == 0)				/* end of byte? */
		{
			pq_sendint(&buf, j, 1);
			j = 0;
			k = 1 << 7;
		}
	}
	if (k != (1 << 7))			/* flush last partial byte */
		pq_sendint(&buf, j, 1);

	/*
	 * send the attributes of this tuple
	 */
	for (i = 0; i < natts; ++i)
	{
		PrinttupAttrInfo *thisState = myState->myinfo + i;
		Datum		attr = slot->tts_values[i];
		char	   *outputstr;

		if (slot->tts_isnull[i])
			continue;

		Assert(thisState->format == 0);

		outputstr = OutputFunctionCall(&thisState->finfo, attr);
		pq_sendcountedtext(&buf, outputstr, strlen(outputstr), true);
	}

	pq_endmessage(&buf);

	/* Return to caller's context, and flush row's temporary memory */
	MemoryContextSwitchTo(oldcontext);
	MemoryContextReset(myState->tmpcontext);

	return true;
}
예제 #16
0
/*
 * record_out		- output routine for any composite type.
 */
Datum
record_out(PG_FUNCTION_ARGS)
{
	HeapTupleHeader rec = PG_GETARG_HEAPTUPLEHEADER(0);
	Oid			tupType;
	int32		tupTypmod;
	TupleDesc	tupdesc;
	HeapTupleData tuple;
	RecordIOData *my_extra;
	bool		needComma = false;
	int			ncolumns;
	int			i;
	Datum	   *values;
	bool	   *nulls;
	StringInfoData buf;

	/* Extract type info from the tuple itself */
	tupType = HeapTupleHeaderGetTypeId(rec);
	tupTypmod = HeapTupleHeaderGetTypMod(rec);
	tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
	ncolumns = tupdesc->natts;

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

	/* Break down the tuple into fields */
	heap_deform_tuple(&tuple, tupdesc, values, nulls);

	/* And build the result string */
	initStringInfo(&buf);

	appendStringInfoChar(&buf, '(');

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

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

		if (needComma)
			appendStringInfoChar(&buf, ',');
		needComma = true;

		if (nulls[i])
		{
			/* emit nothing... */
			continue;
		}

		/*
		 * Convert the column value to text
		 */
		if (column_info->column_type != column_type)
		{
			bool		typIsVarlena;

			getTypeOutputInfo(column_type,
							  &column_info->typiofunc,
							  &typIsVarlena);
			fmgr_info_cxt(column_info->typiofunc, &column_info->proc,
						  fcinfo->flinfo->fn_mcxt);
			column_info->column_type = column_type;
		}

		value = OutputFunctionCall(&column_info->proc, values[i]);

		/* Detect whether we need double quotes for this value */
		nq = (value[0] == '\0');	/* force quotes for empty string */
		for (tmp = value; *tmp; tmp++)
		{
			char		ch = *tmp;

			if (ch == '"' || ch == '\\' ||
				ch == '(' || ch == ')' || ch == ',' ||
				isspace((unsigned char) ch))
			{
				nq = true;
				break;
			}
		}

		/* And emit the string */
		if (nq)
			appendStringInfoChar(&buf, '"');
		for (tmp = value; *tmp; tmp++)
		{
			char		ch = *tmp;

			if (ch == '"' || ch == '\\')
				appendStringInfoChar(&buf, ch);
			appendStringInfoChar(&buf, ch);
		}
		if (nq)
			appendStringInfoChar(&buf, '"');
	}

	appendStringInfoChar(&buf, ')');

	pfree(values);
	pfree(nulls);
	ReleaseTupleDesc(tupdesc);

	PG_RETURN_CSTRING(buf.data);
}
예제 #17
0
Datum serialize_array(PG_FUNCTION_ARGS)
{
	ArrayType  *v = PG_GETARG_ARRAYTYPE_P(0);
	Oid		 element_type = ARR_ELEMTYPE(v);
	int16		typlen;
	bool		typbyval;
	char		typalign;
	char		typdelim;
	char	   *p, *value;
	char 		type_category;
	bool		needComma = false;

	bits8	  *bitmap;
	int		 bitmask;
	int		 nitems, i;
	int		 ndim, *dims;

	Oid			typioparam, typiofunc;
	HeapTuple 	type_tuple;
	FmgrInfo	proc, flinfo;

	StringInfoData buf;

//	FILE* log;

//	log = fopen("/var/lib/postgresql/serializer.log", "a");

//	fprintf(log, "Doing serialize_array\n");
//	fflush(log);

	/*
	 * Get info about element type, including its output conversion proc
	 */
	get_type_io_data(element_type, IOFunc_output,
					 &typlen, &typbyval,
					 &typalign, &typdelim,
					 &typioparam, &typiofunc);

	fmgr_info_cxt( typiofunc, &proc, fcinfo->flinfo->fn_mcxt );

	ndim = ARR_NDIM(v);
	dims = ARR_DIMS(v);
	nitems = ArrayGetNItems(ndim, dims);

	if( ndim > 1 )
		elog( ERROR, "multidimensional arrays doesn't supported" );

	p = ARR_DATA_PTR(v);
	bitmap = ARR_NULLBITMAP(v);
	bitmask = 1;

	/* obtain type information from pg_catalog */
	type_tuple = SearchSysCache1( TYPEOID, ObjectIdGetDatum(element_type) );
	if (!HeapTupleIsValid( type_tuple ))
		elog(ERROR, "cache lookup failed for relation %u", element_type);

	type_category = ((Form_pg_type) GETSTRUCT( type_tuple ))->typcategory;

	ReleaseSysCache( type_tuple );

	/* Build the result string */
	initStringInfo(&buf);

	appendStringInfoChar(&buf, '[');
	for (i = 0; i < nitems; i++)
	{
		if (needComma)
			appendStringInfoChar(&buf, ',');
		needComma = true;

		/* Get source element, checking for NULL */
		if (bitmap && (*bitmap & bitmask) == 0)
		{
			// append null
			appendStringInfoString(&buf, "null");
		}
		else
		{
			/* get item value and advance array data pointer */
			Datum itemvalue = fetch_att(p, typbyval, typlen);
			p = att_addlength_pointer(p, typlen, p);
			p = (char *) att_align_nominal(p, typalign);

			//------------------------
			switch( type_category )
			{
				// http://www.postgresql.org/docs/current/static/catalog-pg-type.html#CATALOG-TYPCATEGORY-TABLE

				case 'A': //array - impossible case
				break;

				case 'C': //composite
					//call to serialize_record( ... )
					MemSet( &flinfo, 0, sizeof( flinfo ) );
					flinfo.fn_addr = serialize_record;
					flinfo.fn_nargs = 1;
					flinfo.fn_mcxt = fcinfo->flinfo->fn_mcxt;

					value = PG_TEXT_DATUM_GET_CSTR( FunctionCall1( &flinfo, itemvalue ) );

					appendStringInfoString(&buf, value);
				break;

				case 'N': //numeric

					// get column text value
					value = OutputFunctionCall( &proc, itemvalue );

					appendStringInfoString(&buf, value);
				break;

				default: //another

					// get column text value
					value = OutputFunctionCall( &proc, itemvalue );

					appendStringInfoQuotedString(&buf, value);
			}
		}

		/* advance bitmap pointer if any */
		if (bitmap)
		{
			bitmask <<= 1;
			if (bitmask == 0x100)
			{
				bitmap++;
				bitmask = 1;
			}
		}
	}
	appendStringInfoChar(&buf, ']');

//	fclose(log);

	//PG_RETURN_CSTRING(retval);
	PG_RETURN_TEXT_P( PG_CSTR_GET_TEXT( buf.data ) );
}
예제 #18
0
파일: printtup.c 프로젝트: 0x0FFF/postgres
/* ----------------
 *		printtup --- print a tuple in protocol 3.0
 * ----------------
 */
static bool
printtup(TupleTableSlot *slot, DestReceiver *self)
{
	TupleDesc	typeinfo = slot->tts_tupleDescriptor;
	DR_printtup *myState = (DR_printtup *) self;
	MemoryContext oldcontext;
	StringInfoData buf;
	int			natts = typeinfo->natts;
	int			i;

	/* Set or update my derived attribute info, if needed */
	if (myState->attrinfo != typeinfo || myState->nattrs != natts)
		printtup_prepare_info(myState, typeinfo, natts);

	/* Make sure the tuple is fully deconstructed */
	slot_getallattrs(slot);

	/* Switch into per-row context so we can recover memory below */
	oldcontext = MemoryContextSwitchTo(myState->tmpcontext);

	/*
	 * Prepare a DataRow message (note buffer is in per-row context)
	 */
	pq_beginmessage(&buf, 'D');

	pq_sendint(&buf, natts, 2);

	/*
	 * send the attributes of this tuple
	 */
	for (i = 0; i < natts; ++i)
	{
		PrinttupAttrInfo *thisState = myState->myinfo + i;
		Datum		attr = slot->tts_values[i];

		if (slot->tts_isnull[i])
		{
			pq_sendint(&buf, -1, 4);
			continue;
		}

		/*
		 * Here we catch undefined bytes in datums that are returned to the
		 * client without hitting disk; see comments at the related check in
		 * PageAddItem().  This test is most useful for uncompressed,
		 * non-external datums, but we're quite likely to see such here when
		 * testing new C functions.
		 */
		if (thisState->typisvarlena)
			VALGRIND_CHECK_MEM_IS_DEFINED(DatumGetPointer(attr),
										  VARSIZE_ANY(attr));

		if (thisState->format == 0)
		{
			/* Text output */
			char	   *outputstr;

			outputstr = OutputFunctionCall(&thisState->finfo, attr);
			pq_sendcountedtext(&buf, outputstr, strlen(outputstr), false);
		}
		else
		{
			/* Binary output */
			bytea	   *outputbytes;

			outputbytes = SendFunctionCall(&thisState->finfo, attr);
			pq_sendint(&buf, VARSIZE(outputbytes) - VARHDRSZ, 4);
			pq_sendbytes(&buf, VARDATA(outputbytes),
						 VARSIZE(outputbytes) - VARHDRSZ);
		}
	}

	pq_endmessage(&buf);

	/* Return to caller's context, and flush row's temporary memory */
	MemoryContextSwitchTo(oldcontext);
	MemoryContextReset(myState->tmpcontext);

	return true;
}
예제 #19
0
/*
 * Extract all item values from a BRIN index page
 *
 * Usage: SELECT * FROM brin_page_items(get_raw_page('idx', 1), 'idx'::regclass);
 */
Datum
brin_page_items(PG_FUNCTION_ARGS)
{
	brin_page_state *state;
	FuncCallContext *fctx;

	if (!superuser())
		ereport(ERROR,
				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
				 (errmsg("must be superuser to use raw page functions"))));

	if (SRF_IS_FIRSTCALL())
	{
		bytea	   *raw_page = PG_GETARG_BYTEA_P(0);
		Oid			indexRelid = PG_GETARG_OID(1);
		Page		page;
		TupleDesc	tupdesc;
		MemoryContext mctx;
		Relation	indexRel;
		AttrNumber	attno;

		/* minimally verify the page we got */
		page = verify_brin_page(raw_page, BRIN_PAGETYPE_REGULAR, "regular");

		/* create a function context for cross-call persistence */
		fctx = SRF_FIRSTCALL_INIT();

		/* switch to memory context appropriate for multiple function calls */
		mctx = MemoryContextSwitchTo(fctx->multi_call_memory_ctx);

		/* Build a tuple descriptor for our result type */
		if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
			elog(ERROR, "return type must be a row type");

		indexRel = index_open(indexRelid, AccessShareLock);

		state = palloc(offsetof(brin_page_state, columns) +
			  sizeof(brin_column_state) * RelationGetDescr(indexRel)->natts);

		state->bdesc = brin_build_desc(indexRel);
		state->page = page;
		state->offset = FirstOffsetNumber;
		state->unusedItem = false;
		state->done = false;
		state->dtup = NULL;

		/*
		 * Initialize output functions for all indexed datatypes; simplifies
		 * calling them later.
		 */
		for (attno = 1; attno <= state->bdesc->bd_tupdesc->natts; attno++)
		{
			Oid			output;
			bool		isVarlena;
			BrinOpcInfo *opcinfo;
			int			i;
			brin_column_state *column;

			opcinfo = state->bdesc->bd_info[attno - 1];
			column = palloc(offsetof(brin_column_state, outputFn) +
							sizeof(FmgrInfo) * opcinfo->oi_nstored);

			column->nstored = opcinfo->oi_nstored;
			for (i = 0; i < opcinfo->oi_nstored; i++)
			{
				getTypeOutputInfo(opcinfo->oi_typcache[i]->type_id, &output, &isVarlena);
				fmgr_info(output, &column->outputFn[i]);
			}

			state->columns[attno - 1] = column;
		}

		index_close(indexRel, AccessShareLock);

		fctx->user_fctx = state;
		fctx->tuple_desc = BlessTupleDesc(tupdesc);

		MemoryContextSwitchTo(mctx);
	}

	fctx = SRF_PERCALL_SETUP();
	state = fctx->user_fctx;

	if (!state->done)
	{
		HeapTuple	result;
		Datum		values[7];
		bool		nulls[7];

		/*
		 * This loop is called once for every attribute of every tuple in the
		 * page.  At the start of a tuple, we get a NULL dtup; that's our
		 * signal for obtaining and decoding the next one.  If that's not the
		 * case, we output the next attribute.
		 */
		if (state->dtup == NULL)
		{
			BrinTuple  *tup;
			MemoryContext mctx;
			ItemId		itemId;

			/* deformed tuple must live across calls */
			mctx = MemoryContextSwitchTo(fctx->multi_call_memory_ctx);

			/* verify item status: if there's no data, we can't decode */
			itemId = PageGetItemId(state->page, state->offset);
			if (ItemIdIsUsed(itemId))
			{
				tup = (BrinTuple *) PageGetItem(state->page,
												PageGetItemId(state->page,
															  state->offset));
				state->dtup = brin_deform_tuple(state->bdesc, tup);
				state->attno = 1;
				state->unusedItem = false;
			}
			else
				state->unusedItem = true;

			MemoryContextSwitchTo(mctx);
		}
		else
			state->attno++;

		MemSet(nulls, 0, sizeof(nulls));

		if (state->unusedItem)
		{
			values[0] = UInt16GetDatum(state->offset);
			nulls[1] = true;
			nulls[2] = true;
			nulls[3] = true;
			nulls[4] = true;
			nulls[5] = true;
			nulls[6] = true;
		}
		else
		{
			int			att = state->attno - 1;

			values[0] = UInt16GetDatum(state->offset);
			values[1] = UInt32GetDatum(state->dtup->bt_blkno);
			values[2] = UInt16GetDatum(state->attno);
			values[3] = BoolGetDatum(state->dtup->bt_columns[att].bv_allnulls);
			values[4] = BoolGetDatum(state->dtup->bt_columns[att].bv_hasnulls);
			values[5] = BoolGetDatum(state->dtup->bt_placeholder);
			if (!state->dtup->bt_columns[att].bv_allnulls)
			{
				BrinValues *bvalues = &state->dtup->bt_columns[att];
				StringInfoData s;
				bool		first;
				int			i;

				initStringInfo(&s);
				appendStringInfoChar(&s, '{');

				first = true;
				for (i = 0; i < state->columns[att]->nstored; i++)
				{
					char	   *val;

					if (!first)
						appendStringInfoString(&s, " .. ");
					first = false;
					val = OutputFunctionCall(&state->columns[att]->outputFn[i],
											 bvalues->bv_values[i]);
					appendStringInfoString(&s, val);
					pfree(val);
				}
				appendStringInfoChar(&s, '}');

				values[6] = CStringGetTextDatum(s.data);
				pfree(s.data);
			}
			else
			{
				nulls[6] = true;
			}
		}

		result = heap_form_tuple(fctx->tuple_desc, values, nulls);

		/*
		 * If the item was unused, jump straight to the next one; otherwise,
		 * the only cleanup needed here is to set our signal to go to the next
		 * tuple in the following iteration, by freeing the current one.
		 */
		if (state->unusedItem)
			state->offset = OffsetNumberNext(state->offset);
		else if (state->attno >= state->bdesc->bd_tupdesc->natts)
		{
			pfree(state->dtup);
			state->dtup = NULL;
			state->offset = OffsetNumberNext(state->offset);
		}

		/*
		 * If we're beyond the end of the page, set flag to end the function
		 * in the following iteration.
		 */
		if (state->offset > PageGetMaxOffsetNumber(state->page))
			state->done = true;

		SRF_RETURN_NEXT(fctx, HeapTupleGetDatum(result));
	}

	brin_free_desc(state->bdesc);

	SRF_RETURN_DONE(fctx);
}
예제 #20
0
/*
 * Extract all item values from a BRIN index page
 *
 * Usage: SELECT * FROM brin_page_items(get_raw_page('idx', 1), 'idx'::regclass);
 */
Datum
brin_page_items(PG_FUNCTION_ARGS)
{
    bytea	   *raw_page = PG_GETARG_BYTEA_P(0);
    Oid			indexRelid = PG_GETARG_OID(1);
    ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
    TupleDesc	tupdesc;
    MemoryContext oldcontext;
    Tuplestorestate *tupstore;
    Relation	indexRel;
    brin_column_state **columns;
    BrinDesc   *bdesc;
    BrinMemTuple *dtup;
    Page		page;
    OffsetNumber offset;
    AttrNumber	attno;
    bool		unusedItem;

    if (!superuser())
        ereport(ERROR,
                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                 (errmsg("must be superuser to use raw page functions"))));

    /* check to see if caller supports us returning a tuplestore */
    if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
        ereport(ERROR,
                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                 errmsg("set-valued function called in context that cannot accept a set")));
    if (!(rsinfo->allowedModes & SFRM_Materialize) ||
            rsinfo->expectedDesc == NULL)
        ereport(ERROR,
                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                 errmsg("materialize mode required, but it is not allowed in this context")));

    /* Build a tuple descriptor for our result type */
    if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
        elog(ERROR, "return type must be a row type");

    /* Build tuplestore to hold the result rows */
    oldcontext = MemoryContextSwitchTo(rsinfo->econtext->ecxt_per_query_memory);

    tupstore = tuplestore_begin_heap(true, false, work_mem);
    rsinfo->returnMode = SFRM_Materialize;
    rsinfo->setResult = tupstore;
    rsinfo->setDesc = tupdesc;

    MemoryContextSwitchTo(oldcontext);

    indexRel = index_open(indexRelid, AccessShareLock);
    bdesc = brin_build_desc(indexRel);

    /* minimally verify the page we got */
    page = verify_brin_page(raw_page, BRIN_PAGETYPE_REGULAR, "regular");

    /*
     * Initialize output functions for all indexed datatypes; simplifies
     * calling them later.
     */
    columns = palloc(sizeof(brin_column_state *) * RelationGetDescr(indexRel)->natts);
    for (attno = 1; attno <= bdesc->bd_tupdesc->natts; attno++)
    {
        Oid			output;
        bool		isVarlena;
        BrinOpcInfo *opcinfo;
        int			i;
        brin_column_state *column;

        opcinfo = bdesc->bd_info[attno - 1];
        column = palloc(offsetof(brin_column_state, outputFn) +
                        sizeof(FmgrInfo) * opcinfo->oi_nstored);

        column->nstored = opcinfo->oi_nstored;
        for (i = 0; i < opcinfo->oi_nstored; i++)
        {
            getTypeOutputInfo(opcinfo->oi_typcache[i]->type_id, &output, &isVarlena);
            fmgr_info(output, &column->outputFn[i]);
        }

        columns[attno - 1] = column;
    }

    offset = FirstOffsetNumber;
    unusedItem = false;
    dtup = NULL;
    for (;;)
    {
        Datum		values[7];
        bool		nulls[7];

        /*
         * This loop is called once for every attribute of every tuple in the
         * page.  At the start of a tuple, we get a NULL dtup; that's our
         * signal for obtaining and decoding the next one.  If that's not the
         * case, we output the next attribute.
         */
        if (dtup == NULL)
        {
            ItemId		itemId;

            /* verify item status: if there's no data, we can't decode */
            itemId = PageGetItemId(page, offset);
            if (ItemIdIsUsed(itemId))
            {
                dtup = brin_deform_tuple(bdesc,
                                         (BrinTuple *) PageGetItem(page, itemId));
                attno = 1;
                unusedItem = false;
            }
            else
                unusedItem = true;
        }
        else
            attno++;

        MemSet(nulls, 0, sizeof(nulls));

        if (unusedItem)
        {
            values[0] = UInt16GetDatum(offset);
            nulls[1] = true;
            nulls[2] = true;
            nulls[3] = true;
            nulls[4] = true;
            nulls[5] = true;
            nulls[6] = true;
        }
        else
        {
            int			att = attno - 1;

            values[0] = UInt16GetDatum(offset);
            values[1] = UInt32GetDatum(dtup->bt_blkno);
            values[2] = UInt16GetDatum(attno);
            values[3] = BoolGetDatum(dtup->bt_columns[att].bv_allnulls);
            values[4] = BoolGetDatum(dtup->bt_columns[att].bv_hasnulls);
            values[5] = BoolGetDatum(dtup->bt_placeholder);
            if (!dtup->bt_columns[att].bv_allnulls)
            {
                BrinValues *bvalues = &dtup->bt_columns[att];
                StringInfoData s;
                bool		first;
                int			i;

                initStringInfo(&s);
                appendStringInfoChar(&s, '{');

                first = true;
                for (i = 0; i < columns[att]->nstored; i++)
                {
                    char	   *val;

                    if (!first)
                        appendStringInfoString(&s, " .. ");
                    first = false;
                    val = OutputFunctionCall(&columns[att]->outputFn[i],
                                             bvalues->bv_values[i]);
                    appendStringInfoString(&s, val);
                    pfree(val);
                }
                appendStringInfoChar(&s, '}');

                values[6] = CStringGetTextDatum(s.data);
                pfree(s.data);
            }
            else
            {
                nulls[6] = true;
            }
        }

        tuplestore_putvalues(tupstore, tupdesc, values, nulls);

        /*
         * If the item was unused, jump straight to the next one; otherwise,
         * the only cleanup needed here is to set our signal to go to the next
         * tuple in the following iteration, by freeing the current one.
         */
        if (unusedItem)
            offset = OffsetNumberNext(offset);
        else if (attno >= bdesc->bd_tupdesc->natts)
        {
            pfree(dtup);
            dtup = NULL;
            offset = OffsetNumberNext(offset);
        }

        /*
         * If we're beyond the end of the page, we're done.
         */
        if (offset > PageGetMaxOffsetNumber(page))
            break;
    }

    /* clean up and return the tuplestore */
    brin_free_desc(bdesc);
    tuplestore_donestoring(tupstore);
    index_close(indexRel, AccessShareLock);

    return (Datum) 0;
}
예제 #21
0
/*
 * CopyOps_BuildOneRowTo
 * Build one row message to be sent to remote nodes through COPY protocol
 */
char *
CopyOps_BuildOneRowTo(TupleDesc tupdesc, Datum *values, bool *nulls, int *len)
{
	bool		need_delim = false;
	char	   *res;
	int			i;
	FmgrInfo   *out_functions;
	Form_pg_attribute *attr = tupdesc->attrs;
	StringInfo	buf;

	/* Get info about the columns we need to process. */
	out_functions = (FmgrInfo *) palloc(tupdesc->natts * sizeof(FmgrInfo));
	for (i = 0; i < tupdesc->natts; i++)
	{
		Oid			out_func_oid;
		bool		isvarlena;

		/* Do not need any information for dropped attributes */
		if (attr[i]->attisdropped)
			continue;

		getTypeOutputInfo(attr[i]->atttypid,
						  &out_func_oid,
						  &isvarlena);
		fmgr_info(out_func_oid, &out_functions[i]);
	}

	/* Initialize output buffer */
	buf = makeStringInfo();

	for (i = 0; i < tupdesc->natts; i++)
	{
		Datum		value = values[i];
		bool		isnull = nulls[i];

		/* Do not need any information for dropped attributes */
		if (attr[i]->attisdropped)
			continue;

		if (need_delim)
			appendStringInfoCharMacro(buf, COPYOPS_DELIMITER);
		need_delim = true;

		if (isnull)
		{
			/* Null print value to client */
			appendBinaryStringInfo(buf, "\\N", strlen("\\N"));
		}
		else
		{
			char *string;
			string = OutputFunctionCall(&out_functions[i],
										value);
			attribute_out_text(buf, string);
			pfree(string);
		}
	}

	/* Record length of message */
	*len = buf->len;
	res = pstrdup(buf->data);
	pfree(out_functions);
	pfree(buf->data);
	pfree(buf);
	return res;
}