diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 13:44:03 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 13:44:03 +0000 |
commit | 293913568e6a7a86fd1479e1cff8e2ecb58d6568 (patch) | |
tree | fc3b469a3ec5ab71b36ea97cc7aaddb838423a0c /doc/src/sgml/ltree.sgml | |
parent | Initial commit. (diff) | |
download | postgresql-16-293913568e6a7a86fd1479e1cff8e2ecb58d6568.tar.xz postgresql-16-293913568e6a7a86fd1479e1cff8e2ecb58d6568.zip |
Adding upstream version 16.2.upstream/16.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'doc/src/sgml/ltree.sgml')
-rw-r--r-- | doc/src/sgml/ltree.sgml | 859 |
1 files changed, 859 insertions, 0 deletions
diff --git a/doc/src/sgml/ltree.sgml b/doc/src/sgml/ltree.sgml new file mode 100644 index 0000000..00a6ae7 --- /dev/null +++ b/doc/src/sgml/ltree.sgml @@ -0,0 +1,859 @@ +<!-- doc/src/sgml/ltree.sgml --> + +<sect1 id="ltree" xreflabel="ltree"> + <title>ltree — hierarchical tree-like data type</title> + + <indexterm zone="ltree"> + <primary>ltree</primary> + </indexterm> + + <para> + This module implements a data type <type>ltree</type> for representing + labels of data stored in a hierarchical tree-like structure. + Extensive facilities for searching through label trees are provided. + </para> + + <para> + This module is considered <quote>trusted</quote>, that is, it can be + installed by non-superusers who have <literal>CREATE</literal> privilege + on the current database. + </para> + + <sect2 id="ltree-definitions"> + <title>Definitions</title> + + <para> + A <firstterm>label</firstterm> is a sequence of alphanumeric characters, + underscores, and hyphens. Valid alphanumeric character ranges are + dependent on the database locale. For example, in C locale, the characters + <literal>A-Za-z0-9_-</literal> are allowed. + Labels must be no more than 1000 characters long. + </para> + + <para> + Examples: <literal>42</literal>, <literal>Personal_Services</literal> + </para> + + <para> + A <firstterm>label path</firstterm> is a sequence of zero or more + labels separated by dots, for example <literal>L1.L2.L3</literal>, representing + a path from the root of a hierarchical tree to a particular node. The + length of a label path cannot exceed 65535 labels. + </para> + + <para> + Example: <literal>Top.Countries.Europe.Russia</literal> + </para> + + <para> + The <filename>ltree</filename> module provides several data types: + </para> + + <itemizedlist> + <listitem> + <para> + <type>ltree</type> stores a label path. + </para> + </listitem> + + <listitem> + <para> + <type>lquery</type> represents a regular-expression-like pattern + for matching <type>ltree</type> values. A simple word matches that + label within a path. A star symbol (<literal>*</literal>) matches zero + or more labels. These can be joined with dots to form a pattern that + must match the whole label path. For example: +<synopsis> +foo <lineannotation>Match the exact label path <literal>foo</literal></lineannotation> +*.foo.* <lineannotation>Match any label path containing the label <literal>foo</literal></lineannotation> +*.foo <lineannotation>Match any label path whose last label is <literal>foo</literal></lineannotation> +</synopsis> + </para> + + <para> + Both star symbols and simple words can be quantified to restrict how many + labels they can match: +<synopsis> +*{<replaceable>n</replaceable>} <lineannotation>Match exactly <replaceable>n</replaceable> labels</lineannotation> +*{<replaceable>n</replaceable>,} <lineannotation>Match at least <replaceable>n</replaceable> labels</lineannotation> +*{<replaceable>n</replaceable>,<replaceable>m</replaceable>} <lineannotation>Match at least <replaceable>n</replaceable> but not more than <replaceable>m</replaceable> labels</lineannotation> +*{,<replaceable>m</replaceable>} <lineannotation>Match at most <replaceable>m</replaceable> labels — same as </lineannotation>*{0,<replaceable>m</replaceable>} +foo{<replaceable>n</replaceable>,<replaceable>m</replaceable>} <lineannotation>Match at least <replaceable>n</replaceable> but not more than <replaceable>m</replaceable> occurrences of <literal>foo</literal></lineannotation> +foo{,} <lineannotation>Match any number of occurrences of <literal>foo</literal>, including zero</lineannotation> +</synopsis> + In the absence of any explicit quantifier, the default for a star symbol + is to match any number of labels (that is, <literal>{,}</literal>) while + the default for a non-star item is to match exactly once (that + is, <literal>{1}</literal>). + </para> + + <para> + There are several modifiers that can be put at the end of a non-star + <type>lquery</type> item to make it match more than just the exact match: +<synopsis> +@ <lineannotation>Match case-insensitively, for example <literal>a@</literal> matches <literal>A</literal></lineannotation> +* <lineannotation>Match any label with this prefix, for example <literal>foo*</literal> matches <literal>foobar</literal></lineannotation> +% <lineannotation>Match initial underscore-separated words</lineannotation> +</synopsis> + The behavior of <literal>%</literal> is a bit complicated. It tries to match + words rather than the entire label. For example + <literal>foo_bar%</literal> matches <literal>foo_bar_baz</literal> but not + <literal>foo_barbaz</literal>. If combined with <literal>*</literal>, prefix + matching applies to each word separately, for example + <literal>foo_bar%*</literal> matches <literal>foo1_bar2_baz</literal> but + not <literal>foo1_br2_baz</literal>. + </para> + + <para> + Also, you can write several possibly-modified non-star items separated with + <literal>|</literal> (OR) to match any of those items, and you can put + <literal>!</literal> (NOT) at the start of a non-star group to match any + label that doesn't match any of the alternatives. A quantifier, if any, + goes at the end of the group; it means some number of matches for the + group as a whole (that is, some number of labels matching or not matching + any of the alternatives). + </para> + + <para> + Here's an annotated example of <type>lquery</type>: +<programlisting> +Top.*{0,2}.sport*@.!football|tennis{1,}.Russ*|Spain +a. b. c. d. e. +</programlisting> + This query will match any label path that: + </para> + <orderedlist numeration="loweralpha"> + <listitem> + <para> + begins with the label <literal>Top</literal> + </para> + </listitem> + <listitem> + <para> + and next has zero to two labels before + </para> + </listitem> + <listitem> + <para> + a label beginning with the case-insensitive prefix <literal>sport</literal> + </para> + </listitem> + <listitem> + <para> + then has one or more labels, none of which + match <literal>football</literal> nor <literal>tennis</literal> + </para> + </listitem> + <listitem> + <para> + and then ends with a label beginning with <literal>Russ</literal> or + exactly matching <literal>Spain</literal>. + </para> + </listitem> + </orderedlist> + </listitem> + + <listitem> + <para><type>ltxtquery</type> represents a full-text-search-like + pattern for matching <type>ltree</type> values. An + <type>ltxtquery</type> value contains words, possibly with the + modifiers <literal>@</literal>, <literal>*</literal>, <literal>%</literal> at the end; + the modifiers have the same meanings as in <type>lquery</type>. + Words can be combined with <literal>&</literal> (AND), + <literal>|</literal> (OR), <literal>!</literal> (NOT), and parentheses. + The key difference from + <type>lquery</type> is that <type>ltxtquery</type> matches words without + regard to their position in the label path. + </para> + + <para> + Here's an example <type>ltxtquery</type>: +<programlisting> +Europe & Russia*@ & !Transportation +</programlisting> + This will match paths that contain the label <literal>Europe</literal> and + any label beginning with <literal>Russia</literal> (case-insensitive), + but not paths containing the label <literal>Transportation</literal>. + The location of these words within the path is not important. + Also, when <literal>%</literal> is used, the word can be matched to any + underscore-separated word within a label, regardless of position. + </para> + </listitem> + + </itemizedlist> + + <para> + Note: <type>ltxtquery</type> allows whitespace between symbols, but + <type>ltree</type> and <type>lquery</type> do not. + </para> + </sect2> + + <sect2 id="ltree-ops-funcs"> + <title>Operators and Functions</title> + + <para> + Type <type>ltree</type> has the usual comparison operators + <literal>=</literal>, <literal><></literal>, + <literal><</literal>, <literal>></literal>, <literal><=</literal>, <literal>>=</literal>. + Comparison sorts in the order of a tree traversal, with the children + of a node sorted by label text. In addition, the specialized + operators shown in <xref linkend="ltree-op-table"/> are available. + </para> + + <table id="ltree-op-table"> + <title><type>ltree</type> Operators</title> + <tgroup cols="1"> + <thead> + <row> + <entry role="func_table_entry"><para role="func_signature"> + Operator + </para> + <para> + Description + </para></entry> + </row> + </thead> + + <tbody> + <row> + <entry role="func_table_entry"><para role="func_signature"> + <type>ltree</type> <literal>@></literal> <type>ltree</type> + <returnvalue>boolean</returnvalue> + </para> + <para> + Is left argument an ancestor of right (or equal)? + </para></entry> + </row> + + <row> + <entry role="func_table_entry"><para role="func_signature"> + <type>ltree</type> <literal><@</literal> <type>ltree</type> + <returnvalue>boolean</returnvalue> + </para> + <para> + Is left argument a descendant of right (or equal)? + </para></entry> + </row> + + <row> + <entry role="func_table_entry"><para role="func_signature"> + <type>ltree</type> <literal>~</literal> <type>lquery</type> + <returnvalue>boolean</returnvalue> + </para> + <para role="func_signature"> + <type>lquery</type> <literal>~</literal> <type>ltree</type> + <returnvalue>boolean</returnvalue> + </para> + <para> + Does <type>ltree</type> match <type>lquery</type>? + </para></entry> + </row> + + <row> + <entry role="func_table_entry"><para role="func_signature"> + <type>ltree</type> <literal>?</literal> <type>lquery[]</type> + <returnvalue>boolean</returnvalue> + </para> + <para role="func_signature"> + <type>lquery[]</type> <literal>?</literal> <type>ltree</type> + <returnvalue>boolean</returnvalue> + </para> + <para> + Does <type>ltree</type> match any <type>lquery</type> in array? + </para></entry> + </row> + + <row> + <entry role="func_table_entry"><para role="func_signature"> + <type>ltree</type> <literal>@</literal> <type>ltxtquery</type> + <returnvalue>boolean</returnvalue> + </para> + <para role="func_signature"> + <type>ltxtquery</type> <literal>@</literal> <type>ltree</type> + <returnvalue>boolean</returnvalue> + </para> + <para> + Does <type>ltree</type> match <type>ltxtquery</type>? + </para></entry> + </row> + + <row> + <entry role="func_table_entry"><para role="func_signature"> + <type>ltree</type> <literal>||</literal> <type>ltree</type> + <returnvalue>ltree</returnvalue> + </para> + <para> + Concatenates <type>ltree</type> paths. + </para></entry> + </row> + + <row> + <entry role="func_table_entry"><para role="func_signature"> + <type>ltree</type> <literal>||</literal> <type>text</type> + <returnvalue>ltree</returnvalue> + </para> + <para role="func_signature"> + <type>text</type> <literal>||</literal> <type>ltree</type> + <returnvalue>ltree</returnvalue> + </para> + <para> + Converts text to <type>ltree</type> and concatenates. + </para></entry> + </row> + + <row> + <entry role="func_table_entry"><para role="func_signature"> + <type>ltree[]</type> <literal>@></literal> <type>ltree</type> + <returnvalue>boolean</returnvalue> + </para> + <para role="func_signature"> + <type>ltree</type> <literal><@</literal> <type>ltree[]</type> + <returnvalue>boolean</returnvalue> + </para> + <para> + Does array contain an ancestor of <type>ltree</type>? + </para></entry> + </row> + + <row> + <entry role="func_table_entry"><para role="func_signature"> + <type>ltree[]</type> <literal><@</literal> <type>ltree</type> + <returnvalue>boolean</returnvalue> + </para> + <para role="func_signature"> + <type>ltree</type> <literal>@></literal> <type>ltree[]</type> + <returnvalue>boolean</returnvalue> + </para> + <para> + Does array contain a descendant of <type>ltree</type>? + </para></entry> + </row> + + <row> + <entry role="func_table_entry"><para role="func_signature"> + <type>ltree[]</type> <literal>~</literal> <type>lquery</type> + <returnvalue>boolean</returnvalue> + </para> + <para role="func_signature"> + <type>lquery</type> <literal>~</literal> <type>ltree[]</type> + <returnvalue>boolean</returnvalue> + </para> + <para> + Does array contain any path matching <type>lquery</type>? + </para></entry> + </row> + + <row> + <entry role="func_table_entry"><para role="func_signature"> + <type>ltree[]</type> <literal>?</literal> <type>lquery[]</type> + <returnvalue>boolean</returnvalue> + </para> + <para role="func_signature"> + <type>lquery[]</type> <literal>?</literal> <type>ltree[]</type> + <returnvalue>boolean</returnvalue> + </para> + <para> + Does <type>ltree</type> array contain any path matching + any <type>lquery</type>? + </para></entry> + </row> + + <row> + <entry role="func_table_entry"><para role="func_signature"> + <type>ltree[]</type> <literal>@</literal> <type>ltxtquery</type> + <returnvalue>boolean</returnvalue> + </para> + <para role="func_signature"> + <type>ltxtquery</type> <literal>@</literal> <type>ltree[]</type> + <returnvalue>boolean</returnvalue> + </para> + <para> + Does array contain any path matching <type>ltxtquery</type>? + </para></entry> + </row> + + <row> + <entry role="func_table_entry"><para role="func_signature"> + <type>ltree[]</type> <literal>?@></literal> <type>ltree</type> + <returnvalue>ltree</returnvalue> + </para> + <para> + Returns first array entry that is an ancestor of <type>ltree</type>, + or <literal>NULL</literal> if none. + </para></entry> + </row> + + <row> + <entry role="func_table_entry"><para role="func_signature"> + <type>ltree[]</type> <literal>?<@</literal> <type>ltree</type> + <returnvalue>ltree</returnvalue> + </para> + <para> + Returns first array entry that is a descendant of <type>ltree</type>, + or <literal>NULL</literal> if none. + </para></entry> + </row> + + <row> + <entry role="func_table_entry"><para role="func_signature"> + <type>ltree[]</type> <literal>?~</literal> <type>lquery</type> + <returnvalue>ltree</returnvalue> + </para> + <para> + Returns first array entry that matches <type>lquery</type>, + or <literal>NULL</literal> if none. + </para></entry> + </row> + + <row> + <entry role="func_table_entry"><para role="func_signature"> + <type>ltree[]</type> <literal>?@</literal> <type>ltxtquery</type> + <returnvalue>ltree</returnvalue> + </para> + <para> + Returns first array entry that matches <type>ltxtquery</type>, + or <literal>NULL</literal> if none. + </para></entry> + </row> + </tbody> + </tgroup> + </table> + + <para> + The operators <literal><@</literal>, <literal>@></literal>, + <literal>@</literal> and <literal>~</literal> have analogues + <literal>^<@</literal>, <literal>^@></literal>, <literal>^@</literal>, + <literal>^~</literal>, which are the same except they do not use + indexes. These are useful only for testing purposes. + </para> + + <para> + The available functions are shown in <xref linkend="ltree-func-table"/>. + </para> + + <table id="ltree-func-table"> + <title><type>ltree</type> Functions</title> + <tgroup cols="1"> + <thead> + <row> + <entry role="func_table_entry"><para role="func_signature"> + Function + </para> + <para> + Description + </para> + <para> + Example(s) + </para></entry> + </row> + </thead> + + <tbody> + <row> + <entry role="func_table_entry"><para role="func_signature"> + <indexterm><primary>subltree</primary></indexterm> + <function>subltree</function> ( <type>ltree</type>, <parameter>start</parameter> <type>integer</type>, <parameter>end</parameter> <type>integer</type> ) + <returnvalue>ltree</returnvalue> + </para> + <para> + Returns subpath of <type>ltree</type> from + position <parameter>start</parameter> to + position <parameter>end</parameter>-1 (counting from 0). + </para> + <para> + <literal>subltree('Top.Child1.Child2', 1, 2)</literal> + <returnvalue>Child1</returnvalue> + </para></entry> + </row> + + <row> + <entry role="func_table_entry"><para role="func_signature"> + <indexterm><primary>subpath</primary></indexterm> + <function>subpath</function> ( <type>ltree</type>, <parameter>offset</parameter> <type>integer</type>, <parameter>len</parameter> <type>integer</type> ) + <returnvalue>ltree</returnvalue> + </para> + <para> + Returns subpath of <type>ltree</type> starting at + position <parameter>offset</parameter>, with + length <parameter>len</parameter>. If <parameter>offset</parameter> + is negative, subpath starts that far from the end of the path. + If <parameter>len</parameter> is negative, leaves that many labels off + the end of the path. + </para> + <para> + <literal>subpath('Top.Child1.Child2', 0, 2)</literal> + <returnvalue>Top.Child1</returnvalue> + </para></entry> + </row> + + <row> + <entry role="func_table_entry"><para role="func_signature"> + <function>subpath</function> ( <type>ltree</type>, <parameter>offset</parameter> <type>integer</type> ) + <returnvalue>ltree</returnvalue> + </para> + <para> + Returns subpath of <type>ltree</type> starting at + position <parameter>offset</parameter>, extending to end of path. + If <parameter>offset</parameter> is negative, subpath starts that far + from the end of the path. + </para> + <para> + <literal>subpath('Top.Child1.Child2', 1)</literal> + <returnvalue>Child1.Child2</returnvalue> + </para></entry> + </row> + + <row> + <entry role="func_table_entry"><para role="func_signature"> + <indexterm><primary>nlevel</primary></indexterm> + <function>nlevel</function> ( <type>ltree</type> ) + <returnvalue>integer</returnvalue> + </para> + <para> + Returns number of labels in path. + </para> + <para> + <literal>nlevel('Top.Child1.Child2')</literal> + <returnvalue>3</returnvalue> + </para></entry> + </row> + + <row> + <entry role="func_table_entry"><para role="func_signature"> + <indexterm><primary>index</primary></indexterm> + <function>index</function> ( <parameter>a</parameter> <type>ltree</type>, <parameter>b</parameter> <type>ltree</type> ) + <returnvalue>integer</returnvalue> + </para> + <para> + Returns position of first occurrence of <parameter>b</parameter> in + <parameter>a</parameter>, or -1 if not found. + </para> + <para> + <literal>index('0.1.2.3.5.4.5.6.8.5.6.8', '5.6')</literal> + <returnvalue>6</returnvalue> + </para></entry> + </row> + + <row> + <entry role="func_table_entry"><para role="func_signature"> + <function>index</function> ( <parameter>a</parameter> <type>ltree</type>, <parameter>b</parameter> <type>ltree</type>, <parameter>offset</parameter> <type>integer</type> ) + <returnvalue>integer</returnvalue> + </para> + <para> + Returns position of first occurrence of <parameter>b</parameter> + in <parameter>a</parameter>, or -1 if not found. The search starts at + position <parameter>offset</parameter>; + negative <parameter>offset</parameter> means + start <parameter>-offset</parameter> labels from the end of the path. + </para> + <para> + <literal>index('0.1.2.3.5.4.5.6.8.5.6.8', '5.6', -4)</literal> + <returnvalue>9</returnvalue> + </para></entry> + </row> + + <row> + <entry role="func_table_entry"><para role="func_signature"> + <indexterm><primary>text2ltree</primary></indexterm> + <function>text2ltree</function> ( <type>text</type> ) + <returnvalue>ltree</returnvalue> + </para> + <para> + Casts <type>text</type> to <type>ltree</type>. + </para></entry> + </row> + + <row> + <entry role="func_table_entry"><para role="func_signature"> + <indexterm><primary>ltree2text</primary></indexterm> + <function>ltree2text</function> ( <type>ltree</type> ) + <returnvalue>text</returnvalue> + </para> + <para> + Casts <type>ltree</type> to <type>text</type>. + </para></entry> + </row> + + <row> + <entry role="func_table_entry"><para role="func_signature"> + <indexterm><primary>lca</primary></indexterm> + <function>lca</function> ( <type>ltree</type> <optional>, <type>ltree</type> <optional>, ... </optional></optional> ) + <returnvalue>ltree</returnvalue> + </para> + <para> + Computes longest common ancestor of paths + (up to 8 arguments are supported). + </para> + <para> + <literal>lca('1.2.3', '1.2.3.4.5.6')</literal> + <returnvalue>1.2</returnvalue> + </para></entry> + </row> + + <row> + <entry role="func_table_entry"><para role="func_signature"> + <function>lca</function> ( <type>ltree[]</type> ) + <returnvalue>ltree</returnvalue> + </para> + <para> + Computes longest common ancestor of paths in array. + </para> + <para> + <literal>lca(array['1.2.3'::ltree,'1.2.3.4'])</literal> + <returnvalue>1.2</returnvalue> + </para></entry> + </row> + </tbody> + </tgroup> + </table> + </sect2> + + <sect2 id="ltree-indexes"> + <title>Indexes</title> + <para> + <filename>ltree</filename> supports several types of indexes that can speed + up the indicated operators: + </para> + + <itemizedlist> + <listitem> + <para> + B-tree index over <type>ltree</type>: + <literal><</literal>, <literal><=</literal>, <literal>=</literal>, + <literal>>=</literal>, <literal>></literal> + </para> + </listitem> + <listitem> + <para> + GiST index over <type>ltree</type> (<literal>gist_ltree_ops</literal> + opclass): + <literal><</literal>, <literal><=</literal>, <literal>=</literal>, + <literal>>=</literal>, <literal>></literal>, + <literal>@></literal>, <literal><@</literal>, + <literal>@</literal>, <literal>~</literal>, <literal>?</literal> + </para> + <para> + <literal>gist_ltree_ops</literal> GiST opclass approximates a set of + path labels as a bitmap signature. Its optional integer parameter + <literal>siglen</literal> determines the + signature length in bytes. The default signature length is 8 bytes. + The length must be a positive multiple of <type>int</type> alignment + (4 bytes on most machines)) up to 2024. Longer + signatures lead to a more precise search (scanning a smaller fraction of the index and + fewer heap pages), at the cost of a larger index. + </para> + <para> + Example of creating such an index with the default signature length of 8 bytes: + </para> +<programlisting> +CREATE INDEX path_gist_idx ON test USING GIST (path); +</programlisting> + <para> + Example of creating such an index with a signature length of 100 bytes: + </para> +<programlisting> +CREATE INDEX path_gist_idx ON test USING GIST (path gist_ltree_ops(siglen=100)); +</programlisting> + </listitem> + <listitem> + <para> + GiST index over <type>ltree[]</type> (<literal>gist__ltree_ops</literal> + opclass): + <literal>ltree[] <@ ltree</literal>, <literal>ltree @> ltree[]</literal>, + <literal>@</literal>, <literal>~</literal>, <literal>?</literal> + </para> + <para> + <literal>gist__ltree_ops</literal> GiST opclass works similarly to + <literal>gist_ltree_ops</literal> and also takes signature length as + a parameter. The default value of <literal>siglen</literal> in + <literal>gist__ltree_ops</literal> is 28 bytes. + </para> + <para> + Example of creating such an index with the default signature length of 28 bytes: + </para> +<programlisting> +CREATE INDEX path_gist_idx ON test USING GIST (array_path); +</programlisting> + <para> + Example of creating such an index with a signature length of 100 bytes: + </para> +<programlisting> +CREATE INDEX path_gist_idx ON test USING GIST (array_path gist__ltree_ops(siglen=100)); +</programlisting> + <para> + Note: This index type is lossy. + </para> + </listitem> + </itemizedlist> + </sect2> + + <sect2 id="ltree-example"> + <title>Example</title> + + <para> + This example uses the following data (also available in file + <filename>contrib/ltree/ltreetest.sql</filename> in the source distribution): + </para> + +<programlisting> +CREATE TABLE test (path ltree); +INSERT INTO test VALUES ('Top'); +INSERT INTO test VALUES ('Top.Science'); +INSERT INTO test VALUES ('Top.Science.Astronomy'); +INSERT INTO test VALUES ('Top.Science.Astronomy.Astrophysics'); +INSERT INTO test VALUES ('Top.Science.Astronomy.Cosmology'); +INSERT INTO test VALUES ('Top.Hobbies'); +INSERT INTO test VALUES ('Top.Hobbies.Amateurs_Astronomy'); +INSERT INTO test VALUES ('Top.Collections'); +INSERT INTO test VALUES ('Top.Collections.Pictures'); +INSERT INTO test VALUES ('Top.Collections.Pictures.Astronomy'); +INSERT INTO test VALUES ('Top.Collections.Pictures.Astronomy.Stars'); +INSERT INTO test VALUES ('Top.Collections.Pictures.Astronomy.Galaxies'); +INSERT INTO test VALUES ('Top.Collections.Pictures.Astronomy.Astronauts'); +CREATE INDEX path_gist_idx ON test USING GIST (path); +CREATE INDEX path_idx ON test USING BTREE (path); +</programlisting> + + <para> + Now, we have a table <structname>test</structname> populated with data describing + the hierarchy shown below: + </para> + +<literallayout class="monospaced"> + Top + / | \ + Science Hobbies Collections + / | \ + Astronomy Amateurs_Astronomy Pictures + / \ | +Astrophysics Cosmology Astronomy + / | \ + Galaxies Stars Astronauts +</literallayout> + + <para> + We can do inheritance: +<screen> +ltreetest=> SELECT path FROM test WHERE path <@ 'Top.Science'; + path +------------------------------------ + Top.Science + Top.Science.Astronomy + Top.Science.Astronomy.Astrophysics + Top.Science.Astronomy.Cosmology +(4 rows) +</screen> + </para> + + <para> + Here are some examples of path matching: +<screen> +ltreetest=> SELECT path FROM test WHERE path ~ '*.Astronomy.*'; + path +----------------------------------------------- + Top.Science.Astronomy + Top.Science.Astronomy.Astrophysics + Top.Science.Astronomy.Cosmology + Top.Collections.Pictures.Astronomy + Top.Collections.Pictures.Astronomy.Stars + Top.Collections.Pictures.Astronomy.Galaxies + Top.Collections.Pictures.Astronomy.Astronauts +(7 rows) + +ltreetest=> SELECT path FROM test WHERE path ~ '*.!pictures@.Astronomy.*'; + path +------------------------------------ + Top.Science.Astronomy + Top.Science.Astronomy.Astrophysics + Top.Science.Astronomy.Cosmology +(3 rows) +</screen> + </para> + + <para> + Here are some examples of full text search: +<screen> +ltreetest=> SELECT path FROM test WHERE path @ 'Astro*% & !pictures@'; + path +------------------------------------ + Top.Science.Astronomy + Top.Science.Astronomy.Astrophysics + Top.Science.Astronomy.Cosmology + Top.Hobbies.Amateurs_Astronomy +(4 rows) + +ltreetest=> SELECT path FROM test WHERE path @ 'Astro* & !pictures@'; + path +------------------------------------ + Top.Science.Astronomy + Top.Science.Astronomy.Astrophysics + Top.Science.Astronomy.Cosmology +(3 rows) +</screen> + </para> + + <para> + Path construction using functions: +<screen> +ltreetest=> SELECT subpath(path,0,2)||'Space'||subpath(path,2) FROM test WHERE path <@ 'Top.Science.Astronomy'; + ?column? +------------------------------------------ + Top.Science.Space.Astronomy + Top.Science.Space.Astronomy.Astrophysics + Top.Science.Space.Astronomy.Cosmology +(3 rows) +</screen> + </para> + + <para> + We could simplify this by creating an SQL function that inserts a label + at a specified position in a path: +<screen> +CREATE FUNCTION ins_label(ltree, int, text) RETURNS ltree + AS 'select subpath($1,0,$2) || $3 || subpath($1,$2);' + LANGUAGE SQL IMMUTABLE; + +ltreetest=> SELECT ins_label(path,2,'Space') FROM test WHERE path <@ 'Top.Science.Astronomy'; + ins_label +------------------------------------------ + Top.Science.Space.Astronomy + Top.Science.Space.Astronomy.Astrophysics + Top.Science.Space.Astronomy.Cosmology +(3 rows) +</screen> + </para> + </sect2> + + <sect2 id="ltree-transforms"> + <title>Transforms</title> + + <para> + The <literal>ltree_plpython3u</literal> extension implements transforms for + the <type>ltree</type> type for PL/Python. If installed and specified when + creating a function, <type>ltree</type> values are mapped to Python lists. + (The reverse is currently not supported, however.) + </para> + + <caution> + <para> + It is strongly recommended that the transform extension be installed in + the same schema as <filename>ltree</filename>. Otherwise there are + installation-time security hazards if a transform extension's schema + contains objects defined by a hostile user. + </para> + </caution> + </sect2> + + <sect2 id="ltree-authors"> + <title>Authors</title> + + <para> + All work was done by Teodor Sigaev (<email>teodor@stack.net</email>) and + Oleg Bartunov (<email>oleg@sai.msu.su</email>). See + <ulink url="http://www.sai.msu.su/~megera/postgres/gist/"></ulink> for + additional information. Authors would like to thank Eugeny Rodichev for + helpful discussions. Comments and bug reports are welcome. + </para> + </sect2> + +</sect1> |