mirror of
				https://github.com/postgres/postgres.git
				synced 2025-11-03 09:13:20 +03:00 
			
		
		
		
	Fix coredump in plpgsql when trying to return a rowtype result.
Need to return a TupleTableSlot, not just a bare tuple.
This commit is contained in:
		@@ -1272,6 +1272,135 @@ TBD
 | 
				
			|||||||
<!-- *********************************************** -->
 | 
					<!-- *********************************************** -->
 | 
				
			||||||
<!-- *********************************************** -->
 | 
					<!-- *********************************************** -->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<REFENTRY ID="SPI-SPICOPYTUPLEINTOSLOT">
 | 
				
			||||||
 | 
					<REFMETA>
 | 
				
			||||||
 | 
					<REFENTRYTITLE>SPI_copytupleintoslot</REFENTRYTITLE>
 | 
				
			||||||
 | 
					<REFMISCINFO>SPI - Tuple and Descriptor Copy</REFMISCINFO>
 | 
				
			||||||
 | 
					</REFMETA>
 | 
				
			||||||
 | 
					<REFNAMEDIV>
 | 
				
			||||||
 | 
					<REFNAME>SPI_copytupleintoslot
 | 
				
			||||||
 | 
					</REFNAME>
 | 
				
			||||||
 | 
					<REFPURPOSE>
 | 
				
			||||||
 | 
					Makes copy of tuple and descriptor in upper Executor context
 | 
				
			||||||
 | 
					</REFPURPOSE>
 | 
				
			||||||
 | 
					<INDEXTERM ID="IX-SPI-SPICOPYTUPLEINTOSLOT-1"><PRIMARY>SPI</PRIMARY><SECONDARY>copying tuples</SECONDARY></INDEXTERM>
 | 
				
			||||||
 | 
					<INDEXTERM ID="IX-SPI-SPICOPYTUPLEINTOSLOT-2"><PRIMARY>SPI_copytupleintoslot</PRIMARY></INDEXTERM>
 | 
				
			||||||
 | 
					</REFNAMEDIV>
 | 
				
			||||||
 | 
					<REFSYNOPSISDIV>
 | 
				
			||||||
 | 
					<REFSYNOPSISDIVINFO>
 | 
				
			||||||
 | 
					<DATE>1997-12-24</DATE>
 | 
				
			||||||
 | 
					</REFSYNOPSISDIVINFO>
 | 
				
			||||||
 | 
					<SYNOPSIS>
 | 
				
			||||||
 | 
					SPI_copytupleintoslot(<REPLACEABLE CLASS="PARAMETER">tuple</REPLACEABLE>, <REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE>)
 | 
				
			||||||
 | 
					</SYNOPSIS>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<REFSECT2 ID="R2-SPI-SPICOPYTUPLEINTOSLOT-1">
 | 
				
			||||||
 | 
					<REFSECT2INFO>
 | 
				
			||||||
 | 
					<DATE>1997-12-24</DATE>
 | 
				
			||||||
 | 
					</REFSECT2INFO>
 | 
				
			||||||
 | 
					<TITLE>Inputs
 | 
				
			||||||
 | 
					</TITLE>
 | 
				
			||||||
 | 
					<VARIABLELIST>
 | 
				
			||||||
 | 
					<VARLISTENTRY>
 | 
				
			||||||
 | 
					<TERM>
 | 
				
			||||||
 | 
					HeapTuple <REPLACEABLE CLASS="PARAMETER">tuple</REPLACEABLE>
 | 
				
			||||||
 | 
					</TERM>
 | 
				
			||||||
 | 
					<LISTITEM>
 | 
				
			||||||
 | 
					<PARA>
 | 
				
			||||||
 | 
					Input tuple to be copied
 | 
				
			||||||
 | 
					</PARA>
 | 
				
			||||||
 | 
					</LISTITEM>
 | 
				
			||||||
 | 
					</VARLISTENTRY>
 | 
				
			||||||
 | 
					<VARLISTENTRY>
 | 
				
			||||||
 | 
					<TERM>
 | 
				
			||||||
 | 
					TupleDesc <REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE>
 | 
				
			||||||
 | 
					</TERM>
 | 
				
			||||||
 | 
					<LISTITEM>
 | 
				
			||||||
 | 
					<PARA>
 | 
				
			||||||
 | 
					Input tuple descriptor to be copied
 | 
				
			||||||
 | 
					</PARA>
 | 
				
			||||||
 | 
					</LISTITEM>
 | 
				
			||||||
 | 
					</VARLISTENTRY>
 | 
				
			||||||
 | 
					</VARIABLELIST>
 | 
				
			||||||
 | 
					</REFSECT2>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<REFSECT2 ID="R2-SPI-SPICOPYTUPLEINTOSLOT-2">
 | 
				
			||||||
 | 
					<REFSECT2INFO>
 | 
				
			||||||
 | 
					<DATE>1997-12-24</DATE>
 | 
				
			||||||
 | 
					</REFSECT2INFO>
 | 
				
			||||||
 | 
					<TITLE>Outputs
 | 
				
			||||||
 | 
					</TITLE>
 | 
				
			||||||
 | 
					<VARIABLELIST>
 | 
				
			||||||
 | 
					<VARLISTENTRY>
 | 
				
			||||||
 | 
					<TERM>
 | 
				
			||||||
 | 
					TupleTableSlot *
 | 
				
			||||||
 | 
					</TERM>
 | 
				
			||||||
 | 
					<LISTITEM>
 | 
				
			||||||
 | 
					<PARA>
 | 
				
			||||||
 | 
					Tuple slot containing copied tuple and descriptor
 | 
				
			||||||
 | 
					<SimpleList>
 | 
				
			||||||
 | 
					<Member>
 | 
				
			||||||
 | 
					 <ReturnValue>non-NULL</ReturnValue>
 | 
				
			||||||
 | 
					 if <REPLACEABLE CLASS="PARAMETER">tuple</REPLACEABLE>
 | 
				
			||||||
 | 
					 and <REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE>
 | 
				
			||||||
 | 
					 are not NULL and the copy was successful
 | 
				
			||||||
 | 
					</Member>
 | 
				
			||||||
 | 
					<Member>
 | 
				
			||||||
 | 
					   <ReturnValue>NULL</ReturnValue>
 | 
				
			||||||
 | 
					 only if <REPLACEABLE CLASS="PARAMETER">tuple</REPLACEABLE>
 | 
				
			||||||
 | 
					 or <REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE>
 | 
				
			||||||
 | 
					 is NULL
 | 
				
			||||||
 | 
					</Member>
 | 
				
			||||||
 | 
					</SimpleList>
 | 
				
			||||||
 | 
					</para>
 | 
				
			||||||
 | 
					</LISTITEM>
 | 
				
			||||||
 | 
					</VARLISTENTRY>
 | 
				
			||||||
 | 
					</VARIABLELIST>
 | 
				
			||||||
 | 
					</REFSECT2>
 | 
				
			||||||
 | 
					</REFSYNOPSISDIV>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<REFSECT1 ID="R1-SPI-SPICOPYTUPLEINTOSLOT-1">
 | 
				
			||||||
 | 
					<REFSECT1INFO>
 | 
				
			||||||
 | 
					<DATE>1997-12-24</DATE>
 | 
				
			||||||
 | 
					</REFSECT1INFO>
 | 
				
			||||||
 | 
					<TITLE>Description
 | 
				
			||||||
 | 
					</TITLE>
 | 
				
			||||||
 | 
					<PARA>
 | 
				
			||||||
 | 
					<FUNCTION>SPI_copytupleintoslot</FUNCTION> 
 | 
				
			||||||
 | 
					   makes a copy of tuple in upper Executor context, returning it in the
 | 
				
			||||||
 | 
					   form of a filled-in TupleTableSlot.
 | 
				
			||||||
 | 
					   See the section on Memory Management.
 | 
				
			||||||
 | 
					</PARA>
 | 
				
			||||||
 | 
					</REFSECT1>
 | 
				
			||||||
 | 
					<REFSECT1 ID="R1-SPI-SPICOPYTUPLEINTOSLOT-2">
 | 
				
			||||||
 | 
					<TITLE>Usage
 | 
				
			||||||
 | 
					</TITLE>
 | 
				
			||||||
 | 
					<Para>
 | 
				
			||||||
 | 
					TBD
 | 
				
			||||||
 | 
					</PARA>
 | 
				
			||||||
 | 
					</REFSECT1>
 | 
				
			||||||
 | 
					<!--
 | 
				
			||||||
 | 
					<REFSECT1 ID="R1-SPI-SPICOPYTUPLEINTOSLOT-3">
 | 
				
			||||||
 | 
					<TITLE>Algorithm
 | 
				
			||||||
 | 
					</TITLE>
 | 
				
			||||||
 | 
					<PARA>
 | 
				
			||||||
 | 
					</PARA>
 | 
				
			||||||
 | 
					</REFSECT1>
 | 
				
			||||||
 | 
					-->
 | 
				
			||||||
 | 
					<!--
 | 
				
			||||||
 | 
					<REFSECT1 ID="R1-SPI-SPICOPYTUPLEINTOSLOT-4">
 | 
				
			||||||
 | 
					<TITLE>Structures
 | 
				
			||||||
 | 
					</TITLE>
 | 
				
			||||||
 | 
					<PARA>None
 | 
				
			||||||
 | 
					</PARA>
 | 
				
			||||||
 | 
					</REFSECT1>
 | 
				
			||||||
 | 
					-->
 | 
				
			||||||
 | 
					</REFENTRY>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<!-- *********************************************** -->
 | 
				
			||||||
 | 
					<!-- *********************************************** -->
 | 
				
			||||||
 | 
					<!-- *********************************************** -->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<REFENTRY ID="SPI-SPIMODIFYTUPLE">
 | 
					<REFENTRY ID="SPI-SPIMODIFYTUPLE">
 | 
				
			||||||
