list_free(indexoidlist); if (!hasUniqueIndex) ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("cannot refresh materialized view \"%s\" concurrently", quote_qualified_identifier(get_namespace_name(RelationGetNamespace(matviewRel)), RelationGetRelationName(matviewRel))), errhint("Create a unique index with no WHERE clause on one or more columns of the materialized view."))); } /* * The stored query was rewritten at the time of the MV definition, but * has not been scribbled on by the planner. */ dataQuery = linitial_node(Query, actions); /* * Check for active uses of the relation in the current transaction, such * as open scans. * * NB: We count on this to protect us against problems with refreshing the * data using HEAP_INSERT_FROZEN. */ CheckTableNotInUse(matviewRel, "REFRESH MATERIALIZED VIEW"); /* * Tentatively mark the matview as populated or not (this will roll back * if we fail later). */ SetMatViewPopulatedState(matviewRel, !stmt->skipData);
/* * InsertRule - * takes the arguments and inserts them as a row into the system * relation "pg_rewrite" */ static Oid InsertRule(const char *rulname, int evtype, Oid eventrel_oid, bool evinstead, Node *event_qual, List *action, bool replace) { char *evqual = nodeToString(event_qual); char *actiontree = nodeToString((Node *) action); Datum values[Natts_pg_rewrite]; bool nulls[Natts_pg_rewrite]; bool replaces[Natts_pg_rewrite]; NameData rname; Relation pg_rewrite_desc; HeapTuple tup, oldtup; Oid rewriteObjectId; ObjectAddress myself, referenced; bool is_update = false; /* * Set up *nulls and *values arrays */ MemSet(nulls, false, sizeof(nulls)); namestrcpy(&rname, rulname); values[Anum_pg_rewrite_rulename - 1] = NameGetDatum(&rname); values[Anum_pg_rewrite_ev_class - 1] = ObjectIdGetDatum(eventrel_oid); values[Anum_pg_rewrite_ev_type - 1] = CharGetDatum(evtype + '0'); values[Anum_pg_rewrite_ev_enabled - 1] = CharGetDatum(RULE_FIRES_ON_ORIGIN); values[Anum_pg_rewrite_is_instead - 1] = BoolGetDatum(evinstead); values[Anum_pg_rewrite_ev_qual - 1] = CStringGetTextDatum(evqual); values[Anum_pg_rewrite_ev_action - 1] = CStringGetTextDatum(actiontree); /* * Ready to store new pg_rewrite tuple */ pg_rewrite_desc = heap_open(RewriteRelationId, RowExclusiveLock); /* * Check to see if we are replacing an existing tuple */ oldtup = SearchSysCache2(RULERELNAME, ObjectIdGetDatum(eventrel_oid), PointerGetDatum(rulname)); if (HeapTupleIsValid(oldtup)) { if (!replace) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("rule \"%s\" for relation \"%s\" already exists", rulname, get_rel_name(eventrel_oid)))); /* * When replacing, we don't need to replace every attribute */ MemSet(replaces, false, sizeof(replaces)); replaces[Anum_pg_rewrite_ev_type - 1] = true; replaces[Anum_pg_rewrite_is_instead - 1] = true; replaces[Anum_pg_rewrite_ev_qual - 1] = true; replaces[Anum_pg_rewrite_ev_action - 1] = true; tup = heap_modify_tuple(oldtup, RelationGetDescr(pg_rewrite_desc), values, nulls, replaces); CatalogTupleUpdate(pg_rewrite_desc, &tup->t_self, tup); ReleaseSysCache(oldtup); rewriteObjectId = HeapTupleGetOid(tup); is_update = true; } else { tup = heap_form_tuple(pg_rewrite_desc->rd_att, values, nulls); rewriteObjectId = CatalogTupleInsert(pg_rewrite_desc, tup); } heap_freetuple(tup); /* If replacing, get rid of old dependencies and make new ones */ if (is_update) deleteDependencyRecordsFor(RewriteRelationId, rewriteObjectId, false); /* * Install dependency on rule's relation to ensure it will go away on * relation deletion. If the rule is ON SELECT, make the dependency * implicit --- this prevents deleting a view's SELECT rule. Other kinds * of rules can be AUTO. */ myself.classId = RewriteRelationId; myself.objectId = rewriteObjectId; myself.objectSubId = 0; referenced.classId = RelationRelationId; referenced.objectId = eventrel_oid; referenced.objectSubId = 0; recordDependencyOn(&myself, &referenced, (evtype == CMD_SELECT) ? DEPENDENCY_INTERNAL : DEPENDENCY_AUTO); /* * Also install dependencies on objects referenced in action and qual. */ recordDependencyOnExpr(&myself, (Node *) action, NIL, DEPENDENCY_NORMAL); if (event_qual != NULL) { /* Find query containing OLD/NEW rtable entries */ Query *qry = linitial_node(Query, action); qry = getInsertSelectQuery(qry, NULL); recordDependencyOnExpr(&myself, event_qual, qry->rtable, DEPENDENCY_NORMAL); } /* Post creation hook for new rule */ InvokeObjectPostCreateHook(RewriteRelationId, rewriteObjectId, 0); heap_close(pg_rewrite_desc, RowExclusiveLock); return rewriteObjectId; }