*Subject:* Contribution Interest – Bug Fix on Reducing "Var IS [NOT] NULL" Quals During Constant Folding
Dear Team, I hope this message finds you well. With reference to the conversation ongioing in message ID: (CAMbWs487wxHq0fUu+Cew7Y+n+wpY_B--PT-61syXrE40uZqErw <https://www.postgresql.org/message-id/CAMbWs487wxHq0fUu%2BCew7Y%2Bn%2BwpY_B--PT-61syXrE40uZqErw%40mail.gmail.com> , I am writing to express my interest in contributing to the ongoing work on fixing the bug related to reducing “Var IS [NOT] NULL” quals during constant folding. As part of my initial efforts, I have been exploring the planner code paths and introducing an approach to gather early catalog information for base relations. Specifically, I have implemented the following: - Preprocessing Relation RTEs - Added a new static function preprocess_relation_rtes() in src/backend/optimizer/plan/planner.c to collect attribute-level metadata (e.g., NOT NULL, generated columns, inheritance flags) at an early stage. - Hash Table for Attribute Info - Defined a new planner-local hash table (relattrinfo_htab) for storing per-attribute information. - Created a supporting header (src/include/optimizer/relattrinfo.h) and implementation file (src/backend/optimizer/util/relattrinfo.c). - Planner Integration - Initialized the attribute info hash table in subquery_planner(). - Ensured preprocessing is invoked before pull_up_sublinks(). - Optimization Step - Extended the constant folding path to check stored attribute metadata during IS [NOT] NULL qual simplification, allowing safe reduction to constant true/false where applicable. 1. Declare - *preprocess_relation_rtes()* File: in subquery_planner() inside *src/backend/optimizer/plan/planner.c*. - Insert your new step *before* pull_up_sublinks(). *Snippet:* /* * Do preprocessing of RTEs before we pull up sublinks */ preprocess_relation_rtes(root); 2.Create a new static function *preprocess_relation_rtes()* in planner.c: File: *src/backend/optimizer/plan/planner.c* *Snippet:* /* * preprocess_relation_rtes * Gather early catalog info for each base relation * (NOT NULL attrs, generated cols, inheritance flags). */static void preprocess_relation_rtes(PlannerInfo *root){ ListCell *lc; Relation rel; foreach(lc, root->parse->rtable) { RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc); if (rte->rtekind == RTE_RELATION) { rel = table_open(rte->relid, AccessShareLock); /* Collect attnotnull info */ TupleDesc tupdesc = RelationGetDescr(rel); for (int attno = 0; attno < tupdesc->natts; attno++) { Form_pg_attribute attr = TupleDescAttr(tupdesc, attno); if (!attr->attisdropped) { if (attr->attnotnull) store_notnull_info(root, rte->relid, attno + 1); if (attr->attgenerated) store_generated_info(root, rte->relid, attno + 1); } } /* Inheritance flag */ if (rel->rd_rel->relhassubclass) store_inh_info(root, rte->relid); table_close(rel, AccessShareLock); } } } 3. Filename* – **src/include/nodes/pathnodes.h* *Snippet:* typedef struct PlannerInfo { HTAB *relattrinfo_htab; /* plannerlocal cache of attr metadata */ } PlannerInfo; 4. Create a new header. Location: *src/include/optimizer/relattrinfo.h* *Snippet: * #ifndef RELATTRINFO_H #define RELATTRINFO_H #include "postgres.h" #include "utils/hsearch.h" /* key for hash table */ typedef struct RelAttrInfoKey { Oid relid; /* relation OID */ AttrNumber attno; /* attribute number (1-based) */ } RelAttrInfoKey; /* value stored in hash table */ typedef struct RelAttrInfoEntry { RelAttrInfoKey key; bool notnull; bool generated; } RelAttrInfoEntry; extern HTAB *create_relattrinfo_htab(void); #endif /* RELATTRINFO_H */ 5. Created a new file. Location: *src/backend/optimizer/util/relattrinfo.c* *Snippet:* #include "postgres.h" #include "optimizer/relattrinfo.h" HTAB *create_relattrinfo_htab(void) { HASHCTL ctl; memset(&ctl, 0, sizeof(ctl)); ctl.keysize = sizeof(RelAttrInfoKey); ctl.entrysize = sizeof(RelAttrInfoEntry); return hash_create("Planner relattr info cache", 128, /* initial size */ &ctl, HASH_ELEM | HASH_BLOBS); } 6. File: *src/backend/optimizer/plan/planner.c* in *subquery_planner()* (this runs before most rewrites). *Snippet:* */** Create hash table for early attr info */ root->relattrinfo_htab = create_relattrinfo_htab(); /* Collect early info before pull_up_sublinks */ preprocess_relation_rtes(root); 7. *C**reate**d** a hash table* File: *src/backend/optimizer/plan/planner.c* *Example:* typedef struct RelAttrInfoKey{ Oid relid; AttrNumber attno;} RelAttrInfoKey; typedef struct RelAttrInfoEntry{ RelAttrInfoKey key; bool notnull; bool generated;} RelAttrInfoEntry; Initialize it in *subquery_planner()*: root->relattrinfo_htab = create_relattrinfo_htab(); 8. Constant folding if (IsA(arg, Var)){ Var *var = (Var *) arg; if (lookup_notnull_info(root, var->varno, var->varattno)) { if (ntest->nulltesttype == IS_NOT_NULL) return (Expr *) makeBoolConst(true, false); else return (Expr *) makeBoolConst(false, false); }} With this groundwork, my plan is to continue refining the approach, validating correctness against inheritance cases, and ensuring compliance with planner invariants. I would also like to engage with reviewers to align this with the broader design direction. Please let me know how best I can proceed with submitting my patch for review and contributing further to this fix. Thank you for your time and consideration. Best Regards, Soumya