Introduce traversalValue for SP-GiST scan
authorTeodor Sigaev <teodor@sigaev.ru>
Wed, 30 Mar 2016 15:29:28 +0000 (18:29 +0300)
committerTeodor Sigaev <teodor@sigaev.ru>
Wed, 30 Mar 2016 15:29:28 +0000 (18:29 +0300)
During scan sometimes it would be very helpful to know some information about
parent node or all  ancestor nodes. Right now reconstructedValue could be used
but it's not a right usage of it (range opclass uses that).

traversalValue is arbitrary piece of memory in separate MemoryContext while
reconstructedVale should have the same type as indexed column.

Subsequent patches for range opclass and quad4d tree will use it.

Author: Alexander Lebedev, Teodor Sigaev

doc/src/sgml/spgist.sgml
src/backend/access/spgist/spgscan.c
src/include/access/spgist.h

index 56827e520dd62a7a07ac2959e8530143a3fb7dc9..0d44d064aaa039f2b47d61b1de8a8366a6dbbdd7 100644 (file)
@@ -542,6 +542,8 @@ typedef struct spgInnerConsistentIn
     int         nkeys;          /* length of array */
 
     Datum       reconstructedValue;     /* value reconstructed at parent */
+    void       *traversalValue; /* opclass-specific traverse value */
+    MemoryContext traversalMemoryContext;
     int         level;          /* current level (counting from zero) */
     bool        returnData;     /* original data must be returned? */
 
@@ -559,6 +561,8 @@ typedef struct spgInnerConsistentOut
     int        *nodeNumbers;    /* their indexes in the node array */
     int        *levelAdds;      /* increment level by this much for each */
     Datum      *reconstructedValues;    /* associated reconstructed values */
+    void      **traversalValues;        /* opclass-specific traverse values */
+
 } spgInnerConsistentOut;
 </programlisting>
 
@@ -593,6 +597,9 @@ typedef struct spgInnerConsistentOut
        inner tuple, and
        <structfield>nodeLabels</> is an array of their label values, or
        NULL if the nodes do not have labels.
+       <structfield>traversalValue</> is a pointer to data that
+       <function>inner_consistent</> gets when called on child nodes from an
+       outer call of <function>inner_consistent</> on parent nodes.
       </para>
 
       <para>
@@ -612,6 +619,13 @@ typedef struct spgInnerConsistentOut
        responsible for palloc'ing the
        <structfield>nodeNumbers</>, <structfield>levelAdds</> and
        <structfield>reconstructedValues</> arrays.
+       Sometimes accumulating some information is needed, while 
+       descending from parent to child node was happened. In this case
+       <structfield>traversalValues</> array keeps pointers to
+       specific data you need to accumulate for every child node.
+       Memory for <structfield>traversalValues</> should be allocated in
+       the default context, but each element of it should be allocated in
+       <structfield>traversalMemoryContext</>.
       </para>
      </listitem>
     </varlistentry>
@@ -638,6 +652,7 @@ typedef struct spgLeafConsistentIn
     ScanKey     scankeys;       /* array of operators and comparison values */
     int         nkeys;          /* length of array */
 
+    void       *traversalValue; /* opclass-specific traverse value */
     Datum       reconstructedValue;     /* value reconstructed at parent */
     int         level;          /* current level (counting from zero) */
     bool        returnData;     /* original data must be returned? */
index 620e7461998bff019e0a75b387542a8a68ab0a1e..8aa28ecbc390dffba8281c04a59b12ce653631a0 100644 (file)
@@ -30,6 +30,7 @@ typedef void (*storeRes_func) (SpGistScanOpaque so, ItemPointer heapPtr,
 typedef struct ScanStackEntry
 {
    Datum       reconstructedValue;     /* value reconstructed from parent */
+   void       *traversalValue; /* opclass-specific traverse value */
    int         level;          /* level of items on this page */
    ItemPointerData ptr;        /* block and offset to scan from */
 } ScanStackEntry;
@@ -42,6 +43,9 @@ freeScanStackEntry(SpGistScanOpaque so, ScanStackEntry *stackEntry)
    if (!so->state.attType.attbyval &&
        DatumGetPointer(stackEntry->reconstructedValue) != NULL)
        pfree(DatumGetPointer(stackEntry->reconstructedValue));
+   if (stackEntry->traversalValue)
+       pfree(stackEntry->traversalValue);
+
    pfree(stackEntry);
 }
 
