src/pl/tcl/pltcl.c
static HeapTuple
pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj **kvObjv, int kvObjc,
						 pltcl_call_state *call_state)
{
	HeapTuple	tuple;
	TupleDesc	tupdesc;
	AttInMetadata *attinmeta;
	char	  **values;
	int			i;

	if (call_state->ret_tupdesc)
	{
		tupdesc = call_state->ret_tupdesc;
		attinmeta = call_state->attinmeta;
	}
	else if (call_state->trigdata)
	{
		tupdesc = RelationGetDescr(call_state->trigdata->tg_relation);
		attinmeta = TupleDescGetAttInMetadata(tupdesc);
	}
	else
	{
		elog(ERROR, "PL/Tcl function does not return a tuple");
		tupdesc = NULL;			/* keep compiler quiet */
		attinmeta = NULL;
	}

	values = (char **) palloc0(tupdesc->natts * sizeof(char *));

	if (kvObjc % 2 != 0)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("column name/value list must have even number of elements")));

	for (i = 0; i < kvObjc; i += 2)
	{
		char	   *fieldName = utf_u2e(Tcl_GetString(kvObjv[i]));
		int			attn = SPI_fnumber(tupdesc, fieldName);

		/*
		 * We silently ignore ".tupno", if it's present but doesn't match any
		 * actual output column.  This allows direct use of a row returned by
		 * pltcl_set_tuple_values().
		 */
		if (attn == SPI_ERROR_NOATTRIBUTE)
		{
			if (strcmp(fieldName, ".tupno") == 0)
				continue;
			ereport(ERROR,
					(errcode(ERRCODE_UNDEFINED_COLUMN),
					 errmsg("column name/value list contains nonexistent column name \"%s\"",
							fieldName)));
		}

		if (attn <= 0)
			ereport(ERROR,
					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
					 errmsg("cannot set system attribute \"%s\"",
							fieldName)));

		if (TupleDescAttr(tupdesc, attn - 1)->attgenerated)
			ereport(ERROR,
					(errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
					 errmsg("cannot set generated column \"%s\"",
							fieldName)));

		values[attn - 1] = utf_u2e(Tcl_GetString(kvObjv[i + 1]));
	}

	tuple = BuildTupleFromCStrings(attinmeta, values);

	/* if result type is domain-over-composite, check domain constraints */
	if (call_state->prodesc->fn_retisdomain)
		domain_check(HeapTupleGetDatum(tuple), false,
					 call_state->prodesc->result_typid,
					 &call_state->prodesc->domain_info,
					 call_state->prodesc->fn_cxt);

	return tuple;
}
/**********************************************************************
 * pltcl_build_tuple_result() - Build a tuple of function's result rowtype
 *				  from a Tcl list of column names and values
 *
 * In a trigger function, we build a tuple of the trigger table's rowtype.
 *
 * Note: this function leaks memory.  Even if we made it clean up its own
 * mess, there's no way to prevent the datatype input functions it calls
 * from leaking.  Run it in a short-lived context, unless we're about to
 * exit the procedure anyway.
 **********************************************************************/
Build a tuple of function's result rowtype
from a Tcl list of column names and values

In a trigger function, we build a tuple of the trigger table's rowtype.

