Skip to content

Commit 18ce3a4

Browse files
committed
Add infrastructure to support EphemeralNamedRelation references.
A QueryEnvironment concept is added, which allows new types of objects to be passed into queries from parsing on through execution. At this point, the only thing implemented is a collection of EphemeralNamedRelation objects -- relations which can be referenced by name in queries, but do not exist in the catalogs. The only type of ENR implemented is NamedTuplestore, but provision is made to add more types fairly easily. An ENR can carry its own TupleDesc or reference a relation in the catalogs by relid. Although these features can be used without SPI, convenience functions are added to SPI so that ENRs can easily be used by code run through SPI. The initial use of all this is going to be transition tables in AFTER triggers, but that will be added to each PL as a separate commit. An incidental effect of this patch is to produce a more informative error message if an attempt is made to modify the contents of a CTE from a referencing DML statement. No tests previously covered that possibility, so one is added. Kevin Grittner and Thomas Munro Reviewed by Heikki Linnakangas, David Fetter, and Thomas Munro with valuable comments and suggestions from many others
1 parent 25dc142 commit 18ce3a4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

78 files changed

+1598
-122
lines changed

contrib/pg_stat_statements/pg_stat_statements.c

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,7 @@ static void pgss_ExecutorFinish(QueryDesc *queryDesc);
299299
static void pgss_ExecutorEnd(QueryDesc *queryDesc);
300300
static void pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
301301
ProcessUtilityContext context, ParamListInfo params,
302+
QueryEnvironment *queryEnv,
302303
DestReceiver *dest, char *completionTag);
303304
static uint32 pgss_hash_fn(const void *key, Size keysize);
304305
static int pgss_match_fn(const void *key1, const void *key2, Size keysize);
@@ -956,7 +957,8 @@ pgss_ExecutorEnd(QueryDesc *queryDesc)
956957
*/
957958
static void
958959
pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
959-
ProcessUtilityContext context, ParamListInfo params,
960+
ProcessUtilityContext context,
961+
ParamListInfo params, QueryEnvironment *queryEnv,
960962
DestReceiver *dest, char *completionTag)
961963
{
962964
Node *parsetree = pstmt->utilityStmt;
@@ -994,11 +996,11 @@ pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
994996
{
995997
if (prev_ProcessUtility)
996998
prev_ProcessUtility(pstmt, queryString,
997-
context, params,
999+
context, params, queryEnv,
9981000
dest, completionTag);
9991001
else
10001002
standard_ProcessUtility(pstmt, queryString,
1001-
context, params,
1003+
context, params, queryEnv,
10021004
dest, completionTag);
10031005
nested_level--;
10041006
}
@@ -1058,11 +1060,11 @@ pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
10581060
{
10591061
if (prev_ProcessUtility)
10601062
prev_ProcessUtility(pstmt, queryString,
1061-
context, params,
1063+
context, params, queryEnv,
10621064
dest, completionTag);
10631065
else
10641066
standard_ProcessUtility(pstmt, queryString,
1065-
context, params,
1067+
context, params, queryEnv,
10661068
dest, completionTag);
10671069
}
10681070
}
@@ -2424,6 +2426,9 @@ JumbleRangeTable(pgssJumbleState *jstate, List *rtable)
24242426
APP_JUMB_STRING(rte->ctename);
24252427
APP_JUMB(rte->ctelevelsup);
24262428
break;
2429+
case RTE_NAMEDTUPLESTORE:
2430+
APP_JUMB_STRING(rte->enrname);
2431+
break;
24272432
default:
24282433
elog(ERROR, "unrecognized RTE kind: %d", (int) rte->rtekind);
24292434
break;

doc/src/sgml/spi.sgml

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2639,6 +2639,210 @@ SPIPlanPtr SPI_saveplan(SPIPlanPtr <parameter>plan</parameter>)
26392639
</refsect1>
26402640
</refentry>
26412641