<REFMETA>
 | 
					<REFMETA>
 | 
				
			||||||
<REFENTRYTITLE>SPI_modifytuple</REFENTRYTITLE>
 | 
					<REFENTRYTITLE>SPI_modifytuple</REFENTRYTITLE>
 | 
				
			||||||
@@ -2695,6 +2824,7 @@ made in this context.
 | 
				
			|||||||
<Function>palloc</Function>/<Function>repalloc</Function> or by SPI utility
 | 
					<Function>palloc</Function>/<Function>repalloc</Function> or by SPI utility
 | 
				
			||||||
functions (except for <Function>SPI_copytuple</Function>,
 | 
					functions (except for <Function>SPI_copytuple</Function>,
 | 
				
			||||||
<Function>SPI_copytupledesc</Function>,
 | 
					<Function>SPI_copytupledesc</Function>,
 | 
				
			||||||
 | 
					<Function>SPI_copytupleintoslot</Function>,
 | 
				
			||||||
<Function>SPI_modifytuple</Function>,
 | 
					<Function>SPI_modifytuple</Function>,
 | 
				
			||||||
<Function>SPI_palloc</Function> and <Function>SPI_repalloc</Function>) are
 | 
					<Function>SPI_palloc</Function> and <Function>SPI_repalloc</Function>) are
 | 
				
			||||||
