Index: tablefunc.c
===================================================================
RCS file: /opt/src/cvs/pgsql/contrib/tablefunc/tablefunc.c,v
retrieving revision 1.47
diff -c -r1.47 tablefunc.c
*** tablefunc.c	3 Mar 2007 19:32:54 -0000	1.47
--- tablefunc.c	25 Oct 2007 02:11:06 -0000
***************
*** 355,360 ****
--- 355,361 ----
  	crosstab_fctx *fctx;
  	int			i;
  	int			num_categories;
+ 	bool		firstpass = false;
  	MemoryContext oldcontext;
  
  	/* stuff done only on the first call of the function */
***************
*** 469,474 ****
--- 470,476 ----
  		funcctx->max_calls = proc;
  
  		MemoryContextSwitchTo(oldcontext);
+ 		firstpass = true;
  	}
  
  	/* stuff done on every call of the function */
***************
*** 500,506 ****
  		HeapTuple	tuple;
  		Datum		result;
  		char	  **values;
! 		bool		allnulls = true;
  
  		while (true)
  		{
--- 502,508 ----
  		HeapTuple	tuple;
  		Datum		result;
  		char	  **values;
! 		bool		skip_tuple = false;
  
  		while (true)
  		{
***************
*** 530,555 ****
  				rowid = SPI_getvalue(spi_tuple, spi_tupdesc, 1);
  
  				/*
! 				 * If this is the first pass through the values for this rowid
! 				 * set it, otherwise make sure it hasn't changed on us. Also
! 				 * check to see if the rowid is the same as that of the last
! 				 * tuple sent -- if so, skip this tuple entirely
  				 */
  				if (i == 0)
- 					values[0] = pstrdup(rowid);
- 
- 				if ((rowid != NULL) && (strcmp(rowid, values[0]) == 0))
  				{
! 					if ((lastrowid != NULL) && (strcmp(rowid, lastrowid) == 0))
  						break;
! 					else if (allnulls == true)
! 						allnulls = false;
  
  					/*
! 					 * Get the next category item value, which is alway
  					 * attribute number three.
  					 *
! 					 * Be careful to sssign the value to the array index based
  					 * on which category we are presently processing.
  					 */
  					values[1 + i] = SPI_getvalue(spi_tuple, spi_tupdesc, 3);
--- 532,574 ----
  				rowid = SPI_getvalue(spi_tuple, spi_tupdesc, 1);
  
  				/*
! 				 * If this is the first pass through the values for this
! 				 * rowid, set the first column to rowid
  				 */
  				if (i == 0)
  				{
! 					if (rowid)
! 						values[0] = pstrdup(rowid);
! 					else
! 						values[0] = NULL;
! 
! 					/*
! 					 * Check to see if the rowid is the same as that of the last
! 					 * tuple sent -- if so, skip this tuple entirely
! 					 */
! 					if (!firstpass &&
! 						(((lastrowid == NULL) && (rowid == NULL)) ||
! 						 ((lastrowid != NULL) &&
! 						  (rowid != NULL) &&
! 						  (strcmp(rowid, lastrowid) == 0))))
! 					{
! 						skip_tuple = true;
  						break;
! 					}
! 				}
  
+ 				/*
+ 				 * If rowid hasn't changed on us, continue building the
+ 				 * ouput tuple.
+ 				 */
+ 				if ((rowid && values[0] && (strcmp(rowid, values[0]) == 0)) ||
+ 					((rowid == NULL) && (values[0] == NULL)))
+ 				{
  					/*
! 					 * Get the next category item value, which is always
  					 * attribute number three.
  					 *
! 					 * Be careful to assign the value to the array index based
  					 * on which category we are presently processing.
  					 */
  					values[1 + i] = SPI_getvalue(spi_tuple, spi_tupdesc, 3);
***************
*** 572,584 ****
  					call_cntr = --funcctx->call_cntr;
  					break;
  				}
! 
! 				if (rowid != NULL)
! 					xpfree(rowid);
  			}
  
  			xpfree(fctx->lastrowid);
- 
  			if (values[0] != NULL)
  			{
  				/*
--- 591,600 ----
  					call_cntr = --funcctx->call_cntr;
  					break;
  				}
! 				xpfree(rowid);
  			}
  
  			xpfree(fctx->lastrowid);
  			if (values[0] != NULL)
  			{
  				/*
***************
*** 586,597 ****
  				 * calls
  				 */
  				oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
- 
  				lastrowid = fctx->lastrowid = pstrdup(values[0]);
  				MemoryContextSwitchTo(oldcontext);
  			}
  
! 			if (!allnulls)
  			{
  				/* build the tuple */
  				tuple = BuildTupleFromCStrings(attinmeta, values);
--- 602,614 ----
  				 * calls
  				 */
  				oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
  				lastrowid = fctx->lastrowid = pstrdup(values[0]);
  				MemoryContextSwitchTo(oldcontext);
  			}
+ 			else
+ 				lastrowid = fctx->lastrowid = NULL;
  
! 			if (!skip_tuple)
  			{
  				/* build the tuple */
  				tuple = BuildTupleFromCStrings(attinmeta, values);
***************
*** 625,630 ****
--- 642,650 ----
  					SPI_finish();
  					SRF_RETURN_DONE(funcctx);
  				}
+ 
+ 				/* need to reset this before the next tuple is started */
+ 				skip_tuple = false;
  			}
  		}
  	}
