diff --git a/src/backend/commands/createas.c b/src/backend/commands/createas.c
index 5a853c4..3336061 100644
--- a/src/backend/commands/createas.c
+++ b/src/backend/commands/createas.c
@@ -36,6 +36,8 @@
 #include "commands/tablecmds.h"
 #include "commands/view.h"
 #include "miscadmin.h"
+#include "nodes/makefuncs.h"
+#include "nodes/nodeFuncs.h"
 #include "parser/parse_clause.h"
 #include "rewrite/rewriteHandler.h"
 #include "storage/smgr.h"
@@ -65,6 +67,126 @@ static void intorel_startup(DestReceiver *self, int operation, TupleDesc typeinf
 static bool intorel_receive(TupleTableSlot *slot, DestReceiver *self);
 static void intorel_shutdown(DestReceiver *self);
 static void intorel_destroy(DestReceiver *self);
+static void CreateMatView(Query *query, IntoClause *into);
+
+/*
+ * CreateMatView
+ *
+ * Create materialized view using the rewritten query tree and an INTO clause
+ * defined via CREATE TABLE AS.
+ * XXX: rework that.
+ */
+static void
+CreateMatView(Query *query, IntoClause *into)
+{
+	CreateStmt *createStmt = makeNode(CreateStmt);
+	List	   *tlist = query->targetList;
+	List	   *attrList;
+	ListCell   *t, *lc;
+	Datum		toast_options;
+	static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
+
+	/* Build list of attributes */
+	attrList = NIL;
+	lc = list_head(into->colNames);
+	foreach(t, tlist)
+	{
+		TargetEntry *tle = lfirst(t);
+
+		if (!tle->resjunk)
+		{
+			ColumnDef  *def = makeNode(ColumnDef);
+
+			if (lc)
+			{
+				def->colname = strVal(lfirst(lc));
+				lc = lnext(lc);
+			}
+			else
+				def->colname = pstrdup(tle->resname);
+
+			def->typeName = makeTypeNameFromOid(exprType((Node *) tle->expr),
+												exprTypmod((Node *) tle->expr));
+			def->inhcount = 0;
+			def->is_local = true;
+			def->is_not_null = false;
+			def->is_from_type = false;
+			def->storage = 0;
+			def->raw_default = NULL;
+			def->cooked_default = NULL;
+			def->collClause = NULL;
+			def->collOid = exprCollation((Node *) tle->expr);
+			def->location = -1;
+
+			/*
+			 * It's possible that the column is of a collatable type but the
+			 * collation could not be resolved, so double-check.
+			 */
+			if (type_is_collatable(exprType((Node *) tle->expr)))
+			{
+				if (!OidIsValid(def->collOid))
+					ereport(ERROR,
+							(errcode(ERRCODE_INDETERMINATE_COLLATION),
+							 errmsg("could not determine which collation to use for view column \"%s\"",
+									def->colname),
+							 errhint("Use the COLLATE clause to set the collation explicitly.")));
+			}
+			else
+				Assert(!OidIsValid(def->collOid));
+			def->constraints = NIL;
+
+			attrList = lappend(attrList, def);
+		}
+	}
+
+	if (lc != NULL)
+		ereport(ERROR,
+				(errcode(ERRCODE_SYNTAX_ERROR),
+				 errmsg("too many column names were specified")));
+
+	/*
+	 * Options for materialized views.
+	 */
+	createStmt->relation = into->rel;
+	createStmt->tableElts = attrList;
+	createStmt->inhRelations = NIL;
+	createStmt->constraints = NIL;
+	createStmt->options = into->options;
+	createStmt->oncommit = into->onCommit;
+	createStmt->tablespacename = into->tableSpaceName;
+	createStmt->if_not_exists = false;
+
+	/*
+	 * finally create the relation (this will error out if there's an
+	 * existing view, so we don't need more code to complain if "replace"
+	 * is false).
+	 */
+	CreateAsReladdr = DefineRelation(createStmt, RELKIND_MATVIEW, InvalidOid, NULL);
+
+	/*
+	 * If necessary, create a TOAST table for the target table.  Note that
+	 * NewRelationCreateToastTable ends with CommandCounterIncrement(), so
+	 * that the TOAST table will be visible for insertion.
+	 */
+	CommandCounterIncrement();
+
+	/* parse and validate reloptions for the toast table */
+	toast_options = transformRelOptions((Datum) 0,
+										createStmt->options,
+										"toast",
+										validnsps,
+										true, false);
+
+	(void) heap_reloptions(RELKIND_TOASTVALUE, toast_options, true);
+
+	NewRelationCreateToastTable(CreateAsReladdr.objectId, toast_options);
+
+	/* Create the "view" part of a materialized view. */
+	StoreViewQuery(CreateAsReladdr.objectId,
+				   (Query *) copyObject(into->viewQuery),
+				   false);
+	CommandCounterIncrement();
+}
 
 
 /*
@@ -161,6 +283,17 @@ ExecCreateTableAs(CreateTableAsStmt *stmt, const char *queryString,
 	query = (Query *) linitial(rewritten);
 	Assert(query->commandType == CMD_SELECT);
 
+	/*
+	 * For a materialized view with no data defined, there is no need to
+	 * go through the parser and the executor. Just define the relation
+	 * with everything it needs and leave.
+	 */
+	if (is_matview && into->skipData)
+	{
+		CreateMatView(query, into);
+		goto finish;
+	}
+
 	/* plan the query */
 	plan = pg_plan_query(query, 0, params);
 
@@ -207,6 +340,8 @@ ExecCreateTableAs(CreateTableAsStmt *stmt, const char *queryString,
 
 	PopActiveSnapshot();
 
+finish:
+
 	if (is_matview)
 	{
 		/* Roll back any GUC changes */
