Hello

this patch remove a multiple detoasting of varlena values in plpgsql.

It is usable mainly for iteration over longer array directly loaded
from relation.

It's doesn't have a impact on semantic or behave - it's just eliminate
some performance trap.

sample: table 10000 rows one column with array with 1000 string fields:

patched pl time: 6 sec
unpatched pl time: 170 sec

This doesn't change my opinion on FOR-IN-ARRAY cycle (is still
important for readability) - just remove one critical performance
issue

Regards

Pavel Stehule
*** ./pl_exec.c.orig	2010-11-16 10:28:42.000000000 +0100
--- ./pl_exec.c	2010-11-22 13:33:01.597726809 +0100
***************
*** 222,227 ****
--- 222,228 ----
  	 * Setup the execution state
  	 */
  	plpgsql_estate_setup(&estate, func, (ReturnSetInfo *) fcinfo->resultinfo);
+ 	estate.fn_mcxt = CurrentMemoryContext;
  
  	/*
  	 * Setup error traceback support for ereport()
***************
*** 255,260 ****
--- 256,265 ----
  					var->value = fcinfo->arg[i];
  					var->isnull = fcinfo->argnull[i];
  					var->freeval = false;
+ 
+ 					/* only varlena types should be detoasted */
+ 					var->should_be_detoasted = !var->isnull && !var->datatype->typbyval
+ 											&& var->datatype->typlen == -1;
  				}
  				break;
  
***************
*** 493,498 ****
--- 498,504 ----
  	 * Setup the execution state
  	 */
  	plpgsql_estate_setup(&estate, func, NULL);