made in this context.
 | 
					made in this context.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,7 +8,7 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * IDENTIFICATION
 | 
					 * IDENTIFICATION
 | 
				
			||||||
 *	  $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.60 2001/10/25 05:49:29 momjian Exp $
 | 
					 *	  $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.61 2001/11/05 19:41:56 tgl Exp $
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *-------------------------------------------------------------------------
 | 
					 *-------------------------------------------------------------------------
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@@ -360,6 +360,40 @@ SPI_copytupledesc(TupleDesc tupdesc)
 | 
				
			|||||||
	return ctupdesc;
 | 
						return ctupdesc;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TupleTableSlot *
 | 
				
			||||||
 | 
					SPI_copytupleintoslot(HeapTuple tuple, TupleDesc tupdesc)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						MemoryContext oldcxt = NULL;
 | 
				
			||||||
 | 
						TupleTableSlot *cslot;
 | 
				
			||||||
 | 
						HeapTuple	ctuple;
 | 
				
			||||||
 | 
						TupleDesc	ctupdesc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (tuple == NULL || tupdesc == NULL)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							SPI_result = SPI_ERROR_ARGUMENT;
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (_SPI_curid + 1 == _SPI_connected)		/* connected */
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (_SPI_current != &(_SPI_stack[_SPI_curid + 1]))
 | 
				
			||||||
 | 
								elog(FATAL, "SPI: stack corrupted");
 | 
				
			||||||
 | 
							oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ctuple = heap_copytuple(tuple);
 | 
				
			||||||
 | 
						ctupdesc = CreateTupleDescCopy(tupdesc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cslot = MakeTupleTableSlot();
 | 
				
			||||||
 | 
						ExecSetSlotDescriptor(cslot, ctupdesc, true);
 | 
				
			||||||
 | 
						cslot = ExecStoreTuple(ctuple, cslot, InvalidBuffer, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (oldcxt)
 | 
				
			||||||
 | 
							MemoryContextSwitchTo(oldcxt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return cslot;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
HeapTuple
 | 
					HeapTuple
 | 
				
			||||||
SPI_modifytuple(Relation rel, HeapTuple tuple, int natts, int *attnum,
 | 
					SPI_modifytuple(Relation rel, HeapTuple tuple, int natts, int *attnum,
 | 
				
			||||||
				Datum *Values, char *Nulls)
 | 
									Datum *Values, char *Nulls)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,7 +2,7 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 * spi.h
 | 
					 * spi.h
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * $Id: spi.h,v 1.31 2001/11/05 17:46:33 momjian Exp $
 | 
					 * $Id: spi.h,v 1.32 2001/11/05 19:41:56 tgl Exp $
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *-------------------------------------------------------------------------
 | 
					 *-------------------------------------------------------------------------
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@@ -89,6 +89,8 @@ extern int	SPI_freeplan(void *plan);
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
extern HeapTuple SPI_copytuple(HeapTuple tuple);
 | 
					extern HeapTuple SPI_copytuple(HeapTuple tuple);
 | 
				
			||||||
extern TupleDesc SPI_copytupledesc(TupleDesc tupdesc);
 | 
					extern TupleDesc SPI_copytupledesc(TupleDesc tupdesc);
 | 
				
			||||||
 | 
					extern TupleTableSlot *SPI_copytupleintoslot(HeapTuple tuple,
 | 
				
			||||||
 | 
																 TupleDesc tupdesc);
 | 
				
			||||||
extern HeapTuple SPI_modifytuple(Relation rel, HeapTuple tuple, int natts,
 | 
					extern HeapTuple SPI_modifytuple(Relation rel, HeapTuple tuple, int natts,
 | 
				
			||||||
				int *attnum, Datum *Values, char *Nulls);
 | 
									int *attnum, Datum *Values, char *Nulls);
 | 
				
			||||||
extern int	SPI_fnumber(TupleDesc tupdesc, char *fname);
 | 
					extern int	SPI_fnumber(TupleDesc tupdesc, char *fname);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,7 +3,7 @@
 | 
				
			|||||||
 *			  procedural language
 | 
					 *			  procedural language
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * IDENTIFICATION
 | 
					 * IDENTIFICATION
 | 
				
			||||||
 *	  $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.48 2001/10/25 05:50:20 momjian Exp $
 | 
					 *	  $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.49 2001/11/05 19:41:56 tgl Exp $
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *	  This software is copyrighted by Jan Wieck - Hamburg.
 | 
					 *	  This software is copyrighted by Jan Wieck - Hamburg.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
@@ -400,15 +400,25 @@ plpgsql_exec_function(PLpgSQL_function * func, FunctionCallInfo fcinfo)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	fcinfo->isnull = estate.retisnull;
 | 
						fcinfo->isnull = estate.retisnull;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!estate.retistuple)
 | 
						if (!estate.retisnull)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
 | 
							if (estate.retistuple)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								/* Copy tuple to upper executor memory */
 | 
				
			||||||
 | 
								/* Here we need to return a TupleTableSlot not just a tuple */
 | 
				
			||||||
 | 
								estate.retval = (Datum)
 | 
				
			||||||
 | 
									SPI_copytupleintoslot((HeapTuple) (estate.retval),
 | 
				
			||||||
 | 
														  estate.rettupdesc);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								/* Cast value to proper type */
 | 
				
			||||||
			estate.retval = exec_cast_value(estate.retval, estate.rettype,
 | 
								estate.retval = exec_cast_value(estate.retval, estate.rettype,
 | 
				
			||||||
											func->fn_rettype,
 | 
																func->fn_rettype,
 | 
				
			||||||
											&(func->fn_retinput),
 | 
																&(func->fn_retinput),
 | 
				
			||||||
											func->fn_rettypelem,
 | 
																func->fn_rettypelem,
 | 
				
			||||||
											-1,
 | 
																-1,
 | 
				
			||||||
											&fcinfo->isnull);
 | 
																&fcinfo->isnull);
 | 
				
			||||||
 | 
					 | 
				
			||||||
			/*
 | 
								/*
 | 
				
			||||||
			 * If the functions return type isn't by value, copy the value
 | 
								 * If the functions return type isn't by value, copy the value
 | 
				
			||||||
			 * into upper executor memory context.
 | 
								 * into upper executor memory context.
 | 
				
			||||||
@@ -428,6 +438,7 @@ plpgsql_exec_function(PLpgSQL_function * func, FunctionCallInfo fcinfo)
 | 
				
			|||||||
				estate.retval = tmp;
 | 
									estate.retval = tmp;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Clean up any leftover temporary memory */
 | 
						/* Clean up any leftover temporary memory */
 | 
				
			||||||
	exec_eval_cleanup(&estate);
 | 
						exec_eval_cleanup(&estate);
 | 
				
			||||||
@@ -1619,8 +1630,8 @@ exec_stmt_return(PLpgSQL_execstate * estate, PLpgSQL_stmt_return * stmt)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
			if (HeapTupleIsValid(rec->tup))
 | 
								if (HeapTupleIsValid(rec->tup))
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				estate->retval = (Datum) SPI_copytuple(rec->tup);
 | 
									estate->retval = (Datum) rec->tup;
 | 
				
			||||||
				estate->rettupdesc = SPI_copytupledesc(rec->tupdesc);
 | 
									estate->rettupdesc = rec->tupdesc;
 | 
				
			||||||
				estate->retisnull = false;
 | 
									estate->retisnull = false;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			return PLPGSQL_RC_RETURN;
 | 
								return PLPGSQL_RC_RETURN;
 | 
				
			||||||
@@ -1631,16 +1642,10 @@ exec_stmt_return(PLpgSQL_execstate * estate, PLpgSQL_stmt_return * stmt)
 | 
				
			|||||||
			exec_run_select(estate, stmt->expr, 1, NULL);
 | 
								exec_run_select(estate, stmt->expr, 1, NULL);
 | 
				
			||||||
			if (estate->eval_processed > 0)
 | 
								if (estate->eval_processed > 0)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				estate->retval = (Datum) SPI_copytuple(estate->eval_tuptable->vals[0]);
 | 
									estate->retval = (Datum) estate->eval_tuptable->vals[0];
 | 
				
			||||||
				estate->rettupdesc = SPI_copytupledesc(estate->eval_tuptable->tupdesc);
 | 
									estate->rettupdesc = estate->eval_tuptable->tupdesc;
 | 
				
			||||||
				estate->retisnull = false;
 | 
									estate->retisnull = false;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					 | 
				
			||||||
			/*
 | 
					 | 
				
			||||||
			 * Okay to clean up here, since we already copied result tuple
 | 
					 | 
				
			||||||
			 * to upper executor.
 | 
					 | 
				
			||||||
			 */
 | 
					 | 
				
			||||||
			exec_eval_cleanup(estate);
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return PLPGSQL_RC_RETURN;
 | 
							return PLPGSQL_RC_RETURN;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user