@@ -239,6 +243,7 @@ static bool
 spgLeafTest(Relation index, SpGistScanOpaque so,
            SpGistLeafTuple leafTuple, bool isnull,
            int level, Datum reconstructedValue,
+           void *traversalValue,
            Datum *leafValue, bool *recheck)
 {
    bool        result;
@@ -265,6 +270,7 @@ spgLeafTest(Relation index, SpGistScanOpaque so,
    in.scankeys = so->keyData;
    in.nkeys = so->numberOfKeys;
    in.reconstructedValue = reconstructedValue;
+   in.traversalValue = traversalValue;
    in.level = level;
    in.returnData = so->want_itup;
    in.leafDatum = leafDatum;
@@ -365,6 +371,7 @@ redirect:
                                    leafTuple, isnull,
                                    stackEntry->level,
                                    stackEntry->reconstructedValue,
+                                   stackEntry->traversalValue,
                                    &leafValue,
                                    &recheck))
                    {
@@ -411,6 +418,7 @@ redirect:
                                    leafTuple, isnull,
                                    stackEntry->level,
                                    stackEntry->reconstructedValue,
+                                   stackEntry->traversalValue,
                                    &leafValue,
                                    &recheck))
                    {
@@ -456,6 +464,8 @@ redirect:
            in.scankeys = so->keyData;
            in.nkeys = so->numberOfKeys;
            in.reconstructedValue = stackEntry->reconstructedValue;
+           in.traversalMemoryContext = oldCtx;
+           in.traversalValue = stackEntry->traversalValue;
            in.level = stackEntry->level;
            in.returnData = so->want_itup;
            in.allTheSame = innerTuple->allTheSame;
@@ -523,6 +533,14 @@ redirect:
                    else
                        newEntry->reconstructedValue = (Datum) 0;
 
+                   /*
+                    * Elements of out.traversalValues should be allocated in
+                    * in.traversalMemoryContext, which is actually a long
+                    * lived context of index scan.
+                    */
+                   newEntry->traversalValue = (out.traversalValues) ?
+                       out.traversalValues[i] : NULL;
+
                    so->scanStack = lcons(newEntry, so->scanStack);
                }
            }
index 1994f718eb11f6413056e0f18c83b2b9d74cedbe..f39a2d6938c69a745ddcae4be58348acebe6ecfb 100644 (file)
@@ -133,6 +133,8 @@ typedef struct spgInnerConsistentIn
    int         nkeys;          /* length of array */
 
    Datum       reconstructedValue;     /* value reconstructed at parent */
+   void       *traversalValue; /* opclass-specific traverse value */
+   MemoryContext traversalMemoryContext;
    int         level;          /* current level (counting from zero) */
    bool        returnData;     /* original data must be returned? */
 
@@ -150,6 +152,7 @@ typedef struct spgInnerConsistentOut
    int        *nodeNumbers;    /* their indexes in the node array */
    int        *levelAdds;      /* increment level by this much for each */
    Datum      *reconstructedValues;    /* associated reconstructed values */
+   void      **traversalValues;    /* opclass-specific traverse values */
 } spgInnerConsistentOut;
 
 /*
@@ -160,6 +163,7 @@ typedef struct spgLeafConsistentIn
    ScanKey     scankeys;       /* array of operators and comparison values */
    int         nkeys;          /* length of array */
 
+   void       *traversalValue; /* opclass-specific traverse value */
    Datum       reconstructedValue;     /* value reconstructed at parent */
    int         level;          /* current level (counting from zero) */
    bool        returnData;     /* original data must be returned? */