Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions doc/src/sgml/datatype.sgml
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,12 @@
<entry>autoincrementing four-byte integer</entry>
</row>

<row>
<entry><type>sql_query</type></entry>
<entry></entry>
<entry>pre-parsed, analyzed SQL query</entry>
</row>

<row>
<entry><type>text</type></entry>
<entry></entry>
Expand Down Expand Up @@ -5148,6 +5154,73 @@ WHERE ...
</para>
</sect1>

<sect1 id="datatype-sql-query">
<title><type>sql_query</type> Type</title>

<indexterm zone="datatype-sql-query">
<primary>sql_query</primary>
</indexterm>

<para>
The <type>sql_query</type> data type stores a fully analyzed SQL query.
Its input function parses and semantically analyzes the input SQL text,
resolving all object names to object identifiers (OIDs) at that time.
Its output function deparsed the stored query back to canonical SQL text
using <productname>PostgreSQL</productname>'s deparser, which is sensitive
to the current <varname>search_path</varname>: when the search path is
empty, all relation and type names are emitted in schema-qualified form.
</para>

<para>
This type is used as the argument type for <function>ts_stat</function>
when the SQL query argument should be pre-validated and schema-qualified
at assignment time rather than at execution time. The canonical use case
is a materialized view body that calls <function>ts_stat</function>: when
<productname>PostgreSQL</productname> refreshes the view (e.g., via
<command>pg_restore</command>) with an empty <varname>search_path</varname>
for security, a <type>text</type> argument containing unqualified table
names would fail to resolve. A <type>sql_query</type> value instead
emits <literal>public.articles</literal> from its output function and the
query executes correctly.
</para>

<para>
Internally, the value is stored in the same
<function>nodeToString</function> serialization format used by
<type>pg_node_tree</type> catalog columns. Unlike <type>pg_node_tree</type>,
<type>sql_query</type> accepts SQL text as input. The serialized format is
not intended to be stable across major <productname>PostgreSQL</productname>
versions; values are correctly round-tripped by <command>pg_dump</command>
because the dump writes the canonical SQL text produced by the output
function.
</para>

<para>
The <type>sql_query</type> type supports the standard comparison operators
(<literal>=</literal>, <literal>&lt;&gt;</literal>,
<literal>&lt;</literal>, <literal>&lt;=</literal>,
<literal>&gt;</literal>, <literal>&gt;=</literal>)
and a B-tree operator class, which makes it usable in
<literal>ORDER BY</literal> clauses and indexes. Comparison is performed
on the canonical SQL text.
</para>

<para>
A cast from <type>text</type> to <type>sql_query</type> is available but
requires an explicit cast (<literal>CAST(... AS sql_query)</literal> or
the <literal>::sql_query</literal> notation). No implicit cast is
defined, to prevent accidental substitution. The reverse cast from
<type>sql_query</type> to <type>text</type> is implicit.
</para>

<para>
<function>ts_stat</function> accepts a <type>sql_query</type> value
directly; no column definition list is needed because the output columns
are declared as named <literal>OUT</literal> parameters.
See <xref linkend="textsearch-statistics"/> for details.
</para>
</sect1>

<sect1 id="datatype-pseudo">
<title>Pseudo-Types</title>

Expand Down
23 changes: 23 additions & 0 deletions doc/src/sgml/func/func-textsearch.sgml
Original file line number Diff line number Diff line change
Expand Up @@ -1039,6 +1039,29 @@
<returnvalue>(foo,10,15) ...</returnvalue>
</para></entry>
</row>

<row>
<entry role="func_table_entry"><para role="func_signature">
<function>ts_stat</function> ( <parameter>sqlquery</parameter> <type>sql_query</type>
<optional>, <parameter>weights</parameter> <type>text</type> </optional> )
<returnvalue>setof record</returnvalue>
( <parameter>word</parameter> <type>text</type>,
<parameter>ndoc</parameter> <type>integer</type>,
<parameter>nentry</parameter> <type>integer</type> )
</para>
<para>
Like the <type>text</type> form, but accepts a pre-parsed
<type>sql_query</type> value. The query is deparsed at execution
time using the current <varname>search_path</varname>, which ensures
that schema-qualified names are emitted when the search path is
empty (as during <command>pg_restore</command>'s
<command>REFRESH MATERIALIZED VIEW</command> step).
</para>
<para>
<literal>ts_stat($$ SELECT vector FROM apod $$::sql_query)</literal>
<returnvalue>(foo,10,15) ...</returnvalue>
</para></entry>
</row>
</tbody>
</tgroup>
</table>
Expand Down
28 changes: 28 additions & 0 deletions src/backend/catalog/dependency.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,12 @@
#include "funcapi.h"
#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
#include "nodes/nodes.h"
#include "nodes/parsenodes.h"
#include "parser/parsetree.h"
#include "rewrite/rewriteRemove.h"
#include "storage/lmgr.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
Expand Down Expand Up @@ -1943,6 +1946,31 @@ find_expr_references_walker(Node *node,
context->addrs);
break;

/*
* A sql_query constant holds a nodeToString-serialized
* analyzed Query. Recursively extract all objects
* referenced by that inner query so they become
* dependencies of the outer expression (e.g. a matview
* body). This is what lets pg_restore order REFRESH
* MATERIALIZED VIEW after the tables the query references.
*/
case SQL_QUERYOID:
{
char *nodestr;
Query *innerq;

nodestr = TextDatumGetCString(con->constvalue);
innerq = castNode(Query, stringToNode(nodestr));
pfree(nodestr);

context->rtables = lcons(innerq->rtable,
context->rtables);
find_expr_references_walker((Node *) innerq, context);
context->rtables =
list_delete_first(context->rtables);
break;
}

/*
* Dependencies for regrole should be shared among all
* databases, so explicitly inhibit to have dependencies.
Expand Down
1 change: 1 addition & 0 deletions src/backend/utils/adt/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ backend_sources += files(
'ruleutils.c',
'selfuncs.c',
'skipsupport.c',
'sqlquery.c',
'tid.c',
'timestamp.c',
'trigfuncs.c',
Expand Down
Loading