***************
*** 856,861 ****
--- 876,882 ----
  		int			ncols = spi_tupdesc->natts;
  		char	   *rowid;
  		char	   *lastrowid = NULL;
+ 		bool		firstpass = true;
  		int			i,
  					j;
  		int			result_ncols;
***************
*** 918,938 ****
  			/* get the rowid from the current sql result tuple */
  			rowid = SPI_getvalue(spi_tuple, spi_tupdesc, 1);
  
- 			/* if rowid is null, skip this tuple entirely */
- 			if (rowid == NULL)
- 				continue;
- 
  			/*
  			 * if we're on a new output row, grab the column values up to
  			 * column N-2 now
  			 */
! 			if ((lastrowid == NULL) || (strcmp(rowid, lastrowid) != 0))
  			{
  				/*
  				 * a new row means we need to flush the old one first, unless
  				 * we're on the very first row
  				 */
! 				if (lastrowid != NULL)
  				{
  					/* rowid changed, flush the previous output row */
  					tuple = BuildTupleFromCStrings(attinmeta, values);
--- 939,958 ----
  			/* get the rowid from the current sql result tuple */
  			rowid = SPI_getvalue(spi_tuple, spi_tupdesc, 1);
  
  			/*
  			 * if we're on a new output row, grab the column values up to
  			 * column N-2 now
  			 */
! 			if (firstpass || 
! 				(lastrowid == NULL && rowid != NULL) ||
! 				(lastrowid != NULL && rowid == NULL) ||
! 				(lastrowid != NULL && rowid != NULL && (strcmp(rowid, lastrowid) != 0)))
  			{
  				/*
  				 * a new row means we need to flush the old one first, unless
  				 * we're on the very first row
  				 */
! 				if (!firstpass)
  				{
  					/* rowid changed, flush the previous output row */
  					tuple = BuildTupleFromCStrings(attinmeta, values);
***************
*** 949,954 ****
--- 969,977 ----
  				values[0] = rowid;
  				for (j = 1; j < ncols - 2; j++)
  					values[j] = SPI_getvalue(spi_tuple, spi_tupdesc, j + 1);
+ 
+ 				/* we're no longer on the first pass */
+ 				firstpass = false;
  			}
  
  			/* look up the category and fill in the appropriate column */
***************
*** 964,970 ****
  			}
  
  			xpfree(lastrowid);
! 			lastrowid = pstrdup(rowid);
  		}
  
  		/* flush the last output row */
--- 987,994 ----
  			}
  
  			xpfree(lastrowid);
! 			if (rowid)
! 				lastrowid = pstrdup(rowid);
  		}
  
  		/* flush the last output row */