2642+
<!-- *********************************************** -->
2643+
2644+
<refentry id="spi-spi-register-relation">
2645+
<indexterm><primary>SPI_register_relation</primary></indexterm>
2646+
2647+
<refmeta>
2648+
<refentrytitle>SPI_register_relation</refentrytitle>
2649+
<manvolnum>3</manvolnum>
2650+
</refmeta>
2651+
2652+
<refnamediv>
2653+
<refname>SPI_register_relation</refname>
2654+
<refpurpose>make a ephemeral named relation available by name in SPI queries</refpurpose>
2655+
</refnamediv>
2656+
2657+
<refsynopsisdiv>
2658+
<synopsis>
2659+
int SPI_register_relation(EphemeralNamedRelation <parameter>enr</parameter>)
2660+
</synopsis>
2661+
</refsynopsisdiv>
2662+
2663+
<refsect1>
2664+
<title>Description</title>
2665+
2666+
<para>
2667+
<function>SPI_register_relation</function> makes an ephemeral named
2668+
relation, with associated information, available to queries planned and
2669+
executed through the current SPI connection.
2670+
</para>
2671+
</refsect1>
2672+
2673+
<refsect1>
2674+
<title>Arguments</title>
2675+
2676+
<variablelist>
2677+
<varlistentry>
2678+
<term><literal>EphemeralNamedRelation <parameter>enr</parameter></literal></term>
2679+
<listitem>
2680+
<para>
2681+
the ephemeral named relation registry entry
2682+
</para>
2683+
</listitem>
2684+
</varlistentry>
2685+
</variablelist>
2686+
</refsect1>
2687+
2688+
<refsect1>
2689+
<title>Return Value</title>
2690+
2691+
<para>
2692+
If the execution of the command was successful then the following
2693+
(nonnegative) value will be returned:
2694+
2695+
<variablelist>
2696+
<varlistentry>
2697+
<term><symbol>SPI_OK_REL_REGISTER</symbol></term>
2698+
<listitem>
2699+
<para>
2700+
if the relation has been successfully registered by name
2701+
</para>
2702+
</listitem>
2703+
</varlistentry>
2704+
</variablelist>
2705+
</para>
2706+
2707+
<para>
2708+
On error, one of the following negative values is returned:
2709+
2710+
<variablelist>
2711+
<varlistentry>
2712+
<term><symbol>SPI_ERROR_ARGUMENT</symbol></term>
2713+
<listitem>
2714+
<para>
2715+
if <parameter>enr</parameter> is <symbol>NULL</symbol> or its
2716+
<varname>name</varname> field is <symbol>NULL</symbol>
2717+
</para>
2718+
</listitem>
2719+
</varlistentry>
2720+
2721+
<varlistentry>
2722+
<term><symbol>SPI_ERROR_UNCONNECTED</symbol></term>
2723+
<listitem>
2724+
<para>
2725+
if called from an unconnected procedure
2726+
</para>
2727+
</listitem>
2728+
</varlistentry>
2729+
2730+
<varlistentry>
2731+
<term><symbol>SPI_ERROR_REL_DUPLICATE</symbol></term>
2732+
<listitem>
2733+
<para>
2734+
if the name specified in the <varname>name</varname> field of
2735+
<parameter>enr</parameter> is already registered for this connection
2736+
</para>
2737+
</listitem>
2738+
</varlistentry>
2739+
</variablelist>
2740+
</para>
2741+
</refsect1>
2742+
</refentry>
2743+
2744+
<!-- *********************************************** -->
2745+
2746+
<refentry id="spi-spi-unregister-relation">
2747+
<indexterm><primary>SPI_unregister_relation</primary></indexterm>
2748+
2749+
<refmeta>
2750+
<refentrytitle>SPI_unregister_relation</refentrytitle>
2751+
<manvolnum>3</manvolnum>
2752+
</refmeta>
2753+
2754+
<refnamediv>
2755+
<refname>SPI_unregister_relation</refname>
2756+
<refpurpose>remove an ephemeral named relation from the registry</refpurpose>
2757+
</refnamediv>
2758+
2759+
<refsynopsisdiv>
2760+
<synopsis>
2761+
int SPI_unregister_relation(const char * <parameter>name</parameter>)
2762+
</synopsis>
2763+
</refsynopsisdiv>
2764+
2765+
<refsect1>
2766+
<title>Description</title>
2767+
2768+
<para>
2769+
<function>SPI_unregister_relation</function> removes an ephemeral named
2770+
relation from the registry for the current connection.
2771+
</para>
2772+
</refsect1>
2773+
2774+
<refsect1>
2775+
<title>Arguments</title>
2776+
2777+
<variablelist>
2778+
<varlistentry>
2779+
<term><literal>const char * <parameter>name</parameter></literal></term>
2780+
<listitem>
2781+
<para>
2782+
the relation registry entry name
2783+
</para>
2784+
</listitem>
2785+
</varlistentry>
2786+
</variablelist>
2787+
</refsect1>
2788+
2789+
<refsect1>
2790+
<title>Return Value</title>
2791+
2792+
<para>
2793+
If the execution of the command was successful then the following
2794+
(nonnegative) value will be returned:
2795+
2796+
<variablelist>
2797+
<varlistentry>
2798+
<term><symbol>SPI_OK_REL_UNREGISTER</symbol></term>
2799+
<listitem>
2800+
<para>
2801+
if the tuplestore has been successfully removed from the registry
2802+
</para>
2803+
</listitem>
2804+
</varlistentry>
2805+
</variablelist>
2806+
</para>
2807+
2808+
<para>
2809+
On error, one of the following negative values is returned:
2810+
2811+
<variablelist>
2812+
<varlistentry>
2813+
<term><symbol>SPI_ERROR_ARGUMENT</symbol></term>
2814+
<listitem>
2815+
<para>
2816+
if <parameter>name</parameter> is <symbol>NULL</symbol>
2817+
</para>
2818+
</listitem>
2819+
</varlistentry>
2820+
2821+
<varlistentry>
2822+
<term><symbol>SPI_ERROR_UNCONNECTED</symbol></term>
2823+
<listitem>
2824+
<para>
2825+
if called from an unconnected procedure
2826+
</para>
2827+
</listitem>
2828+
</varlistentry>
2829+
2830+
<varlistentry>
2831+
<term><symbol>SPI_ERROR_REL_NOT_FOUND</symbol></term>
2832+
<listitem>
2833+
<para>
2834+
if <parameter>name</parameter> is not found in the registry for the
2835+
current connection
2836+
</para>
2837+
</listitem>
2838+
</varlistentry>
2839+
</variablelist>
2840+
</para>
2841+
</refsect1>
2842+
</refentry>
2843+
2844+
<!-- *********************************************** -->
2845+
26422846
</sect1>
26432847

