Commit 85c0eac1 authored by Neil Conway's avatar Neil Conway

Add TABLESPACE and ON COMMIT clauses to CREATE TABLE AS. ON COMMIT is

required by the SQL standard, and TABLESPACE is useful functionality.
Patch from Kris Jurka, minor editorialization by Neil Conway.
parent 8c5dfbab
<!-- <!--
$PostgreSQL: pgsql/doc/src/sgml/ref/create_table.sgml,v 1.99 2006/01/16 20:48:49 momjian Exp $ $PostgreSQL: pgsql/doc/src/sgml/ref/create_table.sgml,v 1.100 2006/02/19 00:04:26 neilc Exp $
PostgreSQL documentation PostgreSQL documentation
--> -->
...@@ -580,9 +580,10 @@ and <replaceable class="PARAMETER">table_constraint</replaceable> is: ...@@ -580,9 +580,10 @@ and <replaceable class="PARAMETER">table_constraint</replaceable> is:
<term><literal>DELETE ROWS</literal></term> <term><literal>DELETE ROWS</literal></term>
<listitem> <listitem>
<para> <para>
All rows in the temporary table will be deleted at the All rows in the temporary table will be deleted at the end
end of each transaction block. Essentially, an automatic of each transaction block. Essentially, an automatic <xref
<xref linkend="sql-truncate"> is done at each commit. linkend="sql-truncate" endterm="sql-truncate-title"> is done
at each commit.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
......
<!-- <!--
$PostgreSQL: pgsql/doc/src/sgml/ref/create_table_as.sgml,v 1.31 2005/11/01 21:09:50 tgl Exp $ $PostgreSQL: pgsql/doc/src/sgml/ref/create_table_as.sgml,v 1.32 2006/02/19 00:04:26 neilc Exp $
PostgreSQL documentation PostgreSQL documentation
--> -->
...@@ -21,7 +21,10 @@ PostgreSQL documentation ...@@ -21,7 +21,10 @@ PostgreSQL documentation
<refsynopsisdiv> <refsynopsisdiv>
<synopsis> <synopsis>
CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } ] TABLE <replaceable>table_name</replaceable> CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } ] TABLE <replaceable>table_name</replaceable>
[ (<replaceable>column_name</replaceable> [, ...] ) ] [ [ WITH | WITHOUT ] OIDS ] [ (<replaceable>column_name</replaceable> [, ...] ) ]
[ WITH OIDS | WITHOUT OIDS ]
[ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ]
[ TABLESPACE <replaceable class="PARAMETER">tablespace</replaceable> ]
AS <replaceable>query</replaceable> AS <replaceable>query</replaceable>
</synopsis> </synopsis>
</refsynopsisdiv> </refsynopsisdiv>
...@@ -113,6 +116,65 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } ] TABLE <replaceable>table_name ...@@ -113,6 +116,65 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } ] TABLE <replaceable>table_name
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><literal>ON COMMIT</literal></term>
<listitem>
<para>
The behavior of temporary tables at the end of a transaction
block can be controlled using <literal>ON COMMIT</literal>.
The three options are:
<variablelist>
<varlistentry>
<term><literal>PRESERVE ROWS</literal></term>
<listitem>
<para>
No special action is taken at the ends of transactions.
This is the default behavior.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>DELETE ROWS</literal></term>
<listitem>
<para>
All rows in the temporary table will be deleted at the end
of each transaction block. Essentially, an automatic <xref
linkend="sql-truncate" endterm="sql-truncate-title"> is done
at each commit.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>DROP</literal></term>
<listitem>
<para>
The temporary table will be dropped at the end of the current
transaction block.
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>TABLESPACE <replaceable class="PARAMETER">tablespace</replaceable></literal></term>
<listitem>
<para>
The <replaceable class="PARAMETER">tablespace</replaceable> is the name
of the tablespace in which the new table is to be created.
If not specified,
<xref linkend="guc-default-tablespace"> is used, or the database's
default tablespace if <varname>default_tablespace</> is an empty
string.
</para>
</listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><replaceable>query</replaceable></term> <term><replaceable>query</replaceable></term>
<listitem> <listitem>
...@@ -168,6 +230,20 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } ] TABLE <replaceable>table_name ...@@ -168,6 +230,20 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } ] TABLE <replaceable>table_name
<programlisting> <programlisting>
CREATE TABLE films_recent AS CREATE TABLE films_recent AS
SELECT * FROM films WHERE date_prod &gt;= '2002-01-01'; SELECT * FROM films WHERE date_prod &gt;= '2002-01-01';
</programlisting>
</para>
<para>
Create a new temporary table that will be dropped at commit
<literal>films_recent</literal> with oids consisting of only
recent entries from the table <literal>films</literal> using a
prepared statement:
<programlisting>
PREPARE recentfilms(date) AS
SELECT * FROM films WHERE date_prod &gt; $1;
CREATE TEMP TABLE films_recent WITH OIDS ON COMMIT DROP AS
EXECUTE recentfilms('2002-01-01');
</programlisting> </programlisting>
</para> </para>
</refsect1> </refsect1>
...@@ -188,13 +264,6 @@ CREATE TABLE films_recent AS ...@@ -188,13 +264,6 @@ CREATE TABLE films_recent AS
</para> </para>
</listitem> </listitem>
<listitem>
<para>
The standard defines an <literal>ON COMMIT</literal> clause;
this is not currently implemented by <productname>PostgreSQL</>.
</para>
</listitem>
<listitem> <listitem>
<para> <para>
The standard defines a <literal>WITH [ NO ] DATA</literal> clause; The standard defines a <literal>WITH [ NO ] DATA</literal> clause;
...@@ -219,6 +288,14 @@ CREATE TABLE films_recent AS ...@@ -219,6 +288,14 @@ CREATE TABLE films_recent AS
for details. for details.
</para> </para>
</listitem> </listitem>
<listitem>
<para>
The <productname>PostgreSQL</productname> concept of tablespaces is not
part of the standard. Hence, the clause <literal>TABLESPACE</literal>
is an extension.
</para>
</listitem>
</itemizedlist> </itemizedlist>
</para> </para>
</refsect1> </refsect1>
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* Copyright (c) 2002-2005, PostgreSQL Global Development Group * Copyright (c) 2002-2005, PostgreSQL Global Development Group
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.47 2006/01/18 06:49:26 neilc Exp $ * $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.48 2006/02/19 00:04:26 neilc Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -196,6 +196,10 @@ ExecuteQuery(ExecuteStmt *stmt, ParamListInfo params, ...@@ -196,6 +196,10 @@ ExecuteQuery(ExecuteStmt *stmt, ParamListInfo params,
(errcode(ERRCODE_WRONG_OBJECT_TYPE), (errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("prepared statement is not a SELECT"))); errmsg("prepared statement is not a SELECT")));
query->into = copyObject(stmt->into); query->into = copyObject(stmt->into);
query->intoHasOids = stmt->into_has_oids;
query->intoOnCommit = stmt->into_on_commit;
if (stmt->into_tbl_space)
query->intoTableSpaceName = pstrdup(stmt->into_tbl_space);
MemoryContextSwitchTo(oldContext); MemoryContextSwitchTo(oldContext);
} }
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.265 2006/01/12 21:48:53 tgl Exp $ * $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.266 2006/02/19 00:04:26 neilc Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include "catalog/heap.h" #include "catalog/heap.h"
#include "catalog/namespace.h" #include "catalog/namespace.h"
#include "commands/tablecmds.h" #include "commands/tablecmds.h"
#include "commands/tablespace.h"
#include "commands/trigger.h" #include "commands/trigger.h"
#include "executor/execdebug.h" #include "executor/execdebug.h"
#include "executor/execdefs.h" #include "executor/execdefs.h"
...@@ -730,10 +731,19 @@ InitPlan(QueryDesc *queryDesc, bool explainOnly) ...@@ -730,10 +731,19 @@ InitPlan(QueryDesc *queryDesc, bool explainOnly)
{ {
char *intoName; char *intoName;
Oid namespaceId; Oid namespaceId;
Oid tablespaceId;
AclResult aclresult; AclResult aclresult;
Oid intoRelationId; Oid intoRelationId;
TupleDesc tupdesc; TupleDesc tupdesc;
/*
* Check consistency of arguments
*/
if (parseTree->intoOnCommit != ONCOMMIT_NOOP && !parseTree->into->istemp)
ereport(ERROR,
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
errmsg("ON COMMIT can only be used on temporary tables")));
/* /*
* find namespace to create in, check permissions * find namespace to create in, check permissions
*/ */
...@@ -746,6 +756,37 @@ InitPlan(QueryDesc *queryDesc, bool explainOnly) ...@@ -746,6 +756,37 @@ InitPlan(QueryDesc *queryDesc, bool explainOnly)
aclcheck_error(aclresult, ACL_KIND_NAMESPACE, aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
get_namespace_name(namespaceId)); get_namespace_name(namespaceId));
/*
* Select tablespace to use. If not specified, use default_tablespace
* (which may in turn default to database's default).
*/
if (parseTree->intoTableSpaceName)
{
tablespaceId = get_tablespace_oid(parseTree->intoTableSpaceName);
if (!OidIsValid(tablespaceId))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("tablespace \"%s\" does not exist",
parseTree->intoTableSpaceName)));
} else
{
tablespaceId = GetDefaultTablespace();
/* note InvalidOid is OK in this case */
}
/* Check permissions except when using the database's default */
if (OidIsValid(tablespaceId))
{
AclResult aclresult;
aclresult = pg_tablespace_aclcheck(tablespaceId, GetUserId(),
ACL_CREATE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_TABLESPACE,
get_tablespace_name(tablespaceId));
}
/* /*
* have to copy tupType to get rid of constraints * have to copy tupType to get rid of constraints
*/ */
...@@ -753,7 +794,7 @@ InitPlan(QueryDesc *queryDesc, bool explainOnly) ...@@ -753,7 +794,7 @@ InitPlan(QueryDesc *queryDesc, bool explainOnly)
intoRelationId = heap_create_with_catalog(intoName, intoRelationId = heap_create_with_catalog(intoName,
namespaceId, namespaceId,
InvalidOid, tablespaceId,
InvalidOid, InvalidOid,
GetUserId(), GetUserId(),
tupdesc, tupdesc,
...@@ -761,7 +802,7 @@ InitPlan(QueryDesc *queryDesc, bool explainOnly) ...@@ -761,7 +802,7 @@ InitPlan(QueryDesc *queryDesc, bool explainOnly)
false, false,
true, true,
0, 0,
ONCOMMIT_NOOP, parseTree->intoOnCommit,
allowSystemTableMods); allowSystemTableMods);
FreeTupleDesc(tupdesc); FreeTupleDesc(tupdesc);
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.326 2006/02/04 19:06:46 adunstan Exp $ * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.327 2006/02/19 00:04:26 neilc Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1662,6 +1662,8 @@ _copyQuery(Query *from) ...@@ -1662,6 +1662,8 @@ _copyQuery(Query *from)
COPY_SCALAR_FIELD(resultRelation); COPY_SCALAR_FIELD(resultRelation);
COPY_NODE_FIELD(into); COPY_NODE_FIELD(into);
COPY_SCALAR_FIELD(intoHasOids); COPY_SCALAR_FIELD(intoHasOids);
COPY_SCALAR_FIELD(intoOnCommit);
COPY_STRING_FIELD(intoTableSpaceName);
COPY_SCALAR_FIELD(hasAggs); COPY_SCALAR_FIELD(hasAggs);
COPY_SCALAR_FIELD(hasSubLinks); COPY_SCALAR_FIELD(hasSubLinks);
COPY_NODE_FIELD(rtable); COPY_NODE_FIELD(rtable);
...@@ -1729,6 +1731,8 @@ _copySelectStmt(SelectStmt *from) ...@@ -1729,6 +1731,8 @@ _copySelectStmt(SelectStmt *from)
COPY_NODE_FIELD(into); COPY_NODE_FIELD(into);
COPY_NODE_FIELD(intoColNames); COPY_NODE_FIELD(intoColNames);
COPY_SCALAR_FIELD(intoHasOids); COPY_SCALAR_FIELD(intoHasOids);
COPY_SCALAR_FIELD(intoOnCommit);
COPY_STRING_FIELD(intoTableSpaceName);
COPY_NODE_FIELD(targetList); COPY_NODE_FIELD(targetList);
COPY_NODE_FIELD(fromClause); COPY_NODE_FIELD(fromClause);
COPY_NODE_FIELD(whereClause); COPY_NODE_FIELD(whereClause);
...@@ -2631,6 +2635,10 @@ _copyExecuteStmt(ExecuteStmt *from) ...@@ -2631,6 +2635,10 @@ _copyExecuteStmt(ExecuteStmt *from)
COPY_STRING_FIELD(name); COPY_STRING_FIELD(name);
COPY_NODE_FIELD(into); COPY_NODE_FIELD(into);
COPY_SCALAR_FIELD(into_contains_oids);
COPY_SCALAR_FIELD(into_has_oids);
COPY_SCALAR_FIELD(into_on_commit);
COPY_STRING_FIELD(into_tbl_space);
COPY_NODE_FIELD(params); COPY_NODE_FIELD(params);
return newnode; return newnode;
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.262 2006/02/04 19:06:46 adunstan Exp $ * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.263 2006/02/19 00:04:26 neilc Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -673,6 +673,8 @@ _equalQuery(Query *a, Query *b) ...@@ -673,6 +673,8 @@ _equalQuery(Query *a, Query *b)
COMPARE_SCALAR_FIELD(resultRelation); COMPARE_SCALAR_FIELD(resultRelation);
COMPARE_NODE_FIELD(into); COMPARE_NODE_FIELD(into);
COMPARE_SCALAR_FIELD(intoHasOids); COMPARE_SCALAR_FIELD(intoHasOids);
COMPARE_SCALAR_FIELD(intoOnCommit);
COMPARE_STRING_FIELD(intoTableSpaceName);
COMPARE_SCALAR_FIELD(hasAggs); COMPARE_SCALAR_FIELD(hasAggs);
COMPARE_SCALAR_FIELD(hasSubLinks); COMPARE_SCALAR_FIELD(hasSubLinks);
COMPARE_NODE_FIELD(rtable); COMPARE_NODE_FIELD(rtable);
...@@ -732,6 +734,8 @@ _equalSelectStmt(SelectStmt *a, SelectStmt *b) ...@@ -732,6 +734,8 @@ _equalSelectStmt(SelectStmt *a, SelectStmt *b)
COMPARE_NODE_FIELD(into); COMPARE_NODE_FIELD(into);
COMPARE_NODE_FIELD(intoColNames); COMPARE_NODE_FIELD(intoColNames);
COMPARE_SCALAR_FIELD(intoHasOids); COMPARE_SCALAR_FIELD(intoHasOids);
COMPARE_SCALAR_FIELD(intoOnCommit);
COMPARE_STRING_FIELD(intoTableSpaceName);
COMPARE_NODE_FIELD(targetList); COMPARE_NODE_FIELD(targetList);
COMPARE_NODE_FIELD(fromClause); COMPARE_NODE_FIELD(fromClause);
COMPARE_NODE_FIELD(whereClause); COMPARE_NODE_FIELD(whereClause);
...@@ -1493,6 +1497,10 @@ _equalExecuteStmt(ExecuteStmt *a, ExecuteStmt *b) ...@@ -1493,6 +1497,10 @@ _equalExecuteStmt(ExecuteStmt *a, ExecuteStmt *b)
{ {
COMPARE_STRING_FIELD(name); COMPARE_STRING_FIELD(name);
COMPARE_NODE_FIELD(into); COMPARE_NODE_FIELD(into);
COMPARE_SCALAR_FIELD(into_contains_oids);
COMPARE_SCALAR_FIELD(into_has_oids);
COMPARE_SCALAR_FIELD(into_on_commit);
COMPARE_STRING_FIELD(into_tbl_space);
COMPARE_NODE_FIELD(params); COMPARE_NODE_FIELD(params);
return true; return true;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.267 2006/01/31 21:39:23 tgl Exp $ * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.268 2006/02/19 00:04:26 neilc Exp $
* *
* NOTES * NOTES
* Every node type that can appear in stored rules' parsetrees *must* * Every node type that can appear in stored rules' parsetrees *must*
...@@ -1374,6 +1374,8 @@ _outSelectStmt(StringInfo str, SelectStmt *node) ...@@ -1374,6 +1374,8 @@ _outSelectStmt(StringInfo str, SelectStmt *node)
WRITE_NODE_FIELD(into); WRITE_NODE_FIELD(into);
WRITE_NODE_FIELD(intoColNames); WRITE_NODE_FIELD(intoColNames);
WRITE_ENUM_FIELD(intoHasOids, ContainsOids); WRITE_ENUM_FIELD(intoHasOids, ContainsOids);
WRITE_ENUM_FIELD(intoOnCommit, OnCommitAction);
WRITE_STRING_FIELD(intoTableSpaceName);
WRITE_NODE_FIELD(targetList); WRITE_NODE_FIELD(targetList);
WRITE_NODE_FIELD(fromClause); WRITE_NODE_FIELD(fromClause);
WRITE_NODE_FIELD(whereClause); WRITE_NODE_FIELD(whereClause);
...@@ -1504,6 +1506,9 @@ _outQuery(StringInfo str, Query *node) ...@@ -1504,6 +1506,9 @@ _outQuery(StringInfo str, Query *node)
WRITE_INT_FIELD(resultRelation); WRITE_INT_FIELD(resultRelation);
WRITE_NODE_FIELD(into); WRITE_NODE_FIELD(into);
WRITE_BOOL_FIELD(intoHasOids);
WRITE_ENUM_FIELD(intoOnCommit, OnCommitAction);
WRITE_STRING_FIELD(intoTableSpaceName);
WRITE_BOOL_FIELD(hasAggs); WRITE_BOOL_FIELD(hasAggs);
WRITE_BOOL_FIELD(hasSubLinks); WRITE_BOOL_FIELD(hasSubLinks);
WRITE_NODE_FIELD(rtable); WRITE_NODE_FIELD(rtable);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.183 2005/12/28 01:29:59 tgl Exp $ * $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.184 2006/02/19 00:04:26 neilc Exp $
* *
* NOTES * NOTES
* Path and Plan nodes do not have any readfuncs support, because we * Path and Plan nodes do not have any readfuncs support, because we
...@@ -140,6 +140,9 @@ _readQuery(void) ...@@ -140,6 +140,9 @@ _readQuery(void)
READ_NODE_FIELD(utilityStmt); READ_NODE_FIELD(utilityStmt);
READ_INT_FIELD(resultRelation); READ_INT_FIELD(resultRelation);
READ_NODE_FIELD(into); READ_NODE_FIELD(into);
READ_BOOL_FIELD(intoHasOids);
READ_ENUM_FIELD(intoOnCommit, OnCommitAction);
READ_STRING_FIELD(intoTableSpaceName);
READ_BOOL_FIELD(hasAggs); READ_BOOL_FIELD(hasAggs);
READ_BOOL_FIELD(hasSubLinks); READ_BOOL_FIELD(hasSubLinks);
READ_NODE_FIELD(rtable); READ_NODE_FIELD(rtable);
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.328 2006/01/15 22:18:46 neilc Exp $ * $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.329 2006/02/19 00:04:26 neilc Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1818,6 +1818,8 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt) ...@@ -1818,6 +1818,8 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
applyColumnNames(qry->targetList, stmt->intoColNames); applyColumnNames(qry->targetList, stmt->intoColNames);
qry->intoHasOids = interpretOidsOption(stmt->intoHasOids); qry->intoHasOids = interpretOidsOption(stmt->intoHasOids);
qry->intoOnCommit = stmt->intoOnCommit;
qry->intoTableSpaceName = stmt->intoTableSpaceName;
/* mark column origins */ /* mark column origins */
markTargetListOrigins(pstate, qry->targetList); markTargetListOrigins(pstate, qry->targetList);
...@@ -2662,6 +2664,8 @@ transformExecuteStmt(ParseState *pstate, ExecuteStmt *stmt) ...@@ -2662,6 +2664,8 @@ transformExecuteStmt(ParseState *pstate, ExecuteStmt *stmt)
paramtypes = FetchPreparedStatementParams(stmt->name); paramtypes = FetchPreparedStatementParams(stmt->name);
stmt->into_has_oids = interpretOidsOption(stmt->into_contains_oids);
if (stmt->params || paramtypes) if (stmt->params || paramtypes)
{ {
int nparams = list_length(stmt->params); int nparams = list_length(stmt->params);
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.529 2006/02/12 19:11:01 momjian Exp $ * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.530 2006/02/19 00:04:27 neilc Exp $
* *
* HISTORY * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
...@@ -239,7 +239,7 @@ static void doNegateFloat(Value *v); ...@@ -239,7 +239,7 @@ static void doNegateFloat(Value *v);
%type <boolean> TriggerForType OptTemp %type <boolean> TriggerForType OptTemp
%type <oncommit> OnCommitOption %type <oncommit> OnCommitOption
%type <withoids> OptWithOids WithOidsAs %type <withoids> OptWithOids
%type <node> for_locking_clause opt_for_locking_clause %type <node> for_locking_clause opt_for_locking_clause
%type <list> locked_rels_list %type <list> locked_rels_list
...@@ -2171,7 +2171,8 @@ OptConsTableSpace: USING INDEX TABLESPACE name { $$ = $4; } ...@@ -2171,7 +2171,8 @@ OptConsTableSpace: USING INDEX TABLESPACE name { $$ = $4; }
*/ */
CreateAsStmt: CreateAsStmt:
CREATE OptTemp TABLE qualified_name OptCreateAs WithOidsAs SelectStmt CREATE OptTemp TABLE qualified_name OptCreateAs
OptWithOids OnCommitOption OptTableSpace AS SelectStmt
{ {
/* /*
* When the SelectStmt is a set-operation tree, we must * When the SelectStmt is a set-operation tree, we must
...@@ -2180,7 +2181,7 @@ CreateAsStmt: ...@@ -2180,7 +2181,7 @@ CreateAsStmt:
* to find it. Similarly, the output column names must * to find it. Similarly, the output column names must
* be attached to that Select's target list. * be attached to that Select's target list.
*/ */
SelectStmt *n = findLeftmostSelect((SelectStmt *) $7); SelectStmt *n = findLeftmostSelect((SelectStmt *) $10);
if (n->into != NULL) if (n->into != NULL)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR), (errcode(ERRCODE_SYNTAX_ERROR),
...@@ -2189,22 +2190,12 @@ CreateAsStmt: ...@@ -2189,22 +2190,12 @@ CreateAsStmt:
n->into = $4; n->into = $4;
n->intoColNames = $5; n->intoColNames = $5;
n->intoHasOids = $6; n->intoHasOids = $6;
$$ = $7; n->intoOnCommit = $7;
n->intoTableSpaceName = $8;
$$ = $10;
} }
; ;
/*
* To avoid a shift/reduce conflict in CreateAsStmt, we need to
* include the 'AS' terminal in the parsing of WITH/WITHOUT
* OIDS. Unfortunately that means this production is effectively a
* duplicate of OptWithOids.
*/
WithOidsAs:
WITH OIDS AS { $$ = MUST_HAVE_OIDS; }
| WITHOUT OIDS AS { $$ = MUST_NOT_HAVE_OIDS; }
| AS { $$ = DEFAULT_OIDS; }
;
OptCreateAs: OptCreateAs:
'(' CreateAsList ')' { $$ = $2; } '(' CreateAsList ')' { $$ = $2; }
| /*EMPTY*/ { $$ = NIL; } | /*EMPTY*/ { $$ = NIL; }
...@@ -5066,13 +5057,18 @@ ExecuteStmt: EXECUTE name execute_param_clause ...@@ -5066,13 +5057,18 @@ ExecuteStmt: EXECUTE name execute_param_clause
n->into = NULL; n->into = NULL;
$$ = (Node *) n; $$ = (Node *) n;
} }
| CREATE OptTemp TABLE qualified_name OptCreateAs AS EXECUTE name execute_param_clause | CREATE OptTemp TABLE qualified_name OptCreateAs
OptWithOids OnCommitOption OptTableSpace AS
EXECUTE name execute_param_clause
{ {
ExecuteStmt *n = makeNode(ExecuteStmt); ExecuteStmt *n = makeNode(ExecuteStmt);
n->name = $8; n->name = $11;
n->params = $9; n->params = $12;
$4->istemp = $2; $4->istemp = $2;
n->into = $4; n->into = $4;
n->into_contains_oids = $6;
n->into_on_commit = $7;
n->into_tbl_space = $8;
if ($5) if ($5)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.300 2006/02/04 19:06:46 adunstan Exp $ * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.301 2006/02/19 00:04:27 neilc Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -27,6 +27,16 @@ typedef enum QuerySource ...@@ -27,6 +27,16 @@ typedef enum QuerySource
QSRC_NON_INSTEAD_RULE /* added by non-INSTEAD rule */ QSRC_NON_INSTEAD_RULE /* added by non-INSTEAD rule */
} QuerySource; } QuerySource;
/* What to do at commit time for temporary relations */
typedef enum OnCommitAction
{
ONCOMMIT_NOOP, /* No ON COMMIT clause (do nothing) */
ONCOMMIT_PRESERVE_ROWS, /* ON COMMIT PRESERVE ROWS (do nothing) */
ONCOMMIT_DELETE_ROWS, /* ON COMMIT DELETE ROWS */
ONCOMMIT_DROP /* ON COMMIT DROP */
} OnCommitAction;
/* /*
* Grantable rights are encoded so that we can OR them together in a bitmask. * Grantable rights are encoded so that we can OR them together in a bitmask.
* The present representation of AclItem limits us to 16 distinct rights, * The present representation of AclItem limits us to 16 distinct rights,
...@@ -82,6 +92,8 @@ typedef struct Query ...@@ -82,6 +92,8 @@ typedef struct Query
RangeVar *into; /* target relation for SELECT INTO */ RangeVar *into; /* target relation for SELECT INTO */
bool intoHasOids; /* should target relation contain OIDs? */ bool intoHasOids; /* should target relation contain OIDs? */
OnCommitAction intoOnCommit; /* what do we do at COMMIT? */
char *intoTableSpaceName; /* table space to use, or NULL */
bool hasAggs; /* has aggregates in tlist or havingQual */ bool hasAggs; /* has aggregates in tlist or havingQual */
bool hasSubLinks; /* has subquery SubLink */ bool hasSubLinks; /* has subquery SubLink */
...@@ -674,14 +686,16 @@ typedef struct SelectStmt ...@@ -674,14 +686,16 @@ typedef struct SelectStmt
/* /*
* These fields are used only in "leaf" SelectStmts. * These fields are used only in "leaf" SelectStmts.
* *
* into, intoColNames and intoHasOids are a kluge; they belong somewhere * into, intoColNames, intoHasOids, intoOnCommit, and
* else... * intoTableSpaceName are a kluge; they belong somewhere else...
*/ */
List *distinctClause; /* NULL, list of DISTINCT ON exprs, or List *distinctClause; /* NULL, list of DISTINCT ON exprs, or
* lcons(NIL,NIL) for all (SELECT DISTINCT) */ * lcons(NIL,NIL) for all (SELECT DISTINCT) */
RangeVar *into; /* target table (for select into table) */ RangeVar *into; /* target table (for select into table) */
List *intoColNames; /* column names for into table */ List *intoColNames; /* column names for into table */
ContainsOids intoHasOids; /* should target table have OIDs? */ ContainsOids intoHasOids; /* should target table have OIDs? */
OnCommitAction intoOnCommit; /* what do we do at COMMIT? */
char *intoTableSpaceName; /* table space to use, or NULL */
List *targetList; /* the target list (of ResTarget) */ List *targetList; /* the target list (of ResTarget) */
List *fromClause; /* the FROM clause */ List *fromClause; /* the FROM clause */
Node *whereClause; /* WHERE qualification */ Node *whereClause; /* WHERE qualification */
...@@ -976,15 +990,6 @@ typedef struct CopyStmt ...@@ -976,15 +990,6 @@ typedef struct CopyStmt
* ---------------------- * ----------------------
*/ */
/* What to do at commit time for temporary relations */
typedef enum OnCommitAction
{
ONCOMMIT_NOOP, /* No ON COMMIT clause (do nothing) */
ONCOMMIT_PRESERVE_ROWS, /* ON COMMIT PRESERVE ROWS (do nothing) */
ONCOMMIT_DELETE_ROWS, /* ON COMMIT DELETE ROWS */
ONCOMMIT_DROP /* ON COMMIT DROP */
} OnCommitAction;
typedef struct CreateStmt typedef struct CreateStmt
{ {
NodeTag type; NodeTag type;
...@@ -1865,6 +1870,10 @@ typedef struct ExecuteStmt ...@@ -1865,6 +1870,10 @@ typedef struct ExecuteStmt
NodeTag type; NodeTag type;
char *name; /* The name of the plan to execute */ char *name; /* The name of the plan to execute */
RangeVar *into; /* Optional table to store results in */ RangeVar *into; /* Optional table to store results in */
ContainsOids into_contains_oids; /* Should it have OIDs? */
bool into_has_oids; /* Merge GUC info with user input */
OnCommitAction into_on_commit; /* What do we do at COMMIT? */
char *into_tbl_space; /* Tablespace to use, or NULL */
List *params; /* Values to assign to parameters */ List *params; /* Values to assign to parameters */
} ExecuteStmt; } ExecuteStmt;
......
...@@ -63,6 +63,21 @@ SELECT * FROM temptest; ...@@ -63,6 +63,21 @@ SELECT * FROM temptest;
----- -----
(0 rows) (0 rows)
DROP TABLE temptest;
BEGIN;
CREATE TEMP TABLE temptest(col) ON COMMIT DELETE ROWS AS SELECT 1;
SELECT * FROM temptest;
col
-----
1
(1 row)
COMMIT;
SELECT * FROM temptest;
col
-----
(0 rows)
DROP TABLE temptest; DROP TABLE temptest;
-- Test ON COMMIT DROP -- Test ON COMMIT DROP
BEGIN; BEGIN;
...@@ -76,12 +91,25 @@ SELECT * FROM temptest; ...@@ -76,12 +91,25 @@ SELECT * FROM temptest;
2 2
(2 rows) (2 rows)
COMMIT;
SELECT * FROM temptest;
ERROR: relation "temptest" does not exist
BEGIN;
CREATE TEMP TABLE temptest(col) ON COMMIT DROP AS SELECT 1;
SELECT * FROM temptest;
col
-----
1
(1 row)
COMMIT; COMMIT;
SELECT * FROM temptest; SELECT * FROM temptest;
ERROR: relation "temptest" does not exist ERROR: relation "temptest" does not exist
-- ON COMMIT is only allowed for TEMP -- ON COMMIT is only allowed for TEMP
CREATE TABLE temptest(col int) ON COMMIT DELETE ROWS; CREATE TABLE temptest(col int) ON COMMIT DELETE ROWS;
ERROR: ON COMMIT can only be used on temporary tables ERROR: ON COMMIT can only be used on temporary tables
CREATE TABLE temptest(col) ON COMMIT DELETE ROWS AS SELECT 1;
ERROR: ON COMMIT can only be used on temporary tables
-- Test foreign keys -- Test foreign keys
BEGIN; BEGIN;
CREATE TEMP TABLE temptest1(col int PRIMARY KEY); CREATE TEMP TABLE temptest1(col int PRIMARY KEY);
......
...@@ -76,6 +76,21 @@ SELECT count(oid) FROM create_table_test2; ...@@ -76,6 +76,21 @@ SELECT count(oid) FROM create_table_test2;
-- should fail -- should fail
SELECT count(oid) FROM create_table_test3; SELECT count(oid) FROM create_table_test3;
ERROR: column "oid" does not exist ERROR: column "oid" does not exist
PREPARE table_source(int) AS
SELECT a + b AS c1, a - b AS c2, $1 AS c3 FROM create_table_test;
CREATE TABLE execute_with WITH OIDS AS EXECUTE table_source(1);
CREATE TABLE execute_without WITHOUT OIDS AS EXECUTE table_source(2);
SELECT count(oid) FROM execute_with;
count
-------
2
(1 row)
-- should fail
SELECT count(oid) FROM execute_without;
ERROR: column "oid" does not exist
DROP TABLE create_table_test; DROP TABLE create_table_test;
DROP TABLE create_table_test2; DROP TABLE create_table_test2;
DROP TABLE create_table_test3; DROP TABLE create_table_test3;
DROP TABLE execute_with;
DROP TABLE execute_without;
...@@ -12,6 +12,17 @@ SELECT relname, spcname FROM pg_catalog.pg_tablespace t, pg_catalog.pg_class c ...@@ -12,6 +12,17 @@ SELECT relname, spcname FROM pg_catalog.pg_tablespace t, pg_catalog.pg_class c
INSERT INTO testschema.foo VALUES(1); INSERT INTO testschema.foo VALUES(1);
INSERT INTO testschema.foo VALUES(2); INSERT INTO testschema.foo VALUES(2);
-- tables from dynamic sources
CREATE TABLE testschema.asselect TABLESPACE testspace AS SELECT 1;
SELECT relname, spcname FROM pg_catalog.pg_tablespace t, pg_catalog.pg_class c
where c.reltablespace = t.oid AND c.relname = 'asselect';
PREPARE selectsource(int) AS SELECT $1;
CREATE TABLE testschema.asexecute TABLESPACE testspace
AS EXECUTE selectsource(2);
SELECT relname, spcname FROM pg_catalog.pg_tablespace t, pg_catalog.pg_class c
where c.reltablespace = t.oid AND c.relname = 'asexecute';
-- index -- index
CREATE INDEX foo_idx on testschema.foo(i) TABLESPACE testspace; CREATE INDEX foo_idx on testschema.foo(i) TABLESPACE testspace;
SELECT relname, spcname FROM pg_catalog.pg_tablespace t, pg_catalog.pg_class c SELECT relname, spcname FROM pg_catalog.pg_tablespace t, pg_catalog.pg_class c
......
...@@ -13,6 +13,25 @@ SELECT relname, spcname FROM pg_catalog.pg_tablespace t, pg_catalog.pg_class c ...@@ -13,6 +13,25 @@ SELECT relname, spcname FROM pg_catalog.pg_tablespace t, pg_catalog.pg_class c
INSERT INTO testschema.foo VALUES(1); INSERT INTO testschema.foo VALUES(1);
INSERT INTO testschema.foo VALUES(2); INSERT INTO testschema.foo VALUES(2);
-- tables from dynamic sources
CREATE TABLE testschema.asselect TABLESPACE testspace AS SELECT 1;
SELECT relname, spcname FROM pg_catalog.pg_tablespace t, pg_catalog.pg_class c
where c.reltablespace = t.oid AND c.relname = 'asselect';
relname | spcname
----------+-----------
asselect | testspace
(1 row)
PREPARE selectsource(int) AS SELECT $1;
CREATE TABLE testschema.asexecute TABLESPACE testspace
AS EXECUTE selectsource(2);
SELECT relname, spcname FROM pg_catalog.pg_tablespace t, pg_catalog.pg_class c
where c.reltablespace = t.oid AND c.relname = 'asexecute';
relname | spcname
-----------+-----------
asexecute | testspace
(1 row)
-- index -- index
CREATE INDEX foo_idx on testschema.foo(i) TABLESPACE testspace; CREATE INDEX foo_idx on testschema.foo(i) TABLESPACE testspace;
SELECT relname, spcname FROM pg_catalog.pg_tablespace t, pg_catalog.pg_class c SELECT relname, spcname FROM pg_catalog.pg_tablespace t, pg_catalog.pg_class c
...@@ -32,6 +51,8 @@ ERROR: tablespace "nosuchspace" does not exist ...@@ -32,6 +51,8 @@ ERROR: tablespace "nosuchspace" does not exist
DROP TABLESPACE testspace; DROP TABLESPACE testspace;
ERROR: tablespace "testspace" is not empty ERROR: tablespace "testspace" is not empty
DROP SCHEMA testschema CASCADE; DROP SCHEMA testschema CASCADE;
NOTICE: drop cascades to table testschema.asexecute
NOTICE: drop cascades to table testschema.asselect
NOTICE: drop cascades to table testschema.foo NOTICE: drop cascades to table testschema.foo
-- Should succeed -- Should succeed
DROP TABLESPACE testspace; DROP TABLESPACE testspace;
...@@ -66,6 +66,16 @@ SELECT * FROM temptest; ...@@ -66,6 +66,16 @@ SELECT * FROM temptest;
DROP TABLE temptest; DROP TABLE temptest;
BEGIN;
CREATE TEMP TABLE temptest(col) ON COMMIT DELETE ROWS AS SELECT 1;
SELECT * FROM temptest;
COMMIT;
SELECT * FROM temptest;
DROP TABLE temptest;
-- Test ON COMMIT DROP -- Test ON COMMIT DROP
BEGIN; BEGIN;
...@@ -80,9 +90,18 @@ COMMIT; ...@@ -80,9 +90,18 @@ COMMIT;
SELECT * FROM temptest; SELECT * FROM temptest;
BEGIN;
CREATE TEMP TABLE temptest(col) ON COMMIT DROP AS SELECT 1;
SELECT * FROM temptest;
COMMIT;
SELECT * FROM temptest;
-- ON COMMIT is only allowed for TEMP -- ON COMMIT is only allowed for TEMP
CREATE TABLE temptest(col int) ON COMMIT DELETE ROWS; CREATE TABLE temptest(col int) ON COMMIT DELETE ROWS;
CREATE TABLE temptest(col) ON COMMIT DELETE ROWS AS SELECT 1;
-- Test foreign keys -- Test foreign keys
BEGIN; BEGIN;
......
...@@ -74,6 +74,18 @@ SELECT count(oid) FROM create_table_test2; ...@@ -74,6 +74,18 @@ SELECT count(oid) FROM create_table_test2;
-- should fail -- should fail
SELECT count(oid) FROM create_table_test3; SELECT count(oid) FROM create_table_test3;
PREPARE table_source(int) AS
SELECT a + b AS c1, a - b AS c2, $1 AS c3 FROM create_table_test;
CREATE TABLE execute_with WITH OIDS AS EXECUTE table_source(1);
CREATE TABLE execute_without WITHOUT OIDS AS EXECUTE table_source(2);
SELECT count(oid) FROM execute_with;
-- should fail
SELECT count(oid) FROM execute_without;
DROP TABLE create_table_test; DROP TABLE create_table_test;
DROP TABLE create_table_test2; DROP TABLE create_table_test2;
DROP TABLE create_table_test3; DROP TABLE create_table_test3;
DROP TABLE execute_with;
DROP TABLE execute_without;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment