]> granicus.if.org Git - postgresql/blobdiff - src/backend/access/gin/ginutil.c
Report progress of CREATE INDEX operations
[postgresql] / src / backend / access / gin / ginutil.c
index b4c69e7bfe7c0e4ce1eb33079acf196082ae14ae..d2360eeafb0ee357473c7c76a4331dc9d4a2a598 100644 (file)
@@ -4,7 +4,7 @@
  *       Utility routines for the Postgres inverted index access method.
  *
  *
- * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
@@ -15,6 +15,7 @@
 #include "postgres.h"
 
 #include "access/gin_private.h"
+#include "access/ginxlog.h"
 #include "access/reloptions.h"
 #include "access/xloginsert.h"
 #include "catalog/pg_collation.h"
 #include "miscadmin.h"
 #include "storage/indexfsm.h"
 #include "storage/lmgr.h"
+#include "storage/predicate.h"
+#include "utils/builtins.h"
 #include "utils/index_selfuncs.h"
+#include "utils/typcache.h"
 
 
 /*
@@ -35,7 +39,7 @@ ginhandler(PG_FUNCTION_ARGS)
        IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
 
        amroutine->amstrategies = 0;
-       amroutine->amsupport = 6;
+       amroutine->amsupport = GINNProcs;
        amroutine->amcanorder = false;
        amroutine->amcanorderbyop = false;
        amroutine->amcanbackward = false;
@@ -46,7 +50,8 @@ ginhandler(PG_FUNCTION_ARGS)
        amroutine->amsearchnulls = false;
        amroutine->amstorage = true;
        amroutine->amclusterable = false;
-       amroutine->ampredlocks = false;
+       amroutine->ampredlocks = true;
+       amroutine->amcanparallel = false;
        amroutine->amcaninclude = false;
        amroutine->amkeytype = InvalidOid;
 
@@ -58,6 +63,8 @@ ginhandler(PG_FUNCTION_ARGS)
        amroutine->amcanreturn = NULL;
        amroutine->amcostestimate = gincostestimate;
        amroutine->amoptions = ginoptions;
+       amroutine->amproperty = NULL;
+       amroutine->ambuildphasename = NULL;
        amroutine->amvalidate = ginvalidate;
        amroutine->ambeginscan = ginbeginscan;
        amroutine->amrescan = ginrescan;
@@ -66,6 +73,9 @@ ginhandler(PG_FUNCTION_ARGS)
        amroutine->amendscan = ginendscan;
        amroutine->ammarkpos = NULL;
        amroutine->amrestrpos = NULL;
+       amroutine->amestimateparallelscan = NULL;
+       amroutine->aminitparallelscan = NULL;
+       amroutine->amparallelrescan = NULL;
 
        PG_RETURN_POINTER(amroutine);
 }
@@ -89,25 +99,51 @@ initGinState(GinState *state, Relation index)
 
        for (i = 0; i < origTupdesc->natts; i++)
        {
+               Form_pg_attribute attr = TupleDescAttr(origTupdesc, i);
+
                if (state->oneCol)
                        state->tupdesc[i] = state->origTupdesc;
                else
                {
-                       state->tupdesc[i] = CreateTemplateTupleDesc(2, false);
+                       state->tupdesc[i] = CreateTemplateTupleDesc(2);
 
                        TupleDescInitEntry(state->tupdesc[i], (AttrNumber) 1, NULL,
                                                           INT2OID, -1, 0);
                        TupleDescInitEntry(state->tupdesc[i], (AttrNumber) 2, NULL,
-                                                          origTupdesc->attrs[i]->atttypid,
-                                                          origTupdesc->attrs[i]->atttypmod,
-                                                          origTupdesc->attrs[i]->attndims);
+                                                          attr->atttypid,
+                                                          attr->atttypmod,
+                                                          attr->attndims);
                        TupleDescInitEntryCollation(state->tupdesc[i], (AttrNumber) 2,
-                                                                               origTupdesc->attrs[i]->attcollation);
+                                                                               attr->attcollation);
                }
 
-               fmgr_info_copy(&(state->compareFn[i]),
-                                          index_getprocinfo(index, i + 1, GIN_COMPARE_PROC),
-                                          CurrentMemoryContext);
+               /*
+                * If the compare proc isn't specified in the opclass definition, look
+                * up the index key type's default btree comparator.
+                */
+               if (index_getprocid(index, i + 1, GIN_COMPARE_PROC) != InvalidOid)
+               {
+                       fmgr_info_copy(&(state->compareFn[i]),
+                                                  index_getprocinfo(index, i + 1, GIN_COMPARE_PROC),
+                                                  CurrentMemoryContext);
+               }
+               else
+               {
+                       TypeCacheEntry *typentry;
+
+                       typentry = lookup_type_cache(attr->atttypid,
+                                                                                TYPECACHE_CMP_PROC_FINFO);
+                       if (!OidIsValid(typentry->cmp_proc_finfo.fn_oid))
+                               ereport(ERROR,
+                                               (errcode(ERRCODE_UNDEFINED_FUNCTION),
+                                                errmsg("could not identify a comparison function for type %s",
+                                                               format_type_be(attr->atttypid))));
+                       fmgr_info_copy(&(state->compareFn[i]),
+                                                  &(typentry->cmp_proc_finfo),
+                                                  CurrentMemoryContext);
+               }
+
+               /* Opclass must always provide extract procs */
                fmgr_info_copy(&(state->extractValueFn[i]),
                                           index_getprocinfo(index, i + 1, GIN_EXTRACTVALUE_PROC),
                                           CurrentMemoryContext);
@@ -122,14 +158,14 @@ initGinState(GinState *state, Relation index)
                if (index_getprocid(index, i + 1, GIN_TRICONSISTENT_PROC) != InvalidOid)
                {
                        fmgr_info_copy(&(state->triConsistentFn[i]),
-                                        index_getprocinfo(index, i + 1, GIN_TRICONSISTENT_PROC),
+                                                  index_getprocinfo(index, i + 1, GIN_TRICONSISTENT_PROC),
                                                   CurrentMemoryContext);
                }
 
                if (index_getprocid(index, i + 1, GIN_CONSISTENT_PROC) != InvalidOid)
                {
                        fmgr_info_copy(&(state->consistentFn[i]),
-                                               index_getprocinfo(index, i + 1, GIN_CONSISTENT_PROC),
+                                                  index_getprocinfo(index, i + 1, GIN_CONSISTENT_PROC),
                                                   CurrentMemoryContext);
                }
 
@@ -147,7 +183,7 @@ initGinState(GinState *state, Relation index)
                if (index_getprocid(index, i + 1, GIN_COMPARE_PARTIAL_PROC) != InvalidOid)
                {
                        fmgr_info_copy(&(state->comparePartialFn[i]),
-                                  index_getprocinfo(index, i + 1, GIN_COMPARE_PARTIAL_PROC),
+                                                  index_getprocinfo(index, i + 1, GIN_COMPARE_PARTIAL_PROC),
                                                   CurrentMemoryContext);
                        state->canPartialMatch[i] = true;
                }
@@ -274,12 +310,7 @@ GinNewBuffer(Relation index)
                 */
                if (ConditionalLockBuffer(buffer))
                {
-                       Page            page = BufferGetPage(buffer);
-
-                       if (PageIsNew(page))
-                               return buffer;  /* OK to use, if never initialized */
-
-                       if (GinPageIsDeleted(page))
+                       if (GinPageIsRecyclable(BufferGetPage(buffer)))
                                return buffer;  /* OK to use */
 
                        LockBuffer(buffer, GIN_UNLOCK);
@@ -341,6 +372,14 @@ GinInitMetabuffer(Buffer b)
        metadata->nDataPages = 0;
        metadata->nEntries = 0;
        metadata->ginVersion = GIN_CURRENT_VERSION;
+
+       /*
+        * Set pd_lower just past the end of the metadata.  This is essential,
+        * because without doing so, metadata will be lost if xlog.c compresses
+        * the page.
+        */
+       ((PageHeader) page)->pd_lower =
+               ((char *) metadata + sizeof(GinMetaPageData)) - (char *) page;
 }
 
 /*
@@ -361,7 +400,7 @@ ginCompareEntries(GinState *ginstate, OffsetNumber attnum,
 
        /* both not null, so safe to call the compareFn */
        return DatumGetInt32(FunctionCall2Coll(&ginstate->compareFn[attnum - 1],
-                                                                         ginstate->supportCollation[attnum - 1],
+                                                                                  ginstate->supportCollation[attnum - 1],
                                                                                   a, b));
 }
 
@@ -468,7 +507,7 @@ ginExtractEntries(GinState *ginstate, OffsetNumber attnum,
        nullFlags = NULL;                       /* in case extractValue doesn't set it */
        entries = (Datum *)
                DatumGetPointer(FunctionCall3Coll(&ginstate->extractValueFn[attnum - 1],
-                                                                         ginstate->supportCollation[attnum - 1],
+                                                                                 ginstate->supportCollation[attnum - 1],
                                                                                  value,
                                                                                  PointerGetDatum(nentries),
                                                                                  PointerGetDatum(&nullFlags)));
@@ -488,19 +527,10 @@ ginExtractEntries(GinState *ginstate, OffsetNumber attnum,
 
        /*
         * If the extractValueFn didn't create a nullFlags array, create one,
-        * assuming that everything's non-null.  Otherwise, run through the array
-        * and make sure each value is exactly 0 or 1; this ensures binary
-        * compatibility with the GinNullCategory representation.
+        * assuming that everything's non-null.
         */
        if (nullFlags == NULL)
                nullFlags = (bool *) palloc0(*nentries * sizeof(bool));
-       else
-       {
-               for (i = 0; i < *nentries; i++)
-                       nullFlags[i] = (nullFlags[i] ? true : false);
-       }
-       /* now we can use the nullFlags as category codes */
-       *categories = (GinNullCategory *) nullFlags;
 
        /*
         * If there's more than one key, sort and unique-ify.
@@ -559,6 +589,13 @@ ginExtractEntries(GinState *ginstate, OffsetNumber attnum,
                pfree(keydata);
        }
 
+       /*
+        * Create GinNullCategory representation from nullFlags.
+        */
+       *categories = (GinNullCategory *) palloc0(*nentries * sizeof(GinNullCategory));
+       for (i = 0; i < *nentries; i++)
+               (*categories)[i] = (nullFlags[i] ? GIN_CAT_NULL_KEY : GIN_CAT_NORM_KEY);
+
        return entries;
 }
 
@@ -571,7 +608,7 @@ ginoptions(Datum reloptions, bool validate)
        static const relopt_parse_elt tab[] = {
                {"fastupdate", RELOPT_TYPE_BOOL, offsetof(GinOptions, useFastUpdate)},
                {"gin_pending_list_limit", RELOPT_TYPE_INT, offsetof(GinOptions,
-                                                                                                        pendingListCleanupSize)}
+                                                                                                                        pendingListCleanupSize)}
        };
 
        options = parseRelOptions(reloptions, validate, RELOPT_KIND_GIN,
@@ -643,6 +680,16 @@ ginUpdateStats(Relation index, const GinStatsData *stats)
        metadata->nDataPages = stats->nDataPages;
        metadata->nEntries = stats->nEntries;
 
+       /*
+        * Set pd_lower just past the end of the metadata.  This is essential,
+        * because without doing so, metadata will be lost if xlog.c compresses
+        * the page.  (We must do this here because pre-v11 versions of PG did not
+        * set the metapage's pd_lower correctly, so a pg_upgraded index might
+        * contain the wrong value.)
+        */
+       ((PageHeader) metapage)->pd_lower =
+               ((char *) metadata + sizeof(GinMetaPageData)) - (char *) metapage;
+
        MarkBufferDirty(metabuffer);
 
        if (RelationNeedsWAL(index))
@@ -657,7 +704,7 @@ ginUpdateStats(Relation index, const GinStatsData *stats)
 
                XLogBeginInsert();
                XLogRegisterData((char *) &data, sizeof(ginxlogUpdateMeta));
-               XLogRegisterBuffer(0, metabuffer, REGBUF_WILL_INIT);
+               XLogRegisterBuffer(0, metabuffer, REGBUF_WILL_INIT | REGBUF_STANDARD);
 
                recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_UPDATE_META_PAGE);
                PageSetLSN(metapage, recptr);