Make Bitmapsets be valid Nodes.
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 13 Nov 2022 15:22:45 +0000 (10:22 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Sun, 13 Nov 2022 15:22:45 +0000 (10:22 -0500)
Add a NodeTag field to struct Bitmapset.  This is free because of
alignment considerations on 64-bit hardware.  While it adds some
space on 32-bit machines, we aren't optimizing for that case anymore.
The advantage is that data structures such as Lists of Bitmapsets
are now first-class objects to the Node infrastructure, and don't
require special-case code to handle.

This patch includes removal of one such special case, in indxpath.c:
bms_equal_any() can now be replaced by list_member().  There may be
more existing code that could be simplified, but I didn't look very
hard.  We also get to drop the read_write_ignore annotations on a
couple of RelOptInfo fields.

The outfuncs/readfuncs support is arranged so that nothing changes
in the string representation of a Bitmapset field; therefore, this
doesn't need a catversion bump.

Amit Langote and Tom Lane

Discussion: https://postgr.es/m/109089.1668197158@sss.pgh.pa.us

12 files changed:
src/backend/nodes/Makefile
src/backend/nodes/bitmapset.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/nodes/gen_node_support.pl
src/backend/nodes/outfuncs.c
src/backend/nodes/read.c
src/backend/nodes/readfuncs.c
src/backend/optimizer/path/indxpath.c
src/include/nodes/bitmapset.h
src/include/nodes/meson.build
src/include/nodes/pathnodes.h

index 7450e191ee205fefc909c109eece16589606edb2..d7b4261b474f4ef0a4f84dab9d2030dec2126823 100644 (file)
@@ -52,6 +52,7 @@ node_headers = \
        commands/trigger.h \
        executor/tuptable.h \
        foreign/fdwapi.h \
+       nodes/bitmapset.h \
        nodes/extensible.h \
        nodes/lockoptions.h \
        nodes/replnodes.h \
index 0a6c30e4ebce97ca6b40c5f57ced8f56fea26b1c..b7b274aeff3bae720a9f4b1e80211f2049aec6a8 100644 (file)
@@ -194,6 +194,7 @@ bms_make_singleton(int x)
        wordnum = WORDNUM(x);
        bitnum = BITNUM(x);
        result = (Bitmapset *) palloc0(BITMAPSET_SIZE(wordnum + 1));
+       result->type = T_Bitmapset;
        result->nwords = wordnum + 1;
        result->words[wordnum] = ((bitmapword) 1 << bitnum);
        return result;
@@ -852,6 +853,7 @@ bms_add_range(Bitmapset *a, int lower, int upper)
        if (a == NULL)
        {
                a = (Bitmapset *) palloc0(BITMAPSET_SIZE(uwordnum + 1));
+               a->type = T_Bitmapset;
                a->nwords = uwordnum + 1;
        }
        else if (uwordnum >= a->nwords)
index e76fda8eba3cfcaa6519856d4db7eee59786eea9..84f5e2e6ad161c4b8ceb8729c2079cffb1d1bc27 100644 (file)
@@ -160,6 +160,12 @@ _copyExtensibleNode(const ExtensibleNode *from)
        return newnode;
 }
 
+static Bitmapset *
+_copyBitmapset(const Bitmapset *from)
+{
+       return bms_copy(from);
+}
+
 
 /*
  * copyObjectImpl -- implementation of copyObject(); see nodes/nodes.h
index 0373aa30fe9fd1bcc91023188bb279507911d087..b2f07da62e0a394096b335ef1bef322d6c5fcc7b 100644 (file)
@@ -145,6 +145,12 @@ _equalA_Const(const A_Const *a, const A_Const *b)
        return true;
 }
 
+static bool
+_equalBitmapset(const Bitmapset *a, const Bitmapset *b)
+{
+       return bms_equal(a, b);
+}
+
 /*
  * Lists are handled specially
  */
