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 ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers