v13 support
[plantuner.git] / plantuner.c
index 5a1d480..f87dcea 100644 (file)
@@ -30,7 +30,9 @@
 #include <postgres.h>
 
 #include <fmgr.h>
+#include <miscadmin.h>
 #include <access/heapam.h>
+#include <access/xact.h>
 #include <catalog/namespace.h>
 #include <catalog/pg_class.h>
 #include <nodes/pg_list.h>
 
 PG_MODULE_MAGIC;
 
+#if PG_VERSION_NUM >= 130000
+#define heap_open(r, l)                                        table_open(r, l)
+#define heap_close(r, l)                               table_close(r, l)
+#endif
+
 static int     nDisabledIndexes = 0;
 static Oid     *disabledIndexes = NULL;
 static char *disableIndexesOutStr = "";
@@ -55,12 +62,26 @@ static int  nEnabledIndexes = 0;
 static Oid     *enabledIndexes = NULL;
 static char *enableIndexesOutStr = "";
 
+static int     nOnlyIndexes = 0;
+static Oid     *onlyIndexes = NULL;
+static char *onlyIndexesOutStr = "";
+
 get_relation_info_hook_type    prevHook = NULL;
 static bool    fix_empty_table = false;
 
+static bool    plantuner_enable_inited = false;
+static bool    plantuner_only_inited = false;
+static bool    plantuner_disable_inited = false;
+
+typedef enum IndexListKind {
+       EnabledKind,
+       DisabledKind,
+       OnlyKind
+} IndexListKind;
 
 static const char *
-indexesAssign(const char * newval, bool doit, GucSource source, bool isDisable)
+indexesAssign(const char * newval, bool doit, GucSource source,
+                         IndexListKind kind)
 {
        char            *rawname;
        List            *namelist;
@@ -74,6 +95,32 @@ indexesAssign(const char * newval, bool doit, GucSource source, bool isDisable)
        if (!SplitIdentifierString(rawname, ',', &namelist))
                goto cleanup;
 
+       /*
+        * follow work could be done only in normal processing because of
+        * accsess to system catalog
+        */
+       if (MyBackendId == InvalidBackendId || !IsUnderPostmaster ||
+               !IsTransactionState())
+       {
+               /* reset init state */
+               switch(kind)
+               {
+                       case EnabledKind:
+                               plantuner_enable_inited = false;
+                               break;
+                       case DisabledKind:
+                               plantuner_disable_inited = false;
+                               break;
+                       case OnlyKind:
+                               plantuner_only_inited = false;
+                               break;
+                       default:
+                               elog(ERROR, "wrong kind");
+               }
+
+               return newval;
+       }
+
        if (doit)
        {
                nOids = list_length(namelist);
@@ -83,6 +130,21 @@ indexesAssign(const char * newval, bool doit, GucSource source, bool isDisable)
                                 (int)(sizeof(Oid) * (nOids+1)));
        }
 
+       switch(kind)
+       {
+               case EnabledKind:
+                       plantuner_enable_inited = true;
+                       break;
+               case DisabledKind:
+                       plantuner_disable_inited = true;
+                       break;
+               case OnlyKind:
+                       plantuner_only_inited = true;
+                       break;
+               default:
+                       elog(ERROR, "wrong kind");
+       }
+
        foreach(l, namelist)
        {
                char    *curname = (char *) lfirst(l);
@@ -120,19 +182,28 @@ indexesAssign(const char * newval, bool doit, GucSource source, bool isDisable)
 
        if (doit)
        {
-               if (isDisable)
-               {
-                       nDisabledIndexes = i;
-                       if (disabledIndexes)
-                               free(disabledIndexes);
-                       disabledIndexes = newOids;
-               }
-               else
+               switch(kind)
                {
-                       nEnabledIndexes = i;
-                       if (enabledIndexes)
-                               free(enabledIndexes);
-                       enabledIndexes = newOids;
+                       case EnabledKind:
+                               nEnabledIndexes = i;
+                               if (enabledIndexes)
+                                       free(enabledIndexes);
+                               enabledIndexes = newOids;
+                               break;
+                       case DisabledKind:
+                               nDisabledIndexes = i;
+                               if (disabledIndexes)
+                                       free(disabledIndexes);
+                               disabledIndexes = newOids;
+                               break;
+                       case OnlyKind:
+                               nOnlyIndexes = i;
+                               if (onlyIndexes)
+                                       free(onlyIndexes);
+                               onlyIndexes = newOids;
+                               break;
+                       default:
+                               elog(ERROR, "wrong kind");
                }
        }
 
@@ -152,23 +223,56 @@ cleanup:
 static const char *
 assignDisabledIndexes(const char * newval, bool doit, GucSource source)
 {
-       return indexesAssign(newval, doit, source, true);
+       return indexesAssign(newval, doit, source, DisabledKind);
 }
 
 static const char *
 assignEnabledIndexes(const char * newval, bool doit, GucSource source)
 {
-       return indexesAssign(newval, doit, source, false);
+       return indexesAssign(newval, doit, source, EnabledKind);
+}
+
+static const char *
+assignOnlyIndexes(const char * newval, bool doit, GucSource source)
+{
+       return indexesAssign(newval, doit, source, OnlyKind);
+}
+
+static void
+lateInit()
+{
+       if (!plantuner_only_inited)
+               indexesAssign(onlyIndexesOutStr, true, PGC_S_USER, OnlyKind);
+       if (!plantuner_enable_inited)
+               indexesAssign(enableIndexesOutStr, true, PGC_S_USER, EnabledKind);
+       if (!plantuner_disable_inited)
+               indexesAssign(disableIndexesOutStr, true, PGC_S_USER, DisabledKind);
 }
 
 #if PG_VERSION_NUM >= 90100
 
+static bool
+checkOnlyIndexes(char **newval, void **extra, GucSource source)
+{
+       char *val;
+
+       val = (char*)indexesAssign(*newval, false, source, OnlyKind);
+
+       if (val)
+       {
+               *newval = val;
+               return true;
+       }
+
+       return false;
+}
+
 static bool
 checkDisabledIndexes(char **newval, void **extra, GucSource source)
 {
        char *val;
 
-       val = (char*)indexesAssign(*newval, false, source, true);
+       val = (char*)indexesAssign(*newval, false, source, DisabledKind);
 
        if (val)
        {
@@ -184,7 +288,7 @@ checkEnabledIndexes(char **newval, void **extra, GucSource source)
 {
        char *val;
 
-       val = (char*)indexesAssign(*newval, false, source, false);
+       val = (char*)indexesAssign(*newval, false, source, EnabledKind);
 
        if (val)
        {
@@ -207,6 +311,12 @@ assignEnabledIndexesNew(const char *newval, void *extra)
        assignEnabledIndexes(newval, true, PGC_S_USER /* doesn't matter */);
 }
 
+static void
+assignOnlyIndexesNew(const char *newval, void *extra)
+{
+       assignOnlyIndexes(newval, true, PGC_S_USER /* doesn't matter */);
+}
+
 #endif
 
 static void
@@ -215,7 +325,33 @@ indexFilter(PlannerInfo *root, Oid relationObjectId, bool inhparent,
 {
        int i;
 
-       for(i=0;i<nDisabledIndexes;i++)
+       lateInit();
+
+       if (nOnlyIndexes > 0)
+       {
+               ListCell        *l;
+
+restart1:
+               foreach(l, rel->indexlist)
+               {
+                       IndexOptInfo    *info = (IndexOptInfo*)lfirst(l);
+                       bool                    remove = true;
+
+                       for(i=0; remove && i<nOnlyIndexes; i++)
+                               if (onlyIndexes[i] == info->indexoid)
+                                       remove = false;
+
+                       if (remove)
+                       {
+                               rel->indexlist = list_delete_ptr(rel->indexlist, info);
+                               goto restart1;
+                       }
+               }
+
+               return;
+       }
+
+       for(i=0; i<nDisabledIndexes; i++)
        {
                ListCell   *l;
 
@@ -255,7 +391,7 @@ execPlantuner(PlannerInfo *root, Oid relationObjectId, bool inhparent,
                         * estimate_rel_size() could be too pessimistic for particular
                         * workload
                         */
-                       rel->pages = 0.0;
+                       rel->pages = 1.0;
                        rel->tuples = 0.0;
                }
 
@@ -277,6 +413,8 @@ IndexFilterShow(Oid* indexes, int nIndexes)
        int             i,
                        len;
 
+       lateInit();
+
        len = 1 /* \0 */ + nIndexes * (2 * NAMEDATALEN + 2 /* ', ' */ + 1 /* . */);
        ptr = val = palloc(len);
 
@@ -311,6 +449,12 @@ enabledIndexFilterShow(void)
        return IndexFilterShow(enabledIndexes, nEnabledIndexes);
 }
 
+static const char*
+onlyIndexFilterShow(void)
+{
+       return IndexFilterShow(onlyIndexes, nOnlyIndexes);
+}
+
 void _PG_init(void);
 void
 _PG_init(void)
@@ -366,6 +510,23 @@ _PG_init(void)
                enabledIndexFilterShow
        );
 
+       DefineCustomStringVariable(
+               "plantuner.only_index",
+               "List of explicitly enabled indexes (overload plantuner.disable_index and plantuner.enable_index)",
+               "Only indexes in this list are allowed",
+               &onlyIndexesOutStr,
+               "",
+               PGC_USERSET,
+               0,
+#if PG_VERSION_NUM >= 90100
+               checkOnlyIndexes,
+               assignOnlyIndexesNew,
+#else
+               assignOnlyIndexes,
+#endif
+               onlyIndexFilterShow
+       );
+
        DefineCustomBoolVariable(
                "plantuner.fix_empty_table",
                "Sets to zero estimations for empty tables",