index 81b8c184a90bb52a3474d547e4a75d73fbf61042..d3f25299ded7643deb6e66995dce8d3519b2542a 100644 (file)
@@ -65,6 +65,7 @@ my @all_input_files = qw(
   commands/trigger.h
   executor/tuptable.h
   foreign/fdwapi.h
+  nodes/bitmapset.h
   nodes/extensible.h
   nodes/lockoptions.h
   nodes/replnodes.h
index 64c65f060b4ad786337a6bbaa4e1f9d7ce5828db..f05e72f0dc3d0956f707fd2a7bf6b89f8deb64ba 100644 (file)
@@ -314,6 +314,9 @@ _outList(StringInfo str, const List *node)
  *        converts a bitmap set of integers
  *
  * Note: the output format is "(b int int ...)", similar to an integer List.
+ *
+ * We export this function for use by extensions that define extensible nodes.
+ * That's somewhat historical, though, because calling outNode() will work.
  */
 void
 outBitmapset(StringInfo str, const Bitmapset *bms)
@@ -844,6 +847,8 @@ outNode(StringInfo str, const void *obj)
                _outString(str, (String *) obj);
        else if (IsA(obj, BitString))
                _outBitString(str, (BitString *) obj);
+       else if (IsA(obj, Bitmapset))
+               outBitmapset(str, (Bitmapset *) obj);
        else
        {
                appendStringInfoChar(str, '{');
index fe84f140eefe8a95ef9228849af36865ab4b9ec2..74d9d754d3efc87408d75f4fd653c41af57f4250 100644 (file)
@@ -22,6 +22,7 @@
 #include <ctype.h>
 
 #include "common/string.h"
+#include "nodes/bitmapset.h"
 #include "nodes/pg_list.h"
 #include "nodes/readfuncs.h"
 #include "nodes/value.h"
@@ -347,6 +348,7 @@ nodeRead(const char *token, int tok_len)
                                 * Could be an integer list:    (i int int ...)
                                 * or an OID list:                              (o int int ...)
                                 * or an XID list:                              (x int int ...)
+                                * or a bitmapset:                              (b int int ...)
                                 * or a list of nodes/values:   (node node ...)
                                 *----------
                                 */
@@ -372,6 +374,7 @@ nodeRead(const char *token, int tok_len)
                                                                 tok_len, token);
                                                l = lappend_int(l, val);
                                        }
+                                       result = (Node *) l;
                                }
                                else if (tok_len == 1 && token[0] == 'o')
                                {
@@ -392,6 +395,7 @@ nodeRead(const char *token, int tok_len)
                                                                 tok_len, token);
                                                l = lappend_oid(l, val);
                                        }
+                                       result = (Node *) l;
                                }
                                else if (tok_len == 1 && token[0] == 'x')
                                {
@@ -412,6 +416,30 @@ nodeRead(const char *token, int tok_len)
                                                                 tok_len, token);
                                                l = lappend_xid(l, val);
                                        }
+                                       result = (Node *) l;
+                               }
+                               else if (tok_len == 1 && token[0] == 'b')
+                               {
+                                       /* Bitmapset -- see also _readBitmapset() */
+                                       Bitmapset  *bms = NULL;
+
+                                       for (;;)
+                                       {
+                                               int                     val;
+                                               char       *endptr;
+
+                                               token = pg_strtok(&tok_len);
+                                               if (token == NULL)
+                                                       elog(ERROR, "unterminated Bitmapset structure");
+                                               if (tok_len == 1 && token[0] == ')')
+                                                       break;
+                                               val = (int) strtol(token, &endptr, 10);
+                                               if (endptr != token + tok_len)
+                                                       elog(ERROR, "unrecognized integer: \"%.*s\"",
+                                                                tok_len, token);
+                                               bms = bms_add_member(bms, val);
+                                       }
+                                       result = (Node *) bms;
                                }
                                else
                                {
@@ -426,8 +454,8 @@ nodeRead(const char *token, int tok_len)
                                                if (token == NULL)
                                                        elog(ERROR, "unterminated List structure");
                                        }
+                                       result = (Node *) l;
                                }
-                               result = (Node *) l;
                                break;
                        }
                case RIGHT_PAREN:
index b4ff855f7c624e6a13821d9c5992e28203f32bf3..23776367c5279dca74d926add80e942ccdcd97ed 100644 (file)
@@ -194,6 +194,10 @@ nullable_string(const char *token, int length)
 
 /*
  * _readBitmapset
+ *
+ * Note: this code is used in contexts where we know that a Bitmapset
+ * is expected.  There is equivalent code in nodeRead() that can read a
+ * Bitmapset when we come across one in other contexts.
  */
 static Bitmapset *
 _readBitmapset(void)
@@ -234,7 +238,8 @@ _readBitmapset(void)
 }
 
 /*
- * for use by extensions which define extensible nodes
+ * We export this function for use by extensions that define extensible nodes.
+ * That's somewhat historical, though, because calling nodeRead() will work.
  */
 Bitmapset *
 readBitmapset(void)
