mv_v1.1.patch
text/x-patch
Filename: mv_v1.1.patch
Type: text/x-patch
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: context
Series: patch v1
| File | + | − |
|---|---|---|
| doc/src/sgml/catalogs.sgml | 2 | 2 |
| doc/src/sgml/ref/alter_view.sgml | 13 | 3 |
| doc/src/sgml/ref/comment.sgml | 2 | 1 |
| doc/src/sgml/ref/create_view.sgml | 13 | 1 |
| src/backend/access/common/reloptions.c | 2 | 0 |
| src/backend/access/heap/heapam.c | 3 | 2 |
| src/backend/catalog/dependency.c | 4 | 0 |
| src/backend/catalog/heap.c | 4 | 1 |
| src/backend/catalog/system_views.sql | 1 | 1 |
| src/backend/commands/alter.c | 3 | 0 |
| src/backend/commands/comment.c | 9 | 0 |
| src/backend/commands/copy.c | 2 | 2 |
| src/backend/commands/indexcmds.c | 1 | 0 |
| src/backend/commands/tablecmds.c | 44 | 2 |
| src/backend/commands/view.c | 15 | 7 |
| src/backend/executor/execMain.c | 107 | 57 |
| src/backend/nodes/copyfuncs.c | 2 | 0 |
| src/backend/nodes/equalfuncs.c | 2 | 0 |
| src/backend/nodes/outfuncs.c | 1 | 0 |
| src/backend/parser/analyze.c | 143 | 0 |
| src/backend/parser/gram.y | 57 | 13 |
| src/backend/rewrite/rewriteDefine.c | 7 | 6 |
| src/backend/rewrite/rewriteHandler.c | 45 | 1 |
| src/backend/rewrite/rewriteSupport.c | 3 | 1 |
| src/backend/tcop/utility.c | 18 | 1 |
| src/backend/utils/adt/dbsize.c | 2 | 0 |
| src/backend/utils/adt/ruleutils.c | 4 | 2 |
| src/bin/pg_dump/pg_backup_archiver.c | 3 | 1 |
| src/bin/pg_dump/pg_dump.c | 64 | 4 |
| src/bin/pg_dump/pg_dump_sort.c | 36 | 1 |
| src/bin/psql/command.c | 2 | 1 |
| src/bin/psql/describe.c | 30 | 11 |
| src/bin/psql/help.c | 2 | 1 |
| src/include/catalog/pg_class.h | 1 | 0 |
| src/include/nodes/nodes.h | 1 | 0 |
| src/include/nodes/parsenodes.h | 4 | 1 |
| src/include/nodes/primnodes.h | 1 | 0 |
| src/include/parser/kwlist.h | 2 | 0 |
*** ./doc/src/sgml/catalogs.sgml.orig 2010-07-06 10:43:16.000000000 +0200
--- ./doc/src/sgml/catalogs.sgml 2010-07-08 15:22:14.000000000 +0200
***************
*** 1559,1565 ****
<entry></entry>
<entry>
<literal>r</> = ordinary table, <literal>i</> = index,
! <literal>S</> = sequence, <literal>v</> = view, <literal>c</> =
composite type, <literal>t</> = TOAST
table
</entry>
--- 1559,1565 ----
<entry></entry>
<entry>
<literal>r</> = ordinary table, <literal>i</> = index,
! <literal>S</> = sequence, <literal>v</> = view, <literal>m</> = materialized view, <literal>c</> =
composite type, <literal>t</> = TOAST
table
</entry>
***************
*** 4086,4092 ****
<entry>
Event type that the rule is for: 1 = <command>SELECT</>, 2 =
<command>UPDATE</>, 3 = <command>INSERT</>, 4 =
! <command>DELETE</>
</entry>
</row>
--- 4086,4092 ----
<entry>
Event type that the rule is for: 1 = <command>SELECT</>, 2 =
<command>UPDATE</>, 3 = <command>INSERT</>, 4 =
! <command>DELETE</>, 6 = <command>REFRESH</>
</entry>
</row>
*** ./doc/src/sgml/ref/alter_view.sgml.orig 2010-07-06 10:43:16.000000000 +0200
--- ./doc/src/sgml/ref/alter_view.sgml 2010-07-08 15:22:14.000000000 +0200
***************
*** 23,31 ****
<synopsis>
ALTER VIEW <replaceable class="parameter">name</replaceable> ALTER [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> SET DEFAULT <replaceable class="PARAMETER">expression</replaceable>
ALTER VIEW <replaceable class="parameter">name</replaceable> ALTER [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> DROP DEFAULT
! ALTER VIEW <replaceable class="parameter">name</replaceable> OWNER TO <replaceable class="PARAMETER">new_owner</replaceable>
! ALTER VIEW <replaceable class="parameter">name</replaceable> RENAME TO <replaceable class="parameter">new_name</replaceable>
! ALTER VIEW <replaceable class="parameter">name</replaceable> SET SCHEMA <replaceable class="parameter">new_schema</replaceable>
</synopsis>
</refsynopsisdiv>
--- 23,32 ----
<synopsis>
ALTER VIEW <replaceable class="parameter">name</replaceable> ALTER [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> SET DEFAULT <replaceable class="PARAMETER">expression</replaceable>
ALTER VIEW <replaceable class="parameter">name</replaceable> ALTER [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> DROP DEFAULT
! ALTER [ MATERIALIZED ] VIEW <replaceable class="parameter">name</replaceable> OWNER TO <replaceable class="PARAMETER">new_owner</replaceable>
! ALTER [ MATERIALIZED ] VIEW <replaceable class="parameter">name</replaceable> RENAME TO <replaceable class="parameter">new_name</replaceable>
! ALTER [ MATERIALIZED ] VIEW <replaceable class="parameter">name</replaceable> SET SCHEMA <replaceable class="parameter">new_schema</replaceable>
! ALTER MATERIALIZED VIEW <replaceable class="parameter">name</replaceable> REFRESH
</synopsis>
</refsynopsisdiv>
***************
*** 102,107 ****
--- 103,117 ----
</para>
</listitem>
</varlistentry>
+
+ <varlistentry>
+ <term><literal>REFRESH</literal></term>
+ <listitem>
+ <para>
+ Refresh data in the materialized view by rebuilding definition.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect1>
*** ./doc/src/sgml/ref/comment.sgml.orig 2010-07-06 10:43:16.000000000 +0200
--- ./doc/src/sgml/ref/comment.sgml 2010-07-08 15:22:14.000000000 +0200
***************
*** 49,55 ****
TEXT SEARCH TEMPLATE <replaceable class="PARAMETER">object_name</replaceable> |
TRIGGER <replaceable class="PARAMETER">trigger_name</replaceable> ON <replaceable class="PARAMETER">table_name</replaceable> |
TYPE <replaceable class="PARAMETER">object_name</replaceable> |
! VIEW <replaceable class="PARAMETER">object_name</replaceable>
} IS '<replaceable class="PARAMETER">text</replaceable>'
</synopsis>
</refsynopsisdiv>
--- 49,55 ----
TEXT SEARCH TEMPLATE <replaceable class="PARAMETER">object_name</replaceable> |
TRIGGER <replaceable class="PARAMETER">trigger_name</replaceable> ON <replaceable class="PARAMETER">table_name</replaceable> |
TYPE <replaceable class="PARAMETER">object_name</replaceable> |
! [ MATERIALIZED ] VIEW <replaceable class="PARAMETER">object_name</replaceable>
} IS '<replaceable class="PARAMETER">text</replaceable>'
</synopsis>
</refsynopsisdiv>
***************
*** 268,273 ****
--- 268,274 ----
COMMENT ON TRIGGER my_trigger ON my_table IS 'Used for RI';
COMMENT ON TYPE complex IS 'Complex number data type';
COMMENT ON VIEW my_view IS 'View of departmental costs';
+ COMMENT ON MATERIALIZED VIEW salaries_mv IS 'Materialized View of salaries according to the profession';
</programlisting>
</para>
</refsect1>
*** ./doc/src/sgml/ref/create_view.sgml.orig 2010-07-06 20:32:12.000000000 +0200
--- ./doc/src/sgml/ref/create_view.sgml 2010-07-08 15:22:14.000000000 +0200
***************
*** 21,27 ****
<refsynopsisdiv>
<synopsis>
! CREATE [ OR REPLACE ] [ TEMP | TEMPORARY ] VIEW <replaceable class="PARAMETER">name</replaceable> [ ( <replaceable class="PARAMETER">column_name</replaceable> [, ...] ) ]
AS <replaceable class="PARAMETER">query</replaceable>
</synopsis>
</refsynopsisdiv>
--- 21,27 ----
<refsynopsisdiv>
<synopsis>
! CREATE [ OR REPLACE ] [ TEMP | TEMPORARY ] [ MATERIALIZED ] VIEW <replaceable class="PARAMETER">name</replaceable> [ ( <replaceable class="PARAMETER">column_name</replaceable> [, ...] ) ]
AS <replaceable class="PARAMETER">query</replaceable>
</synopsis>
</refsynopsisdiv>
***************
*** 80,85 ****
--- 80,97 ----
</varlistentry>
<varlistentry>
+ <term><literal>MATERIALIZED</></term>
+ <listitem>
+ <para>
+ If specified, view is created materialized. The result of
+ definition is stored in physical table. Materialized view
+ is created empty, so to fill materialized view with data
+ run separate refresh command <xref linkend="sql-alterview">.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><replaceable class="parameter">name</replaceable></term>
<listitem>
<para>
*** ./src/backend/access/common/reloptions.c.orig 2010-07-08 20:32:53.000000000 +0200
--- ./src/backend/access/common/reloptions.c 2010-07-08 15:22:14.000000000 +0200
***************
*** 775,780 ****
--- 775,781 ----
switch (classForm->relkind)
{
case RELKIND_RELATION:
+ case RELKIND_MATVIEW:
case RELKIND_TOASTVALUE:
case RELKIND_UNCATALOGED:
options = heap_reloptions(classForm->relkind, datum, false);
***************
*** 1172,1177 ****
--- 1173,1179 ----
}
return (bytea *) rdopts;
case RELKIND_RELATION:
+ case RELKIND_MATVIEW:
return default_reloptions(reloptions, validate, RELOPT_KIND_HEAP);
default:
/* sequences, composite types and views are not supported */
*** ./src/backend/access/heap/heapam.c.orig 2010-07-08 20:32:53.000000000 +0200
--- ./src/backend/access/heap/heapam.c 2010-07-08 20:42:56.000000000 +0200
***************
*** 1877,1883 ****
* Note: below this point, heaptup is the data we actually intend to store
* into the relation; tup is the caller's original untoasted data.
*/
! if (relation->rd_rel->relkind != RELKIND_RELATION)
{
/* toast table entries should never be recursively toasted */
Assert(!HeapTupleHasExternal(tup));
--- 1877,1884 ----
* Note: below this point, heaptup is the data we actually intend to store
* into the relation; tup is the caller's original untoasted data.
*/
! if (relation->rd_rel->relkind != RELKIND_RELATION &&
! relation->rd_rel->relkind != RELKIND_MATVIEW)
{
/* toast table entries should never be recursively toasted */
Assert(!HeapTupleHasExternal(tup));
***************
*** 4126,4132 ****
/*
* We're about to remove tuples. In Hot Standby mode, ensure that there's
* no queries running for which the removed tuples are still visible.
! *
* Not all HEAP2_CLEAN records remove tuples with xids, so we only want to
* conflict on the records that cause MVCC failures for user queries. If
* latestRemovedXid is invalid, skip conflict processing.
--- 4127,4133 ----
/*
* We're about to remove tuples. In Hot Standby mode, ensure that there's
* no queries running for which the removed tuples are still visible.
! *
* Not all HEAP2_CLEAN records remove tuples with xids, so we only want to
* conflict on the records that cause MVCC failures for user queries. If
* latestRemovedXid is invalid, skip conflict processing.
*** ./src/backend/catalog/dependency.c.orig 2010-07-08 20:32:53.000000000 +0200
--- ./src/backend/catalog/dependency.c 2010-07-08 15:22:14.000000000 +0200
***************
*** 2731,2736 ****
--- 2731,2740 ----
appendStringInfo(buffer, _("view %s"),
relname);
break;
+ case RELKIND_MATVIEW:
+ appendStringInfo(buffer, _("materialized view %s"),
+ relname);
+ break;
case RELKIND_COMPOSITE_TYPE:
appendStringInfo(buffer, _("composite type %s"),
relname);
*** ./src/backend/catalog/heap.c.orig 2010-07-08 20:32:53.000000000 +0200
--- ./src/backend/catalog/heap.c 2010-07-08 15:22:14.000000000 +0200
***************
*** 758,763 ****
--- 758,764 ----
case RELKIND_RELATION:
case RELKIND_INDEX:
case RELKIND_TOASTVALUE:
+ case RELKIND_MATVIEW:
/* The relation is real, but as yet empty */
new_rel_reltup->relpages = 0;
new_rel_reltup->reltuples = 0;
***************
*** 776,782 ****
/* Initialize relfrozenxid */
if (relkind == RELKIND_RELATION ||
! relkind == RELKIND_TOASTVALUE)
{
/*
* Initialize to the minimum XID that could put tuples in the table.
--- 777,784 ----
/* Initialize relfrozenxid */
if (relkind == RELKIND_RELATION ||
! relkind == RELKIND_TOASTVALUE ||
! relkind == RELKIND_MATVIEW)
{
/*
* Initialize to the minimum XID that could put tuples in the table.
***************
*** 1027,1032 ****
--- 1029,1035 ----
*/
if (IsUnderPostmaster && (relkind == RELKIND_RELATION ||
relkind == RELKIND_VIEW ||
+ relkind == RELKIND_MATVIEW ||
relkind == RELKIND_COMPOSITE_TYPE))
new_array_oid = AssignTypeArrayOid();
*** ./src/backend/catalog/system_views.sql.orig 2010-07-08 20:32:53.000000000 +0200
--- ./src/backend/catalog/system_views.sql 2010-07-08 15:22:14.000000000 +0200
***************
*** 76,82 ****
pg_get_userbyid(C.relowner) AS viewowner,
pg_get_viewdef(C.oid) AS definition
FROM pg_class C LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace)
! WHERE C.relkind = 'v';
CREATE VIEW pg_tables AS
SELECT
--- 76,82 ----
pg_get_userbyid(C.relowner) AS viewowner,
pg_get_viewdef(C.oid) AS definition
FROM pg_class C LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace)
! WHERE C.relkind = 'v' OR C.relkind = 'm';
CREATE VIEW pg_tables AS
SELECT
*** ./src/backend/commands/alter.c.orig 2010-07-08 20:32:53.000000000 +0200
--- ./src/backend/commands/alter.c 2010-07-08 15:22:14.000000000 +0200
***************
*** 87,92 ****
--- 87,93 ----
case OBJECT_TABLE:
case OBJECT_SEQUENCE:
case OBJECT_VIEW:
+ case OBJECT_MATVIEW:
case OBJECT_INDEX:
case OBJECT_COLUMN:
case OBJECT_TRIGGER:
***************
*** 102,107 ****
--- 103,109 ----
case OBJECT_TABLE:
case OBJECT_SEQUENCE:
case OBJECT_VIEW:
+ case OBJECT_MATVIEW:
case OBJECT_INDEX:
{
/*
***************
*** 188,193 ****
--- 190,196 ----
case OBJECT_SEQUENCE:
case OBJECT_TABLE:
case OBJECT_VIEW:
+ case OBJECT_MATVIEW:
CheckRelationOwnership(stmt->relation, true);
AlterTableNamespace(stmt->relation, stmt->newschema,
stmt->objectType);
*** ./src/backend/commands/comment.c.orig 2010-07-08 20:32:53.000000000 +0200
--- ./src/backend/commands/comment.c 2010-07-08 15:22:14.000000000 +0200
***************
*** 107,112 ****
--- 107,113 ----
case OBJECT_SEQUENCE:
case OBJECT_TABLE:
case OBJECT_VIEW:
+ case OBJECT_MATVIEW:
CommentRelation(stmt->objtype, stmt->objname, stmt->comment);
break;
case OBJECT_COLUMN:
***************
*** 580,585 ****
--- 581,593 ----
errmsg("\"%s\" is not a view",
RelationGetRelationName(relation))));
break;
+ case OBJECT_MATVIEW:
+ if (relation->rd_rel->relkind != RELKIND_MATVIEW)
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("\"%s\" is not a materialized view",
+ RelationGetRelationName(relation))));
+ break;
}
/* Create the comment using the relation's oid */
***************
*** 636,641 ****
--- 644,650 ----
*/
if (relation->rd_rel->relkind != RELKIND_RELATION &&
relation->rd_rel->relkind != RELKIND_VIEW &&
+ relation->rd_rel->relkind != RELKIND_MATVIEW &&
relation->rd_rel->relkind != RELKIND_COMPOSITE_TYPE)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
*** ./src/backend/commands/copy.c.orig 2010-07-08 20:32:53.000000000 +0200
--- ./src/backend/commands/copy.c 2010-07-08 15:22:14.000000000 +0200
***************
*** 1227,1233 ****
if (cstate->rel)
{
! if (cstate->rel->rd_rel->relkind != RELKIND_RELATION)
{
if (cstate->rel->rd_rel->relkind == RELKIND_VIEW)
ereport(ERROR,
--- 1227,1233 ----
if (cstate->rel)
{
! if (cstate->rel->rd_rel->relkind != RELKIND_RELATION && cstate->rel->rd_rel->relkind != RELKIND_MATVIEW)
{
if (cstate->rel->rd_rel->relkind == RELKIND_VIEW)
ereport(ERROR,
***************
*** 1701,1707 ****
Assert(cstate->rel);
! if (cstate->rel->rd_rel->relkind != RELKIND_RELATION)
{
if (cstate->rel->rd_rel->relkind == RELKIND_VIEW)
ereport(ERROR,
--- 1701,1707 ----
Assert(cstate->rel);
! if (cstate->rel->rd_rel->relkind != RELKIND_RELATION && cstate->rel->rd_rel->relkind != RELKIND_MATVIEW)
{
if (cstate->rel->rd_rel->relkind == RELKIND_VIEW)
ereport(ERROR,
*** ./src/backend/commands/indexcmds.c.orig 2010-07-08 20:32:53.000000000 +0200
--- ./src/backend/commands/indexcmds.c 2010-07-08 20:48:53.000000000 +0200
***************
*** 181,186 ****
--- 181,187 ----
/* Note: during bootstrap may see uncataloged relation */
if (rel->rd_rel->relkind != RELKIND_RELATION &&
+ rel->rd_rel->relkind != RELKIND_MATVIEW &&
rel->rd_rel->relkind != RELKIND_UNCATALOGED)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
*** ./src/backend/commands/tablecmds.c.orig 2010-07-08 20:32:53.000000000 +0200
--- ./src/backend/commands/tablecmds.c 2010-07-08 20:52:26.000000000 +0200
***************
*** 205,210 ****
--- 205,216 ----
gettext_noop("view \"%s\" does not exist, skipping"),
gettext_noop("\"%s\" is not a view"),
gettext_noop("Use DROP VIEW to remove a view.")},
+ {RELKIND_MATVIEW,
+ ERRCODE_UNDEFINED_TABLE,
+ gettext_noop("materialized view \"%s\" does not exist"),
+ gettext_noop("materialized view \"%s\" does not exist, skipping"),
+ gettext_noop("\"%s\" is not a materialized view"),
+ gettext_noop("Use DROP MATERIALIZED VIEW to remove a materialized view.")},
{RELKIND_INDEX,
ERRCODE_UNDEFINED_OBJECT,
gettext_noop("index \"%s\" does not exist"),
***************
*** 678,683 ****
--- 684,693 ----
relkind = RELKIND_VIEW;
break;
+ case OBJECT_MATVIEW:
+ relkind = RELKIND_MATVIEW;
+ break;
+
default:
elog(ERROR, "unrecognized drop object type: %d",
(int) drop->removeType);
***************
*** 1970,1977 ****
relkind != RELKIND_INDEX)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
! errmsg("\"%s\" is not a table, view, composite type or index",
! RelationGetRelationName(targetrelation))));
/*
* permissions checking. only the owner of a class can change its schema.
--- 1980,1987 ----
relkind != RELKIND_INDEX)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
! errmsg("\"%s\" is not a table, view, composite type or index",
! RelationGetRelationName(targetrelation))));
/*
* permissions checking. only the owner of a class can change its schema.
***************
*** 2358,2363 ****
--- 2368,2381 ----
RelationGetRelationName(rel))));
break;
+ case OBJECT_MATVIEW:
+ if (rel->rd_rel->relkind != RELKIND_MATVIEW)
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("\"%s\" is not a materialized view",
+ RelationGetRelationName(rel))));
+ break;
+
default:
elog(ERROR, "unrecognized object type: %d", (int) stmt->relkind);
}
***************
*** 3321,3326 ****
--- 3339,3350 ----
{
if (rel->rd_rel->relkind != RELKIND_RELATION)
{
+ if (rel->rd_rel->relkind == RELKIND_MATVIEW)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("Materialized view \"%s\" cannot be altered",
+ RelationGetRelationName(rel))));
+
if (allowView)
{
if (rel->rd_rel->relkind != RELKIND_VIEW)
***************
*** 3359,3364 ****
--- 3383,3389 ----
ATSimplePermissionsRelationOrIndex(Relation rel)
{
if (rel->rd_rel->relkind != RELKIND_RELATION &&
+ rel->rd_rel->relkind != RELKIND_MATVIEW &&
rel->rd_rel->relkind != RELKIND_INDEX)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
***************
*** 4111,4116 ****
--- 4136,4142 ----
* allowSystemTableMods to be turned on.
*/
if (rel->rd_rel->relkind != RELKIND_RELATION &&
+ rel->rd_rel->relkind != RELKIND_MATVIEW &&
rel->rd_rel->relkind != RELKIND_INDEX)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
***************
*** 6439,6444 ****
--- 6465,6471 ----
{
case RELKIND_RELATION:
case RELKIND_VIEW:
+ case RELKIND_MATVIEW:
/* ok to change owner */
break;
case RELKIND_INDEX:
***************
*** 7741,7746 ****
--- 7768,7781 ----
RelationGetRelationName(rel))));
break;
+ case OBJECT_MATVIEW:
+ if (rel->rd_rel->relkind != RELKIND_MATVIEW)
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("\"%s\" is not a materialized view",
+ RelationGetRelationName(rel))));
+ break;
+
default:
elog(ERROR, "unrecognized object type: %d", (int) stmttype);
}
***************
*** 7750,7755 ****
--- 7785,7791 ----
{
case RELKIND_RELATION:
case RELKIND_VIEW:
+ case RELKIND_MATVIEW:
/* ok to change schema */
break;
case RELKIND_SEQUENCE:
***************
*** 7822,7827 ****
--- 7858,7869 ----
AlterConstraintNamespaces(relid, oldNspOid, nspOid, false);
}
+ /* Fix other dependent stuff with materialized view */
+ if (rel->rd_rel->relkind == RELKIND_MATVIEW)
+ {
+ AlterIndexNamespaces(classRel, rel, oldNspOid, nspOid);
+ }
+
heap_close(classRel, RowExclusiveLock);
/* close rel, but keep lock until commit */
*** ./src/backend/commands/view.c.orig 2010-07-08 20:32:53.000000000 +0200
--- ./src/backend/commands/view.c 2010-07-08 15:22:15.000000000 +0200
***************
*** 97,103 ****
*---------------------------------------------------------------------
*/
static Oid
! DefineVirtualRelation(const RangeVar *relation, List *tlist, bool replace)
{
Oid viewOid,
namespaceId;
--- 97,103 ----
*---------------------------------------------------------------------
*/
static Oid
! DefineVirtualRelation(const RangeVar *relation, List *tlist, bool replace, char relkind)
{
Oid viewOid,
namespaceId;
***************
*** 155,160 ****
--- 155,168 ----
rel = relation_open(viewOid, AccessExclusiveLock);
/*
+ * Check if do not try to replace materialized view.
+ */
+ if (rel->rd_rel->relkind == RELKIND_MATVIEW)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("CREATE OR REPLACE on materialized view is not supported!"),
+ errhint("Use CREATE MATERIALIZED VIEW ...")));
+ /*
* Make sure it *is* a view, and do permissions checks.
*/
if (rel->rd_rel->relkind != RELKIND_VIEW)
***************
*** 239,245 ****
* existing view, so we don't need more code to complain if "replace"
* is false).
*/
! return DefineRelation(createStmt, RELKIND_VIEW);
}
}
--- 247,253 ----
* existing view, so we don't need more code to complain if "replace"
* is false).
*/
! return DefineRelation(createStmt, relkind);
}
}
***************
*** 299,305 ****
}
static void
! DefineViewRules(Oid viewOid, Query *viewParse, bool replace)
{
/*
* Set up the ON SELECT rule. Since the query has already been through
--- 307,313 ----
}
static void
! DefineViewRules(Oid viewOid, Query *viewParse, bool is_instead, bool replace, bool is_materialized)
{
/*
* Set up the ON SELECT rule. Since the query has already been through
***************
*** 308,315 ****
DefineQueryRewrite(pstrdup(ViewSelectRuleName),
viewOid,
NULL,
! CMD_SELECT,
! true,
replace,
list_make1(viewParse));
--- 316,323 ----
DefineQueryRewrite(pstrdup(ViewSelectRuleName),
viewOid,
NULL,
! is_materialized ? CMD_REFRESH : CMD_SELECT,
! is_materialized ? false : is_instead,
replace,
list_make1(viewParse));
***************
*** 465,471 ****
* aborted.
*/
viewOid = DefineVirtualRelation(view, viewParse->targetList,
! stmt->replace);
/*
* The relation we have just created is not visible to any other commands
--- 473,479 ----
* aborted.
*/
viewOid = DefineVirtualRelation(view, viewParse->targetList,
! stmt->replace, (stmt->ismaterialized ? RELKIND_MATVIEW : RELKIND_VIEW));
/*
* The relation we have just created is not visible to any other commands
***************
*** 483,487 ****
/*
* Now create the rules associated with the view.
*/
! DefineViewRules(viewOid, viewParse, stmt->replace);
}
--- 491,495 ----
/*
* Now create the rules associated with the view.
*/
! DefineViewRules(viewOid, viewParse, true, stmt->replace, stmt->ismaterialized);
}
*** ./src/backend/executor/execMain.c.orig 2010-07-08 20:32:53.000000000 +0200
--- ./src/backend/executor/execMain.c 2010-07-08 15:22:15.000000000 +0200
***************
*** 39,49 ****
--- 39,52 ----
#include "catalog/heap.h"
#include "catalog/namespace.h"
#include "catalog/toasting.h"
+ #include "catalog/dependency.h"
#include "commands/tablespace.h"
#include "commands/trigger.h"
+ #include "commands/cluster.h"
#include "executor/execdebug.h"
#include "executor/instrument.h"
#include "miscadmin.h"
+ #include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
#include "parser/parse_clause.h"
#include "parser/parsetree.h"
***************
*** 56,61 ****
--- 59,65 ----
#include "utils/memutils.h"
#include "utils/snapmgr.h"
#include "utils/tqual.h"
+ #include "lib/stringinfo.h"
/* Hooks for plugins to get control in ExecutorStart/Run/End() */
***************
*** 868,873 ****
--- 872,878 ----
switch (resultRelationDesc->rd_rel->relkind)
{
case RELKIND_RELATION:
+ case RELKIND_MATVIEW:
/* OK */
break;
case RELKIND_SEQUENCE:
***************
*** 2073,2078 ****
--- 2078,2085 ----
Oid intoRelationId;
TupleDesc tupdesc;
DR_intorel *myState;
+ Oid tableOid;
+ Oid OIDNewHeap;
static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
Assert(into);
***************
*** 2144,2209 ****
get_tablespace_name(tablespaceId));
}
! /* Parse and validate any reloptions */
! reloptions = transformRelOptions((Datum) 0,
! into->options,
! NULL,
! validnsps,
! true,
! false);
! (void) heap_reloptions(RELKIND_RELATION, reloptions, true);
!
! /* Copy the tupdesc because heap_create_with_catalog modifies it */
! tupdesc = CreateTupleDescCopy(queryDesc->tupDesc);
!
! /* Now we can actually create the new relation */
! intoRelationId = heap_create_with_catalog(intoName,
! namespaceId,
! tablespaceId,
! InvalidOid,
! InvalidOid,
! InvalidOid,
! GetUserId(),
! tupdesc,
! NIL,
! RELKIND_RELATION,
! false,
! false,
! true,
! 0,
! into->onCommit,
! reloptions,
! true,
! allowSystemTableMods);
!
! FreeTupleDesc(tupdesc);
!
! /*
! * Advance command counter so that the newly-created relation's catalog
! * tuples will be visible to heap_open.
! */
! CommandCounterIncrement();
!
! /*
! * If necessary, create a TOAST table for the INTO relation. Note that
! * AlterTableCreateToastTable ends with CommandCounterIncrement(), so that
! * the TOAST table will be visible for insertion.
! */
! reloptions = transformRelOptions((Datum) 0,
! into->options,
! "toast",
! validnsps,
! true,
! false);
! (void) heap_reloptions(RELKIND_TOASTVALUE, reloptions, true);
! AlterTableCreateToastTable(intoRelationId, reloptions);
- /*
- * And open the constructed table for writing.
- */
- intoRelationDesc = heap_open(intoRelationId, AccessExclusiveLock);
/*
* Now replace the query's DestReceiver with one for SELECT INTO
--- 2151,2240 ----
get_tablespace_name(tablespaceId));
}
! /*
! * There are two types of SELECT INTO stmt. One for refreshing data
! * in materialized views. The second one for regular SELECT INTO stmt.
! */
! if (into->isrefresh)
! {
! /* Open the constructed table for copying */
! intoRelationDesc = heap_openrv(into->rel, AccessExclusiveLock);
! tableOid = RelationGetRelid(intoRelationDesc);
! /* Close relcache entry */
! heap_close(intoRelationDesc, NoLock);
!
! /* Create new heap, target of REFRESH command */
! OIDNewHeap = make_new_heap(tableOid, tablespaceId);
!
! /* And open the constructed table for writing */
! intoRelationDesc = heap_open(OIDNewHeap, AccessExclusiveLock);
! }
! else
! {
! /* Parse and validate any reloptions */
! reloptions = transformRelOptions((Datum) 0,
! into->options,
! NULL,
! validnsps,
! true,
! false);
! (void) heap_reloptions(RELKIND_RELATION, reloptions, true);
!
! /* Copy the tupdesc because heap_create_with_catalog modifies it */
! tupdesc = CreateTupleDescCopy(queryDesc->tupDesc);
!
! /* Now we can actually create the new relation */
! intoRelationId = heap_create_with_catalog(intoName,
! namespaceId,
! tablespaceId,
! InvalidOid,
! InvalidOid,
! InvalidOid,
! GetUserId(),
! tupdesc,
! NIL,
! RELKIND_RELATION,
! false,
! false,
! true,
! 0,
! into->onCommit,
! reloptions,
! true,
! allowSystemTableMods);
!
! FreeTupleDesc(tupdesc);
!
! /*
! * Advance command counter so that the newly-created relation's catalog
! * tuples will be visible to heap_open.
! */
! CommandCounterIncrement();
!
! /*
! * If necessary, create a TOAST table for the INTO relation. Note that
! * AlterTableCreateToastTable ends with CommandCounterIncrement(), so that
! * the TOAST table will be visible for insertion.
! */
! reloptions = transformRelOptions((Datum) 0,
! into->options,
! "toast",
! validnsps,
! true,
! false);
!
! (void) heap_reloptions(RELKIND_TOASTVALUE, reloptions, true);
!
! AlterTableCreateToastTable(intoRelationId, reloptions);
!
! /*
! * And open the constructed table for writing.
! */
! intoRelationDesc = heap_open(intoRelationId, AccessExclusiveLock);
! }
/*
* Now replace the query's DestReceiver with one for SELECT INTO
***************
*** 2233,2238 ****
--- 2264,2274 ----
CloseIntoRel(QueryDesc *queryDesc)
{
DR_intorel *myState = (DR_intorel *) queryDesc->dest;
+ IntoClause *into = queryDesc->plannedstmt->intoClause;
+ Relation relation;
+ Oid tableOid;
+ Oid tableSpace;
+ Oid OIDTempHeap;
/* OpenIntoRel might never have gotten called */
if (myState && myState->pub.mydest == DestIntoRel && myState->rel)
***************
*** 2246,2251 ****
--- 2282,2301 ----
/* close rel, but keep lock until commit */
heap_close(myState->rel, NoLock);
+ /* check if it's REFRESH command */
+ if (queryDesc->plannedstmt->intoClause->isrefresh)
+ {
+ relation = heap_openrv(into->rel, AccessExclusiveLock);
+ tableOid = relation->rd_id;
+ tableSpace = myState->rel->rd_rel->reltablespace;
+ OIDTempHeap = RelationGetRelid(myState->rel);
+
+ heap_close(relation, NoLock);
+
+ /* swap old heap with new one */
+ finish_heap_swap(tableOid, OIDTempHeap, false, true, myState->rel->rd_rel->relfrozenxid);
+ }
+
myState->rel = NULL;
}
}
*** ./src/backend/nodes/copyfuncs.c.orig 2010-07-08 20:32:53.000000000 +0200
--- ./src/backend/nodes/copyfuncs.c 2010-07-08 15:22:15.000000000 +0200
***************
*** 930,935 ****
--- 930,936 ----
COPY_NODE_FIELD(options);
COPY_SCALAR_FIELD(onCommit);
COPY_STRING_FIELD(tableSpaceName);
+ COPY_SCALAR_FIELD(isrefresh);
return newnode;
}
***************
*** 2845,2850 ****
--- 2846,2852 ----
COPY_NODE_FIELD(aliases);
COPY_NODE_FIELD(query);
COPY_SCALAR_FIELD(replace);
+ COPY_SCALAR_FIELD(ismaterialized);
return newnode;
}
*** ./src/backend/nodes/equalfuncs.c.orig 2010-07-08 20:32:53.000000000 +0200
--- ./src/backend/nodes/equalfuncs.c 2010-07-08 15:22:15.000000000 +0200
***************
*** 119,124 ****
--- 119,125 ----
COMPARE_NODE_FIELD(options);
COMPARE_SCALAR_FIELD(onCommit);
COMPARE_STRING_FIELD(tableSpaceName);
+ COMPARE_SCALAR_FIELD(isrefresh);
return true;
}
***************
*** 1381,1386 ****
--- 1382,1388 ----
COMPARE_NODE_FIELD(aliases);
COMPARE_NODE_FIELD(query);
COMPARE_SCALAR_FIELD(replace);
+ COMPARE_SCALAR_FIELD(ismaterialized);
return true;
}
*** ./src/backend/nodes/outfuncs.c.orig 2010-07-08 20:32:53.000000000 +0200
--- ./src/backend/nodes/outfuncs.c 2010-07-08 15:22:15.000000000 +0200
***************
*** 816,821 ****
--- 816,822 ----
WRITE_NODE_FIELD(options);
WRITE_ENUM_FIELD(onCommit, OnCommitAction);
WRITE_STRING_FIELD(tableSpaceName);
+ WRITE_BOOL_FIELD(isrefresh);
}
static void
*** ./src/backend/parser/analyze.c.orig 2010-07-08 20:32:53.000000000 +0200
--- ./src/backend/parser/analyze.c 2010-07-08 15:22:15.000000000 +0200
***************
*** 28,33 ****
--- 28,34 ----
#include "catalog/pg_type.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
+ #include "nodes/pg_list.h"
#include "optimizer/var.h"
#include "parser/analyze.h"
#include "parser/parse_agg.h"
***************
*** 64,69 ****
--- 65,72 ----
static void transformLockingClause(ParseState *pstate, Query *qry,
LockingClause *lc, bool pushedDown);
+ static SelectStmt *build_refresh_stmt(RangeVar *rv);
+ static bool is_matview_refresh(Node *parseTree);
/*
* parse_analyze
***************
*** 149,154 ****
--- 152,250 ----
return query;
}
+
+ /*
+ * Returns true if ALTER TABLE command is REFRESH
+ * and is the only one command in statement, otherwise return false.
+ *
+ */
+ static bool
+ is_matview_refresh(Node *parseTree)
+ {
+ AlterTableStmt *alter;
+ AlterTableCmd *command;
+ ListCell *l;
+ bool is_refresh = false;
+
+ if (nodeTag(parseTree) == T_AlterTableStmt)
+ {
+ alter = (AlterTableStmt *) parseTree;
+
+ /* check out all types of commands */
+ foreach (l, alter->cmds)
+ {
+ command = (AlterTableCmd *) lfirst(l);
+ if (command->subtype == AT_Refresh)
+ is_refresh = true;
+ }
+
+ /* if is present REFRESH cmd */
+ if (is_refresh)
+ {
+ /* we are expecting just one command, else show error message */
+ if (alter->cmds->length == 1)
+ return true;
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("REFRESH cannot be used with other ALTER commands")));
+ }
+ }
+ return false;
+ }
+
+ /*
+ * Returns complete parsed SELECT INTO stmt, isRefresh flag
+ * in IntoClause indicate it is REFRESH command.
+ */
+ static SelectStmt *
+ build_refresh_stmt(RangeVar *rv)
+ {
+ /* SELECT * INTO matview FROM [matview definition] */
+ IntoClause *intoClause = makeNode(IntoClause);
+ SelectStmt *selectStmt = makeNode(SelectStmt);
+ ColumnRef *cref;
+ A_Star *star;
+ ResTarget *target;
+
+ memset(selectStmt, 0, sizeof(SelectStmt));
+ memset(intoClause, 0, sizeof(IntoClause));
+
+ intoClause->type = T_IntoClause;
+ intoClause->rel = copyObject(rv);
+ intoClause->colNames = NIL;
+ intoClause->options = NIL;
+ intoClause->onCommit = ONCOMMIT_NOOP;
+ intoClause->tableSpaceName = '\0';
+ intoClause->isrefresh = true;
+
+ /* make A_Star node */
+ star = (A_Star *) makeNode(A_Star);
+ star->type = T_A_Star;
+
+ /* make ColumnRef node and to the 'fields' add A_Star */
+ cref = (ColumnRef *) makeNode(ColumnRef);
+ cref->type = T_ColumnRef;
+ cref->fields = list_make1(star);
+ cref->location = 7;
+ /* make ResTarget node and to the 'val' field add list of ColumnRefs */
+ target = (ResTarget *) makeNode(ResTarget);
+ target->type = T_ResTarget;
+ target->name = "";
+ target->indirection = NIL;
+ target->location = 7;
+ target->val = (Node *) cref;
+
+ /* finally create SelectStmt, append target list and intoClause */
+ selectStmt->type = T_SelectStmt;
+ selectStmt->fromClause = list_make1(intoClause->rel);
+ selectStmt->targetList = list_make1(target);
+ selectStmt->intoClause = intoClause;
+ selectStmt->op = SETOP_NONE;
+
+ return selectStmt;
+ }
+
/*
* transformStmt -
* transform a Parse tree into a Query tree.
***************
*** 191,196 ****
--- 287,324 ----
/*
* Special cases
*/
+ case T_AlterTableStmt:
+ {
+ AlterTableStmt *alter = (AlterTableStmt *) parseTree;
+ AlterTableCmd *command;
+ SelectStmt *selectStmt;
+
+ /*
+ * Check if it's REFRESH-ing materialized view,
+ * if not, do the same as default.
+ */
+ if (alter->relkind == OBJECT_MATVIEW &&
+ is_matview_refresh(parseTree))
+ {
+ command = (AlterTableCmd *) linitial(alter->cmds);
+ /* build parsed REFRESH (SELECT INTO) stmt manualy */
+ selectStmt = build_refresh_stmt(alter->relation);
+ /* transfrom as common SELECT INTO */
+ result = transformSelectStmt(pstate, selectStmt);
+ }
+ else
+ {
+ /*
+ * other statements don't require any transformation; just return
+ * the original parsetree with a Query node plastered on top.
+ */
+ result = makeNode(Query);
+ result->commandType = CMD_UTILITY;
+ result->utilityStmt = (Node *) parseTree;
+ }
+ }
+ break;
+
case T_DeclareCursorStmt:
result = transformDeclareCursorStmt(pstate,
(DeclareCursorStmt *) parseTree);
***************
*** 261,266 ****
--- 389,409 ----
result = true;
break;
+ case T_AlterTableStmt:
+ {
+ AlterTableStmt *alter = (AlterTableStmt *) parseTree;
+
+ /*
+ * Check if it's REFRESH-ing materialized view,
+ * if not, do the same as default.
+ */
+ if (alter->relkind == OBJECT_MATVIEW && is_matview_refresh(parseTree))
+ result = true;
+ else
+ result = false;
+ }
+ break;
+
default:
/* other utility statements don't have any real parse analysis */
result = false;
*** ./src/backend/parser/gram.y.orig 2010-07-08 20:32:53.000000000 +0200
--- ./src/backend/parser/gram.y 2010-07-08 15:22:15.000000000 +0200
***************
*** 310,316 ****
%type <fun_param_mode> arg_class
%type <typnam> func_return func_type
! %type <boolean> TriggerForType OptTemp
%type <oncommit> OnCommitOption
%type <node> for_locking_item
--- 310,316 ----
%type <fun_param_mode> arg_class
%type <typnam> func_return func_type
! %type <boolean> TriggerForType OptTemp OptMaterialized
%type <oncommit> OnCommitOption
%type <node> for_locking_item
***************
*** 502,508 ****
LEAST LEFT LEVEL LIKE LIMIT LISTEN LOAD LOCAL LOCALTIME LOCALTIMESTAMP
LOCATION LOCK_P LOGIN_P
! MAPPING MATCH MAXVALUE MINUTE_P MINVALUE MODE MONTH_P MOVE
NAME_P NAMES NATIONAL NATURAL NCHAR NEXT NO NOCREATEDB
NOCREATEROLE NOCREATEUSER NOINHERIT NOLOGIN_P NONE NOSUPERUSER
--- 502,508 ----
LEAST LEFT LEVEL LIKE LIMIT LISTEN LOAD LOCAL LOCALTIME LOCALTIMESTAMP
LOCATION LOCK_P LOGIN_P
! MAPPING MATCH MATERIALIZED MAXVALUE MINUTE_P MINVALUE MODE MONTH_P MOVE
NAME_P NAMES NATIONAL NATURAL NCHAR NEXT NO NOCREATEDB
NOCREATEROLE NOCREATEUSER NOINHERIT NOLOGIN_P NONE NOSUPERUSER
***************
*** 517,523 ****
QUOTE
! RANGE READ REAL REASSIGN RECHECK RECURSIVE REFERENCES REINDEX
RELATIVE_P RELEASE RENAME REPEATABLE REPLACE REPLICA RESET RESTART
RESTRICT RETURNING RETURNS REVOKE RIGHT ROLE ROLLBACK ROW ROWS RULE
--- 517,523 ----
QUOTE
! RANGE READ REAL REASSIGN RECHECK RECURSIVE REFERENCES REFRESH REINDEX
RELATIVE_P RELEASE RENAME REPEATABLE REPLACE REPLICA RESET RESTART
RESTRICT RETURNING RETURNS REVOKE RIGHT ROLE ROLLBACK ROW ROWS RULE
***************
*** 1598,1603 ****
--- 1598,1611 ----
n->relkind = OBJECT_VIEW;
$$ = (Node *)n;
}
+ | ALTER MATERIALIZED VIEW qualified_name alter_table_cmds
+ {
+ AlterTableStmt *n = makeNode(AlterTableStmt);
+ n->relation = $4;
+ n->cmds = $5;
+ n->relkind = OBJECT_MATVIEW;
+ $$ = (Node *)n;
+ }
;
alter_table_cmds:
***************
*** 1914,1919 ****
--- 1922,1934 ----
n->def = (Node *)$2;
$$ = (Node *)n;
}
+ /* ALTER TABLE <name> REFRESH */
+ | REFRESH
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_Refresh;
+ $$ = (Node *)n;
+ }
;
alter_column_default:
***************
*** 4046,4051 ****
--- 4061,4067 ----
drop_type: TABLE { $$ = OBJECT_TABLE; }
| SEQUENCE { $$ = OBJECT_SEQUENCE; }
| VIEW { $$ = OBJECT_VIEW; }
+ | MATERIALIZED VIEW { $$ = OBJECT_MATVIEW; }
| INDEX { $$ = OBJECT_INDEX; }
| TYPE_P { $$ = OBJECT_TYPE; }
| DOMAIN_P { $$ = OBJECT_DOMAIN; }
***************
*** 4102,4108 ****
* The COMMENT ON statement can take different forms based upon the type of
* the object associated with the comment. The form of the statement is:
*
! * COMMENT ON [ [ DATABASE | DOMAIN | INDEX | SEQUENCE | TABLE | TYPE | VIEW |
* CONVERSION | LANGUAGE | OPERATOR CLASS | LARGE OBJECT |
* CAST | COLUMN | SCHEMA | TABLESPACE | ROLE |
* TEXT SEARCH PARSER | TEXT SEARCH DICTIONARY |
--- 4118,4124 ----
* The COMMENT ON statement can take different forms based upon the type of
* the object associated with the comment. The form of the statement is:
*
! * COMMENT ON [ [ DATABASE | DOMAIN | INDEX | SEQUENCE | TABLE | TYPE | [MATERIALIZED] VIEW |
* CONVERSION | LANGUAGE | OPERATOR CLASS | LARGE OBJECT |
* CAST | COLUMN | SCHEMA | TABLESPACE | ROLE |
* TEXT SEARCH PARSER | TEXT SEARCH DICTIONARY |
***************
*** 4281,4286 ****
--- 4297,4303 ----
| DOMAIN_P { $$ = OBJECT_TYPE; }
| TYPE_P { $$ = OBJECT_TYPE; }
| VIEW { $$ = OBJECT_VIEW; }
+ | MATERIALIZED VIEW { $$ = OBJECT_MATVIEW; }
| CONVERSION_P { $$ = OBJECT_CONVERSION; }
| TABLESPACE { $$ = OBJECT_TABLESPACE; }
| ROLE { $$ = OBJECT_ROLE; }
***************
*** 5691,5696 ****
--- 5708,5722 ----
n->newname = $6;
$$ = (Node *)n;
}
+ | ALTER MATERIALIZED VIEW qualified_name RENAME TO name
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_MATVIEW;
+ n->relation = $4;
+ n->subname = NULL;
+ n->newname = $7;
+ $$ = (Node *)n;
+ }
| ALTER INDEX qualified_name RENAME TO name
{
RenameStmt *n = makeNode(RenameStmt);
***************
*** 5867,5872 ****
--- 5893,5906 ----
n->newschema = $6;
$$ = (Node *)n;
}
+ | ALTER MATERIALIZED VIEW qualified_name SET SCHEMA name
+ {
+ AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ n->objectType = OBJECT_MATVIEW;
+ n->relation = $4;
+ n->newschema = $7;
+ $$ = (Node *)n;
+ }
| ALTER TYPE_P any_name SET SCHEMA name
{
AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
***************
*** 6319,6353 ****
/*****************************************************************************
*
* QUERY:
! * CREATE [ OR REPLACE ] [ TEMP ] VIEW <viewname> '('target-list ')'
* AS <query> [ WITH [ CASCADED | LOCAL ] CHECK OPTION ]
*
*****************************************************************************/
! ViewStmt: CREATE OptTemp VIEW qualified_name opt_column_list
AS SelectStmt opt_check_option
{
ViewStmt *n = makeNode(ViewStmt);
! n->view = $4;
n->view->istemp = $2;
! n->aliases = $5;
! n->query = $7;
n->replace = false;
$$ = (Node *) n;
}
! | CREATE OR REPLACE OptTemp VIEW qualified_name opt_column_list
AS SelectStmt opt_check_option
{
ViewStmt *n = makeNode(ViewStmt);
! n->view = $6;
n->view->istemp = $4;
! n->aliases = $7;
! n->query = $9;
n->replace = true;
$$ = (Node *) n;
}
;
opt_check_option:
WITH CHECK OPTION
{
--- 6353,6394 ----
/*****************************************************************************
*
* QUERY:
! * CREATE [ OR REPLACE ] [ TEMP ] [ MATERIALIZED ] VIEW <viewname> '('target-list ')'
* AS <query> [ WITH [ CASCADED | LOCAL ] CHECK OPTION ]
*
*****************************************************************************/
! ViewStmt: CREATE OptTemp OptMaterialized VIEW qualified_name opt_column_list
AS SelectStmt opt_check_option
{
ViewStmt *n = makeNode(ViewStmt);
! n->view = $5;
n->view->istemp = $2;
! n->ismaterialized = $3;
! n->aliases = $6;
! n->query = $8;
n->replace = false;
$$ = (Node *) n;
}
! | CREATE OR REPLACE OptTemp OptMaterialized VIEW qualified_name opt_column_list
AS SelectStmt opt_check_option
{
ViewStmt *n = makeNode(ViewStmt);
! n->view = $7;
n->view->istemp = $4;
! n->ismaterialized = $5;
! n->aliases = $8;
! n->query = $10;
n->replace = true;
$$ = (Node *) n;
}
;
+
+ OptMaterialized: MATERIALIZED { $$ = true; }
+ | /* EMPTY */ { $$ = false; }
+ ;
+
opt_check_option:
WITH CHECK OPTION
{
***************
*** 7577,7582 ****
--- 7618,7624 ----
$$->options = NIL;
$$->onCommit = ONCOMMIT_NOOP;
$$->tableSpaceName = NULL;
+ $$->isrefresh = FALSE;
}
| /*EMPTY*/
{ $$ = NULL; }
***************
*** 10982,10987 ****
--- 11024,11030 ----
| REASSIGN
| RECHECK
| RECURSIVE
+ | REFRESH
| REINDEX
| RELATIVE_P
| RELEASE
***************
*** 11211,11216 ****
--- 11254,11260 ----
| LIMIT
| LOCALTIME
| LOCALTIMESTAMP
+ | MATERIALIZED
| NOT
| NULL_P
| OFF
*** ./src/backend/rewrite/rewriteDefine.c.orig 2010-07-08 20:32:53.000000000 +0200
--- ./src/backend/rewrite/rewriteDefine.c 2010-07-08 15:22:15.000000000 +0200
***************
*** 159,165 ****
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced,
! (evtype == CMD_SELECT) ? DEPENDENCY_INTERNAL : DEPENDENCY_AUTO);
/*
* Also install dependencies on objects referenced in action and qual.
--- 159,165 ----
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced,
! (evtype == CMD_SELECT || evtype == CMD_REFRESH) ? DEPENDENCY_INTERNAL : DEPENDENCY_AUTO);
/*
* Also install dependencies on objects referenced in action and qual.
***************
*** 246,252 ****
* Verify relation is of a type that rules can sensibly be applied to.
*/
if (event_relation->rd_rel->relkind != RELKIND_RELATION &&
! event_relation->rd_rel->relkind != RELKIND_VIEW)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("\"%s\" is not a table or view",
--- 246,253 ----
* Verify relation is of a type that rules can sensibly be applied to.
*/
if (event_relation->rd_rel->relkind != RELKIND_RELATION &&
! event_relation->rd_rel->relkind != RELKIND_VIEW &&
! event_relation->rd_rel->relkind != RELKIND_MATVIEW)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("\"%s\" is not a table or view",
***************
*** 288,294 ****
errhint("Use triggers instead.")));
}
! if (event_type == CMD_SELECT)
{
/*
* Rules ON SELECT are restricted to view definitions
--- 289,295 ----
errhint("Use triggers instead.")));
}
! if (event_type == CMD_SELECT || event_type == CMD_REFRESH)
{
/*
* Rules ON SELECT are restricted to view definitions
***************
*** 313,319 ****
* ... the one action must be a SELECT, ...
*/
query = (Query *) linitial(action);
! if (!is_instead ||
query->commandType != CMD_SELECT ||
query->utilityStmt != NULL ||
query->intoClause != NULL)
--- 314,320 ----
* ... the one action must be a SELECT, ...
*/
query = (Query *) linitial(action);
! if ((!is_instead && (event_relation->rd_rel->relkind != RELKIND_MATVIEW)) ||
query->commandType != CMD_SELECT ||
query->utilityStmt != NULL ||
query->intoClause != NULL)
***************
*** 349,355 ****
RewriteRule *rule;
rule = event_relation->rd_rules->rules[i];
! if (rule->event == CMD_SELECT)
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("\"%s\" is already a view",
--- 350,356 ----
RewriteRule *rule;
rule = event_relation->rd_rules->rules[i];
! if (rule->event == CMD_SELECT || rule->event == CMD_REFRESH)
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("\"%s\" is already a view",
***************
*** 499,505 ****
*
* XXX what about getting rid of its TOAST table? For now, we don't.
*/
! if (RelisBecomingView)
RelationDropStorage(event_relation);
/* Close rel, but keep lock till commit... */
--- 500,506 ----
*
* XXX what about getting rid of its TOAST table? For now, we don't.
*/
! if (RelisBecomingView && (event_relation->rd_rel->relkind != RELKIND_MATVIEW))
RelationDropStorage(event_relation);
/* Close rel, but keep lock till commit... */
*** ./src/backend/rewrite/rewriteHandler.c.orig 2010-07-08 20:32:53.000000000 +0200
--- ./src/backend/rewrite/rewriteHandler.c 2010-07-08 15:22:15.000000000 +0200
***************
*** 1390,1396 ****
for (i = 0; i < rules->numLocks; i++)
{
rule = rules->rules[i];
! if (rule->event != CMD_SELECT)
continue;
if (rule->attrno > 0)
--- 1390,1396 ----
for (i = 0; i < rules->numLocks; i++)
{
rule = rules->rules[i];
! if (rule->event != CMD_SELECT && rule->event != CMD_REFRESH)
continue;
if (rule->attrno > 0)
***************
*** 1422,1427 ****
--- 1422,1441 ----
{
rule = lfirst(l);
+ /*
+ * There are two cases when we want to prevent firing rule:
+ * 1) command is just SELECT stmt
+ * 2) commant is SELECT INTO stmt, not REFRESHing MV
+ */
+ if ((rule->event == CMD_REFRESH && parsetree->intoClause == NULL)
+ ||
+ (rule->event == CMD_REFRESH &&
+ parsetree->intoClause != NULL &&
+ !parsetree->intoClause->isrefresh))
+ {
+ continue;
+ }
+
parsetree = ApplyRetrieveRule(parsetree,
rule,
rt_index,
***************
*** 1659,1664 ****
--- 1673,1708 ----
rt_entry_relation = heap_open(rt_entry->relid, NoLock);
/*
+ * Inserting, updating or deleting row in materilized views are not allowed
+ */
+ if (rt_entry_relation->rd_rel->relkind == RELKIND_MATVIEW)
+ {
+ heap_close(rt_entry_relation, NoLock);
+ switch (parsetree->commandType)
+ {
+ case CMD_INSERT:
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("cannot insert into a materialized view")));
+ break;
+ case CMD_UPDATE:
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("cannot update a materialized view")));
+ break;
+ case CMD_DELETE:
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("cannot delete from a materialized view")));
+ break;
+ default:
+ elog(ERROR, "unrecognized commandType: %d",
+ (int) parsetree->commandType);
+ break;
+ }
+ }
+
+ /*
* If it's an INSERT or UPDATE, rewrite the targetlist into standard
* form. This will be needed by the planner anyway, and doing it now
* ensures that any references to NEW.field will behave sanely.
*** ./src/backend/rewrite/rewriteSupport.c.orig 2010-07-08 20:32:53.000000000 +0200
--- ./src/backend/rewrite/rewriteSupport.c 2010-07-08 15:22:15.000000000 +0200
***************
*** 69,75 ****
{
/* Do the update */
classForm->relhasrules = relHasRules;
! if (relIsBecomingView)
classForm->relkind = RELKIND_VIEW;
simple_heap_update(relationRelation, &tuple->t_self, tuple);
--- 69,77 ----
{
/* Do the update */
classForm->relhasrules = relHasRules;
!
! /* do not change RELKIND if its Materialized View */
! if (relIsBecomingView && classForm->relkind != RELKIND_MATVIEW)
classForm->relkind = RELKIND_VIEW;
simple_heap_update(relationRelation, &tuple->t_self, tuple);
*** ./src/backend/tcop/utility.c.orig 2010-07-08 20:32:53.000000000 +0200
--- ./src/backend/tcop/utility.c 2010-07-08 15:22:15.000000000 +0200
***************
*** 606,611 ****
--- 606,612 ----
case OBJECT_TABLE:
case OBJECT_SEQUENCE:
case OBJECT_VIEW:
+ case OBJECT_MATVIEW:
case OBJECT_INDEX:
RemoveRelations(stmt);
break;
***************
*** 1544,1549 ****
--- 1545,1553 ----
case OBJECT_VIEW:
tag = "DROP VIEW";
break;
+ case OBJECT_MATVIEW:
+ tag = "DROP MATERIALIZED VIEW";
+ break;
case OBJECT_INDEX:
tag = "DROP INDEX";
break;
***************
*** 1637,1642 ****
--- 1641,1649 ----
case OBJECT_VIEW:
tag = "ALTER VIEW";
break;
+ case OBJECT_MATVIEW:
+ tag = "ALTER MATERIALIZED VIEW";
+ break;
case OBJECT_TSPARSER:
tag = "ALTER TEXT SEARCH PARSER";
break;
***************
*** 1694,1699 ****
--- 1701,1709 ----
case OBJECT_VIEW:
tag = "ALTER VIEW";
break;
+ case OBJECT_MATVIEW:
+ tag = "ALTER MATERIALIZED VIEW";
+ break;
default:
tag = "???";
break;
***************
*** 1775,1780 ****
--- 1785,1793 ----
case OBJECT_VIEW:
tag = "ALTER VIEW";
break;
+ case OBJECT_MATVIEW:
+ tag = "ALTER MATERIALIZED VIEW";
+ break;
default:
tag = "???";
break;
***************
*** 1847,1853 ****
break;
case T_ViewStmt:
! tag = "CREATE VIEW";
break;
case T_CreateFunctionStmt:
--- 1860,1870 ----
break;
case T_ViewStmt:
! {
! ViewStmt *stmt = (ViewStmt *) parsetree;
!
! tag = (stmt->ismaterialized) ? "CREATE MATERIALIZED VIEW" : "CREATE VIEW";
! }
break;
case T_CreateFunctionStmt:
*** ./src/backend/utils/adt/dbsize.c.orig 2010-07-06 10:43:16.000000000 +0200
--- ./src/backend/utils/adt/dbsize.c 2010-07-08 15:22:15.000000000 +0200
***************
*** 541,546 ****
--- 541,547 ----
case RELKIND_INDEX:
case RELKIND_SEQUENCE:
case RELKIND_TOASTVALUE:
+ case RELKIND_MATVIEW:
/* okay, these have storage */
if (relform->relfilenode)
result = relform->relfilenode;
***************
*** 588,593 ****
--- 589,595 ----
case RELKIND_INDEX:
case RELKIND_SEQUENCE:
case RELKIND_TOASTVALUE:
+ case RELKIND_MATVIEW:
/* okay, these have storage */
/* This logic should match RelationInitPhysicalAddr */
*** ./src/backend/utils/adt/ruleutils.c.orig 2010-07-08 20:32:53.000000000 +0200
--- ./src/backend/utils/adt/ruleutils.c 2010-07-08 15:22:15.000000000 +0200
***************
*** 2384,2391 ****
query = (Query *) linitial(actions);
! if (ev_type != '1' || ev_attr >= 0 || !is_instead ||
! strcmp(ev_qual, "<>") != 0 || query->commandType != CMD_SELECT)
{
appendStringInfo(buf, "Not a view");
return;
--- 2384,2393 ----
query = (Query *) linitial(actions);
! /* ev_type == 1 SELECT, ev_type == 6 REFRESH */
! if (ev_attr >= 0 || strcmp(ev_qual, "<>") != 0 || query->commandType != CMD_SELECT ||
! ((!is_instead || ev_type != '1') &&
! (is_instead || ev_type != '6')))
{
appendStringInfo(buf, "Not a view");
return;
*** ./src/bin/pg_dump/pg_backup_archiver.c.orig 2010-07-08 20:32:53.000000000 +0200
--- ./src/bin/pg_dump/pg_backup_archiver.c 2010-07-08 21:10:12.000000000 +0200
***************
*** 2699,2705 ****
const char *type = te->desc;
/* Use ALTER TABLE for views and sequences */
! if (strcmp(type, "VIEW") == 0 || strcmp(type, "SEQUENCE") == 0)
type = "TABLE";
/* objects named by a schema and name */
--- 2699,2705 ----
const char *type = te->desc;
/* Use ALTER TABLE for views and sequences */
! if (strcmp(type, "VIEW") == 0 || strcmp(type, "MATERIALIZED VIEW") == 0 || strcmp(type, "SEQUENCE") == 0)
type = "TABLE";
/* objects named by a schema and name */
***************
*** 2898,2903 ****
--- 2898,2904 ----
strcmp(te->desc, "TABLE") == 0 ||
strcmp(te->desc, "TYPE") == 0 ||
strcmp(te->desc, "VIEW") == 0 ||
+ strcmp(te->desc, "MATERIALIZED VIEW") == 0 ||
strcmp(te->desc, "SEQUENCE") == 0 ||
strcmp(te->desc, "TEXT SEARCH DICTIONARY") == 0 ||
strcmp(te->desc, "TEXT SEARCH CONFIGURATION") == 0 ||
***************
*** 3010,3015 ****
--- 3011,3017 ----
AH->version = ((AH->vmaj * 256 + AH->vmin) * 256 + AH->vrev) * 256 + 0;
+
if (AH->version < K_VERS_1_0 || AH->version > K_VERS_MAX)
die_horribly(AH, modulename, "unsupported version (%d.%d) in file header\n",
AH->vmaj, AH->vmin);
*** ./src/bin/pg_dump/pg_dump.c.orig 2010-07-08 20:32:53.000000000 +0200
--- ./src/bin/pg_dump/pg_dump.c 2010-07-08 21:12:23.000000000 +0200
***************
*** 1434,1439 ****
--- 1434,1442 ----
/* Skip VIEWs (no data to dump) */
if (tblinfo[i].relkind == RELKIND_VIEW)
continue;
+ /* Skip MATERIALIZED VIEWs (redundant data are not dumped) */
+ if (tblinfo[i].relkind == RELKIND_MATVIEW)
+ continue;
/* Skip SEQUENCEs (handled elsewhere) */
if (tblinfo[i].relkind == RELKIND_SEQUENCE)
continue;
***************
*** 3464,3475 ****
"d.objsubid = 0 AND "
"d.refclassid = c.tableoid AND d.deptype = 'a') "
"LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
! "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
"ORDER BY c.oid",
username_subquery,
RELKIND_SEQUENCE,
RELKIND_RELATION, RELKIND_SEQUENCE,
! RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
}
else if (g_fout->remoteVersion >= 80400)
{
--- 3467,3478 ----
"d.objsubid = 0 AND "
"d.refclassid = c.tableoid AND d.deptype = 'a') "
"LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
! "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c') "
"ORDER BY c.oid",
username_subquery,
RELKIND_SEQUENCE,
RELKIND_RELATION, RELKIND_SEQUENCE,
! RELKIND_VIEW, RELKIND_MATVIEW, RELKIND_COMPOSITE_TYPE);
}
else if (g_fout->remoteVersion >= 80400)
{
***************
*** 4515,4522 ****
* for the rule affect the table's positioning. Other rules are
* forced to appear after their table.
*/
! if (ruleinfo[i].ruletable->relkind == RELKIND_VIEW &&
! ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
{
addObjectDependency(&ruleinfo[i].ruletable->dobj,
ruleinfo[i].dobj.dumpId);
--- 4518,4528 ----
* for the rule affect the table's positioning. Other rules are
* forced to appear after their table.
*/
! if ((ruleinfo[i].ruletable->relkind == RELKIND_VIEW &&
! ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead) ||
! (ruleinfo[i].ruletable->relkind == RELKIND_MATVIEW &&
! ruleinfo[i].ev_type == '6' && !ruleinfo[i].is_instead)
! )
{
addObjectDependency(&ruleinfo[i].ruletable->dobj,
ruleinfo[i].dobj.dumpId);
***************
*** 10574,10579 ****
--- 10580,10639 ----
PQclear(res);
}
+ else if (tbinfo->relkind == RELKIND_MATVIEW)
+ {
+ char *viewdef;
+
+ reltypename = "MATERIALIZED VIEW";
+
+ /* Fetch the view definition */
+ appendPQExpBuffer(query,
+ "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef",
+ tbinfo->dobj.catId.oid);
+
+ res = PQexec(g_conn, query->data);
+ check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
+
+ if (PQntuples(res) != 1)
+ {
+ if (PQntuples(res) < 1)
+ write_msg(NULL, "query to obtain definition of view \"%s\" returned no data\n",
+ tbinfo->dobj.name);
+ else
+ write_msg(NULL, "query to obtain definition of view \"%s\" returned more than one definition\n",
+ tbinfo->dobj.name);
+ exit_nicely();
+ }
+
+ viewdef = PQgetvalue(res, 0, 0);
+
+ if (strlen(viewdef) == 0)
+ {
+ write_msg(NULL, "definition of view \"%s\" appears to be empty (length zero)\n",
+ tbinfo->dobj.name);
+ exit_nicely();
+ }
+
+ /*
+ * DROP must be fully qualified in case same name appears in
+ * pg_catalog
+ */
+ appendPQExpBuffer(delq, "DROP MATERIALIZED VIEW %s.",
+ fmtId(tbinfo->dobj.namespace->dobj.name));
+ appendPQExpBuffer(delq, "%s;\n",
+ fmtId(tbinfo->dobj.name));
+
+ if (binary_upgrade)
+ binary_upgrade_set_relfilenodes(q, tbinfo->dobj.catId.oid, false);
+
+ appendPQExpBuffer(q, "CREATE MATERIALIZED VIEW %s AS\n %s\n\n",
+ fmtId(tbinfo->dobj.name), viewdef);
+
+ appendPQExpBuffer(q, "ALTER MATERIALIZED VIEW %s REFRESH;\n",
+ fmtId(tbinfo->dobj.name));
+
+ PQclear(res);
+ }
else
{
reltypename = "TABLE";
*** ./src/bin/pg_dump/pg_dump_sort.c.orig 2010-07-08 20:32:53.000000000 +0200
--- ./src/bin/pg_dump/pg_dump_sort.c 2010-07-08 15:22:15.000000000 +0200
***************
*** 823,829 ****
return;
}
! /* Indirect loop involving view and ON SELECT rule */
if (nLoop > 2)
{
for (i = 0; i < nLoop; i++)
--- 823,854 ----
return;
}
! /* Materialized View and its ON REFRESH rule */
! if (nLoop == 2 &&
! loop[0]->objType == DO_TABLE &&
! loop[1]->objType == DO_RULE &&
! ((RuleInfo *) loop[1])->ev_type == '6' &&
! !((RuleInfo *) loop[1])->is_instead &&
! ((RuleInfo *) loop[1])->ruletable == (TableInfo *) loop[0])
! {
! repairViewRuleLoop(loop[0], loop[1]);
! return;
! }
! if (nLoop == 2 &&
! loop[1]->objType == DO_TABLE &&
! loop[0]->objType == DO_RULE &&
! ((RuleInfo *) loop[0])->ev_type == '6' &&
! !((RuleInfo *) loop[0])->is_instead &&
! ((RuleInfo *) loop[0])->ruletable == (TableInfo *) loop[1])
! {
! repairViewRuleLoop(loop[1], loop[0]);
! return;
! }
!
! /*
! * Indirect loop involving view and ON SELECT rule
! * and materialized view and its ON REFRESH rule
! */
if (nLoop > 2)
{
for (i = 0; i < nLoop; i++)
***************
*** 832,837 ****
--- 857,863 ----
{
for (j = 0; j < nLoop; j++)
{
+ /* view and ON SELECT rule */
if (loop[j]->objType == DO_RULE &&
((RuleInfo *) loop[j])->ev_type == '1' &&
((RuleInfo *) loop[j])->is_instead &&
***************
*** 840,845 ****
--- 866,880 ----
repairViewRuleMultiLoop(loop[i], loop[j]);
return;
}
+ /* materialized view and ON REFRESH rule */
+ if (loop[j]->objType == DO_RULE &&
+ ((RuleInfo *) loop[j])->ev_type == '6' &&
+ !((RuleInfo *) loop[j])->is_instead &&
+ ((RuleInfo *) loop[j])->ruletable == (TableInfo *) loop[i])
+ {
+ repairViewRuleMultiLoop(loop[i], loop[j]);
+ return;
+ }
}
}
}
*** ./src/bin/psql/command.c.orig 2010-07-06 10:43:17.000000000 +0200
--- ./src/bin/psql/command.c 2010-07-08 15:22:15.000000000 +0200
***************
*** 346,352 ****
success = describeTableDetails(pattern, show_verbose, show_system);
else
/* standard listing of interesting things */
! success = listTables("tvs", NULL, show_verbose, show_system);
break;
case 'a':
success = describeAggregates(pattern, show_verbose, show_system);
--- 346,352 ----
success = describeTableDetails(pattern, show_verbose, show_system);
else
/* standard listing of interesting things */
! success = listTables("tvms", NULL, show_verbose, show_system);
break;
case 'a':
success = describeAggregates(pattern, show_verbose, show_system);
***************
*** 407,412 ****
--- 407,413 ----
break;
case 't':
case 'v':
+ case 'm':
case 'i':
case 's':
success = listTables(&cmd[1], pattern, show_verbose, show_system);
*** ./src/bin/psql/describe.c.orig 2010-07-06 10:43:17.000000000 +0200
--- ./src/bin/psql/describe.c 2010-07-08 15:22:15.000000000 +0200
***************
*** 911,923 ****
" n.nspname as nspname,\n"
" CAST(c.relname AS pg_catalog.text) as name,\n"
" CAST(\n"
! " CASE c.relkind WHEN 'r' THEN '%s' WHEN 'v' THEN '%s' WHEN 'i' THEN '%s' WHEN 'S' THEN '%s' END"
" AS pg_catalog.text) as object\n"
" FROM pg_catalog.pg_class c\n"
" LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n"
! " WHERE c.relkind IN ('r', 'v', 'i', 'S')\n",
gettext_noop("table"),
gettext_noop("view"),
gettext_noop("index"),
gettext_noop("sequence"));
--- 911,924 ----
" n.nspname as nspname,\n"
" CAST(c.relname AS pg_catalog.text) as name,\n"
" CAST(\n"
! " CASE c.relkind WHEN 'r' THEN '%s' WHEN 'v' THEN '%s' WHEN 'm' THEN '%s' WHEN 'i' THEN '%s' WHEN 'S' THEN '%s' END"
" AS pg_catalog.text) as object\n"
" FROM pg_catalog.pg_class c\n"
" LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n"
! " WHERE c.relkind IN ('r', 'v', 'm', 'i', 'S')\n",
gettext_noop("table"),
gettext_noop("view"),
+ gettext_noop("materialized view"),
gettext_noop("index"),
gettext_noop("sequence"));
***************
*** 1266,1271 ****
--- 1267,1276 ----
printfPQExpBuffer(&title, _("View \"%s.%s\""),
schemaname, relationname);
break;
+ case 'm':
+ printfPQExpBuffer(&title, _("Materialized View \"%s.%s\""),
+ schemaname, relationname);
+ break;
case 'S':
printfPQExpBuffer(&title, _("Sequence \"%s.%s\""),
schemaname, relationname);
***************
*** 1299,1305 ****
headers[1] = gettext_noop("Type");
cols = 2;
! if (tableinfo.relkind == 'r' || tableinfo.relkind == 'v')
{
show_modifiers = true;
headers[cols++] = gettext_noop("Modifiers");
--- 1304,1310 ----
headers[1] = gettext_noop("Type");
cols = 2;
! if (tableinfo.relkind == 'r' || tableinfo.relkind == 'v' || tableinfo.relkind == 'm')
{
show_modifiers = true;
headers[cols++] = gettext_noop("Modifiers");
***************
*** 1325,1331 ****
printTableAddHeader(&cont, headers[i], true, 'l');
/* Check if table is a view */
! if (tableinfo.relkind == 'v' && verbose)
{
PGresult *result;
--- 1330,1336 ----
printTableAddHeader(&cont, headers[i], true, 'l');
/* Check if table is a view */
! if ((tableinfo.relkind == 'v' || tableinfo.relkind == 'm') && verbose)
{
PGresult *result;
***************
*** 1527,1533 ****
PQclear(result);
}
}
! else if (tableinfo.relkind == 'r')
{
/* Footer information about a table */
PGresult *result = NULL;
--- 1532,1538 ----
PQclear(result);
}
}
! if (tableinfo.relkind == 'r' || tableinfo.relkind == 'm')
{
/* Footer information about a table */
PGresult *result = NULL;
***************
*** 1724,1730 ****
/* print rules */
if (tableinfo.hasrules)
{
! if (pset.sversion >= 80300)
{
printfPQExpBuffer(&buf,
"SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true)), "
--- 1729,1744 ----
/* print rules */
if (tableinfo.hasrules)
{
! if (pset.sversion >= 90000)
! {
! printfPQExpBuffer(&buf,
! "SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true)), "
! "ev_enabled\n"
! "FROM pg_catalog.pg_rewrite r\n"
! "WHERE r.ev_class = '%s' AND r.rulename <> '_RETURN' ORDER BY 1",
! oid);
! }
! else if (pset.sversion >= 80300)
{
printfPQExpBuffer(&buf,
"SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true)), "
***************
*** 2006,2012 ****
}
/* OIDs and options */
! if (verbose)
{
const char *s = _("Has OIDs");
--- 2020,2026 ----
}
/* OIDs and options */
! if (verbose && tableinfo.relkind != 'm')
{
const char *s = _("Has OIDs");
***************
*** 2079,2085 ****
Oid tablespace, const bool newline)
{
/* relkinds for which we support tablespaces */
! if (relkind == 'r' || relkind == 'i')
{
/*
* We ignore the database default tablespace so that users not using
--- 2093,2099 ----
Oid tablespace, const bool newline)
{
/* relkinds for which we support tablespaces */
! if (relkind == 'r' || relkind == 'i' || relkind == 'm')
{
/*
* We ignore the database default tablespace so that users not using
***************
*** 2339,2344 ****
--- 2353,2359 ----
* t - tables
* i - indexes
* v - views
+ * m - materialized views
* s - sequences
* (any order of the above is fine)
* If tabtypes is empty, we default to \dtvs.
***************
*** 2349,2354 ****
--- 2364,2370 ----
bool showTables = strchr(tabtypes, 't') != NULL;
bool showIndexes = strchr(tabtypes, 'i') != NULL;
bool showViews = strchr(tabtypes, 'v') != NULL;
+ bool showMatViews = strchr(tabtypes, 'm') != NULL;
bool showSeq = strchr(tabtypes, 's') != NULL;
PQExpBufferData buf;
***************
*** 2356,2363 ****
printQueryOpt myopt = pset.popt;
static const bool translate_columns[] = {false, false, true, false, false, false, false};
! if (!(showTables || showIndexes || showViews || showSeq))
! showTables = showViews = showSeq = true;
initPQExpBuffer(&buf);
--- 2372,2379 ----
printQueryOpt myopt = pset.popt;
static const bool translate_columns[] = {false, false, true, false, false, false, false};
! if (!(showTables || showIndexes || showViews || showMatViews || showSeq))
! showTables = showViews = showMatViews = showSeq = true;
initPQExpBuffer(&buf);
***************
*** 2368,2379 ****
printfPQExpBuffer(&buf,
"SELECT n.nspname as \"%s\",\n"
" c.relname as \"%s\",\n"
! " CASE c.relkind WHEN 'r' THEN '%s' WHEN 'v' THEN '%s' WHEN 'i' THEN '%s' WHEN 'S' THEN '%s' WHEN 's' THEN '%s' END as \"%s\",\n"
" pg_catalog.pg_get_userbyid(c.relowner) as \"%s\"",
gettext_noop("Schema"),
gettext_noop("Name"),
gettext_noop("table"),
gettext_noop("view"),
gettext_noop("index"),
gettext_noop("sequence"),
gettext_noop("special"),
--- 2384,2396 ----
printfPQExpBuffer(&buf,
"SELECT n.nspname as \"%s\",\n"
" c.relname as \"%s\",\n"
! " CASE c.relkind WHEN 'r' THEN '%s' WHEN 'v' THEN '%s' WHEN 'm' THEN '%s' WHEN 'i' THEN '%s' WHEN 'S' THEN '%s' WHEN 's' THEN '%s' END as \"%s\",\n"
" pg_catalog.pg_get_userbyid(c.relowner) as \"%s\"",
gettext_noop("Schema"),
gettext_noop("Name"),
gettext_noop("table"),
gettext_noop("view"),
+ gettext_noop("materialized view"),
gettext_noop("index"),
gettext_noop("sequence"),
gettext_noop("special"),
***************
*** 2407,2412 ****
--- 2424,2431 ----
appendPQExpBuffer(&buf, "'r',");
if (showViews)
appendPQExpBuffer(&buf, "'v',");
+ if (showMatViews)
+ appendPQExpBuffer(&buf, "'m',");
if (showIndexes)
appendPQExpBuffer(&buf, "'i',");
if (showSeq)
*** ./src/bin/psql/help.c.orig 2010-07-06 10:43:17.000000000 +0200
--- ./src/bin/psql/help.c 2010-07-08 15:22:15.000000000 +0200
***************
*** 194,200 ****
fprintf(output, _("Informational\n"));
fprintf(output, _(" (options: S = show system objects, + = additional detail)\n"));
! fprintf(output, _(" \\d[S+] list tables, views, and sequences\n"));
fprintf(output, _(" \\d[S+] NAME describe table, view, sequence, or index\n"));
fprintf(output, _(" \\da[S] [PATTERN] list aggregates\n"));
fprintf(output, _(" \\db[+] [PATTERN] list tablespaces\n"));
--- 194,200 ----
fprintf(output, _("Informational\n"));
fprintf(output, _(" (options: S = show system objects, + = additional detail)\n"));
! fprintf(output, _(" \\d[S+] list tables, views, materialized views, and sequences\n"));
fprintf(output, _(" \\d[S+] NAME describe table, view, sequence, or index\n"));
fprintf(output, _(" \\da[S] [PATTERN] list aggregates\n"));
fprintf(output, _(" \\db[+] [PATTERN] list tablespaces\n"));
***************
*** 223,228 ****
--- 223,229 ----
fprintf(output, _(" \\dT[S+] [PATTERN] list data types\n"));
fprintf(output, _(" \\du[+] [PATTERN] list roles (users)\n"));
fprintf(output, _(" \\dv[S+] [PATTERN] list views\n"));
+ fprintf(output, _(" \\dm[S+] [PATTERN] list materialized views\n"));
fprintf(output, _(" \\l[+] list all databases\n"));
fprintf(output, _(" \\z [PATTERN] same as \\dp\n"));
fprintf(output, "\n");
*** ./src/include/catalog/pg_class.h.orig 2010-07-08 20:32:53.000000000 +0200
--- ./src/include/catalog/pg_class.h 2010-07-08 15:22:15.000000000 +0200
***************
*** 147,152 ****
--- 147,153 ----
#define RELKIND_UNCATALOGED 'u' /* temporary heap */
#define RELKIND_TOASTVALUE 't' /* moved off huge values */
#define RELKIND_VIEW 'v' /* view */
+ #define RELKIND_MATVIEW 'm' /* materialized view */
#define RELKIND_COMPOSITE_TYPE 'c' /* composite type */
#endif /* PG_CLASS_H */
*** ./src/include/nodes/nodes.h.orig 2010-07-08 20:32:54.000000000 +0200
--- ./src/include/nodes/nodes.h 2010-07-08 15:22:15.000000000 +0200
***************
*** 512,517 ****
--- 512,518 ----
CMD_DELETE,
CMD_UTILITY, /* cmds like create, destroy, copy, vacuum,
* etc. */
+ CMD_REFRESH, /* refreshing tables, like materialized views */
CMD_NOTHING /* dummy command for instead nothing rules
* with qual */
} CmdType;
*** ./src/include/nodes/parsenodes.h.orig 2010-07-08 20:32:54.000000000 +0200
--- ./src/include/nodes/parsenodes.h 2010-07-08 15:22:15.000000000 +0200
***************
*** 1055,1060 ****
--- 1055,1061 ----
OBJECT_INDEX,
OBJECT_LANGUAGE,
OBJECT_LARGEOBJECT,
+ OBJECT_MATVIEW,
OBJECT_OPCLASS,
OBJECT_OPERATOR,
OBJECT_OPFAMILY,
***************
*** 1150,1156 ****
AT_EnableReplicaRule, /* ENABLE REPLICA RULE name */
AT_DisableRule, /* DISABLE RULE name */
AT_AddInherit, /* INHERIT parent */
! AT_DropInherit /* NO INHERIT parent */
} AlterTableType;
typedef struct AlterTableCmd /* one subcommand of an ALTER TABLE */
--- 1151,1158 ----
AT_EnableReplicaRule, /* ENABLE REPLICA RULE name */
AT_DisableRule, /* DISABLE RULE name */
AT_AddInherit, /* INHERIT parent */
! AT_DropInherit, /* NO INHERIT parent */
! AT_Refresh /* alter materialized view REFRESH */
} AlterTableType;
typedef struct AlterTableCmd /* one subcommand of an ALTER TABLE */
***************
*** 2181,2186 ****
--- 2183,2189 ----
List *aliases; /* target column names */
Node *query; /* the SELECT query */
bool replace; /* replace an existing view? */
+ bool ismaterialized; /* materialize view? */
} ViewStmt;
/* ----------------------
*** ./src/include/nodes/primnodes.h.orig 2010-07-08 20:32:54.000000000 +0200
--- ./src/include/nodes/primnodes.h 2010-07-08 15:22:15.000000000 +0200
***************
*** 91,96 ****
--- 91,97 ----
List *options; /* options from WITH clause */
OnCommitAction onCommit; /* what do we do at COMMIT? */
char *tableSpaceName; /* table space to use, or NULL */
+ bool isrefresh; /* refreshing table? */
} IntoClause;
*** ./src/include/parser/kwlist.h.orig 2010-07-08 20:32:54.000000000 +0200
--- ./src/include/parser/kwlist.h 2010-07-08 15:22:15.000000000 +0200
***************
*** 229,234 ****
--- 229,235 ----
PG_KEYWORD("login", LOGIN_P, UNRESERVED_KEYWORD)
PG_KEYWORD("mapping", MAPPING, UNRESERVED_KEYWORD)
PG_KEYWORD("match", MATCH, UNRESERVED_KEYWORD)
+ PG_KEYWORD("materialized", MATERIALIZED, RESERVED_KEYWORD)
PG_KEYWORD("maxvalue", MAXVALUE, UNRESERVED_KEYWORD)
PG_KEYWORD("minute", MINUTE_P, UNRESERVED_KEYWORD)
PG_KEYWORD("minvalue", MINVALUE, UNRESERVED_KEYWORD)
***************
*** 302,307 ****
--- 303,309 ----
PG_KEYWORD("recheck", RECHECK, UNRESERVED_KEYWORD)
PG_KEYWORD("recursive", RECURSIVE, UNRESERVED_KEYWORD)
PG_KEYWORD("references", REFERENCES, RESERVED_KEYWORD)
+ PG_KEYWORD("refresh", REFRESH, UNRESERVED_KEYWORD)
PG_KEYWORD("reindex", REINDEX, UNRESERVED_KEYWORD)
PG_KEYWORD("relative", RELATIVE_P, UNRESERVED_KEYWORD)
PG_KEYWORD("release", RELEASE, UNRESERVED_KEYWORD)