this function leaks memory.  Even if we made it clean up its own
mess, there's no way to prevent the datatype input functions it calls
from leaking.  Run it in a short-lived context, unless we're about to
exit the procedure anyway.
Build a tuple of function ' s result rowtype from a Tcl list of column names and values In a trigger function we build a tuple of the trigger table ' s rowtype . this function leaks memory . Even if we made it clean up its own mess there ' s no way to prevent the datatype input functions it calls from leaking . Run it in a short - lived context unless we ' re about to exit the procedure anyway .
static HeapTuple
pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj **kvObjv, int kvObjc,
						 pltcl_call_state *call_state)
{
	HeapTuple	tuple;
	TupleDesc	tupdesc;
	AttInMetadata *attinmeta;
	char	  **values;
	int			i;
	if (call_state->ret_tupdesc)
	{
		tupdesc = call_state->ret_tupdesc;
		attinmeta = call_state->attinmeta;
	}
	else if (call_state->trigdata)
	{
		tupdesc = RelationGetDescr(call_state->trigdata->tg_relation);
		attinmeta = TupleDescGetAttInMetadata(tupdesc);
	}
	else
	{
		elog(ERROR, "PL/Tcl function does not return a tuple");
		tupdesc = NULL;			
		attinmeta = NULL;
	}
	values = (char **) palloc0(tupdesc->natts * sizeof(char *));
	if (kvObjc % 2 != 0)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("column name/value list must have even number of elements")));
	for (i = 0; i < kvObjc; i += 2)
	{
		char	   *fieldName = utf_u2e(Tcl_GetString(kvObjv[i]));
		int			attn = SPI_fnumber(tupdesc, fieldName);
		if (attn == SPI_ERROR_NOATTRIBUTE)
		{
			if (strcmp(fieldName, ".tupno") == 0)
				continue;
			ereport(ERROR,
					(errcode(ERRCODE_UNDEFINED_COLUMN),
					 errmsg("column name/value list contains nonexistent column name \"%s\"",
							fieldName)));
		}
		if (attn <= 0)
			ereport(ERROR,
					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
					 errmsg("cannot set system attribute \"%s\"",
							fieldName)));
		if (TupleDescAttr(tupdesc, attn - 1)->attgenerated)
			ereport(ERROR,
					(errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
					 errmsg("cannot set generated column \"%s\"",
							fieldName)));
		values[attn - 1] = utf_u2e(Tcl_GetString(kvObjv[i + 1]));
	}
	tuple = BuildTupleFromCStrings(attinmeta, values);
	if (call_state->prodesc->fn_retisdomain)
		domain_check(HeapTupleGetDatum(tuple), false,
					 call_state->prodesc->result_typid,
					 &call_state->prodesc->domain_info,
					 call_state->prodesc->fn_cxt);
	return tuple;
}
static HeapTuple pltcl_build_tuple_result ( Tcl_Interp * interp , Tcl_Obj * * kvObjv , int kvObjc , pltcl_call_state * call_state ) { HeapTuple tuple ; TupleDesc tupdesc ; AttInMetadata * attinmeta ; char * * values ; int i ; if ( call_state -> ret_tupdesc ) { tupdesc = call_state -> ret_tupdesc ; attinmeta = call_state -> attinmeta ; } else if ( call_state -> trigdata ) { tupdesc = RelationGetDescr ( call_state -> trigdata -> tg_relation ) ; attinmeta = TupleDescGetAttInMetadata ( tupdesc ) ; } else { elog ( ERROR , " " ) ; tupdesc = NULL ; attinmeta = NULL ; } values = ( char * * ) palloc0 ( tupdesc -> natts * sizeof ( char * ) ) ; if ( kvObjc % 2 != 0 ) ereport ( ERROR , ( errcode ( ERRCODE_INVALID_PARAMETER_VALUE ) , errmsg ( " " ) ) ) ; for ( i = 0 ; i < kvObjc ; i += 2 ) { char * fieldName = utf_u2e ( Tcl_GetString ( kvObjv [ i ] ) ) ; int attn = SPI_fnumber ( tupdesc , fieldName ) ; if ( attn == SPI_ERROR_NOATTRIBUTE ) { if ( strcmp ( fieldName , " " ) == 0 ) continue ; ereport ( ERROR , ( errcode ( ERRCODE_UNDEFINED_COLUMN ) , errmsg ( " \" \" " , fieldName ) ) ) ; } if ( attn <= 0 ) ereport ( ERROR , ( errcode ( ERRCODE_FEATURE_NOT_SUPPORTED ) , errmsg ( " \" \" " , fieldName ) ) ) ; if ( TupleDescAttr ( tupdesc , attn - 1 ) -> attgenerated ) ereport ( ERROR , ( errcode ( ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED ) , errmsg ( " \" \" " , fieldName ) ) ) ; values [ attn - 1 ] = utf_u2e ( Tcl_GetString ( kvObjv [ i + 1 ] ) ) ; } tuple = BuildTupleFromCStrings ( attinmeta , values ) ; if ( call_state -> prodesc -> fn_retisdomain ) domain_check ( HeapTupleGetDatum ( tuple ) , false , call_state -> prodesc -> result_typid , & call_state -> prodesc -> domain_info , call_state -> prodesc -> fn_cxt ) ; return tuple ; }
pltcl_build_tuple_result() - Build a tuple of function's result rowtype
                                from a Tcl list of column names and values
pltcl_build_tuple_result () - Build a tuple of function ' s result rowtype from a Tcl list of column names and values
/* keep compiler quiet */ /*
		 * We silently ignore ".tupno", if it's present but doesn't match any
		 * actual output column.  This allows direct use of a row returned by
		 * pltcl_set_tuple_values().
		 */ /* if result type is domain-over-composite, check domain constraints */