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