codekingpro/portable-devtools
114k
1<?xml version="1.0" encoding="UTF-8" standalone="no"?>2<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>69.3. Extensibility</title><link rel="stylesheet" type="text/css" href="stylesheet.css" /><link rev="made" href="pgsql-docs@lists.postgresql.org" /><meta name="generator" content="DocBook XSL Stylesheets Vsnapshot" /><link rel="prev" href="spgist-builtin-opclasses.html" title="69.2. Built-in Operator Classes" /><link rel="next" href="spgist-implementation.html" title="69.4. Implementation" /></head><body id="docContent" class="container-fluid col-10"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="5" align="center">69.3. Extensibility</th></tr><tr><td width="10%" align="left"><a accesskey="p" href="spgist-builtin-opclasses.html" title="69.2. Built-in Operator Classes">Prev</a> </td><td width="10%" align="left"><a accesskey="u" href="spgist.html" title="Chapter 69. SP-GiST Indexes">Up</a></td><th width="60%" align="center">Chapter 69. SP-GiST Indexes</th><td width="10%" align="right"><a accesskey="h" href="index.html" title="PostgreSQL 16.3 Documentation">Home</a></td><td width="10%" align="right"> <a accesskey="n" href="spgist-implementation.html" title="69.4. Implementation">Next</a></td></tr></table><hr /></div><div class="sect1" id="SPGIST-EXTENSIBILITY"><div class="titlepage"><div><div><h2 class="title" style="clear: both">69.3. Extensibility <a href="#SPGIST-EXTENSIBILITY" class="id_link">#</a></h2></div></div></div><p>3 <acronym class="acronym">SP-GiST</acronym> offers an interface with a high level of4 abstraction, requiring the access method developer to implement only5 methods specific to a given data type. The <acronym class="acronym">SP-GiST</acronym> core6 is responsible for efficient disk mapping and searching the tree structure.7 It also takes care of concurrency and logging considerations.8 </p><p>9 Leaf tuples of an <acronym class="acronym">SP-GiST</acronym> tree usually contain values10 of the same data type as the indexed column, although it is also possible11 for them to contain lossy representations of the indexed column.12 Leaf tuples stored at the root level will directly represent13 the original indexed data value, but leaf tuples at lower14 levels might contain only a partial value, such as a suffix.15 In that case the operator class support functions must be able to16 reconstruct the original value using information accumulated from the17 inner tuples that are passed through to reach the leaf level.18 </p><p>19 When an <acronym class="acronym">SP-GiST</acronym> index is created with20 <code class="literal">INCLUDE</code> columns, the values of those columns are also21 stored in leaf tuples. The <code class="literal">INCLUDE</code> columns are of no22 concern to the <acronym class="acronym">SP-GiST</acronym> operator class, so they are23 not discussed further here.24 </p><p>25 Inner tuples are more complex, since they are branching points in the26 search tree. Each inner tuple contains a set of one or more27 <em class="firstterm">nodes</em>, which represent groups of similar leaf values.28 A node contains a downlink that leads either to another, lower-level inner29 tuple, or to a short list of leaf tuples that all lie on the same index page.30 Each node normally has a <em class="firstterm">label</em> that describes it; for example,31 in a radix tree the node label could be the next character of the string32 value. (Alternatively, an operator class can omit the node labels, if it33 works with a fixed set of nodes for all inner tuples;34 see <a class="xref" href="spgist-implementation.html#SPGIST-NULL-LABELS" title="69.4.2. SP-GiST Without Node Labels">Section 69.4.2</a>.)35 Optionally, an inner tuple can have a <em class="firstterm">prefix</em> value36 that describes all its members. In a radix tree this could be the common37 prefix of the represented strings. The prefix value is not necessarily38 really a prefix, but can be any data needed by the operator class;39 for example, in a quad-tree it can store the central point that the four40 quadrants are measured with respect to. A quad-tree inner tuple would41 then also contain four nodes corresponding to the quadrants around this42 central point.43 </p><p>44 Some tree algorithms require knowledge of level (or depth) of the current45 tuple, so the <acronym class="acronym">SP-GiST</acronym> core provides the possibility for46 operator classes to manage level counting while descending the tree.47 There is also support for incrementally reconstructing the represented48 value when that is needed, and for passing down additional data (called49 <em class="firstterm">traverse values</em>) during a tree descent.50 </p><div class="note"><h3 class="title">Note</h3><p>51 The <acronym class="acronym">SP-GiST</acronym> core code takes care of null entries.52 Although <acronym class="acronym">SP-GiST</acronym> indexes do store entries for nulls53 in indexed columns, this is hidden from the index operator class code:54 no null index entries or search conditions will ever be passed to the55 operator class methods. (It is assumed that <acronym class="acronym">SP-GiST</acronym>56 operators are strict and so cannot succeed for null values.) Null values57 are therefore not discussed further here.58 </p></div><p>59 There are five user-defined methods that an index operator class for60 <acronym class="acronym">SP-GiST</acronym> must provide, and two are optional. All five61 mandatory methods follow the convention of accepting two <code class="type">internal</code>62 arguments, the first of which is a pointer to a C struct containing input63 values for the support method, while the second argument is a pointer to a64 C struct where output values must be placed. Four of the mandatory methods just65 return <code class="type">void</code>, since all their results appear in the output struct; but66 <code class="function">leaf_consistent</code> returns a <code class="type">boolean</code> result.67 The methods must not modify any fields of their input structs. In all68 cases, the output struct is initialized to zeroes before calling the69 user-defined method. The optional sixth method <code class="function">compress</code>70 accepts a <code class="type">datum</code> to be indexed as the only argument and returns a value suitable71 for physical storage in a leaf tuple. The optional seventh method72 <code class="function">options</code> accepts an <code class="type">internal</code> pointer to a C struct, where73 opclass-specific parameters should be placed, and returns <code class="type">void</code>.74 </p><p>75 The five mandatory user-defined methods are:76 </p><div class="variablelist"><dl class="variablelist"><dt><span class="term"><code class="function">config</code></span></dt><dd><p>77 Returns static information about the index implementation, including78 the data type OIDs of the prefix and node label data types.79 </p><p>80 The <acronym class="acronym">SQL</acronym> declaration of the function must look like this:81</p><pre class="programlisting">82CREATE FUNCTION my_config(internal, internal) RETURNS void ...83</pre><p>84 The first argument is a pointer to a <code class="structname">spgConfigIn</code>85 C struct, containing input data for the function.86 The second argument is a pointer to a <code class="structname">spgConfigOut</code>87 C struct, which the function must fill with result data.88</p><pre class="programlisting">89typedef struct spgConfigIn90{91 Oid attType; /* Data type to be indexed */92} spgConfigIn;93 94typedef struct spgConfigOut95{96 Oid prefixType; /* Data type of inner-tuple prefixes */97 Oid labelType; /* Data type of inner-tuple node labels */98 Oid leafType; /* Data type of leaf-tuple values */99 bool canReturnData; /* Opclass can reconstruct original data */100 bool longValuesOK; /* Opclass can cope with values > 1 page */101} spgConfigOut;102</pre><p>103 104 <code class="structfield">attType</code> is passed in order to support polymorphic105 index operator classes; for ordinary fixed-data-type operator classes, it106 will always have the same value and so can be ignored.107 </p><p>108 For operator classes that do not use prefixes,109 <code class="structfield">prefixType</code> can be set to <code class="literal">VOIDOID</code>.110 Likewise, for operator classes that do not use node labels,111 <code class="structfield">labelType</code> can be set to <code class="literal">VOIDOID</code>.112 <code class="structfield">canReturnData</code> should be set true if the operator class113 is capable of reconstructing the originally-supplied index value.114 <code class="structfield">longValuesOK</code> should be set true only when the115 <code class="structfield">attType</code> is of variable length and the operator116 class is capable of segmenting long values by repeated suffixing117 (see <a class="xref" href="spgist-implementation.html#SPGIST-LIMITS" title="69.4.1. SP-GiST Limits">Section 69.4.1</a>).118 </p><p>119 <code class="structfield">leafType</code> should match the index storage type120 defined by the operator class's <code class="structfield">opckeytype</code>121 catalog entry.122 (Note that <code class="structfield">opckeytype</code> can be zero,123 implying the storage type is the same as the operator class's input124 type, which is the most common situation.)125 For reasons of backward compatibility, the <code class="function">config</code>126 method can set <code class="structfield">leafType</code> to some other value,127 and that value will be used; but this is deprecated since the index128 contents are then incorrectly identified in the catalogs.129 Also, it's permissible to130 leave <code class="structfield">leafType</code> uninitialized (zero);131 that is interpreted as meaning the index storage type derived from132 <code class="structfield">opckeytype</code>.133 </p><p>134 When <code class="structfield">attType</code>135 and <code class="structfield">leafType</code> are different, the optional136 method <code class="function">compress</code> must be provided.137 Method <code class="function">compress</code> is responsible138 for transformation of datums to be indexed from <code class="structfield">attType</code>139 to <code class="structfield">leafType</code>.140 </p></dd><dt><span class="term"><code class="function">choose</code></span></dt><dd><p>141 Chooses a method for inserting a new value into an inner tuple.142 </p><p>143 The <acronym class="acronym">SQL</acronym> declaration of the function must look like this:144</p><pre class="programlisting">145CREATE FUNCTION my_choose(internal, internal) RETURNS void ...146</pre><p>147 The first argument is a pointer to a <code class="structname">spgChooseIn</code>148 C struct, containing input data for the function.149 The second argument is a pointer to a <code class="structname">spgChooseOut</code>150 C struct, which the function must fill with result data.151</p><pre class="programlisting">152typedef struct spgChooseIn153{154 Datum datum; /* original datum to be indexed */155 Datum leafDatum; /* current datum to be stored at leaf */156 int level; /* current level (counting from zero) */157 158 /* Data from current inner tuple */159 bool allTheSame; /* tuple is marked all-the-same? */160 bool hasPrefix; /* tuple has a prefix? */161 Datum prefixDatum; /* if so, the prefix value */162 int nNodes; /* number of nodes in the inner tuple */163 Datum *nodeLabels; /* node label values (NULL if none) */164} spgChooseIn;165 166typedef enum spgChooseResultType167{168 spgMatchNode = 1, /* descend into existing node */169 spgAddNode, /* add a node to the inner tuple */170 spgSplitTuple /* split inner tuple (change its prefix) */171} spgChooseResultType;172 173typedef struct spgChooseOut174{175 spgChooseResultType resultType; /* action code, see above */176 union177 {178 struct /* results for spgMatchNode */179 {180 int nodeN; /* descend to this node (index from 0) */181 int levelAdd; /* increment level by this much */182 Datum restDatum; /* new leaf datum */183 } matchNode;184 struct /* results for spgAddNode */185 {186 Datum nodeLabel; /* new node's label */187 int nodeN; /* where to insert it (index from 0) */188 } addNode;189 struct /* results for spgSplitTuple */190 {191 /* Info to form new upper-level inner tuple with one child tuple */192 bool prefixHasPrefix; /* tuple should have a prefix? */193 Datum prefixPrefixDatum; /* if so, its value */194 int prefixNNodes; /* number of nodes */195 Datum *prefixNodeLabels; /* their labels (or NULL for196 * no labels) */197 int childNodeN; /* which node gets child tuple */198 199 /* Info to form new lower-level inner tuple with all old nodes */200 bool postfixHasPrefix; /* tuple should have a prefix? */201 Datum postfixPrefixDatum; /* if so, its value */202 } splitTuple;203 } result;204} spgChooseOut;205</pre><p>206 207 <code class="structfield">datum</code> is the original datum of208 <code class="structname">spgConfigIn</code>.<code class="structfield">attType</code>209 type that was to be inserted into the index.210 <code class="structfield">leafDatum</code> is a value of211 <code class="structname">spgConfigOut</code>.<code class="structfield">leafType</code>212 type, which is initially a result of method213 <code class="function">compress</code> applied to <code class="structfield">datum</code>214 when method <code class="function">compress</code> is provided, or the same value as215 <code class="structfield">datum</code> otherwise.216 <code class="structfield">leafDatum</code> can change at lower levels of the tree217 if the <code class="function">choose</code> or <code class="function">picksplit</code>218 methods change it. When the insertion search reaches a leaf page,219 the current value of <code class="structfield">leafDatum</code> is what will be stored220 in the newly created leaf tuple.221 <code class="structfield">level</code> is the current inner tuple's level, starting at222 zero for the root level.223 <code class="structfield">allTheSame</code> is true if the current inner tuple is224 marked as containing multiple equivalent nodes225 (see <a class="xref" href="spgist-implementation.html#SPGIST-ALL-THE-SAME" title="69.4.3. “All-the-Same” Inner Tuples">Section 69.4.3</a>).226 <code class="structfield">hasPrefix</code> is true if the current inner tuple contains227 a prefix; if so,228 <code class="structfield">prefixDatum</code> is its value.229 <code class="structfield">nNodes</code> is the number of child nodes contained in the230 inner tuple, and231 <code class="structfield">nodeLabels</code> is an array of their label values, or232 NULL if there are no labels.233 </p><p>234 The <code class="function">choose</code> function can determine either that235 the new value matches one of the existing child nodes, or that a new236 child node must be added, or that the new value is inconsistent with237 the tuple prefix and so the inner tuple must be split to create a238 less restrictive prefix.239 </p><p>240 If the new value matches one of the existing child nodes,241 set <code class="structfield">resultType</code> to <code class="literal">spgMatchNode</code>.242 Set <code class="structfield">nodeN</code> to the index (from zero) of that node in243 the node array.244 Set <code class="structfield">levelAdd</code> to the increment in245 <code class="structfield">level</code> caused by descending through that node,246 or leave it as zero if the operator class does not use levels.247 Set <code class="structfield">restDatum</code> to equal <code class="structfield">leafDatum</code>248 if the operator class does not modify datums from one level to the249 next, or otherwise set it to the modified value to be used as250 <code class="structfield">leafDatum</code> at the next level.251 </p><p>252 If a new child node must be added,253 set <code class="structfield">resultType</code> to <code class="literal">spgAddNode</code>.254 Set <code class="structfield">nodeLabel</code> to the label to be used for the new255 node, and set <code class="structfield">nodeN</code> to the index (from zero) at which256 to insert the node in the node array.257 After the node has been added, the <code class="function">choose</code>258 function will be called again with the modified inner tuple;259 that call should result in an <code class="literal">spgMatchNode</code> result.260 </p><p>261 If the new value is inconsistent with the tuple prefix,262 set <code class="structfield">resultType</code> to <code class="literal">spgSplitTuple</code>.263 This action moves all the existing nodes into a new lower-level264 inner tuple, and replaces the existing inner tuple with a tuple265 having a single downlink pointing to the new lower-level inner tuple.266 Set <code class="structfield">prefixHasPrefix</code> to indicate whether the new267 upper tuple should have a prefix, and if so set268 <code class="structfield">prefixPrefixDatum</code> to the prefix value. This new269 prefix value must be sufficiently less restrictive than the original270 to accept the new value to be indexed.271 Set <code class="structfield">prefixNNodes</code> to the number of nodes needed in the272 new tuple, and set <code class="structfield">prefixNodeLabels</code> to a palloc'd array273 holding their labels, or to NULL if node labels are not required.274 Note that the total size of the new upper tuple must be no more275 than the total size of the tuple it is replacing; this constrains276 the lengths of the new prefix and new labels.277 Set <code class="structfield">childNodeN</code> to the index (from zero) of the node278 that will downlink to the new lower-level inner tuple.279 Set <code class="structfield">postfixHasPrefix</code> to indicate whether the new280 lower-level inner tuple should have a prefix, and if so set281 <code class="structfield">postfixPrefixDatum</code> to the prefix value. The282 combination of these two prefixes and the downlink node's label283 (if any) must have the same meaning as the original prefix, because284 there is no opportunity to alter the node labels that are moved to285 the new lower-level tuple, nor to change any child index entries.286 After the node has been split, the <code class="function">choose</code>287 function will be called again with the replacement inner tuple.288 That call may return an <code class="literal">spgAddNode</code> result, if no suitable289 node was created by the <code class="literal">spgSplitTuple</code> action. Eventually290 <code class="function">choose</code> must return <code class="literal">spgMatchNode</code> to291 allow the insertion to descend to the next level.292 </p></dd><dt><span class="term"><code class="function">picksplit</code></span></dt><dd><p>293 Decides how to create a new inner tuple over a set of leaf tuples.294 </p><p>295 The <acronym class="acronym">SQL</acronym> declaration of the function must look like this:296</p><pre class="programlisting">297CREATE FUNCTION my_picksplit(internal, internal) RETURNS void ...298</pre><p>299 The first argument is a pointer to a <code class="structname">spgPickSplitIn</code>300 C struct, containing input data for the function.301 The second argument is a pointer to a <code class="structname">spgPickSplitOut</code>302 C struct, which the function must fill with result data.303</p><pre class="programlisting">304typedef struct spgPickSplitIn305{306 int nTuples; /* number of leaf tuples */307 Datum *datums; /* their datums (array of length nTuples) */308 int level; /* current level (counting from zero) */309} spgPickSplitIn;310 311typedef struct spgPickSplitOut312{313 bool hasPrefix; /* new inner tuple should have a prefix? */314 Datum prefixDatum; /* if so, its value */315 316 int nNodes; /* number of nodes for new inner tuple */317 Datum *nodeLabels; /* their labels (or NULL for no labels) */318 319 int *mapTuplesToNodes; /* node index for each leaf tuple */320 Datum *leafTupleDatums; /* datum to store in each new leaf tuple */321} spgPickSplitOut;322</pre><p>323 324 <code class="structfield">nTuples</code> is the number of leaf tuples provided.325 <code class="structfield">datums</code> is an array of their datum values of326 <code class="structname">spgConfigOut</code>.<code class="structfield">leafType</code>327 type.328 <code class="structfield">level</code> is the current level that all the leaf tuples329 share, which will become the level of the new inner tuple.330 </p><p>331 Set <code class="structfield">hasPrefix</code> to indicate whether the new inner332 tuple should have a prefix, and if so set333 <code class="structfield">prefixDatum</code> to the prefix value.334 Set <code class="structfield">nNodes</code> to indicate the number of nodes that335 the new inner tuple will contain, and336 set <code class="structfield">nodeLabels</code> to an array of their label values,337 or to NULL if node labels are not required.338 Set <code class="structfield">mapTuplesToNodes</code> to an array that gives the index339 (from zero) of the node that each leaf tuple should be assigned to.340 Set <code class="structfield">leafTupleDatums</code> to an array of the values to341 be stored in the new leaf tuples (these will be the same as the342 input <code class="structfield">datums</code> if the operator class does not modify343 datums from one level to the next).344 Note that the <code class="function">picksplit</code> function is345 responsible for palloc'ing the346 <code class="structfield">nodeLabels</code>, <code class="structfield">mapTuplesToNodes</code> and347 <code class="structfield">leafTupleDatums</code> arrays.348 </p><p>349 If more than one leaf tuple is supplied, it is expected that the350 <code class="function">picksplit</code> function will classify them into more than351 one node; otherwise it is not possible to split the leaf tuples352 across multiple pages, which is the ultimate purpose of this353 operation. Therefore, if the <code class="function">picksplit</code> function354 ends up placing all the leaf tuples in the same node, the core355 SP-GiST code will override that decision and generate an inner356 tuple in which the leaf tuples are assigned at random to several357 identically-labeled nodes. Such a tuple is marked358 <code class="literal">allTheSame</code> to signify that this has happened. The359 <code class="function">choose</code> and <code class="function">inner_consistent</code> functions360 must take suitable care with such inner tuples.361 See <a class="xref" href="spgist-implementation.html#SPGIST-ALL-THE-SAME" title="69.4.3. “All-the-Same” Inner Tuples">Section 69.4.3</a> for more information.362 </p><p>363 <code class="function">picksplit</code> can be applied to a single leaf tuple only364 in the case that the <code class="function">config</code> function set365 <code class="structfield">longValuesOK</code> to true and a larger-than-a-page input366 value has been supplied. In this case the point of the operation is367 to strip off a prefix and produce a new, shorter leaf datum value.368 The call will be repeated until a leaf datum short enough to fit on369 a page has been produced. See <a class="xref" href="spgist-implementation.html#SPGIST-LIMITS" title="69.4.1. SP-GiST Limits">Section 69.4.1</a> for370 more information.371 </p></dd><dt><span class="term"><code class="function">inner_consistent</code></span></dt><dd><p>372 Returns set of nodes (branches) to follow during tree search.373 </p><p>374 The <acronym class="acronym">SQL</acronym> declaration of the function must look like this:375</p><pre class="programlisting">376CREATE FUNCTION my_inner_consistent(internal, internal) RETURNS void ...377</pre><p>378 The first argument is a pointer to a <code class="structname">spgInnerConsistentIn</code>379 C struct, containing input data for the function.380 The second argument is a pointer to a <code class="structname">spgInnerConsistentOut</code>381 C struct, which the function must fill with result data.382 383</p><pre class="programlisting">384typedef struct spgInnerConsistentIn385{386 ScanKey scankeys; /* array of operators and comparison values */387 ScanKey orderbys; /* array of ordering operators and comparison388 * values */389 int nkeys; /* length of scankeys array */390 int norderbys; /* length of orderbys array */391 392 Datum reconstructedValue; /* value reconstructed at parent */393 void *traversalValue; /* opclass-specific traverse value */394 MemoryContext traversalMemoryContext; /* put new traverse values here */395 int level; /* current level (counting from zero) */396 bool returnData; /* original data must be returned? */397 398 /* Data from current inner tuple */399 bool allTheSame; /* tuple is marked all-the-same? */400 bool hasPrefix; /* tuple has a prefix? */401 Datum prefixDatum; /* if so, the prefix value */402 int nNodes; /* number of nodes in the inner tuple */403 Datum *nodeLabels; /* node label values (NULL if none) */404} spgInnerConsistentIn;405 406typedef struct spgInnerConsistentOut407{408 int nNodes; /* number of child nodes to be visited */409 int *nodeNumbers; /* their indexes in the node array */410 int *levelAdds; /* increment level by this much for each */411 Datum *reconstructedValues; /* associated reconstructed values */412 void **traversalValues; /* opclass-specific traverse values */413 double **distances; /* associated distances */414} spgInnerConsistentOut;415</pre><p>416 417 The array <code class="structfield">scankeys</code>, of length <code class="structfield">nkeys</code>,418 describes the index search condition(s). These conditions are419 combined with AND — only index entries that satisfy all of420 them are interesting. (Note that <code class="structfield">nkeys</code> = 0 implies421 that all index entries satisfy the query.) Usually the consistent422 function only cares about the <code class="structfield">sk_strategy</code> and423 <code class="structfield">sk_argument</code> fields of each array entry, which424 respectively give the indexable operator and comparison value.425 In particular it is not necessary to check <code class="structfield">sk_flags</code> to426 see if the comparison value is NULL, because the SP-GiST core code427 will filter out such conditions.428 The array <code class="structfield">orderbys</code>, of length <code class="structfield">norderbys</code>,429 describes ordering operators (if any) in the same manner.430 <code class="structfield">reconstructedValue</code> is the value reconstructed for the431 parent tuple; it is <code class="literal">(Datum) 0</code> at the root level or if the432 <code class="function">inner_consistent</code> function did not provide a value at the433 parent level.434 <code class="structfield">traversalValue</code> is a pointer to any traverse data435 passed down from the previous call of <code class="function">inner_consistent</code>436 on the parent index tuple, or NULL at the root level.437 <code class="structfield">traversalMemoryContext</code> is the memory context in which438 to store output traverse values (see below).439 <code class="structfield">level</code> is the current inner tuple's level, starting at440 zero for the root level.441 <code class="structfield">returnData</code> is <code class="literal">true</code> if reconstructed data is442 required for this query; this will only be so if the443 <code class="function">config</code> function asserted <code class="structfield">canReturnData</code>.444 <code class="structfield">allTheSame</code> is true if the current inner tuple is445 marked <span class="quote">“<span class="quote">all-the-same</span>”</span>; in this case all the nodes have the446 same label (if any) and so either all or none of them match the query447 (see <a class="xref" href="spgist-implementation.html#SPGIST-ALL-THE-SAME" title="69.4.3. “All-the-Same” Inner Tuples">Section 69.4.3</a>).448 <code class="structfield">hasPrefix</code> is true if the current inner tuple contains449 a prefix; if so,450 <code class="structfield">prefixDatum</code> is its value.451 <code class="structfield">nNodes</code> is the number of child nodes contained in the452 inner tuple, and453 <code class="structfield">nodeLabels</code> is an array of their label values, or454 NULL if the nodes do not have labels.455 </p><p>456 <code class="structfield">nNodes</code> must be set to the number of child nodes that457 need to be visited by the search, and458 <code class="structfield">nodeNumbers</code> must be set to an array of their indexes.459 If the operator class keeps track of levels, set460 <code class="structfield">levelAdds</code> to an array of the level increments461 required when descending to each node to be visited. (Often these462 increments will be the same for all the nodes, but that's not463 necessarily so, so an array is used.)464 If value reconstruction is needed, set465 <code class="structfield">reconstructedValues</code> to an array of the values466 reconstructed for each child node to be visited; otherwise, leave467 <code class="structfield">reconstructedValues</code> as NULL.468 The reconstructed values are assumed to be of type469 <code class="structname">spgConfigOut</code>.<code class="structfield">leafType</code>.470 (However, since the core system will do nothing with them except471 possibly copy them, it is sufficient for them to have the472 same <code class="literal">typlen</code> and <code class="literal">typbyval</code>473 properties as <code class="structfield">leafType</code>.)474 If ordered search is performed, set <code class="structfield">distances</code>475 to an array of distance values according to <code class="structfield">orderbys</code>476 array (nodes with lowest distances will be processed first). Leave it477 NULL otherwise.478 If it is desired to pass down additional out-of-band information479 (<span class="quote">“<span class="quote">traverse values</span>”</span>) to lower levels of the tree search,480 set <code class="structfield">traversalValues</code> to an array of the appropriate481 traverse values, one for each child node to be visited; otherwise,482 leave <code class="structfield">traversalValues</code> as NULL.483 Note that the <code class="function">inner_consistent</code> function is484 responsible for palloc'ing the485 <code class="structfield">nodeNumbers</code>, <code class="structfield">levelAdds</code>,486 <code class="structfield">distances</code>,487 <code class="structfield">reconstructedValues</code>, and488 <code class="structfield">traversalValues</code> arrays in the current memory context.489 However, any output traverse values pointed to by490 the <code class="structfield">traversalValues</code> array should be allocated491 in <code class="structfield">traversalMemoryContext</code>.492 Each traverse value must be a single palloc'd chunk.493 </p></dd><dt><span class="term"><code class="function">leaf_consistent</code></span></dt><dd><p>494 Returns true if a leaf tuple satisfies a query.495 </p><p>496 The <acronym class="acronym">SQL</acronym> declaration of the function must look like this:497</p><pre class="programlisting">498CREATE FUNCTION my_leaf_consistent(internal, internal) RETURNS bool ...499</pre><p>500 The first argument is a pointer to a <code class="structname">spgLeafConsistentIn</code>501 C struct, containing input data for the function.502 The second argument is a pointer to a <code class="structname">spgLeafConsistentOut</code>503 C struct, which the function must fill with result data.504</p><pre class="programlisting">505typedef struct spgLeafConsistentIn506{507 ScanKey scankeys; /* array of operators and comparison values */508 ScanKey orderbys; /* array of ordering operators and comparison509 * values */510 int nkeys; /* length of scankeys array */511 int norderbys; /* length of orderbys array */512 513 Datum reconstructedValue; /* value reconstructed at parent */514 void *traversalValue; /* opclass-specific traverse value */515 int level; /* current level (counting from zero) */516 bool returnData; /* original data must be returned? */517 518 Datum leafDatum; /* datum in leaf tuple */519} spgLeafConsistentIn;520 521typedef struct spgLeafConsistentOut522{523 Datum leafValue; /* reconstructed original data, if any */524 bool recheck; /* set true if operator must be rechecked */525 bool recheckDistances; /* set true if distances must be rechecked */526 double *distances; /* associated distances */527} spgLeafConsistentOut;528</pre><p>529 530 The array <code class="structfield">scankeys</code>, of length <code class="structfield">nkeys</code>,531 describes the index search condition(s). These conditions are532 combined with AND — only index entries that satisfy all of533 them satisfy the query. (Note that <code class="structfield">nkeys</code> = 0 implies534 that all index entries satisfy the query.) Usually the consistent535 function only cares about the <code class="structfield">sk_strategy</code> and536 <code class="structfield">sk_argument</code> fields of each array entry, which537 respectively give the indexable operator and comparison value.538 In particular it is not necessary to check <code class="structfield">sk_flags</code> to539 see if the comparison value is NULL, because the SP-GiST core code540 will filter out such conditions.541 The array <code class="structfield">orderbys</code>, of length <code class="structfield">norderbys</code>,542 describes the ordering operators in the same manner.543 <code class="structfield">reconstructedValue</code> is the value reconstructed for the544 parent tuple; it is <code class="literal">(Datum) 0</code> at the root level or if the545 <code class="function">inner_consistent</code> function did not provide a value at the546 parent level.547 <code class="structfield">traversalValue</code> is a pointer to any traverse data548 passed down from the previous call of <code class="function">inner_consistent</code>549 on the parent index tuple, or NULL at the root level.550 <code class="structfield">level</code> is the current leaf tuple's level, starting at551 zero for the root level.552 <code class="structfield">returnData</code> is <code class="literal">true</code> if reconstructed data is553 required for this query; this will only be so if the554 <code class="function">config</code> function asserted <code class="structfield">canReturnData</code>.555 <code class="structfield">leafDatum</code> is the key value of556 <code class="structname">spgConfigOut</code>.<code class="structfield">leafType</code>557 stored in the current leaf tuple.558 </p><p>559 The function must return <code class="literal">true</code> if the leaf tuple matches the560 query, or <code class="literal">false</code> if not. In the <code class="literal">true</code> case,561 if <code class="structfield">returnData</code> is <code class="literal">true</code> then562 <code class="structfield">leafValue</code> must be set to the value (of type563 <code class="structname">spgConfigIn</code>.<code class="structfield">attType</code>)564 originally supplied to be indexed for this leaf tuple. Also,565 <code class="structfield">recheck</code> may be set to <code class="literal">true</code> if the match566 is uncertain and so the operator(s) must be re-applied to the actual567 heap tuple to verify the match.568 If ordered search is performed, set <code class="structfield">distances</code>569 to an array of distance values according to <code class="structfield">orderbys</code>570 array. Leave it NULL otherwise. If at least one of returned distances571 is not exact, set <code class="structfield">recheckDistances</code> to true.572 In this case, the executor will calculate the exact distances after573 fetching the tuple from the heap, and will reorder the tuples if needed.574 </p></dd></dl></div><p>575 The optional user-defined methods are:576 </p><div class="variablelist"><dl class="variablelist"><dt><span class="term"><code class="function">Datum compress(Datum in)</code></span></dt><dd><p>577 Converts a data item into a format suitable for physical storage in578 a leaf tuple of the index. It accepts a value of type579 <code class="structname">spgConfigIn</code>.<code class="structfield">attType</code>580 and returns a value of type581 <code class="structname">spgConfigOut</code>.<code class="structfield">leafType</code>.582 The output value must not contain an out-of-line TOAST pointer.583 </p><p>584 Note: the <code class="function">compress</code> method is only applied to585 values to be stored. The consistent methods receive query586 <code class="structfield">scankeys</code> unchanged, without transformation587 using <code class="function">compress</code>.588 </p></dd><dt><span class="term"><code class="function">options</code></span></dt><dd><p>589 Defines a set of user-visible parameters that control operator class590 behavior.591 </p><p>592 The <acronym class="acronym">SQL</acronym> declaration of the function must look like this:593 594</p><pre class="programlisting">595CREATE OR REPLACE FUNCTION my_options(internal)596RETURNS void597AS 'MODULE_PATHNAME'598LANGUAGE C STRICT;599</pre><p>600 </p><p>601 The function is passed a pointer to a <code class="structname">local_relopts</code>602 struct, which needs to be filled with a set of operator class603 specific options. The options can be accessed from other support604 functions using the <code class="literal">PG_HAS_OPCLASS_OPTIONS()</code> and605 <code class="literal">PG_GET_OPCLASS_OPTIONS()</code> macros.606 </p><p>607 Since the representation of the key in <acronym class="acronym">SP-GiST</acronym> is608 flexible, it may depend on user-specified parameters.609 </p></dd></dl></div><p>610 All the SP-GiST support methods are normally called in a short-lived611 memory context; that is, <code class="varname">CurrentMemoryContext</code> will be reset612 after processing of each tuple. It is therefore not very important to613 worry about pfree'ing everything you palloc. (The <code class="function">config</code>614 method is an exception: it should try to avoid leaking memory. But615 usually the <code class="function">config</code> method need do nothing but assign616 constants into the passed parameter struct.)617 </p><p>618 If the indexed column is of a collatable data type, the index collation619 will be passed to all the support methods, using the standard620 <code class="function">PG_GET_COLLATION()</code> mechanism.621 </p></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="spgist-builtin-opclasses.html" title="69.2. Built-in Operator Classes">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="spgist.html" title="Chapter 69. SP-GiST Indexes">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="spgist-implementation.html" title="69.4. Implementation">Next</a></td></tr><tr><td width="40%" align="left" valign="top">69.2. Built-in Operator Classes </td><td width="20%" align="center"><a accesskey="h" href="index.html" title="PostgreSQL 16.3 Documentation">Home</a></td><td width="40%" align="right" valign="top"> 69.4. Implementation</td></tr></table></div></body></html>