26442848
<sect1 id="spi-interface-support">

src/backend/catalog/pg_proc.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -934,7 +934,8 @@ fmgr_sql_validator(PG_FUNCTION_ARGS)
934934
querytree_sublist = pg_analyze_and_rewrite_params(parsetree,
935935
prosrc,
936936
(ParserSetupHook) sql_fn_parser_setup,
937-
pinfo);
937+
pinfo,
938+
NULL);
938939
querytree_list = list_concat(querytree_list,
939940
querytree_sublist);
940941
}

src/backend/commands/copy.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1471,7 +1471,8 @@ BeginCopy(ParseState *pstate,
14711471
* DECLARE CURSOR and PREPARE.) XXX FIXME someday.
14721472
*/
14731473
rewritten = pg_analyze_and_rewrite(copyObject(raw_query),
1474-
pstate->p_sourcetext, NULL, 0);
1474+
pstate->p_sourcetext, NULL, 0,
1475+
NULL);
14751476

14761477
/* check that we got back something we can work with */
14771478
if (rewritten == NIL)
@@ -1574,7 +1575,7 @@ BeginCopy(ParseState *pstate,
15741575
cstate->queryDesc = CreateQueryDesc(plan, pstate->p_sourcetext,
15751576
GetActiveSnapshot(),
15761577
InvalidSnapshot,
1577-
dest, NULL, 0);
1578+
dest, NULL, NULL, 0);
15781579

15791580
/*
15801581
* Call ExecutorStart to prepare the plan for execution.

src/backend/commands/createas.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,8 @@ create_ctas_nodata(List *tlist, IntoClause *into)
222222
*/
223223
ObjectAddress
224224
ExecCreateTableAs(CreateTableAsStmt *stmt, const char *queryString,
225-
ParamListInfo params, char *completionTag)
225+
ParamListInfo params, QueryEnvironment *queryEnv,
226+
char *completionTag)
226227
{
227228
Query *query = castNode(Query, stmt->query);
228229
IntoClause *into = stmt->into;
@@ -341,7 +342,7 @@ ExecCreateTableAs(CreateTableAsStmt *stmt, const char *queryString,
341342
/* Create a QueryDesc, redirecting output to our tuple receiver */
342343
queryDesc = CreateQueryDesc(plan, queryString,
343344
GetActiveSnapshot(), InvalidSnapshot,
344-
dest, params, 0);
345+
dest, params, queryEnv, 0);
345346

346347
/* call ExecutorStart to prepare the plan for execution */
347348
ExecutorStart(queryDesc, GetIntoRelEFlags(into));

0 commit comments

Comments
 (0)