2009-05-18 13:08:24 +02:00
|
|
|
<!-- $PostgreSQL: pgsql/doc/src/sgml/xml2.sgml,v 1.7 2009/05/18 11:08:24 petere Exp $ -->
|
2007-12-06 05:12:10 +01:00
|
|
|
|
2007-11-11 00:30:46 +01:00
|
|
|
<sect1 id="xml2">
|
2007-12-06 05:12:10 +01:00
|
|
|
<title>xml2</title>
|
|
|
|
|
2007-11-11 00:30:46 +01:00
|
|
|
<indexterm zone="xml2">
|
|
|
|
<primary>xml2</primary>
|
|
|
|
</indexterm>
|
|
|
|
|
2007-12-06 05:12:10 +01:00
|
|
|
<para>
|
|
|
|
The <filename>xml2</> module provides XPath querying and
|
|
|
|
XSLT functionality.
|
|
|
|
</para>
|
|
|
|
|
2007-11-11 00:30:46 +01:00
|
|
|
<sect2>
|
|
|
|
<title>Deprecation notice</title>
|
2007-12-06 05:12:10 +01:00
|
|
|
|
2007-11-11 00:30:46 +01:00
|
|
|
<para>
|
2007-12-06 05:12:10 +01:00
|
|
|
From <productname>PostgreSQL</> 8.3 on, there is XML-related
|
|
|
|
functionality based on the SQL/XML standard in the core server.
|
|
|
|
That functionality covers XML syntax checking and XPath queries,
|
|
|
|
which is what this module does, and more, but the API is
|
|
|
|
not at all compatible. It is planned that this module will be
|
|
|
|
removed in PostgreSQL 8.4 in favor of the newer standard API, so
|
|
|
|
you are encouraged to try converting your applications. If you
|
|
|
|
find that some of the functionality of this module is not
|
|
|
|
available in an adequate form with the newer API, please explain
|
|
|
|
your issue to pgsql-hackers@postgresql.org so that the deficiency
|
|
|
|
can be addressed.
|
2007-11-11 00:30:46 +01:00
|
|
|
</para>
|
|
|
|
</sect2>
|
2007-12-06 05:12:10 +01:00
|
|
|
|
2007-11-11 00:30:46 +01:00
|
|
|
<sect2>
|
|
|
|
<title>Description of functions</title>
|
2007-12-06 05:12:10 +01:00
|
|
|
|
2007-11-11 00:30:46 +01:00
|
|
|
<para>
|
2009-05-18 13:08:24 +02:00
|
|
|
<xref linkend="xml2-functions-table"> shows the functions provided by this module.
|
2007-12-06 05:12:10 +01:00
|
|
|
These functions provide straightforward XML parsing and XPath queries.
|
|
|
|
All arguments are of type <type>text</>, so for brevity that is not shown.
|
2007-11-11 00:30:46 +01:00
|
|
|
</para>
|
|
|
|
|
2009-05-18 13:08:24 +02:00
|
|
|
<table id="xml2-functions-table">
|
2007-11-11 00:30:46 +01:00
|
|
|
<title>Functions</title>
|
|
|
|
<tgroup cols="2">
|
|
|
|
<tbody>
|
|
|
|
<row>
|
|
|
|
<entry>
|
2007-12-06 05:12:10 +01:00
|
|
|
<synopsis>
|
|
|
|
xml_is_well_formed(document) returns bool
|
|
|
|
</synopsis>
|
2007-11-11 00:30:46 +01:00
|
|
|
</entry>
|
|
|
|
<entry>
|
|
|
|
<para>
|
|
|
|
This parses the document text in its parameter and returns true if the
|
2007-12-06 05:12:10 +01:00
|
|
|
document is well-formed XML. (Note: before PostgreSQL 8.2, this
|
|
|
|
function was called <function>xml_valid()</>. That is the wrong name
|
|
|
|
since validity and well-formedness have different meanings in XML.
|
|
|
|
The old name is still available, but is deprecated.)
|
2007-11-11 00:30:46 +01:00
|
|
|
</para>
|
|
|
|
</entry>
|
|
|
|
</row>
|
|
|
|
<row>
|
|
|
|
<entry>
|
2007-12-06 05:12:10 +01:00
|
|
|
<synopsis>
|
|
|
|
xpath_string(document,query) returns text
|
|
|
|
xpath_number(document,query) returns float4
|
|
|
|
xpath_bool(document,query) returns bool
|
|
|
|
</synopsis>
|
2007-11-11 00:30:46 +01:00
|
|
|
</entry>
|
|
|
|
<entry>
|
|
|
|
<para>
|
|
|
|
These functions evaluate the XPath query on the supplied document, and
|
|
|
|
cast the result to the specified type.
|
|
|
|
</para>
|
|
|
|
</entry>
|
|
|
|
</row>
|
|
|
|
<row>
|
|
|
|
<entry>
|
2007-12-06 05:12:10 +01:00
|
|
|
<synopsis>
|
|
|
|
xpath_nodeset(document,query,toptag,itemtag) returns text
|
|
|
|
</synopsis>
|
2007-11-11 00:30:46 +01:00
|
|
|
</entry>
|
|
|
|
<entry>
|
|
|
|
<para>
|
|
|
|
This evaluates query on document and wraps the result in XML tags. If
|
|
|
|
the result is multivalued, the output will look like:
|
|
|
|
</para>
|
|
|
|
<literal>
|
2007-12-06 05:12:10 +01:00
|
|
|
<toptag>
|
|
|
|
<itemtag>Value 1 which could be an XML fragment</itemtag>
|
|
|
|
<itemtag>Value 2....</itemtag>
|
|
|
|
</toptag>
|
2007-11-11 00:30:46 +01:00
|
|
|
</literal>
|
|
|
|
<para>
|
|
|
|
If either toptag or itemtag is an empty string, the relevant tag is omitted.
|
|
|
|
</para>
|
|
|
|
</entry>
|
|
|
|
</row>
|
|
|
|
<row>
|
|
|
|
<entry>
|
2007-12-06 05:12:10 +01:00
|
|
|
<synopsis>
|
|
|
|
xpath_nodeset(document,query) returns text
|
|
|
|
</synopsis>
|
2007-11-11 00:30:46 +01:00
|
|
|
</entry>
|
|
|
|
<entry>
|
|
|
|
<para>
|
2007-12-06 05:12:10 +01:00
|
|
|
Like xpath_nodeset(document,query,toptag,itemtag) but result omits both tags.
|
2007-11-11 00:30:46 +01:00
|
|
|
</para>
|
|
|
|
</entry>
|
|
|
|
</row>
|
|
|
|
<row>
|
|
|
|
<entry>
|
2007-12-06 05:12:10 +01:00
|
|
|
<synopsis>
|
|
|
|
xpath_nodeset(document,query,itemtag) returns text
|
|
|
|
</synopsis>
|
2007-11-11 00:30:46 +01:00
|
|
|
</entry>
|
|
|
|
<entry>
|
|
|
|
<para>
|
2007-12-06 05:12:10 +01:00
|
|
|
Like xpath_nodeset(document,query,toptag,itemtag) but result omits toptag.
|
2007-11-11 00:30:46 +01:00
|
|
|
</para>
|
|
|
|
</entry>
|
|
|
|
</row>
|
|
|
|
<row>
|
|
|
|
<entry>
|
2007-12-06 05:12:10 +01:00
|
|
|
<synopsis>
|
|
|
|
xpath_list(document,query,separator) returns text
|
|
|
|
</synopsis>
|
2007-11-11 00:30:46 +01:00
|
|
|
</entry>
|
|
|
|
<entry>
|
|
|
|
<para>
|
2007-12-06 05:12:10 +01:00
|
|
|
This function returns multiple values separated by the specified
|
|
|
|
separator, for example <literal>Value 1,Value 2,Value 3</> if
|
|
|
|
separator is <literal>,</>.
|
2007-11-11 00:30:46 +01:00
|
|
|
</para>
|
|
|
|
</entry>
|
|
|
|
</row>
|
|
|
|
<row>
|
|
|
|
<entry>
|
2007-12-06 05:12:10 +01:00
|
|
|
<synopsis>
|
|
|
|
xpath_list(document,query) returns text
|
|
|
|
</synopsis>
|
2007-11-11 00:30:46 +01:00
|
|
|
</entry>
|
|
|
|
<entry>
|
2007-12-06 05:12:10 +01:00
|
|
|
This is a wrapper for the above function that uses <literal>,</>
|
|
|
|
as the separator.
|
2007-11-11 00:30:46 +01:00
|
|
|
</entry>
|
|
|
|
</row>
|
|
|
|
</tbody>
|
|
|
|
</tgroup>
|
|
|
|
</table>
|
|
|
|
</sect2>
|
|
|
|
|
|
|
|
<sect2>
|
|
|
|
<title><literal>xpath_table</literal></title>
|
2007-12-06 05:12:10 +01:00
|
|
|
|
|
|
|
<synopsis>
|
|
|
|
xpath_table(text key, text document, text relation, text xpaths, text criteria) returns setof record
|
|
|
|
</synopsis>
|
|
|
|
|
2007-11-11 00:30:46 +01:00
|
|
|
<para>
|
2007-12-06 05:12:10 +01:00
|
|
|
<function>xpath_table</> is a table function that evaluates a set of XPath
|
|
|
|
queries on each of a set of documents and returns the results as a
|
|
|
|
table. The primary key field from the original document table is returned
|
|
|
|
as the first column of the result so that the result set
|
|
|
|
can readily be used in joins.
|
2007-11-11 00:30:46 +01:00
|
|
|
</para>
|
2007-12-06 05:12:10 +01:00
|
|
|
|
2007-11-11 00:30:46 +01:00
|
|
|
<table>
|
|
|
|
<title>Parameters</title>
|
|
|
|
<tgroup cols="2">
|
|
|
|
<tbody>
|
|
|
|
<row>
|
2007-12-06 05:12:10 +01:00
|
|
|
<entry><parameter>key</parameter></entry>
|
2007-11-11 00:30:46 +01:00
|
|
|
<entry>
|
|
|
|
<para>
|
2007-12-06 05:12:10 +01:00
|
|
|
the name of the <quote>key</> field — this is just a field to be used as
|
2009-04-27 18:27:36 +02:00
|
|
|
the first column of the output table, i.e., it identifies the record from
|
2007-12-06 05:12:10 +01:00
|
|
|
which each output row came (see note below about multiple values)
|
2007-11-11 00:30:46 +01:00
|
|
|
</para>
|
|
|
|
</entry>
|
|
|
|
</row>
|
|
|
|
<row>
|
2007-12-06 05:12:10 +01:00
|
|
|
<entry><parameter>document</parameter></entry>
|
2007-11-11 00:30:46 +01:00
|
|
|
<entry>
|
|
|
|
<para>
|
|
|
|
the name of the field containing the XML document
|
|
|
|
</para>
|
|
|
|
</entry>
|
|
|
|
</row>
|
|
|
|
<row>
|
2007-12-06 05:12:10 +01:00
|
|
|
<entry><parameter>relation</parameter></entry>
|
2007-11-11 00:30:46 +01:00
|
|
|
<entry>
|
|
|
|
<para>
|
|
|
|
the name of the table or view containing the documents
|
|
|
|
</para>
|
|
|
|
</entry>
|
|
|
|
</row>
|
|
|
|
<row>
|
2007-12-06 05:12:10 +01:00
|
|
|
<entry><parameter>xpaths</parameter></entry>
|
2007-11-11 00:30:46 +01:00
|
|
|
<entry>
|
|
|
|
<para>
|
2007-12-06 05:12:10 +01:00
|
|
|
one or more XPath expressions, separated by <literal>|</literal>
|
2007-11-11 00:30:46 +01:00
|
|
|
</para>
|
|
|
|
</entry>
|
|
|
|
</row>
|
|
|
|
<row>
|
2007-12-06 05:12:10 +01:00
|
|
|
<entry><parameter>criteria</parameter></entry>
|
2007-11-11 00:30:46 +01:00
|
|
|
<entry>
|
|
|
|
<para>
|
2007-12-06 05:12:10 +01:00
|
|
|
the contents of the WHERE clause. This cannot be omitted, so use
|
|
|
|
<literal>true</literal> or <literal>1=1</literal> if you want to
|
|
|
|
process all the rows in the relation
|
2007-11-11 00:30:46 +01:00
|
|
|
</para>
|
|
|
|
</entry>
|
|
|
|
</row>
|
|
|
|
</tbody>
|
|
|
|
</tgroup>
|
|
|
|
</table>
|
|
|
|
|
|
|
|
<para>
|
2007-12-06 05:12:10 +01:00
|
|
|
These parameters (except the XPath strings) are just substituted
|
|
|
|
into a plain SQL SELECT statement, so you have some flexibility — the
|
2007-11-11 00:30:46 +01:00
|
|
|
statement is
|
|
|
|
</para>
|
|
|
|
|
|
|
|
<para>
|
|
|
|
<literal>
|
2007-12-06 05:12:10 +01:00
|
|
|
SELECT <key>, <document> FROM <relation> WHERE <criteria>
|
2007-11-11 00:30:46 +01:00
|
|
|
</literal>
|
|
|
|
</para>
|
|
|
|
|
|
|
|
<para>
|
2007-12-06 05:12:10 +01:00
|
|
|
so those parameters can be <emphasis>anything</> valid in those particular
|
2007-11-11 00:30:46 +01:00
|
|
|
locations. The result from this SELECT needs to return exactly two
|
|
|
|
columns (which it will unless you try to list multiple fields for key
|
|
|
|
or document). Beware that this simplistic approach requires that you
|
|
|
|
validate any user-supplied values to avoid SQL injection attacks.
|
|
|
|
</para>
|
2007-12-06 05:12:10 +01:00
|
|
|
|
2007-11-11 00:30:46 +01:00
|
|
|
<para>
|
2007-12-06 05:12:10 +01:00
|
|
|
The function has to be used in a <literal>FROM</> expression, with an
|
|
|
|
<literal>AS</> clause to specify the output columns; for example
|
2007-11-11 00:30:46 +01:00
|
|
|
</para>
|
2007-12-06 05:12:10 +01:00
|
|
|
|
2007-11-11 00:30:46 +01:00
|
|
|
<programlisting>
|
|
|
|
SELECT * FROM
|
2007-12-06 05:12:10 +01:00
|
|
|
xpath_table('article_id',
|
|
|
|
'article_xml',
|
|
|
|
'articles',
|
|
|
|
'/article/author|/article/pages|/article/title',
|
|
|
|
'date_entered > ''2003-01-01'' ')
|
2007-11-11 00:30:46 +01:00
|
|
|
AS t(article_id integer, author text, page_count integer, title text);
|
|
|
|
</programlisting>
|
|
|
|
|
|
|
|
<para>
|
2007-12-06 05:12:10 +01:00
|
|
|
The <literal>AS</> clause defines the names and types of the columns in the
|
|
|
|
output table. The first is the <quote>key</> field and the rest correspond
|
|
|
|
to the XPath queries.
|
|
|
|
If there are more XPath queries than result columns,
|
2007-11-11 00:30:46 +01:00
|
|
|
the extra queries will be ignored. If there are more result columns
|
|
|
|
than XPath queries, the extra columns will be NULL.
|
|
|
|
</para>
|
|
|
|
|
|
|
|
<para>
|
2007-12-06 05:12:10 +01:00
|
|
|
Notice that this example defines the <structname>page_count</> result
|
|
|
|
column as an integer. The function deals internally with string
|
|
|
|
representations, so when you say you want an integer in the output, it will
|
|
|
|
take the string representation of the XPath result and use PostgreSQL input
|
|
|
|
functions to transform it into an integer (or whatever type the <type>AS</>
|
|
|
|
clause requests). An error will result if it can't do this — for
|
|
|
|
example if the result is empty — so you may wish to just stick to
|
|
|
|
<type>text</> as the column type if you think your data has any problems.
|
2007-11-11 00:30:46 +01:00
|
|
|
</para>
|
2007-12-06 05:12:10 +01:00
|
|
|
|
2007-11-11 00:30:46 +01:00
|
|
|
<para>
|
2007-12-06 05:12:10 +01:00
|
|
|
The calling <command>SELECT</> statement doesn't necessarily have be
|
|
|
|
be just <literal>SELECT *</> — it can reference the output
|
2007-11-11 00:30:46 +01:00
|
|
|
columns by name or join them to other tables. The function produces a
|
|
|
|
virtual table with which you can perform any operation you wish (e.g.
|
|
|
|
aggregation, joining, sorting etc). So we could also have:
|
|
|
|
</para>
|
|
|
|
|
|
|
|
<programlisting>
|
2007-12-06 05:12:10 +01:00
|
|
|
SELECT t.title, p.fullname, p.email
|
|
|
|
FROM xpath_table('article_id', 'article_xml', 'articles',
|
|
|
|
'/article/title|/article/author/@id',
|
|
|
|
'xpath_string(article_xml,''/article/@date'') > ''2003-03-20'' ')
|
|
|
|
AS t(article_id integer, title text, author_id integer),
|
|
|
|
tblPeopleInfo AS p
|
2007-11-11 00:30:46 +01:00
|
|
|
WHERE t.author_id = p.person_id;
|
|
|
|
</programlisting>
|
|
|
|
|
|
|
|
<para>
|
|
|
|
as a more complicated example. Of course, you could wrap all
|
|
|
|
of this in a view for convenience.
|
|
|
|
</para>
|
2007-12-06 05:12:10 +01:00
|
|
|
|
2007-11-11 00:30:46 +01:00
|
|
|
<sect3>
|
|
|
|
<title>Multivalued results</title>
|
2007-12-06 05:12:10 +01:00
|
|
|
|
2007-11-11 00:30:46 +01:00
|
|
|
<para>
|
2007-12-06 05:12:10 +01:00
|
|
|
The <function>xpath_table</> function assumes that the results of each XPath query
|
2007-11-11 00:30:46 +01:00
|
|
|
might be multi-valued, so the number of rows returned by the function
|
|
|
|
may not be the same as the number of input documents. The first row
|
|
|
|
returned contains the first result from each query, the second row the
|
|
|
|
second result from each query. If one of the queries has fewer values
|
|
|
|
than the others, NULLs will be returned instead.
|
|
|
|
</para>
|
2007-12-06 05:12:10 +01:00
|
|
|
|
2007-11-11 00:30:46 +01:00
|
|
|
<para>
|
|
|
|
In some cases, a user will know that a given XPath query will return
|
2007-12-06 05:12:10 +01:00
|
|
|
only a single result (perhaps a unique document identifier) — if used
|
2007-11-11 00:30:46 +01:00
|
|
|
alongside an XPath query returning multiple results, the single-valued
|
|
|
|
result will appear only on the first row of the result. The solution
|
|
|
|
to this is to use the key field as part of a join against a simpler
|
|
|
|
XPath query. As an example:
|
|
|
|
</para>
|
2007-12-06 05:12:10 +01:00
|
|
|
|
2007-11-11 00:30:46 +01:00
|
|
|
<programlisting>
|
2007-12-06 05:12:10 +01:00
|
|
|
CREATE TABLE test (
|
|
|
|
id int4 NOT NULL,
|
|
|
|
xml text,
|
|
|
|
CONSTRAINT pk PRIMARY KEY (id)
|
|
|
|
);
|
|
|
|
|
|
|
|
INSERT INTO test VALUES (1, '<doc num="C1">
|
|
|
|
<line num="L1"><a>1</a><b>2</b><c>3</c></line>
|
|
|
|
<line num="L2"><a>11</a><b>22</b><c>33</c></line>
|
|
|
|
</doc>');
|
|
|
|
|
|
|
|
INSERT INTO test VALUES (2, '<doc num="C2">
|
|
|
|
<line num="L1"><a>111</a><b>222</b><c>333</c></line>
|
|
|
|
<line num="L2"><a>111</a><b>222</b><c>333</c></line>
|
|
|
|
</doc>');
|
|
|
|
|
|
|
|
SELECT * FROM
|
|
|
|
xpath_table('id','xml','test',
|
|
|
|
'/doc/@num|/doc/line/@num|/doc/line/a|/doc/line/b|/doc/line/c',
|
|
|
|
'true')
|
|
|
|
AS t(id int4, doc_num varchar(10), line_num varchar(10), val1 int4, val2 int4, val3 int4)
|
|
|
|
WHERE id = 1 ORDER BY doc_num, line_num
|
|
|
|
|
|
|
|
id | doc_num | line_num | val1 | val2 | val3
|
|
|
|
----+---------+----------+------+------+------
|
|
|
|
1 | C1 | L1 | 1 | 2 | 3
|
|
|
|
1 | | L2 | 11 | 22 | 33
|
2007-11-11 00:30:46 +01:00
|
|
|
</programlisting>
|
2007-12-06 05:12:10 +01:00
|
|
|
|
2007-11-11 00:30:46 +01:00
|
|
|
<para>
|
2007-12-06 05:12:10 +01:00
|
|
|
To get doc_num on every line, the solution is to use two invocations
|
|
|
|
of xpath_table and join the results:
|
2007-11-11 00:30:46 +01:00
|
|
|
</para>
|
2007-12-06 05:12:10 +01:00
|
|
|
|
2007-11-11 00:30:46 +01:00
|
|
|
<programlisting>
|
2007-12-06 05:12:10 +01:00
|
|
|
SELECT t.*,i.doc_num FROM
|
|
|
|
xpath_table('id', 'xml', 'test',
|
|
|
|
'/doc/line/@num|/doc/line/a|/doc/line/b|/doc/line/c',
|
|
|
|
'true')
|
|
|
|
AS t(id int4, line_num varchar(10), val1 int4, val2 int4, val3 int4),
|
|
|
|
xpath_table('id', 'xml', 'test', '/doc/@num', 'true')
|
|
|
|
AS i(id int4, doc_num varchar(10))
|
2007-11-11 00:30:46 +01:00
|
|
|
WHERE i.id=t.id AND i.id=1
|
|
|
|
ORDER BY doc_num, line_num;
|
2007-12-06 05:12:10 +01:00
|
|
|
|
2007-11-11 00:30:46 +01:00
|
|
|
id | line_num | val1 | val2 | val3 | doc_num
|
|
|
|
----+----------+------+------+------+---------
|
|
|
|
1 | L1 | 1 | 2 | 3 | C1
|
|
|
|
1 | L2 | 11 | 22 | 33 | C1
|
|
|
|
(2 rows)
|
|
|
|
</programlisting>
|
|
|
|
</sect3>
|
|
|
|
</sect2>
|
|
|
|
|
|
|
|
<sect2>
|
|
|
|
<title>XSLT functions</title>
|
2007-12-06 05:12:10 +01:00
|
|
|
|
2007-11-11 00:30:46 +01:00
|
|
|
<para>
|
2008-05-08 18:49:37 +02:00
|
|
|
The following functions are available if libxslt is installed:
|
2007-11-11 00:30:46 +01:00
|
|
|
</para>
|
|
|
|
|
|
|
|
<sect3>
|
|
|
|
<title><literal>xslt_process</literal></title>
|
2007-12-06 05:12:10 +01:00
|
|
|
|
|
|
|
<synopsis>
|
|
|
|
xslt_process(text document, text stylesheet, text paramlist) returns text
|
|
|
|
</synopsis>
|
2007-11-11 00:30:46 +01:00
|
|
|
|
|
|
|
<para>
|
|
|
|
This function appplies the XSL stylesheet to the document and returns
|
|
|
|
the transformed result. The paramlist is a list of parameter
|
|
|
|
assignments to be used in the transformation, specified in the form
|
2007-12-06 05:12:10 +01:00
|
|
|
<literal>a=1,b=2</>. Note that the
|
|
|
|
parameter parsing is very simple-minded: parameter values cannot
|
|
|
|
contain commas!
|
2007-11-11 00:30:46 +01:00
|
|
|
</para>
|
2007-12-06 05:12:10 +01:00
|
|
|
|
2007-11-11 00:30:46 +01:00
|
|
|
<para>
|
|
|
|
Also note that if either the document or stylesheet values do not
|
2007-12-04 00:49:51 +01:00
|
|
|
begin with a < then they will be treated as URLs and libxslt will
|
2007-12-06 05:12:10 +01:00
|
|
|
fetch them. It follows that you can use <function>xslt_process</> as a
|
|
|
|
means to fetch the contents of URLs — you should be aware of the
|
|
|
|
security implications of this.
|
|
|
|
</para>
|
|
|
|
|
2007-11-11 00:30:46 +01:00
|
|
|
<para>
|
2007-12-06 05:12:10 +01:00
|
|
|
There is also a two-parameter version of <function>xslt_process</> which
|
|
|
|
does not pass any parameters to the transformation.
|
2007-11-11 00:30:46 +01:00
|
|
|
</para>
|
|
|
|
</sect3>
|
|
|
|
</sect2>
|
|
|
|
|
|
|
|
<sect2>
|
2007-12-06 05:12:10 +01:00
|
|
|
<title>Author</title>
|
|
|
|
|
2007-11-11 00:30:46 +01:00
|
|
|
<para>
|
2007-12-06 05:12:10 +01:00
|
|
|
John Gray <email>jgray@azuli.co.uk</email>
|
2007-11-11 00:30:46 +01:00
|
|
|
</para>
|
2007-12-06 05:12:10 +01:00
|
|
|
|
2007-11-11 00:30:46 +01:00
|
|
|
<para>
|
2007-12-06 05:12:10 +01:00
|
|
|
Development of this module was sponsored by Torchbox Ltd. (www.torchbox.com).
|
|
|
|
It has the same BSD licence as PostgreSQL.
|
2007-11-11 00:30:46 +01:00
|
|
|
</para>
|
|
|
|
</sect2>
|
|
|
|
|
2007-12-06 05:12:10 +01:00
|
|
|
</sect1>
|