detoast-v3.patch

text/plain

Patch

Same data as JSON: GET /api/v1/attachments/:id/patch the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes. API reference →
Format: context
Series: patch v3
File+
src/pl/plpgsql/src/pl_exec.c 54 0
src/pl/plpgsql/src/plpgsql.h 4 0
*** a/src/pl/plpgsql/src/pl_exec.c
--- b/src/pl/plpgsql/src/pl_exec.c
***************
*** 255,260 **** plpgsql_exec_function(PLpgSQL_function *func, FunctionCallInfo fcinfo)
--- 255,264 ----
  					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;
  
***************
*** 570,581 **** plpgsql_exec_trigger(PLpgSQL_function *func,
--- 574,587 ----
  		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 **** plpgsql_exec_trigger(PLpgSQL_function *func,
--- 594,600 ----
  		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 **** plpgsql_exec_trigger(PLpgSQL_function *func,
--- 605,631 ----
  		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 **** plpgsql_exec_trigger(PLpgSQL_function *func,
--- 635,647 ----
  												   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 **** plpgsql_exec_trigger(PLpgSQL_function *func,
--- 667,680 ----
  														-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 **** copy_plpgsql_datum(PLpgSQL_datum *datum)
--- 856,862 ----
  				new->value = 0;
  				new->isnull = true;
  				new->freeval = false;
+ 				new->should_be_detoasted = false;
  
  				result = (PLpgSQL_datum *) new;
  			}
***************
*** 2652,2657 **** plpgsql_estate_setup(PLpgSQL_execstate *estate,
--- 2668,2679 ----
  	estate->exitlabel = NULL;
  	estate->cur_error = NULL;
  
+ 	/*
+ 	 * Store the top execution memory context.  exec_eval_datum() explicity
+ 	 * detoasts varlena datums in this context.
+ 	 */
+ 	estate->top_exec_cxt = CurrentMemoryContext;
+ 
  	estate->tuple_store = NULL;
  	if (rsi)
  	{
***************
*** 3544,3550 **** exec_assign_value(PLpgSQL_execstate *estate,
--- 3566,3575 ----
  				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 **** exec_eval_datum(PLpgSQL_execstate *estate,
--- 3969,4002 ----
  
  				*typeid = var->datatype->typoid;
  				*typetypmod = var->datatype->atttypmod;
+ 
+ 				/*
+ 				 * explicit deTOAST and decompress for varlena types
+ 				 */
+ 				if (var->should_be_detoasted)
+ 				{
+ 					Datum dvalue;
+ 
+ 					Assert(!var->isnull);
+ 
+ 					/*
+ 					 * Detoast variables in the top execution context.  The
+ 					 * parser can call this routine (via plpgsql_param_fetch)
+ 					 * with a different current context.
+ 					 */
+ 					oldcontext = MemoryContextSwitchTo(estate->top_exec_cxt);
+ 					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 **** assign_text_var(PLpgSQL_var *var, const char *str)
--- 5605,5611 ----
  	var->value = CStringGetTextDatum(str);
  	var->isnull = false;
  	var->freeval = true;
+ 	var->should_be_detoasted = false;
  }
  
  /*
*** a/src/pl/plpgsql/src/plpgsql.h
--- b/src/pl/plpgsql/src/plpgsql.h
***************
*** 242,247 **** typedef struct
--- 242,248 ----
  	Datum		value;
  	bool		isnull;
  	bool		freeval;
+ 	bool		should_be_detoasted;
  } PLpgSQL_var;
  
  
***************
*** 643,649 **** typedef struct PLpgSQL_function
  	ItemPointerData fn_tid;
  	bool		fn_is_trigger;
  	PLpgSQL_func_hashkey *fn_hashkey;	/* back-link to hashtable key */
! 	MemoryContext fn_cxt;
  
  	Oid			fn_rettype;
  	int			fn_rettyplen;
--- 644,650 ----
  	ItemPointerData fn_tid;
  	bool		fn_is_trigger;
  	PLpgSQL_func_hashkey *fn_hashkey;	/* back-link to hashtable key */
! 	MemoryContext fn_cxt;			/* function's persistent context */
  
  	Oid			fn_rettype;
  	int			fn_rettyplen;
***************
*** 692,697 **** typedef struct PLpgSQL_execstate
--- 693,700 ----
  	Oid			rettype;		/* type of current retval */
  
  	Oid			fn_rettype;		/* info about declared function rettype */
+ 	MemoryContext top_exec_cxt;	/* function's top execution memory context */
+ 
  	bool		retistuple;
  	bool		retisset;