Assorted style changes with a tiny improvement
Hi.
This is a series of patches to change styles, in assorted sources.
IMO, this improves a tiny bit and is worth trying.
1. Avoid dereference iss_SortSupport if it has nulls.
2. Avoid dereference plan_node_id if no dsm area.
3. Avoid dereference spill partitions if zero ntuples.
4. Avoid possible useless palloc call with zero size.
5. Avoid redundant variable initialization in foreign.
6. Check the cheap test first in ExecMain.
7. Check the cheap test first in pathkeys.
8. Delay possible expensive bms_is_empty call in sub_select.
9. Reduce some scope in execPartition.
10. Reduce some scope for TupleDescAttr array dereference.
11. Remove useless duplicate test in ruleutils.
This is already checked at line 4566.
12. Remove useless duplicate test in string_utils.
This is already checked at line 982.
best regards,
Ranier Vilela
Attachments:
check-cheap-test-first-execMain.patchapplication/octet-stream; name=check-cheap-test-first-execMain.patchDownload
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 4d7c92d63c..8bda54f6e5 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -2279,8 +2279,9 @@ ExecBuildSlotValueDescription(Oid reloid,
*/
aclresult = pg_attribute_aclcheck(reloid, att->attnum,
GetUserId(), ACL_SELECT);
- if (bms_is_member(att->attnum - FirstLowInvalidHeapAttributeNumber,
- modifiedCols) || aclresult == ACLCHECK_OK)
+ if (aclresult == ACLCHECK_OK ||
+ bms_is_member(att->attnum - FirstLowInvalidHeapAttributeNumber,
+ modifiedCols))
{
column_perm = any_perm = true;
avoid-dereference-iss_SortSupport-array-if-has-nulls.patchapplication/octet-stream; name=avoid-dereference-iss_SortSupport-array-if-has-nulls.patchDownload
diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c
index 8000feff4c..0e917efd6a 100644
--- a/src/backend/executor/nodeIndexscan.c
+++ b/src/backend/executor/nodeIndexscan.c
@@ -411,7 +411,7 @@ cmp_orderbyvals(const Datum *adist, const bool *anulls,
for (i = 0; i < node->iss_NumOrderByKeys; i++)
{
- SortSupport ssup = &node->iss_SortSupport[i];
+ SortSupport ssup;
/*
* Handle nulls. We only need to support NULLS LAST ordering, because
@@ -425,6 +425,7 @@ cmp_orderbyvals(const Datum *adist, const bool *anulls,
else if (anulls[i] && bnulls[i])
return 0;
+ ssup = &node->iss_SortSupport[i];
result = ssup->comparator(adist[i], bdist[i], ssup);
if (result != 0)
return result;
avoid-dereference-plan_node_id-if-no-dsm-area.patchapplication/octet-stream; name=avoid-dereference-plan_node_id-if-no-dsm-area.patchDownload
diff --git a/src/backend/executor/nodeHashjoin.c b/src/backend/executor/nodeHashjoin.c
index dbf114cd5e..0e25de9c9f 100644
--- a/src/backend/executor/nodeHashjoin.c
+++ b/src/backend/executor/nodeHashjoin.c
@@ -1549,7 +1549,7 @@ ExecHashJoinEstimate(HashJoinState *state, ParallelContext *pcxt)
void
ExecHashJoinInitializeDSM(HashJoinState *state, ParallelContext *pcxt)
{
- int plan_node_id = state->js.ps.plan->plan_node_id;
+ int plan_node_id;
HashState *hashNode;
ParallelHashJoinState *pstate;
@@ -1566,6 +1566,7 @@ ExecHashJoinInitializeDSM(HashJoinState *state, ParallelContext *pcxt)
* Set up the state needed to coordinate access to the shared hash
* table(s), using the plan node ID as the toc key.
*/
+ plan_node_id = state->js.ps.plan->plan_node_id;
pstate = shm_toc_allocate(pcxt->toc, sizeof(ParallelHashJoinState));
shm_toc_insert(pcxt->toc, plan_node_id, pstate);
avoid-dereference-spill-partitions-if-zero-ntuples.patchapplication/octet-stream; name=avoid-dereference-spill-partitions-if-zero-ntuples.patchDownload
diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c
index 53ead77ece..ea81a721ce 100644
--- a/src/backend/executor/nodeAgg.c
+++ b/src/backend/executor/nodeAgg.c
@@ -3100,7 +3100,7 @@ hashagg_spill_finish(AggState *aggstate, HashAggSpill *spill, int setno)
for (i = 0; i < spill->npartitions; i++)
{
- LogicalTape *tape = spill->partitions[i];
+ LogicalTape *tape;
HashAggBatch *new_batch;
double cardinality;
@@ -3108,6 +3108,7 @@ hashagg_spill_finish(AggState *aggstate, HashAggSpill *spill, int setno)
if (spill->ntuples[i] == 0)
continue;
+ tape = spill->partitions[i];
cardinality = estimateHyperLogLog(&spill->hll_card[i]);
freeHyperLogLog(&spill->hll_card[i]);
avoid-possible-useless-palloc-call-with-zero-size-execGrouping.patchapplication/octet-stream; name=avoid-possible-useless-palloc-call-with-zero-size-execGrouping.patchDownload
diff --git a/src/backend/executor/execGrouping.c b/src/backend/executor/execGrouping.c
index 7233f1e3c0..774e4de882 100644
--- a/src/backend/executor/execGrouping.c
+++ b/src/backend/executor/execGrouping.c
@@ -62,13 +62,15 @@ execTuplesMatchPrepare(TupleDesc desc,
const Oid *collations,
PlanState *parent)
{
- Oid *eqFunctions = (Oid *) palloc(numCols * sizeof(Oid));
+ Oid *eqFunctions;
int i;
ExprState *expr;
if (numCols == 0)
return NULL;
+ eqFunctions = (Oid *) palloc(numCols * sizeof(Oid));
+
/* lookup equality functions */
for (i = 0; i < numCols; i++)
eqFunctions[i] = get_opcode(eqOperators[i]);
avoid-redundant-variable-initialization-foreign.patchapplication/octet-stream; name=avoid-redundant-variable-initialization-foreign.patchDownload
diff --git a/src/backend/foreign/foreign.c b/src/backend/foreign/foreign.c
index f4f35728b4..f23581f05a 100644
--- a/src/backend/foreign/foreign.c
+++ b/src/backend/foreign/foreign.c
@@ -514,7 +514,7 @@ pg_options_to_table(PG_FUNCTION_ARGS)
Datum array = PG_GETARG_DATUM(0);
ListCell *cell;
List *options;
- ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+ ReturnSetInfo *rsinfo;
options = untransformRelOptions(array);
rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
check-cheap-test-first-pathkeys.patchapplication/octet-stream; name=check-cheap-test-first-pathkeys.patchDownload
diff --git a/src/backend/optimizer/path/pathkeys.c b/src/backend/optimizer/path/pathkeys.c
index 416fc4e240..6a992ff184 100644
--- a/src/backend/optimizer/path/pathkeys.c
+++ b/src/backend/optimizer/path/pathkeys.c
@@ -408,9 +408,9 @@ group_keys_reorder_by_pathkeys(List *pathkeys, List **group_pathkeys,
* Give up if we can't find the matching pointer. Also give up if
* there is no sortclause reference for some reason.
*/
- if (foreach_current_index(lc) >= num_groupby_pathkeys ||
- !list_member_ptr(grouping_pathkeys, pathkey) ||
- pathkey->pk_eclass->ec_sortref == 0)
+ if (pathkey->pk_eclass->ec_sortref == 0 ||
+ foreach_current_index(lc) >= num_groupby_pathkeys ||
+ !list_member_ptr(grouping_pathkeys, pathkey))
break;
/*
delay-possible-expensive-bms_is_empty_call.patchapplication/octet-stream; name=delay-possible-expensive-bms_is_empty_call.patchDownload
diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c
index 6d003cc8e5..36c1f3c19c 100644
--- a/src/backend/optimizer/plan/subselect.c
+++ b/src/backend/optimizer/plan/subselect.c
@@ -1275,7 +1275,6 @@ convert_ANY_sublink_to_join(PlannerInfo *root, SubLink *sublink,
* LATERAL. (Vars from higher levels don't matter here.)
*/
sub_ref_outer_relids = pull_varnos_of_level(NULL, (Node *) subselect, 1);
- use_lateral = !bms_is_empty(sub_ref_outer_relids);
/*
* Can't convert if the sub-select contains parent-level Vars of relations
@@ -1316,6 +1315,7 @@ convert_ANY_sublink_to_join(PlannerInfo *root, SubLink *sublink,
* below). Therefore this is a lot easier than what pull_up_subqueries has
* to go through.
*/
+ use_lateral = !bms_is_empty(sub_ref_outer_relids);
nsitem = addRangeTableEntryForSubquery(pstate,
subselect,
makeAlias("ANY_subquery", NIL),
reduce-some-scope-execPartition.patchapplication/octet-stream; name=reduce-some-scope-execPartition.patchDownload
diff --git a/src/backend/executor/execPartition.c b/src/backend/executor/execPartition.c
index 7651886229..f7c7343468 100644
--- a/src/backend/executor/execPartition.c
+++ b/src/backend/executor/execPartition.c
@@ -679,8 +679,6 @@ ExecInitPartitionInfo(ModifyTableState *mtstate, EState *estate,
*/
if (node && node->onConflictAction != ONCONFLICT_NONE)
{
- TupleDesc partrelDesc = RelationGetDescr(partrel);
- ExprContext *econtext = mtstate->ps.ps_ExprContext;
ListCell *lc;
List *arbiterIndexes = NIL;
@@ -771,6 +769,8 @@ ExecInitPartitionInfo(ModifyTableState *mtstate, EState *estate,
}
else
{
+ TupleDesc partrelDesc = RelationGetDescr(partrel);
+ ExprContext *econtext = mtstate->ps.ps_ExprContext;
List *onconflset;
List *onconflcols;
reduce-some-scope-for-tupleDescAttr.patchapplication/octet-stream; name=reduce-some-scope-for-tupleDescAttr.patchDownload
diff --git a/src/backend/executor/execTuples.c b/src/backend/executor/execTuples.c
index 00dc339615..a4dc91869f 100644
--- a/src/backend/executor/execTuples.c
+++ b/src/backend/executor/execTuples.c
@@ -1044,7 +1044,7 @@ slot_deform_heap_tuple(TupleTableSlot *slot, HeapTuple tuple, uint32 *offp,
for (; attnum < natts; attnum++)
{
- Form_pg_attribute thisatt = TupleDescAttr(tupleDesc, attnum);
+ Form_pg_attribute thisatt;
if (hasnulls && att_isnull(attnum, bp))
{
@@ -1056,6 +1056,7 @@ slot_deform_heap_tuple(TupleTableSlot *slot, HeapTuple tuple, uint32 *offp,
isnull[attnum] = false;
+ thisatt = TupleDescAttr(tupleDesc, attnum);
if (!slow && thisatt->attcacheoff >= 0)
off = thisatt->attcacheoff;
else if (thisatt->attlen == -1)
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index 5737f9f4eb..57598e79a7 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -591,7 +591,7 @@ tlist_matches_tupdesc(PlanState *ps, List *tlist, int varno, TupleDesc tupdesc)
/* Check the tlist attributes */
for (attrno = 1; attrno <= numattrs; attrno++)
{
- Form_pg_attribute att_tup = TupleDescAttr(tupdesc, attrno - 1);
+ Form_pg_attribute att_tup;
Var *var;
if (tlist_item == NULL)
@@ -604,6 +604,7 @@ tlist_matches_tupdesc(PlanState *ps, List *tlist, int varno, TupleDesc tupdesc)
Assert(var->varlevelsup == 0);
if (var->varattno != attrno)
return false; /* out of order */
+ att_tup = TupleDescAttr(tupdesc, attrno - 1);
if (att_tup->attisdropped)
return false; /* table contains dropped columns */
if (att_tup->atthasmissing)
diff --git a/src/backend/executor/nodeTableFuncscan.c b/src/backend/executor/nodeTableFuncscan.c
index f483221bb8..9e28863d44 100644
--- a/src/backend/executor/nodeTableFuncscan.c
+++ b/src/backend/executor/nodeTableFuncscan.c
@@ -400,11 +400,10 @@ tfuncInitialize(TableFuncScanState *tstate, ExprContext *econtext, Datum doc)
tupdesc = tstate->ss.ss_ScanTupleSlot->tts_tupleDescriptor;
foreach(lc1, tstate->colexprs)
{
- char *colfilter;
- Form_pg_attribute att = TupleDescAttr(tupdesc, colno);
-
if (colno != ordinalitycol)
{
+ char *colfilter;
+ Form_pg_attribute att = TupleDescAttr(tupdesc, colno);
ExprState *colexpr = lfirst(lc1);
if (colexpr != NULL)
@@ -472,8 +471,6 @@ tfuncLoadRows(TableFuncScanState *tstate, ExprContext *econtext)
*/
for (colno = 0; colno < natts; colno++)
{
- Form_pg_attribute att = TupleDescAttr(tupdesc, colno);
-
if (colno == ordinalitycol)
{
/* Fast path for ordinality column */
@@ -482,6 +479,7 @@ tfuncLoadRows(TableFuncScanState *tstate, ExprContext *econtext)
}
else
{
+ Form_pg_attribute att = TupleDescAttr(tupdesc, colno);
bool isnull;
values[colno] = routine->GetValue(tstate,
remove-useless-duplicate-test-ruleutils.patchapplication/octet-stream; name=remove-useless-duplicate-test-ruleutils.patchDownload
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 653685bffc..aa38353185 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -4573,7 +4573,7 @@ set_join_column_names(deparse_namespace *dpns, RangeTblEntry *rte,
if (colname == NULL)
{
/* If user wrote an alias, prefer that over real column name */
- if (rte->alias && i < list_length(rte->alias->colnames))
+ if (i < list_length(rte->alias->colnames))
colname = strVal(list_nth(rte->alias->colnames, i));
else
colname = real_colname;
remove-useless-duplicate-test-string_utils.patchapplication/octet-stream; name=remove-useless-duplicate-test-string_utils.patchDownload
diff --git a/src/fe_utils/string_utils.c b/src/fe_utils/string_utils.c
index 09fd33907d..296a98dfbd 100644
--- a/src/fe_utils/string_utils.c
+++ b/src/fe_utils/string_utils.c
@@ -984,7 +984,7 @@ processSQLNamePattern(PGconn *conn, PQExpBuffer buf, const char *pattern,
/* We have a schema pattern, so constrain the schemavar */
/* Optimize away a "*" pattern */
- if (strcmp(schemabuf.data, "^(.*)$") != 0 && schemavar)
+ if (strcmp(schemabuf.data, "^(.*)$") != 0)
{
WHEREAND();
appendPQExpBuffer(buf, "%s OPERATOR(pg_catalog.~) ", schemavar);
On Tue, Jul 02, 2024 at 02:39:20PM -0300, Ranier Vilela wrote:
This is a series of patches to change styles, in assorted sources.
IMO, this improves a tiny bit and is worth trying.1. Avoid dereference iss_SortSupport if it has nulls.
2. Avoid dereference plan_node_id if no dsm area.
3. Avoid dereference spill partitions if zero ntuples.
4. Avoid possible useless palloc call with zero size.
5. Avoid redundant variable initialization in foreign.
6. Check the cheap test first in ExecMain.
7. Check the cheap test first in pathkeys.
8. Delay possible expensive bms_is_empty call in sub_select.
9. Reduce some scope in execPartition.
10. Reduce some scope for TupleDescAttr array dereference.
11. Remove useless duplicate test in ruleutils.
This is already checked at line 4566.12. Remove useless duplicate test in string_utils.
This is already checked at line 982.
You have something here, but not everything is worth changing without
a reason to do so, other than code "correctness". For example,
bms_is_empty() is a NULL comparison, so it does not matter. I don't
see a point in the three dereference patches, either, as these states
are expected AFAIK so it does not matter. If we crash, it's actually
an indication that something has gone wrong. Same comment about the
two remove-useless patches and the two reduce-some-scope.
The point about group_keys_reorder_by_pathkeys() is to be proved; I
doubt it matters. Same for the ExecBuildSlotValueDescription()
business to check for the acl_result before bms_is_member() does not
really matter performance-wise.
The allocation in execTuplesMatchPrepare() is indeed something that
we'd better avoid, that's minimal but memory that can be avoided is
always less error-prone. pg_options_to_table() also, is a bit better
this way. Applied these two, let's move on.
--
Michael
Thanks Michael.
Em seg., 7 de out. de 2024 às 22:53, Michael Paquier <michael@paquier.xyz>
escreveu:
On Tue, Jul 02, 2024 at 02:39:20PM -0300, Ranier Vilela wrote:
This is a series of patches to change styles, in assorted sources.
IMO, this improves a tiny bit and is worth trying.1. Avoid dereference iss_SortSupport if it has nulls.
2. Avoid dereference plan_node_id if no dsm area.
3. Avoid dereference spill partitions if zero ntuples.
4. Avoid possible useless palloc call with zero size.
5. Avoid redundant variable initialization in foreign.
6. Check the cheap test first in ExecMain.
7. Check the cheap test first in pathkeys.
8. Delay possible expensive bms_is_empty call in sub_select.
9. Reduce some scope in execPartition.
10. Reduce some scope for TupleDescAttr array dereference.
11. Remove useless duplicate test in ruleutils.
This is already checked at line 4566.12. Remove useless duplicate test in string_utils.
This is already checked at line 982.You have something here, but not everything is worth changing without
a reason to do so, other than code "correctness". For example,
bms_is_empty() is a NULL comparison, so it does not matter.
Of course, this is a tiny bit of optimization and it is something laborious
for the comitter.
I don't
see a point in the three dereference patches, either, as these states
are expected AFAIK so it does not matter. If we crash, it's actually
an indication that something has gone wrong.
Sorry by sorry for the confusing name patch.
Actually, these are not null pointers being dereferenced.
The point here is to avoid touching memory (cache or RAM) when it is not
strictly necessary.
Same comment about the
two remove-useless patches and the two reduce-some-scope.
Same motivation here, avoid touching memory (cache or RAM) when it is not
strictly necessary.
The point about group_keys_reorder_by_pathkeys() is to be proved; I
doubt it matters.
If *ec_sortref* is nonzero.
We avoid touching memory, an expensive branch and a call to an expensive
function.
Same for the ExecBuildSlotValueDescription()
business to check for the acl_result before bms_is_member() does not
really matter performance-wise.
Same here, if *aclresult* is ACLCHECK_OK,
we avoid an expensive subtraction and an expensive function call.
The allocation in execTuplesMatchPrepare() is indeed something that
we'd better avoid, that's minimal but memory that can be avoided is
always less error-prone. pg_options_to_table() also, is a bit better
this way. Applied these two, let's move on.
Great.
Thanks for your work.
best regards,
Ranier Vilela