+ 	estate.fn_mcxt = CurrentMemoryContext;
  
  	/*
  	 * Setup error traceback support for ereport()
***************
*** 570,581 ****
--- 576,589 ----
  		elog(ERROR, "unrecognized trigger action: not INSERT, DELETE, UPDATE, or TRUNCATE");
  	var->isnull = false;
  	var->freeval = true;
+ 	var->should_be_detoasted = false;
  
  	var = (PLpgSQL_var *) (estate.datums[func->tg_name_varno]);
  	var->value = DirectFunctionCall1(namein,
  							  CStringGetDatum(trigdata->tg_trigger->tgname));
  	var->isnull = false;
  	var->freeval = true;
+ 	var->should_be_detoasted = false;
  
  	var = (PLpgSQL_var *) (estate.datums[func->tg_when_varno]);
  	if (TRIGGER_FIRED_BEFORE(trigdata->tg_event))
***************
*** 588,593 ****
--- 596,602 ----
  		elog(ERROR, "unrecognized trigger execution time: not BEFORE, AFTER, or INSTEAD OF");
  	var->isnull = false;
  	var->freeval = true;
+ 	var->should_be_detoasted = false;
  
  	var = (PLpgSQL_var *) (estate.datums[func->tg_level_varno]);
  	if (TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
***************
*** 598,620 ****
--- 607,633 ----
  		elog(ERROR, "unrecognized trigger event type: not ROW or STATEMENT");
  	var->isnull = false;
  	var->freeval = true;
+ 	var->should_be_detoasted = false;
  
  	var = (PLpgSQL_var *) (estate.datums[func->tg_relid_varno]);
  	var->value = ObjectIdGetDatum(trigdata->tg_relation->rd_id);
  	var->isnull = false;
  	var->freeval = false;
+ 	var->should_be_detoasted = false;
  
  	var = (PLpgSQL_var *) (estate.datums[func->tg_relname_varno]);
  	var->value = DirectFunctionCall1(namein,
  			CStringGetDatum(RelationGetRelationName(trigdata->tg_relation)));
  	var->isnull = false;
  	var->freeval = true;
+ 	var->should_be_detoasted = false;
  
  	var = (PLpgSQL_var *) (estate.datums[func->tg_table_name_varno]);
  	var->value = DirectFunctionCall1(namein,
  			CStringGetDatum(RelationGetRelationName(trigdata->tg_relation)));
  	var->isnull = false;
  	var->freeval = true;
+ 	var->should_be_detoasted = false;
  
  	var = (PLpgSQL_var *) (estate.datums[func->tg_table_schema_varno]);
  	var->value = DirectFunctionCall1(namein,
***************
*** 624,634 ****
--- 637,649 ----
  												   trigdata->tg_relation))));
  	var->isnull = false;
  	var->freeval = true;
+ 	var->should_be_detoasted = false;
  
  	var = (PLpgSQL_var *) (estate.datums[func->tg_nargs_varno]);
  	var->value = Int16GetDatum(trigdata->tg_trigger->tgnargs);
  	var->isnull = false;
  	var->freeval = false;
+ 	var->should_be_detoasted = false;
  
  	var = (PLpgSQL_var *) (estate.datums[func->tg_argv_varno]);
  	if (trigdata->tg_trigger->tgnargs > 0)
***************
*** 654,665 ****
--- 669,682 ----
  														-1, false, 'i'));
  		var->isnull = false;
  		var->freeval = true;
+ 		var->should_be_detoasted = false;
  	}
  	else
  	{
  		var->value = (Datum) 0;
  		var->isnull = true;
  		var->freeval = false;
+ 		var->should_be_detoasted = false;
  	}
  
  	estate.err_text = gettext_noop("during function entry");
***************
*** 841,846 ****
--- 858,864 ----
  				new->value = 0;
  				new->isnull = true;
  				new->freeval = false;
+ 				new->should_be_detoasted = false;
  
  				result = (PLpgSQL_datum *) new;
  			}
***************
*** 3544,3550 ****
--- 3562,3571 ----
  				var->value = newvalue;
  				var->isnull = *isNull;
  				if (!var->datatype->typbyval && !*isNull)
+ 				{
  					var->freeval = true;
+ 					var->should_be_detoasted = var->datatype->typlen == -1;
+ 				}
  				break;
  			}
  
***************
*** 3944,3949 ****
--- 3965,3993 ----
  
  				*typeid = var->datatype->typoid;
  				*typetypmod = var->datatype->atttypmod;
+ 
+ 				/*
+ 				 * explicit deTOAST and decomprim for varlena types
+ 				 */
+ 				if (var->should_be_detoasted)
+ 				{
+ 					Datum dvalue;
+ 
+ 					Assert(!var->isnull);
+ 
+ 					oldcontext = MemoryContextSwitchTo(estate->fn_mcxt);
+ 					dvalue = PointerGetDatum(PG_DETOAST_DATUM(var->value));
+ 					if (dvalue != var->value)
+ 					{
+ 						if (var->freeval)
+ 							free_var(var);
+ 						var->value = dvalue;
+ 						var->freeval = true;
+ 					}
+ 					MemoryContextSwitchTo(oldcontext); 
+ 					var->should_be_detoasted = false;
+ 				}
+ 
  				*value = var->value;
  				*isnull = var->isnull;
  				break;
***************
*** 5552,5557 ****
--- 5596,5602 ----
  	var->value = CStringGetTextDatum(str);
  	var->isnull = false;
  	var->freeval = true;
+ 	var->should_be_detoasted = false;
  }
  
  /*
*** ./plpgsql.h.orig	2010-11-16 10:28:42.000000000 +0100
--- ./plpgsql.h	2010-11-22 13:12:38.897851879 +0100
***************
*** 242,247 ****
--- 242,248 ----
  	Datum		value;
  	bool		isnull;
  	bool		freeval;
+ 	bool		should_be_detoasted;
  } PLpgSQL_var;
  
  
***************
*** 644,649 ****
--- 645,651 ----
  	bool		fn_is_trigger;
  	PLpgSQL_func_hashkey *fn_hashkey;	/* back-link to hashtable key */
  	MemoryContext fn_cxt;
+ 	MemoryContext	fn_mcxt;		/* link to function's memory context */
  
  	Oid			fn_rettype;
  	int			fn_rettyplen;
***************
*** 692,697 ****
--- 694,701 ----
  	Oid			rettype;		/* type of current retval */
  
  	Oid			fn_rettype;		/* info about declared function rettype */
+ 	MemoryContext	fn_mcxt;		/* link to function's memory context */
+ 
  	bool		retistuple;
  	bool		retisset;
  
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to