index 77f3f81bcb66057f50674661d4240f47170352d0..914bfd90bc6d299718dbc6739d419df349679fb2 100644 (file)
@@ -99,7 +99,6 @@ static void get_join_index_paths(PlannerInfo *root, RelOptInfo *rel,
                                                                 List **considered_relids);
 static bool eclass_already_used(EquivalenceClass *parent_ec, Relids oldrelids,
                                                                List *indexjoinclauses);
-static bool bms_equal_any(Relids relids, List *relids_list);
 static void get_index_paths(PlannerInfo *root, RelOptInfo *rel,
                                                        IndexOptInfo *index, IndexClauseSet *clauses,
                                                        List **bitindexpaths);
@@ -370,8 +369,8 @@ create_index_paths(PlannerInfo *root, RelOptInfo *rel)
                        Path       *path = (Path *) lfirst(lc);
                        Relids          required_outer = PATH_REQ_OUTER(path);
 
-                       if (!bms_equal_any(required_outer, all_path_outers))
-                               all_path_outers = lappend(all_path_outers, required_outer);
+                       all_path_outers = list_append_unique(all_path_outers,
+                                                                                                required_outer);
                }
 
                /* Now, for each distinct parameterization set ... */
@@ -517,7 +516,7 @@ consider_index_join_outer_rels(PlannerInfo *root, RelOptInfo *rel,
                int                     num_considered_relids;
 
                /* If we already tried its relids set, no need to do so again */
-               if (bms_equal_any(clause_relids, *considered_relids))
+               if (list_member(*considered_relids, clause_relids))
                        continue;
 
                /*
@@ -612,7 +611,7 @@ get_join_index_paths(PlannerInfo *root, RelOptInfo *rel,
        int                     indexcol;
 
        /* If we already considered this relids set, don't repeat the work */
-       if (bms_equal_any(relids, *considered_relids))
+       if (list_member(*considered_relids, relids))
                return;
 
        /* Identify indexclauses usable with this relids set */
@@ -694,25 +693,6 @@ eclass_already_used(EquivalenceClass *parent_ec, Relids oldrelids,
        return false;
 }
 
-/*
- * bms_equal_any
- *             True if relids is bms_equal to any member of relids_list
- *
- * Perhaps this should be in bitmapset.c someday.
- */
-static bool
-bms_equal_any(Relids relids, List *relids_list)
-{
-       ListCell   *lc;
-
-       foreach(lc, relids_list)
-       {
-               if (bms_equal(relids, (Relids) lfirst(lc)))
-                       return true;
-       }
-       return false;
-}
-
 
 /*
  * get_index_paths
index 75b5ce1a8e4726623475d00d005e3c14de86545e..27922816581815fc1c57b000d82859f67f239740 100644 (file)
@@ -20,6 +20,8 @@
 #ifndef BITMAPSET_H
 #define BITMAPSET_H
 
+#include "nodes/nodes.h"
+
 /*
  * Forward decl to save including pg_list.h
  */
@@ -48,6 +50,9 @@ typedef int32 signedbitmapword; /* must be the matching signed type */
 
 typedef struct Bitmapset
 {
+       pg_node_attr(custom_copy_equal, special_read_write)
+
+       NodeTag         type;
        int                     nwords;                 /* number of words in array */
        bitmapword      words[FLEXIBLE_ARRAY_MEMBER];   /* really [nwords] */
 } Bitmapset;
index b7df232081f2f29c389e0c6ce92090cc01d401ad..e63881086eef8821d6540e6759433b59d28d6369 100644 (file)
@@ -13,6 +13,7 @@ node_support_input_i = [
   'commands/trigger.h',
   'executor/tuptable.h',
   'foreign/fdwapi.h',
+  'nodes/bitmapset.h',
   'nodes/extensible.h',
   'nodes/lockoptions.h',
   'nodes/replnodes.h',
index 09342d128d57c6c0bc4fab0b6c9dd29d512d91ec..a544b313d36c039b24ab5f9b61d9e5b0a55e82ec 100644 (file)
@@ -911,13 +911,11 @@ typedef struct RelOptInfo
 
        /*
         * cache space for remembering if we have proven this relation unique
-        *
-        * can't print unique_for_rels/non_unique_for_rels; BMSes aren't Nodes
         */
        /* known unique for these other relid set(s) */
-       List       *unique_for_rels pg_node_attr(read_write_ignore);
+       List       *unique_for_rels;
        /* known not unique for these set(s) */
-       List       *non_unique_for_rels pg_node_attr(read_write_ignore);
+       List       *non_unique_for_rels;
 
        /*
         * used by various scans and joins: