diff --git a/src/common/backend/catalog/dependency.cpp b/src/common/backend/catalog/dependency.cpp index 84a4da919a3dd136ca61944076ae280ae162b5ff..a70602bcdec459a304b3738c8645f51401156d4d 100644 --- a/src/common/backend/catalog/dependency.cpp +++ b/src/common/backend/catalog/dependency.cpp @@ -904,6 +904,26 @@ void findDependentObjects(const ObjectAddress* object, int flags, ObjectAddressS add_exact_object_address_extra(object, &extra, targetObjects); } +/* if type is belongs to invalid view, it should not be deleted */ +static bool shouldDeletePgTypeEntry(Oid typeOid, Oid viewOid) +{ + if (!OidIsValid(viewOid)) { + return true; + } + /* array case */ + Oid searchOid = get_element_type(typeOid); + if (!OidIsValid(searchOid)) { + /* record case */ + searchOid = typeOid; + } + + if (get_typ_typrelid(searchOid) == viewOid) { + return false; + } + + return true; +} + /* * reportDependentObjects - report about dependencies, and fail if RESTRICT * @@ -955,11 +975,10 @@ void reportDependentObjects( * In restrict mode, we check targetObjects, remove object entries related to views from targetObjects, * and ensure that no errors are reported due to deleting table fields that have view references. */ - if (behavior == DROP_RESTRICT && - ((origObject != NULL && origObject->objectSubId != 0) || u_sess->attr.attr_sql.dolphin)) { + if (behavior == DROP_RESTRICT && (origObject == NULL || getObjectClass(origObject) == OCLASS_CLASS)) { ObjectAddresses* newTargetObjects = new_object_addresses(); const ObjectAddress* originalObj = NULL; - const int typeOidOffset = 2; + Oid viewOid = InvalidOid; for (i = targetObjects->numrefs - 1; i >= 0; i--) { const ObjectAddress* obj = &targetObjects->refs[i]; const ObjectAddressExtra* extra = &targetObjects->extras[i]; @@ -972,16 +991,16 @@ void reportDependentObjects( if (objClass == OCLASS_CLASS && obj == originalObj) { add_exact_object_address_extra(obj, extra, newTargetObjects); } else if (objClass == OCLASS_CLASS && (relkind == RELKIND_VIEW || relkind == RELKIND_MATVIEW)) { + viewOid = obj->objectId; SetPgObjectValid(obj->objectId, relkind == RELKIND_VIEW ? OBJECT_TYPE_VIEW : OBJECT_TYPE_MATVIEW, false); - } else if (objClass == OCLASS_TYPE && originalObj != NULL && - ((originalObj->objectId + 1) == obj->objectId || - (originalObj->objectId + typeOidOffset) == obj->objectId)) { - // delete pg_type entry - add_exact_object_address_extra(obj, extra, newTargetObjects); + } else if (objClass == OCLASS_TYPE && originalObj != NULL) { + if (shouldDeletePgTypeEntry(obj->objectId, viewOid)) { + // delete pg_type entry + add_exact_object_address_extra(obj, extra, newTargetObjects); + } } else if (objClass != OCLASS_REWRITE || - (u_sess->attr.attr_sql.dolphin && - originalObj != NULL && extra->dependee.objectId == originalObj->objectId)) { + (originalObj != NULL && extra->dependee.objectId == originalObj->objectId)) { // delete constraint and so on add_exact_object_address_extra(obj, extra, newTargetObjects); } diff --git a/src/common/backend/parser/parse_relation.cpp b/src/common/backend/parser/parse_relation.cpp index a35a731502e76dc8ed3c8faae233ceada12a4bcf..cc730a9c2712d5f26ce44db3400996be92b5969a 100755 --- a/src/common/backend/parser/parse_relation.cpp +++ b/src/common/backend/parser/parse_relation.cpp @@ -64,6 +64,7 @@ #ifdef ENABLE_MOT #include "storage/mot/jit_def.h" #endif +#include "rewrite/rewriteManip.h" #define MAXSTRLEN ((1 << 11) - 1) static RangeTblEntry* scanNameSpaceForRefname(ParseState* pstate, const char* refname, int location); @@ -76,6 +77,7 @@ static void expandTupleDesc(TupleDesc tupdesc, Alias* eref, int rtindex, int sub static void setRteOrientation(Relation rel, RangeTblEntry* rte); static int32* getValuesTypmods(RangeTblEntry* rte); static IndexHintType preCheckIndexHints(ParseState* pstate, List* indexhints, Relation relation); +static void change_var_attno(Query* query, Oid rel_oid, int oldAttnum, int newAttnum); #ifndef PGXC static int specialAttNum(const char* attname); @@ -984,56 +986,259 @@ static void buildScalarFunctionAlias(Node* funcexpr, char* funcname, Alias* alia eref->colnames = list_make1(makeString(eref->aliasname)); } -static void CopyAttributeInfo(Form_pg_attribute newtuple, Form_pg_attribute oldtuple) -{ - newtuple->attnum = oldtuple->attnum; - newtuple->atttypid = oldtuple->atttypid; - newtuple->attlen = oldtuple->attlen; - newtuple->atttypmod = oldtuple->atttypmod; - // for matview - newtuple->attcollation = oldtuple->attcollation; - newtuple->attbyval = oldtuple->attbyval; - newtuple->attstorage = oldtuple->attstorage; -} - -static void CheckViewColumnExists(Oid view_oid, int2 attnum, Form_pg_attribute newtuple) +static void CheckViewColumnExists(Oid view_oid, int2 attnum) { HeapTuple tuple; - Form_pg_attribute form_attribute; tuple = SearchSysCache2(ATTNUM, ObjectIdGetDatum(view_oid), Int16GetDatum(attnum)); if (!HeapTupleIsValid(tuple)) { elog(ERROR, "catalog lookup failed for column %d of relation %u", attnum, view_oid); } - form_attribute = (Form_pg_attribute)GETSTRUCT(tuple); - CopyAttributeInfo(newtuple, form_attribute); ReleaseSysCache(tuple); } -static bool CheckRelationColumnExists(Oid rel_oid, int2 attnum, Form_pg_attribute attrtuple) +static bool CheckPartitionList(List *partList, List *rtePartNameList, List *rtePartOidList) +{ + ListCell *nameCell = NULL; + ListCell *oidCell = NULL; + bool result = true; + forboth (nameCell, rtePartNameList, oidCell, rtePartOidList) { + char *partitionName = strVal(lfirst(nameCell)); + Oid rtePartOid = lfirst_oid(oidCell); + ListCell *cell = NULL; + bool hasPartName = false; + foreach (cell, partList) { + Partition partition = (Partition)lfirst(cell); + if (strcmp(partition->pd_part->relname.data, partitionName) == 0) { + hasPartName = true; + if (rtePartOid != partition->pd_id) { + lfirst_oid(oidCell) = partition->pd_id; + } + break; + } + } + if (!hasPartName) { + result = false; + break; + } + } + return result; +} + +static bool CheckPartitionRelation(RangeTblEntry *rte, Oid relationOid) +{ + List *subpartitionList = NIL; + List *partitionList = NIL; + bool hasSubpartName = false; + bool hasPartName = false; + bool result = false; + + Relation rel = relation_open(relationOid, AccessShareLock); + if (rte->isContainSubPartition) { + subpartitionList = RelationGetSubPartitionList(rel, AccessShareLock); + hasSubpartName = CheckPartitionList(subpartitionList, rte->subpartitionNameList, rte->subpartitionOidList); + releasePartitionList(rel, &subpartitionList, AccessShareLock); + } + partitionList = relationGetPartitionList(rel, AccessShareLock); + hasPartName = CheckPartitionList(partitionList, rte->partitionNameList, rte->partitionOidList); + releasePartitionList(rel, &partitionList, AccessShareLock); + relation_close(rel, AccessShareLock); + + if ((rte->isContainPartition && hasPartName) || + (rte->isContainSubPartition && hasSubpartName && hasPartName)) { + result = true; + } + + return result; +} + +/* + * try to get new relation oid by namespace and relname, replace the old ones + * in query and update pg_depend. + */ +static bool CheckRTable(Query *query, Oid rel_oid, Oid rewrite_oid) +{ + ListCell *lc = NULL; + foreach(lc, query->rtable) { + RangeTblEntry *rte = (RangeTblEntry *)lfirst(lc); + if (rte == NULL) { + return false; + } + /* only process RTE_RELATION */ + if (rte->relid == rel_oid || rte->rtekind != RTE_RELATION) { + continue; + } + if (rte->relname == NULL || rte->relnamespace == NULL) { + return false; + } + Oid namespace_oid = get_namespace_oid(rte->relnamespace, true); + if (!OidIsValid(namespace_oid)) { + return false; + } + + Oid newRelOid = get_relname_relid(rte->relname, namespace_oid); + if (!OidIsValid(newRelOid)) { + return false; + } + Oid oldRefId = rte->relid; + if (oldRefId == newRelOid) { + continue; + } + + /* pg_depend update refobjid to newRelOid */ + rte->relid = newRelOid; + HeapTuple dependTup = NULL; + Relation dependRel = heap_open(DependRelationId, RowExclusiveLock); + const int keyNum = 2; + ScanKeyData key[keyNum]; + SysScanDesc scan = NULL; + ScanKeyInit(&key[0], Anum_pg_depend_classid, BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(RewriteRelationId)); + ScanKeyInit(&key[1], Anum_pg_depend_objid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(rewrite_oid)); + List* toBeUpdatedTups = NIL; + ListCell* lc1 = NULL; + + scan = systable_beginscan(dependRel, DependDependerIndexId, true, NULL, keyNum, key); + while (HeapTupleIsValid(dependTup = systable_getnext(scan))) { + Form_pg_depend dep_form = (Form_pg_depend)GETSTRUCT(dependTup); + if (dep_form->refobjid == oldRefId) { + toBeUpdatedTups = lappend(toBeUpdatedTups, heapCopyTuple(dependTup, dependRel->rd_att, NULL)); + } + } + + foreach (lc1, toBeUpdatedTups) { + HeapTuple tuple = (HeapTuple)lfirst(lc1); + Datum values[Natts_pg_depend] = { 0 }; + bool nulls[Natts_pg_depend] = { 0 }; + bool replaces[Natts_pg_depend] = { 0 }; + + values[Anum_pg_depend_refobjid - 1] = ObjectIdGetDatum(newRelOid); + replaces[Anum_pg_depend_refobjid - 1] = true; + + HeapTuple new_dep_tuple = heap_modify_tuple(tuple, RelationGetDescr(dependRel), values, nulls, replaces); + simple_heap_update(dependRel, &new_dep_tuple->t_self, new_dep_tuple); + CatalogUpdateIndexes(dependRel, new_dep_tuple); + CommandCounterIncrement(); + + heap_freetuple_ext(new_dep_tuple); + } + + list_free_deep(toBeUpdatedTups); + + systable_endscan(scan); + heap_close(dependRel, RowExclusiveLock); + + if ((rte->isContainPartition || rte->isContainSubPartition) && !CheckPartitionRelation(rte, newRelOid)) { + return false; + } + } + return true; +} + +typedef struct change_relid_in_rtable_context { + Oid rel_oid; + Oid rewrite_oid; + bool allExist; +} change_relid_in_rtable_context; + +bool change_relid_in_rtable_walker(Node* node, change_relid_in_rtable_context* context) +{ + if (node == NULL) { + return false; + } + if (IsA(node, Query)) { + Query* qry = (Query*)node; + + if (!CheckRTable(qry, context->rel_oid, context->rewrite_oid)) { + /* if there is one rte not exist, abort directly. */ + context->allExist = false; + return true; + } + + return query_tree_walker(qry, (bool (*)())change_relid_in_rtable_walker, context, 0); + } + return expression_tree_walker(node, (bool (*)())change_relid_in_rtable_walker, (void*)context); +} + +/* + * walk through whole query to search all rtables, which some maybe + * hang on a subquery + */ +static bool CheckViewRelation(Oid rel_oid, Oid rewrite_oid, Query* query) +{ + change_relid_in_rtable_context context; + context.rel_oid = rel_oid; + context.rewrite_oid = rewrite_oid; + context.allExist = true; + + change_relid_in_rtable_walker((Node*)query, &context); + + return context.allExist; +} + +typedef struct search_rte_context { + Oid rel_oid; + int2 attnum; + char* attname; +} search_rte_context; + +bool search_rte_walker(Node* node, search_rte_context* context) { + if (node == NULL) { + return false; + } + if (IsA(node, Query)) { + ListCell* lc = NULL; + Query* query = (Query*)node; + foreach (lc, query->rtable) { + RangeTblEntry *rte = (RangeTblEntry *)lfirst(lc); + if (rte->relid == context->rel_oid) { + context->attname = strVal(list_nth(rte->eref->colnames, context->attnum - 1)); + return false; + } + } + + return query_tree_walker(query, (bool (*)())search_rte_walker, context, 0); + } + return expression_tree_walker(node, (bool (*)())search_rte_walker, (void*)context); +} + +/* + * find rte byu walking through all rtables of query and its sublevel query, + * and return colname. + */ +static char* get_attname_from_rte(Query* query, Oid rel_oid, int2 attnum) +{ + search_rte_context context; + context.rel_oid = rel_oid; + context.attnum = attnum; + + (void)search_rte_walker((Node*)query, &context); + return context.attname; +} + +/* return true column if exists, and set newAttnum. */ +static bool CheckRelationColumnExists(Oid rel_oid, int2 attnum, Query* query, int2* newAttnum) +{ + /* get origin attname from rte->eref->colnames of query */ + char* attname = get_attname_from_rte(query, rel_oid, attnum); + HeapTuple tuple; Form_pg_attribute attForm; - tuple = SearchSysCache2(ATTNUM, ObjectIdGetDatum(rel_oid), Int16GetDatum(attnum)); + tuple = SearchSysCache2(ATTNAME, ObjectIdGetDatum(rel_oid), CStringGetDatum(attname)); if (!HeapTupleIsValid(tuple)) { - elog(ERROR, "catalog lookup failed for column %d of relation %u", attnum, rel_oid); + /* if attname not found, use the attnum. */ + tuple = SearchSysCache2(ATTNUM, ObjectIdGetDatum(rel_oid), Int16GetDatum(attnum)); + if (!HeapTupleIsValid(tuple)) { + return false; + } } attForm = (Form_pg_attribute)GETSTRUCT(tuple); - if (!attForm->attisdropped) { - CopyAttributeInfo(attrtuple, attForm); + if (attForm->attisdropped) { ReleaseSysCache(tuple); - return true; - } - const char* droppedname = attForm->attdroppedname.data; - HeapTuple tuple_drop; - Form_pg_attribute attForm_drop; - tuple_drop = SearchSysCache2(ATTNAME, ObjectIdGetDatum(rel_oid), CStringGetDatum(droppedname)); - ReleaseSysCache(tuple); - if (!HeapTupleIsValid(tuple_drop)) { return false; } - attForm_drop = (Form_pg_attribute)GETSTRUCT(tuple_drop); - CopyAttributeInfo(attrtuple, attForm_drop); - ReleaseSysCache(tuple_drop); + *newAttnum = attForm->attnum; + ReleaseSysCache(tuple); return true; } @@ -1076,8 +1281,7 @@ static ValidateDependResult ValidateDependView(Oid view_oid, char objType, List* Oid rw_objid = InvalidOid; Oid type_id = InvalidOid; List* originEvAction = NIL; - List* freshedEvAction = NIL; - // 1. filter the valid view + /* 1. filter the valid view */ if (!force && GetPgObjectValid(view_oid, objType)) { return ValidateDependValid; } @@ -1087,7 +1291,7 @@ static ValidateDependResult ValidateDependView(Oid view_oid, char objType, List* return ValidateDependCircularDepend; } *list = lappend_oid(*list, view_oid); - // 2. find pg_rewrite/pg_type entry which depend on this view internally + /* 2. find pg_rewrite/pg_type entry which depend on this view internally */ const int keyNum = 2; ScanKeyData key[keyNum]; SysScanDesc scan = NULL; @@ -1110,8 +1314,22 @@ static ValidateDependResult ValidateDependView(Oid view_oid, char objType, List* if (!OidIsValid(rw_objid)) { elog(ERROR, "cannot find the internal dependent pg_rewrite entry."); } - // 3.1 find all columns of parent views and tables which this view depends on directly, - // and check their validity recursively. + /* get origin query from ev_action, and we will make some changes on it later */ + originEvAction = GetOriginalViewQuery(rw_objid); + Query *query = (Query*)linitial(originEvAction); + /* + * 3.1 check relation if exist, if not, try to correct it. + * Table on which the view depends maybe rebuilt, so relid of them in view-query + * are invalid, and we need to set the new ones. If table not be rebuilt, view cannot + * be restore, return directly. + */ + if (!CheckViewRelation(view_oid, rw_objid, query)) { + return ValidateDependInvalid; + } + /* + * 3.2 find all columns of parent views and tables which this view depends on directly, + * and check their validity recursively. + */ List *query_str = NIL; ScanKeyData key_dep[keyNum]; SysScanDesc scan_dep = NULL; @@ -1121,9 +1339,7 @@ static ValidateDependResult ValidateDependView(Oid view_oid, char objType, List* ObjectIdGetDatum(RewriteRelationId)); ScanKeyInit(&key_dep[1], Anum_pg_depend_objid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(rw_objid)); scan_dep = systable_beginscan(rel_dep, DependDependerIndexId, true, NULL, keyNum, key_dep); - Form_pg_attribute newtuple = (Form_pg_attribute)palloc0(sizeof(FormData_pg_attribute)); bool circularDependency = false; - bool is_changed = false; while (HeapTupleIsValid((tup_dep = systable_getnext(scan_dep)))) { Form_pg_depend depform = (Form_pg_depend)GETSTRUCT(tup_dep); if (depform->refclassid != RelationRelationId || depform->deptype != DEPENDENCY_NORMAL || @@ -1133,27 +1349,31 @@ static ValidateDependResult ValidateDependView(Oid view_oid, char objType, List* Oid dep_objid = depform->refobjid; int2 dep_objsubid = depform->refobjsubid; char relkind = get_rel_relkind(dep_objid); - char* attName = NULL; + int2 newAttnum = 0; if (relkind == RELKIND_RELATION) { - // the column exists, and its type may have changed or it mat have been deleted and recreated - isValid &= CheckRelationColumnExists(dep_objid, dep_objsubid, newtuple); - if (newtuple->attnum > 0) { - // change pg_depend - if (newtuple->attnum != dep_objsubid) { + /* + * the column exists, but it may have been deleted and recreated, and its + * type and attnum may have changed, so try to get the new attnum. + */ + isValid &= CheckRelationColumnExists(dep_objid, dep_objsubid, query, &newAttnum); + if (newAttnum > 0) { + /* if newAttnum is not equal to refobjsubid, update it. */ + if (newAttnum != dep_objsubid) { Datum values[Natts_pg_depend] = { 0 }; bool nulls[Natts_pg_depend] = { 0 }; bool replaces[Natts_pg_depend] = { 0 }; HeapTuple new_dep_tuple; - values[Anum_pg_depend_refobjsubid - 1] = Int32GetDatum(newtuple->attnum); + values[Anum_pg_depend_refobjsubid - 1] = Int32GetDatum(newAttnum); replaces[Anum_pg_depend_refobjsubid - 1] = true; new_dep_tuple = heap_modify_tuple(tup_dep, RelationGetDescr(rel_dep), values, nulls, replaces); simple_heap_update(rel_dep, &new_dep_tuple->t_self, new_dep_tuple); CatalogUpdateIndexes(rel_dep, new_dep_tuple); heap_freetuple_ext(new_dep_tuple); CommandCounterIncrement(); + + /* change varattno of vars by the way */ + change_var_attno(query, dep_objid, dep_objsubid, newAttnum); } - is_changed |= UpdateChangedColumnForView(view_oid, dep_objid, dep_objsubid, rw_objid, - &originEvAction, &freshedEvAction, newtuple); } } else if (relkind == RELKIND_VIEW || relkind == RELKIND_MATVIEW) { char type = relkind == RELKIND_VIEW ? OBJECT_TYPE_VIEW : OBJECT_TYPE_MATVIEW; @@ -1167,38 +1387,36 @@ static ValidateDependResult ValidateDependView(Oid view_oid, char objType, List* } isValid &= (result != ValidateDependInvalid); if (isValid) { - // here means dep_objid is valid, we should keep the same view_oid.attr with dep_objid.dep_objsubid - // find dep_objid.dep_objsubid - CheckViewColumnExists(dep_objid, dep_objsubid, newtuple); - is_changed |= UpdateChangedColumnForView(view_oid, dep_objid, dep_objsubid, rw_objid, - &originEvAction, &freshedEvAction, newtuple); + /* + * here means dep_objid is valid, we should keep the same view_oid.attr with dep_objid.dep_objsubid + * find dep_objid.dep_objsubid + */ + CheckViewColumnExists(dep_objid, dep_objsubid); } circularDependency |= (result == ValidateDependCircularDepend); } - errno_t rc = memset_s(newtuple, sizeof(FormData_pg_attribute), 0, sizeof(FormData_pg_attribute)); - securec_check_c(rc, "\0", "\0"); - pfree_ext(attName); if (!isValid) { - pfree_ext(newtuple); systable_endscan(scan_dep); heap_close(rel_dep, RowExclusiveLock); return ValidateDependInvalid; } } - pfree_ext(newtuple); systable_endscan(scan_dep); - // 3.2 find views or tables which depend on this view directly, - // and report error if tables exist. + /* + * 3.3 find views or tables which depend on this view directly, + * and report error if tables exist. + */ existTable = findDependentTable(rel_dep, type_id); if (existTable) { elog(ERROR, "The view is invalid. There is a table dependent on the view so it cannot be recompiled."); } heap_close(rel_dep, RowExclusiveLock); - // 3.3 change pg_rewrite's evAction - if (is_changed) { - UpdatePgrewriteForView(rw_objid, freshedEvAction, &query_str); - } - // 4. mark the current view valid + /* + * 3.4 update pg_attribute for column type of view maybe changed + * and pg_rewrite for ev_action + */ + UpdateAttrAndRewriteForView(view_oid, rw_objid, originEvAction, query, &query_str); + /* 4. mark the current view valid */ if (!circularDependency) { SetPgObjectValid(view_oid, objType, true); } @@ -1234,8 +1452,7 @@ static ValidateDependResult ValidateDependView(Oid view_oid, char objType, List* } ReleaseSysCache(tup); } - list_free(originEvAction); - list_free(freshedEvAction); + list_free_deep(originEvAction); /* 0 or 1 */ return (ValidateDependResult)isValid; } @@ -2780,7 +2997,16 @@ char* get_rte_attribute_name(RangeTblEntry* rte, AttrNumber attnum, bool allowDr * built (which can easily happen for rules). */ if (rte->rtekind == RTE_RELATION) { - return get_relid_attribute_name(rte->relid, attnum, allowDropped); + char* rteRelname = get_rel_name(rte->relid); + + /* If base relation has been dropped, use eref->colnames. */ + if (rteRelname == NULL) { + if (attnum > 0 && attnum <= list_length(rte->eref->colnames)) { + return pstrdup(strVal(list_nth(rte->eref->colnames, attnum - 1))); + } + } else { + return get_relid_attribute_name(rte->relid, attnum, allowDropped); + } } /* @@ -3402,3 +3628,93 @@ err: list_free(indexOidList); return retType; } + +typedef struct change_target_list_attrno_context { + Oid rel_oid; + int oldAttnum; + int newAttnum; + int target_varno; + int sublevels_up; +} change_target_list_attrno_context; + +/* + * return true if we found rte in current query->rtable, and save sequence to context, + * which is the target varno we need to match target Vars. + */ +static bool GetTargetVarno(Query* query, change_target_list_attrno_context* context) +{ + ListCell* lc = NULL; + int targetVarno = 0; + foreach (lc, query->rtable) { + targetVarno++; + RangeTblEntry *rte = (RangeTblEntry *)lfirst(lc); + if (rte->relid == context->rel_oid) { + context->target_varno = targetVarno; + return true; + } + } + return false; +} + +/* + * walk through query, to search vars which match target_varno, sublevels_up and oldAttnum, + * and set newAttnum. + */ +bool change_target_list_attrno_walker(Node* node, change_target_list_attrno_context* context) +{ + if (node == NULL) { + return false; + } + if (IsA(node, Var)) { + Var* var = (Var*)node; + if (var->varno == (unsigned int)(context->target_varno) && + var->varlevelsup == (unsigned int)(context->sublevels_up) && + var->varattno == context->oldAttnum) { + var->varattno = context->newAttnum; + } + return false; + } + if (IsA(node, Query)) { + /* + * We need to search twice because Var may refer to the rtable of upper-level. + * So firstly use upper rtindex and sublevels to match var, and secondly use current-level + * rtindex and sublevels if exists to match var. + */ + context->sublevels_up++; + (void)query_tree_walker((Query*)node, (bool (*)())change_target_list_attrno_walker, context, 0); + context->sublevels_up--; + + /* update target varno of current-level rtables */ + int save_target_varno = context->target_varno; + int save_sublevels_up = context->sublevels_up; + if (GetTargetVarno((Query*)node, context)) { + context->sublevels_up = 0; + (void)query_tree_walker((Query*)node, (bool (*)())change_target_list_attrno_walker, context, 0); + } + /* restore sublevels_up and target_varno */ + context->sublevels_up = save_sublevels_up; + context->target_varno = save_target_varno; + + return false; + } + return expression_tree_walker(node, (bool (*)())change_target_list_attrno_walker, (void*)context); +} + +/* + * correct varattno of vars in query, since it maybe different from the past. + */ +static void change_var_attno(Query* query, Oid rel_oid, int oldAttnum, int newAttnum) +{ + change_target_list_attrno_context context; + context.rel_oid = rel_oid; + context.oldAttnum = oldAttnum; + context.newAttnum = newAttnum; + context.sublevels_up = 0; + context.target_varno = 0; + + /* get sequence of relation in rtable list to match varno of vars later. */ + (void)GetTargetVarno(query, &context); + + (void)query_or_expression_tree_walker( + (Node*)query, (bool (*)())change_target_list_attrno_walker, (void*)&context, 0); +} diff --git a/src/common/backend/utils/adt/ruleutils.cpp b/src/common/backend/utils/adt/ruleutils.cpp index 2defb6b78742cb360f22f97ef1fdb87a907af825..229bbbf35756d45896e9cd1afcacf25c4ebb42b4 100644 --- a/src/common/backend/utils/adt/ruleutils.cpp +++ b/src/common/backend/utils/adt/ruleutils.cpp @@ -48,6 +48,7 @@ #include "catalog/pg_trigger.h" #include "catalog/pg_type.h" #include "catalog/pg_set.h" +#include "catalog/pg_object.h" #include "catalog/heap.h" #include "catalog/gs_encrypted_proc.h" #include "catalog/gs_encrypted_columns.h" @@ -80,6 +81,7 @@ #include "parser/parsetree.h" #include "parser/parse_expr.h" #include "parser/parse_utilcmd.h" +#include "parser/parse_relation.h" #ifdef PGXC #include "pgxc/pgxc.h" #include "optimizer/pgxcplan.h" @@ -166,6 +168,7 @@ typedef struct { bool viewdef; /* just for dump viewdef */ bool is_fqs; /* just for fqs query */ bool is_upsert_clause; /* just for upsert clause */ + bool skip_lock; /* no need to lock relation for invalid view */ } deparse_context; /* @@ -317,8 +320,9 @@ static void get_const_expr(Const* constval, deparse_context* context, int showty static void get_const_collation(Const* constval, deparse_context* context); static void simple_quote_literal(StringInfo buf, const char* val); static void get_sublink_expr(SubLink* sublink, deparse_context* context); -static void get_from_clause(Query* query, const char* prefix, deparse_context* context, List* fromlist = NIL); -static void get_from_clause_item(Node* jtnode, Query* query, deparse_context* context); +static void get_from_clause(Query* query, const char* prefix, deparse_context* context, List* fromlist = NIL, + bool isNeedError = true); +static void get_from_clause_item(Node* jtnode, Query* query, deparse_context* context, bool isNeedError = true); static void get_from_clause_partition(RangeTblEntry* rte, StringInfo buf, deparse_context* context); static void get_from_clause_subpartition(RangeTblEntry* rte, StringInfo buf, deparse_context* context); static void get_from_clause_bucket(RangeTblEntry* rte, StringInfo buf, deparse_context* context); @@ -330,8 +334,8 @@ static void GetTimecapsuleDef(const TimeCapsuleClause* timeCapsule, deparse_cont void get_opclass_name(Oid opclass, Oid actual_datatype, StringInfo buf); static Node* processIndirection(Node* node, deparse_context* context, bool printit); static void printSubscripts(ArrayRef* aref, deparse_context* context); -static char* get_relation_name(Oid relid); -static char* generate_relation_name(Oid relid, List* namespaces); +static char* get_relation_name(Oid relid, bool isNeedError = true); +static char* generate_relation_name(Oid relid, List* namespaces, bool isNeedError = true); static char* generate_function_name( Oid funcid, int nargs, List* argnames, Oid* argtypes, bool was_variadic, bool* use_variadic_p); static char* generate_operator_name(Oid operid, Oid arg1, Oid arg2); @@ -6032,22 +6036,49 @@ static void make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc, i ev_relation = heap_open(ev_class, AccessShareLock); - get_query_def(query, - buf, - NIL, - RelationGetDescr(ev_relation), - prettyFlags, - wrapColumn, - 0 + char relKind = get_rel_relkind(ev_class); + if (ev_class >= FirstNormalObjectId && !GetPgObjectValid(ev_class, relKind)) { + if (!ValidateDependView(ev_class, relKind)) { + ereport(WARNING, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("View %s references invalid table(s), view(s) or column(s).", get_rel_name(ev_class)))); + } + get_query_def(query, + buf, + NIL, + RelationGetDescr(ev_relation), + prettyFlags, + wrapColumn, + 0 #ifdef PGXC - , - false, - false, - NULL + , + false, + false, + NULL #endif /* PGXC */ - , - false, - true); + , + false, + true, + false, + true); + } else { + get_query_def(query, + buf, + NIL, + RelationGetDescr(ev_relation), + prettyFlags, + wrapColumn, + 0 +#ifdef PGXC + , + false, + false, + NULL +#endif /* PGXC */ + , + false, + true); + } appendStringInfo(buf, ";"); heap_close(ev_relation, AccessShareLock); @@ -6152,7 +6183,7 @@ void get_query_def(Query* query, StringInfo buf, List* parentnamespace, TupleDes bool finalise_aggs, bool sortgroup_colno, void* parserArg #endif /* PGXC */ , - bool qrw_phase, bool viewdef, bool is_fqs) + bool qrw_phase, bool viewdef, bool is_fqs, bool skip_lock) { deparse_context context; deparse_namespace dpns; @@ -6168,7 +6199,7 @@ void get_query_def(Query* query, StringInfo buf, List* parentnamespace, TupleDes * querytree!For qrw phase, formal rewrite already add lock on relations, * and we don't want to change query tree again, so skip this. */ - if (!qrw_phase) + if (!qrw_phase && !skip_lock) AcquireRewriteLocks(query, false); context.buf = buf; @@ -6188,6 +6219,7 @@ void get_query_def(Query* query, StringInfo buf, List* parentnamespace, TupleDes context.viewdef = viewdef; context.is_fqs = is_fqs; context.is_upsert_clause = false; + context.skip_lock = skip_lock; errno_t rc = memset_s(&dpns, sizeof(dpns), 0, sizeof(dpns)); securec_check(rc, "", ""); @@ -6351,7 +6383,8 @@ static void get_with_clause(Query* query, deparse_context* context) , context->qrw_phase, context->viewdef, - context->is_fqs); + context->is_fqs, + context->skip_lock); if (PRETTY_INDENT(context)) appendContextKeyword(context, "", 0, 0, 0); appendStringInfoChar(buf, ')'); @@ -6646,7 +6679,7 @@ static void get_basic_select_query(Query* query, deparse_context* context, Tuple get_target_list(query, query->targetList, context, resultDesc); /* Add the FROM clause if needed */ - get_from_clause(query, " FROM ", context); + get_from_clause(query, " FROM ", context, NIL, false); /* Add the WHERE clause if given */ if (query->jointree->quals != NULL) { @@ -6977,7 +7010,8 @@ static void get_setop_query(Node* setOp, Query* query, deparse_context* context, , context->qrw_phase, context->viewdef, - context->is_fqs); + context->is_fqs, + context->skip_lock); } else { if (context->qrw_phase) get_setop_query(subquery->setOperations, subquery, context, resultDesc); @@ -6998,7 +7032,8 @@ static void get_setop_query(Node* setOp, Query* query, deparse_context* context, , context->qrw_phase, context->viewdef, - context->is_fqs); + context->is_fqs, + context->skip_lock); } if (need_paren) @@ -11864,7 +11899,8 @@ static void get_sublink_expr(SubLink* sublink, deparse_context* context) , context->qrw_phase, context->viewdef, - context->is_fqs); + context->is_fqs, + context->skip_lock); set_string_info_right(need_paren, buf); } @@ -11877,7 +11913,8 @@ static void get_sublink_expr(SubLink* sublink, deparse_context* context) * is USING when parsing back DELETE. * ---------- */ -static void get_from_clause(Query* query, const char* prefix, deparse_context* context, List* fromlist) +static void get_from_clause(Query* query, const char* prefix, deparse_context* context, List* fromlist, + bool isNeedError) { StringInfo buf = context->buf; bool first = true; @@ -11906,7 +11943,7 @@ static void get_from_clause(Query* query, const char* prefix, deparse_context* c appendContextKeyword(context, prefix, -PRETTYINDENT_STD, PRETTYINDENT_STD, 2); first = false; - get_from_clause_item(jtnode, query, context); + get_from_clause_item(jtnode, query, context, isNeedError); } else { StringInfoData itembuf; @@ -11919,7 +11956,7 @@ static void get_from_clause(Query* query, const char* prefix, deparse_context* c initStringInfo(&itembuf); context->buf = &itembuf; - get_from_clause_item(jtnode, query, context); + get_from_clause_item(jtnode, query, context, isNeedError); /* Restore context's output buffer */ context->buf = buf; @@ -11989,7 +12026,10 @@ static void get_from_clause_partition(RangeTblEntry* rte, StringInfo buf, depars Oid partitionOid = list_nth_oid(rte->partitionOidList, 0); /* get the newest partition name from oid given */ pfree(rte->pname->aliasname); - rte->pname->aliasname = getPartitionName(partitionOid, false); + rte->pname->aliasname = getPartitionName(partitionOid, true); + if (rte->pname->aliasname == NULL && rte->partitionNameList != NIL) { + rte->pname->aliasname = strVal(list_nth(rte->partitionNameList, 0)); + } appendStringInfo(buf, " PARTITION(%s)", quote_identifier(rte->pname->aliasname)); } } @@ -12017,7 +12057,10 @@ static void get_from_clause_subpartition(RangeTblEntry* rte, StringInfo buf, dep Oid subpartitionOid = list_nth_oid(rte->subpartitionOidList, 0); /* get the newest subpartition name from oid given */ pfree(rte->pname->aliasname); - rte->pname->aliasname = getPartitionName(subpartitionOid, false); + rte->pname->aliasname = getPartitionName(subpartitionOid, true); + if (rte->pname->aliasname == NULL && rte->subpartitionNameList != NIL) { + rte->pname->aliasname = strVal(list_nth(rte->subpartitionNameList, 0)); + } appendStringInfo(buf, " SUBPARTITION(%s)", quote_identifier(rte->pname->aliasname)); } } @@ -12040,13 +12083,31 @@ static void get_delete_from_partition_clause(RangeTblEntry* rte, StringInfo buf) appendStringInfo(buf, " PARTITION ("); + ListCell *partNameCell = list_head(rte->partitionNameList); + ListCell *subpartNameCell = list_head(rte->subpartitionNameList); + char *nameStr = NULL; forboth(partCell, rte->partitionOidList, subpartCell, rte->subpartitionOidList) { partitionOid = lfirst_oid(subpartCell); + if (unlikely(subpartNameCell != NULL)) { + nameStr = strVal(lfirst(subpartNameCell)); + } if (!OidIsValid(partitionOid)) { /* InvalidOid means all subpartitions of this partition, just use partition oid. */ partitionOid = lfirst_oid(partCell); + if (unlikely(partNameCell != NULL)) { + nameStr = strVal(lfirst(partNameCell)); + } + } + name = getPartitionName(partitionOid, true); + if (name == NULL) { + name = nameStr; + } + if (unlikely(partNameCell != NULL)) { + partNameCell = lnext(partNameCell); + } + if (unlikely(subpartNameCell != NULL)) { + subpartNameCell = lnext(subpartNameCell); } - name = getPartitionName(partitionOid, false); if (first) { first = false; } else { @@ -12057,7 +12118,7 @@ static void get_delete_from_partition_clause(RangeTblEntry* rte, StringInfo buf) appendStringInfo(buf, ")"); } -static void get_from_clause_item(Node* jtnode, Query* query, deparse_context* context) +static void get_from_clause_item(Node* jtnode, Query* query, deparse_context* context, bool isNeedError) { StringInfo buf = context->buf; @@ -12075,8 +12136,10 @@ static void get_from_clause_item(Node* jtnode, Query* query, deparse_context* co if (OidIsValid(rte->refSynOid)) { appendStringInfo(buf, "%s%s", only_marker(rte), GetQualifiedSynonymName(rte->refSynOid, true)); } else { + char *relname = generate_relation_name(rte->relid, context->namespaces, isNeedError); appendStringInfo( - buf, "%s%s", only_marker(rte), generate_relation_name(rte->relid, context->namespaces)); + buf, "%s%s", only_marker(rte), relname == NULL ? rte->relname : relname + ); } if (rte->orientation == REL_COL_ORIENTED || rte->orientation == REL_TIMESERIES_ORIENTED) query->vec_output = true; @@ -12100,7 +12163,8 @@ static void get_from_clause_item(Node* jtnode, Query* query, deparse_context* co , context->qrw_phase, context->viewdef, - context->is_fqs); + context->is_fqs, + context->skip_lock); appendStringInfoChar(buf, ')'); break; case RTE_FUNCTION: @@ -12132,10 +12196,13 @@ static void get_from_clause_item(Node* jtnode, Query* query, deparse_context* co get_from_clause_bucket(rte, buf, context); } + char *relname = get_relation_name(rte->relid, isNeedError); + relname = relname == NULL ? rte->relname : relname; + if (rte->alias != NULL) { appendStringInfo(buf, " %s", quote_identifier(rte->alias->aliasname)); gavealias = true; - } else if (rte->rtekind == RTE_RELATION && strcmp(rte->eref->aliasname, get_relation_name(rte->relid)) != 0) { + } else if (rte->rtekind == RTE_RELATION && strcmp(rte->eref->aliasname, relname) != 0) { /* * Apparently the rel has been renamed since the rule was made. * Emit a fake alias clause so that variable references will still @@ -12219,7 +12286,7 @@ static void get_from_clause_item(Node* jtnode, Query* query, deparse_context* co if (!PRETTY_PAREN(context) || j->alias != NULL) appendStringInfoChar(buf, '('); - get_from_clause_item(j->larg, query, context); + get_from_clause_item(j->larg, query, context, isNeedError); if (j->isNatural) { if (!PRETTY_INDENT(context)) @@ -12303,7 +12370,7 @@ static void get_from_clause_item(Node* jtnode, Query* query, deparse_context* co if (need_paren_on_right) appendStringInfoChar(buf, '('); - get_from_clause_item(j->rarg, query, context); + get_from_clause_item(j->rarg, query, context, isNeedError); if (need_paren_on_right) appendStringInfoChar(buf, ')'); @@ -12715,12 +12782,16 @@ char* quote_qualified_identifier(const char* qualifier, const char* ident1, cons * This differs from the underlying get_rel_name() function in that it will * throw error instead of silently returning NULL if the OID is bad. */ -static char* get_relation_name(Oid relid) +static char* get_relation_name(Oid relid, bool isNeedError) { char* relname = get_rel_name(relid); - if (relname == NULL) - ereport(ERROR, (errcode(ERRCODE_CACHE_LOOKUP_FAILED), errmsg("cache lookup failed for relation %u", relid))); + if (relname == NULL) { + if (isNeedError) { + ereport(ERROR, (errcode(ERRCODE_CACHE_LOOKUP_FAILED), + errmsg("cache lookup failed for relation %u", relid))); + } + } return relname; } @@ -12734,7 +12805,7 @@ static char* get_relation_name(Oid relid) * We will forcibly qualify the relation name if it equals any CTE name * visible in the namespace list. */ -static char* generate_relation_name(Oid relid, List* namespaces) +static char* generate_relation_name(Oid relid, List* namespaces, bool isNeedError) { HeapTuple tp; Form_pg_class reltup; @@ -12745,8 +12816,15 @@ static char* generate_relation_name(Oid relid, List* namespaces) char* result = NULL; tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid)); - if (!HeapTupleIsValid(tp)) - ereport(ERROR, (errcode(ERRCODE_CACHE_LOOKUP_FAILED), errmsg("cache lookup failed for relation %u", relid))); + if (!HeapTupleIsValid(tp)) { + if (isNeedError) { + ereport(ERROR, (errcode(ERRCODE_CACHE_LOOKUP_FAILED), + errmsg("cache lookup failed for relation %u", relid))); + } else { + return NULL; + } + } + reltup = (Form_pg_class)GETSTRUCT(tp); relname = NameStr(reltup->relname); diff --git a/src/gausskernel/optimizer/commands/tablecmds.cpp b/src/gausskernel/optimizer/commands/tablecmds.cpp index 0ebc3e7c56cced194c80feb725577201355ea3c8..aca0862124208c79dfd22d9b3f3e58f8d2e0189c 100755 --- a/src/gausskernel/optimizer/commands/tablecmds.cpp +++ b/src/gausskernel/optimizer/commands/tablecmds.cpp @@ -534,7 +534,7 @@ static void UpdatePgPartitionFirstAfter(Relation rel, int startattnum, int endat bool is_modified, bool *hasPartition); static void UpdatePgTriggerFirstAfter(Relation rel, int startattnum, int endattnum, bool is_increase); static void UpdatePgRlspolicyFirstAfter(Relation rel, int startattnum, int endattnum, bool is_increase); -static ViewInfoForAdd *GetViewInfoFirstAfter(const char *rel_name, Oid objid, bool keep_star = false); +static ViewInfoForAdd *GetViewInfoFirstAfter(const char *rel_name, Oid objid, bool keep_star); static void UpdateDependRefobjsubidFirstAfter(Relation rel, Oid myrelid, int curattnum, int newattnum, bool *has_depend); @@ -12671,7 +12671,7 @@ static List *CheckPgRewriteFirstAfter(Relation rel) pre_objid = dep_form->objid; - ViewInfoForAdd *info = GetViewInfoFirstAfter(NameStr(rel->rd_rel->relname), dep_form->objid); + ViewInfoForAdd *info = GetViewInfoFirstAfter(NameStr(rel->rd_rel->relname), dep_form->objid, false); foreach (viewinfo, query_str) { ViewInfoForAdd *oldInfo = (ViewInfoForAdd *)lfirst(viewinfo); @@ -12766,7 +12766,7 @@ static void CheckPgAttribute(Oid obj_oid, char* attName, Form_pg_attribute new_a heap_close(rel, RowExclusiveLock); } -static void UpdatePgAttributeForView(TargetEntry* old_tle, TargetEntry* new_tle, Oid view_oid, Form_pg_attribute att_form) +static void UpdatePgAttributeForView(TargetEntry* old_tle, TargetEntry* new_tle, Oid view_oid) { Node* old_node = (Node*)old_tle->expr; Node* new_node = (Node*)new_tle->expr; @@ -12777,8 +12777,9 @@ static void UpdatePgAttributeForView(TargetEntry* old_tle, TargetEntry* new_tle, int32 old_typmod = exprTypmod(old_node); int32 new_typmod = exprTypmod(new_node); if (old_type != new_type || old_typmod != new_typmod) { - // get from pg_type - HeapTuple tp; + /* get from pg_type */ + HeapTuple tp = NULL; + Form_pg_attribute att_form = (Form_pg_attribute)palloc0(sizeof(FormData_pg_attribute)); tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(new_type)); if (HeapTupleIsValid(tp)) { Form_pg_type typtup = (Form_pg_type)GETSTRUCT(tp); @@ -12793,10 +12794,11 @@ static void UpdatePgAttributeForView(TargetEntry* old_tle, TargetEntry* new_tle, elog(ERROR, "Cannot find the type with oid %u.", new_type); } CheckPgAttribute(view_oid, col_name, att_form); + pfree_ext(att_form); } } -static List* GetOriginalViewQuery(Oid rw_oid) +List* GetOriginalViewQuery(Oid rw_oid) { List *evAction = NIL; ScanKeyData entry; @@ -12833,7 +12835,7 @@ List* GetRefreshedViewQuery(Oid view_oid, Oid rw_oid) elog(ERROR, "Cannot find the view with oid %u.", view_oid); } Form_pg_class reltup = (Form_pg_class)GETSTRUCT(tup); - char* view_def = GetCreateViewCommand(NameStr(reltup->relname), tup, reltup, rw_oid, view_oid); + char* view_def = GetCreateViewCommand(NameStr(reltup->relname), tup, reltup, rw_oid, view_oid, false); List* raw_parsetree_list = raw_parser(view_def); Node* stmtNode = (Node*)linitial(raw_parsetree_list); Assert((IsA(stmtNode, ViewStmt) || IsA(stmtNode, CreateTableAsStmt))); @@ -12868,7 +12870,7 @@ void UpdatePgrewriteForView(Oid rw_oid, List* evAction, List **query_str) SysScanDesc rewrite_scan = systable_beginscan(rewrite_rel, RewriteOidIndexId, true, NULL, 1, &entry); HeapTuple rewrite_tup = systable_getnext(rewrite_scan); Form_pg_rewrite rewrite_form = (Form_pg_rewrite)GETSTRUCT(rewrite_tup); - // update pg_rewrite + /* update pg_rewrite */ char* actiontree = nodeToString((Node*)evAction); Datum values[Natts_pg_rewrite] = { 0 }; bool nulls[Natts_pg_rewrite] = { 0 }; @@ -12882,7 +12884,12 @@ void UpdatePgrewriteForView(Oid rw_oid, List* evAction, List **query_str) CommandCounterIncrement(); heap_freetuple_ext(new_dep_tuple); pfree_ext(actiontree); - // get new_query_str from pg_rewrite + /* get new_query_str from pg_rewrite */ + if (query_str == NULL) { + systable_endscan(rewrite_scan); + heap_close(rewrite_rel, RowExclusiveLock); + return; + } Query* query = (Query*)linitial(evAction); StringInfoData buf; initStringInfo(&buf); @@ -12911,17 +12918,21 @@ void UpdatePgrewriteForView(Oid rw_oid, List* evAction, List **query_str) heap_close(rewrite_rel, RowExclusiveLock); } -bool UpdateChangedColumnForView(Oid viewid, Oid relid, int2 attnum, Oid rw_objid, - List **p_originEvAction, List **p_newEvAction, Form_pg_attribute attForm) +void UpdateAttrAndRewriteForView(Oid viewid, Oid rw_objid, List* originEvAction, Query* query, List **query_str) { - if (*p_originEvAction == NIL) { - *p_originEvAction = GetOriginalViewQuery(rw_objid); - } + List* evAction = NIL; + evAction = lappend(evAction, query); + /* + * update pg_rewrite with correct varattno and relation oid firstly, + * so that GetRefreshedViewQuery which would scan pg_rewrite to get ev_action + * can obtain right view_def. + */ + UpdatePgrewriteForView(rw_objid, evAction, NULL); + + List* newEvAction = NIL; PG_TRY(); { - if (*p_newEvAction == NIL) { - *p_newEvAction = GetRefreshedViewQuery(viewid, rw_objid); - } + newEvAction = GetRefreshedViewQuery(viewid, rw_objid); } PG_CATCH(); { @@ -12932,30 +12943,26 @@ bool UpdateChangedColumnForView(Oid viewid, Oid relid, int2 attnum, Oid rw_objid errhint("Please re-add missing table fields."))); } PG_END_TRY(); - List* originEvAction = *p_originEvAction; - List* newEvAction = *p_newEvAction; - bool is_changed = false; - Query* query = (Query*)linitial(originEvAction); + + Query* origin_query = (Query*)linitial(originEvAction); Query* freshed_query = (Query*)linitial(newEvAction); - ViewQueryCheck_context context; - context.relid = relid; - context.attnum = attnum; - context.query = query; - context.attForm = attForm; - // check whether the querytree's targetEntry has changed, - // and update the pg_attribute entry of the changed column if so + /* + * check whether the querytree's targetEntry has changed, + * and update the pg_attribute entry of the changed column if so + */ ListCell* lc1 = NULL; ListCell* lc2 = NULL; - forboth (lc1, query->targetList, lc2, freshed_query->targetList) { + forboth (lc1, origin_query->targetList, lc2, freshed_query->targetList) { TargetEntry* tle = (TargetEntry*)lfirst(lc1); - bool var_changed = check_changed_tle_walker((Node*)(tle->expr), &context); - if (var_changed) { - TargetEntry* tle2 = (TargetEntry*)lfirst(lc2); - UpdatePgAttributeForView(tle, tle2, viewid, attForm); - } - is_changed |= var_changed; + TargetEntry* tle2 = (TargetEntry*)lfirst(lc2); + + UpdatePgAttributeForView(tle, tle2, viewid); } - return is_changed; + + /* update pg_rewrite with final ev_action */ + UpdatePgrewriteForView(rw_objid, newEvAction, query_str); + + list_free_deep(newEvAction); } /* @@ -33934,7 +33941,8 @@ static void ATPrepAlterModifyColumn(List** wqueue, AlteredTableInfo* tab, Relati def->raw_default = tmp_expr; } -char* GetCreateViewCommand(const char *rel_name, HeapTuple tup, Form_pg_class reltup, Oid pg_rewrite_oid, Oid view_oid) +char* GetCreateViewCommand(const char *rel_name, HeapTuple tup, Form_pg_class reltup, Oid pg_rewrite_oid, Oid view_oid, + bool keep_star) { StringInfoData buf; ViewInfoForAdd* view_info = NULL; @@ -33975,7 +33983,7 @@ char* GetCreateViewCommand(const char *rel_name, HeapTuple tup, Form_pg_class re } pfree_ext(view_options); /* concat CREATE VIEW command with query */ - view_info = GetViewInfoFirstAfter(rel_name, pg_rewrite_oid, true); + view_info = GetViewInfoFirstAfter(rel_name, pg_rewrite_oid, keep_star); if (view_info == NULL) { pfree_ext(buf.data); return NULL; /* should not happen */ diff --git a/src/include/commands/tablecmds.h b/src/include/commands/tablecmds.h index 1cc455def4ff22fc5d5f602c36473b29535a9afc..e8b4831d7e683169e36394cad2226aca279da0e8 100644 --- a/src/include/commands/tablecmds.h +++ b/src/include/commands/tablecmds.h @@ -255,11 +255,13 @@ extern void RebuildDependViewForProc(Oid proc_oid); extern void CheckPgRewriteWithDroppedColumn(Oid rel_oid, Oid rw_oid, Form_pg_attribute attForm, int2 old_attnum, char** attName, List **old_query_str); extern void UpdatePgrewriteForView(Oid rw_oid, List* evAction, List **query_str); +extern List* GetOriginalViewQuery(Oid rw_oid); extern List* GetRefreshedViewQuery(Oid view_oid, Oid rw_oid); -extern bool UpdateChangedColumnForView(Oid viewid, Oid relid, int2 attnum, Oid rw_objid, - List **originEvAction1, List **newEvAction1, Form_pg_attribute attForm); +extern void UpdateAttrAndRewriteForView(Oid viewid, Oid rw_objid, List* originEvAction, Query* query, + List **query_str); extern void ReplaceViewQueryFirstAfter(List *query_str); -extern char* GetCreateViewCommand(const char *rel_name, HeapTuple tup, Form_pg_class reltup, Oid pg_rewrite_oid, Oid view_oid); +extern char* GetCreateViewCommand(const char *rel_name, HeapTuple tup, Form_pg_class reltup, Oid pg_rewrite_oid, + Oid view_oid, bool keep_star = true); #ifdef USE_SPQ extern void spq_btbuild_update_pg_class(Relation heap, Relation index); #endif diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index 5c451200b26ff552619bdd7ac8b618c088c1cf80..444d7c0a0588b154cbae5d77733a98ab08301d55 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -917,7 +917,7 @@ extern void get_query_def(Query* query, StringInfo buf, List* parentnamespace, T #ifdef PGXC bool finalise_aggregates, bool sortgroup_colno, void* parserArg = NULL, #endif /* PGXC */ - bool qrw_phase = false, bool viewdef = false, bool is_fqs = false); + bool qrw_phase = false, bool viewdef = false, bool is_fqs = false, bool skip_lock = false); extern char* deparse_create_sequence(Node* stmt, bool owned_by_none = false); extern char* deparse_alter_sequence(Node* stmt, bool owned_by_none = false); #ifdef PGXC diff --git a/src/test/regress/expected/dependent_view.out b/src/test/regress/expected/dependent_view.out index 9ce60f93dfb591729a465b1942421dddbd2b4935..0e5d820be15071aa206af7a0c7a2d0a538ac7a7d 100644 --- a/src/test/regress/expected/dependent_view.out +++ b/src/test/regress/expected/dependent_view.out @@ -306,22 +306,6 @@ select relname, object_type, valid from pg_object join pg_class on object_oid=oi base_table_id | integer | base_table_field | integer | --- 删除整个表,预期报错 -DROP TABLE base_table; -ERROR: cannot drop table base_table because other objects depend on it -DETAIL: view master_view2 depends on table base_table -view dependent_view4 depends on view master_view2 -view master_view3 depends on table base_table -view dependent_view5 depends on view master_view3 -view master_view1 depends on table base_table -view dependent_view3 depends on view master_view1 -view second_dependent_view3 depends on view dependent_view3 -view dependent_view1 depends on view master_view1 -view second_dependent_view1 depends on view dependent_view1 -view dependent_view2 depends on view master_view1 -view second_dependent_view2 depends on view dependent_view2 -HINT: Use DROP ... CASCADE to drop the dependent objects too. --- 删除整个表,预期成功 DROP TABLE base_table CASCADE; NOTICE: drop cascades to 11 other objects DETAIL: drop cascades to view master_view2 diff --git a/src/test/regress/expected/dependent_view1.out b/src/test/regress/expected/dependent_view1.out new file mode 100644 index 0000000000000000000000000000000000000000..c1afba0d3ee86d2ee70e09466403e2c496c2c84b --- /dev/null +++ b/src/test/regress/expected/dependent_view1.out @@ -0,0 +1,1375 @@ +create schema test_view_table_depend; +set current_schema to 'test_view_table_depend'; +create table t1 (c1 int); +create view v1 as select * from t1; +drop table t1; +\d+ v1; +WARNING: View v1 references invalid table(s), view(s) or column(s). +CONTEXT: referenced column: pg_get_viewdef + View "test_view_table_depend.v1" + Column | Type | Modifiers | Storage | Description +--------+---------+-----------+---------+------------- + c1 | integer | | plain | +View definition: + SELECT * + FROM t1; + +create table t1 (c1 int); +\d+ v1; + View "test_view_table_depend.v1" + Column | Type | Modifiers | Storage | Description +--------+---------+-----------+---------+------------- + c1 | integer | | plain | +View definition: + SELECT * + FROM t1; + +select valid = true from pg_class join pg_object on oid = object_oid where relname = 'v1'; + ?column? +---------- + t +(1 row) + +drop table t1 cascade; +NOTICE: drop cascades to view v1 +create table t1 (c1 int); +create view v1 as select * from t1; +drop table t1; +\d v1; +View "test_view_table_depend.v1" + Column | Type | Modifiers +--------+---------+----------- + c1 | integer | + +\d+ v1; +WARNING: View v1 references invalid table(s), view(s) or column(s). +CONTEXT: referenced column: pg_get_viewdef + View "test_view_table_depend.v1" + Column | Type | Modifiers | Storage | Description +--------+---------+-----------+---------+------------- + c1 | integer | | plain | +View definition: + SELECT * + FROM t1; + +select * from v1; +ERROR: The view v1 is invalid, please make it valid before operation. +HINT: Please re-add missing table fields. +create table t2 (c1 int); +select * from v1; +ERROR: The view v1 is invalid, please make it valid before operation. +HINT: Please re-add missing table fields. +drop table t2; +create table t1 (c2 int); +select * from v1; + c1 +---- +(0 rows) + +drop table t1; +create table t1 (c1 int); +insert into t1 values(1); +select * from v1; + c1 +---- + 1 +(1 row) + +\d v1; +View "test_view_table_depend.v1" + Column | Type | Modifiers +--------+---------+----------- + c1 | integer | + +\d+ v1; + View "test_view_table_depend.v1" + Column | Type | Modifiers | Storage | Description +--------+---------+-----------+---------+------------- + c1 | integer | | plain | +View definition: + SELECT t1.c1 + FROM t1; + +drop table t1; +create table t1 (c1 varchar); +insert into t1 values('a'); +select * from v1; + c1 +---- + a +(1 row) + +\d v1; + View "test_view_table_depend.v1" + Column | Type | Modifiers +--------+-------------------+----------- + c1 | character varying | + +\d+ v1; + View "test_view_table_depend.v1" + Column | Type | Modifiers | Storage | Description +--------+-------------------+-----------+----------+------------- + c1 | character varying | | extended | +View definition: + SELECT t1.c1 + FROM t1; + +drop table t1 cascade; +NOTICE: drop cascades to view v1 +create table t1 (c1 int); +create view v1 as select * from t1; +insert into t1 values(1); +select * from v1; + c1 +---- + 1 +(1 row) + +\d v1; +View "test_view_table_depend.v1" + Column | Type | Modifiers +--------+---------+----------- + c1 | integer | + +\d+ v1; + View "test_view_table_depend.v1" + Column | Type | Modifiers | Storage | Description +--------+---------+-----------+---------+------------- + c1 | integer | | plain | +View definition: + SELECT * + FROM t1; + +drop table t1; +create table t1 (c2 int, c3 int, c1 int); +insert into t1 values(2, 3, 1); +select * from v1; + c1 +---- + 1 +(1 row) + +\d v1; +View "test_view_table_depend.v1" + Column | Type | Modifiers +--------+---------+----------- + c1 | integer | + +\d+ v1; + View "test_view_table_depend.v1" + Column | Type | Modifiers | Storage | Description +--------+---------+-----------+---------+------------- + c1 | integer | | plain | +View definition: + SELECT t1.c1 + FROM t1; + +drop table t1 cascade; +NOTICE: drop cascades to view v1 +create table t1 (c1 int, c2 int, c3 int); +create view v1 as select * from t1; +insert into t1 values(1, 2, 3); +select * from v1; + c1 | c2 | c3 +----+----+---- + 1 | 2 | 3 +(1 row) + +\d v1; +View "test_view_table_depend.v1" + Column | Type | Modifiers +--------+---------+----------- + c1 | integer | + c2 | integer | + c3 | integer | + +\d+ v1; + View "test_view_table_depend.v1" + Column | Type | Modifiers | Storage | Description +--------+---------+-----------+---------+------------- + c1 | integer | | plain | + c2 | integer | | plain | + c3 | integer | | plain | +View definition: + SELECT * + FROM t1; + +drop table t1; +create table t1 (c2 int); +insert into t1 values(2); +select * from v1; +ERROR: The view v1 is invalid, please make it valid before operation. +HINT: Please re-add missing table fields. +\d v1; +View "test_view_table_depend.v1" + Column | Type | Modifiers +--------+---------+----------- + c1 | integer | + c2 | integer | + c3 | integer | + +\d+ v1; +WARNING: View v1 references invalid table(s), view(s) or column(s). +CONTEXT: referenced column: pg_get_viewdef + View "test_view_table_depend.v1" + Column | Type | Modifiers | Storage | Description +--------+---------+-----------+---------+------------- + c1 | integer | | plain | + c2 | integer | | plain | + c3 | integer | | plain | +View definition: + SELECT * + FROM t1; + +drop view v1; +drop table t1 cascade; +create table t1 (c1 int); +create view v1 as select * from t1; +create view v2 as select * from v1; +insert into t1 values(1); +select * from v1; + c1 +---- + 1 +(1 row) + +select * from v2; + c1 +---- + 1 +(1 row) + +\d v1; +View "test_view_table_depend.v1" + Column | Type | Modifiers +--------+---------+----------- + c1 | integer | + +\d v2; +View "test_view_table_depend.v2" + Column | Type | Modifiers +--------+---------+----------- + c1 | integer | + +\d+ v1; + View "test_view_table_depend.v1" + Column | Type | Modifiers | Storage | Description +--------+---------+-----------+---------+------------- + c1 | integer | | plain | +View definition: + SELECT * + FROM t1; + +\d+ v2; + View "test_view_table_depend.v2" + Column | Type | Modifiers | Storage | Description +--------+---------+-----------+---------+------------- + c1 | integer | | plain | +View definition: + SELECT * + FROM v1; + +drop table t1; +\d v1; +View "test_view_table_depend.v1" + Column | Type | Modifiers +--------+---------+----------- + c1 | integer | + +\d v2; +View "test_view_table_depend.v2" + Column | Type | Modifiers +--------+---------+----------- + c1 | integer | + +\d+ v1; +WARNING: View v1 references invalid table(s), view(s) or column(s). +CONTEXT: referenced column: pg_get_viewdef + View "test_view_table_depend.v1" + Column | Type | Modifiers | Storage | Description +--------+---------+-----------+---------+------------- + c1 | integer | | plain | +View definition: + SELECT * + FROM t1; + +\d+ v2; +WARNING: View v2 references invalid table(s), view(s) or column(s). +CONTEXT: referenced column: pg_get_viewdef + View "test_view_table_depend.v2" + Column | Type | Modifiers | Storage | Description +--------+---------+-----------+---------+------------- + c1 | integer | | plain | +View definition: + SELECT * + FROM v1; + +select * from v1; +ERROR: The view v1 is invalid, please make it valid before operation. +HINT: Please re-add missing table fields. +select * from v2; +ERROR: The view v2 is invalid, please make it valid before operation. +HINT: Please re-add missing table fields. +create table t1 (c1 varchar); +insert into t1 values('a'); +select * from v1; + c1 +---- + a +(1 row) + +select * from v2; + c1 +---- + a +(1 row) + +\d v1; + View "test_view_table_depend.v1" + Column | Type | Modifiers +--------+-------------------+----------- + c1 | character varying | + +\d v2; + View "test_view_table_depend.v2" + Column | Type | Modifiers +--------+-------------------+----------- + c1 | character varying | + +\d+ v1; + View "test_view_table_depend.v1" + Column | Type | Modifiers | Storage | Description +--------+-------------------+-----------+----------+------------- + c1 | character varying | | extended | +View definition: + SELECT t1.c1 + FROM t1; + +\d+ v2; + View "test_view_table_depend.v2" + Column | Type | Modifiers | Storage | Description +--------+-------------------+-----------+----------+------------- + c1 | character varying | | extended | +View definition: + SELECT v1.c1 + FROM v1; + +drop table t1 cascade; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to view v1 +drop cascades to view v2 +create table t1 (c1 int); +create view v1 as select c1 from t1; +create view v2 as select c1 + 1 from v1; +insert into t1 values(1); +select * from v1; + c1 +---- + 1 +(1 row) + +select * from v2; + ?column? +---------- + 2 +(1 row) + +\d v1; +View "test_view_table_depend.v1" + Column | Type | Modifiers +--------+---------+----------- + c1 | integer | + +\d v2; +View "test_view_table_depend.v2" + Column | Type | Modifiers +----------+---------+----------- + ?column? | integer | + +\d+ v1; + View "test_view_table_depend.v1" + Column | Type | Modifiers | Storage | Description +--------+---------+-----------+---------+------------- + c1 | integer | | plain | +View definition: + SELECT t1.c1 + FROM t1; + +\d+ v2; + View "test_view_table_depend.v2" + Column | Type | Modifiers | Storage | Description +----------+---------+-----------+---------+------------- + ?column? | integer | | plain | +View definition: + SELECT v1.c1 + 1 AS "?column?" + FROM v1; + +drop table t1; +\d v1; +View "test_view_table_depend.v1" + Column | Type | Modifiers +--------+---------+----------- + c1 | integer | + +\d v2; +View "test_view_table_depend.v2" + Column | Type | Modifiers +----------+---------+----------- + ?column? | integer | + +\d+ v1; +WARNING: View v1 references invalid table(s), view(s) or column(s). +CONTEXT: referenced column: pg_get_viewdef + View "test_view_table_depend.v1" + Column | Type | Modifiers | Storage | Description +--------+---------+-----------+---------+------------- + c1 | integer | | plain | +View definition: + SELECT t1.c1 + FROM t1; + +\d+ v2; +WARNING: View v2 references invalid table(s), view(s) or column(s). +CONTEXT: referenced column: pg_get_viewdef + View "test_view_table_depend.v2" + Column | Type | Modifiers | Storage | Description +----------+---------+-----------+---------+------------- + ?column? | integer | | plain | +View definition: + SELECT v1.c1 + 1 AS "?column?" + FROM v1; + +select * from v1; +ERROR: The view v1 is invalid, please make it valid before operation. +HINT: Please re-add missing table fields. +select * from v2; +ERROR: The view v2 is invalid, please make it valid before operation. +HINT: Please re-add missing table fields. +create table t1 (c1 int); +insert into t1 values(1); +select * from v1; + c1 +---- + 1 +(1 row) + +select * from v2; + ?column? +---------- + 2 +(1 row) + +\d v1; +View "test_view_table_depend.v1" + Column | Type | Modifiers +--------+---------+----------- + c1 | integer | + +\d v2; +View "test_view_table_depend.v2" + Column | Type | Modifiers +----------+---------+----------- + ?column? | integer | + +\d+ v1; + View "test_view_table_depend.v1" + Column | Type | Modifiers | Storage | Description +--------+---------+-----------+---------+------------- + c1 | integer | | plain | +View definition: + SELECT t1.c1 + FROM t1; + +\d+ v2; + View "test_view_table_depend.v2" + Column | Type | Modifiers | Storage | Description +----------+---------+-----------+---------+------------- + ?column? | integer | | plain | +View definition: + SELECT v1.c1 + 1 AS "?column?" + FROM v1; + +drop table t1 cascade; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to view v1 +drop cascades to view v2 +create table t1 (c1 int); +create view v1 as select c1 + 1 from t1; +insert into t1 values(1); +select * from v1; + ?column? +---------- + 2 +(1 row) + +\d v1; +View "test_view_table_depend.v1" + Column | Type | Modifiers +----------+---------+----------- + ?column? | integer | + +\d+ v1; + View "test_view_table_depend.v1" + Column | Type | Modifiers | Storage | Description +----------+---------+-----------+---------+------------- + ?column? | integer | | plain | +View definition: + SELECT t1.c1 + 1 AS "?column?" + FROM t1; + +drop table t1; +\d v1; +View "test_view_table_depend.v1" + Column | Type | Modifiers +----------+---------+----------- + ?column? | integer | + +\d+ v1; +WARNING: View v1 references invalid table(s), view(s) or column(s). +CONTEXT: referenced column: pg_get_viewdef + View "test_view_table_depend.v1" + Column | Type | Modifiers | Storage | Description +----------+---------+-----------+---------+------------- + ?column? | integer | | plain | +View definition: + SELECT t1.c1 + 1 AS "?column?" + FROM t1; + +select * from v1; +ERROR: The view v1 is invalid, please make it valid before operation. +HINT: Please re-add missing table fields. +create table t1 (c1 int); +insert into t1 values(1); +select * from v1; + ?column? +---------- + 2 +(1 row) + +\d v1; +View "test_view_table_depend.v1" + Column | Type | Modifiers +----------+---------+----------- + ?column? | integer | + +\d+ v1; + View "test_view_table_depend.v1" + Column | Type | Modifiers | Storage | Description +----------+---------+-----------+---------+------------- + ?column? | integer | | plain | +View definition: + SELECT t1.c1 + 1 AS "?column?" + FROM t1; + +drop table t1 cascade; +NOTICE: drop cascades to view v1 +create table t1 (c1 int); +create table t2 (c2 int); +create view v1 as select c1 + c2 from t1, t2; +insert into t1 values(1); +insert into t2 values(2); +select * from v1; + ?column? +---------- + 3 +(1 row) + +\d v1; +View "test_view_table_depend.v1" + Column | Type | Modifiers +----------+---------+----------- + ?column? | integer | + +\d+ v1; + View "test_view_table_depend.v1" + Column | Type | Modifiers | Storage | Description +----------+---------+-----------+---------+------------- + ?column? | integer | | plain | +View definition: + SELECT t1.c1 + t2.c2 AS "?column?" + FROM t1, t2; + +drop table t1; +\d v1; +View "test_view_table_depend.v1" + Column | Type | Modifiers +----------+---------+----------- + ?column? | integer | + +\d+ v1; +WARNING: View v1 references invalid table(s), view(s) or column(s). +CONTEXT: referenced column: pg_get_viewdef + View "test_view_table_depend.v1" + Column | Type | Modifiers | Storage | Description +----------+---------+-----------+---------+------------- + ?column? | integer | | plain | +View definition: + SELECT t1.c1 + t2.c2 AS "?column?" + FROM t1, t2; + +select * from v1; +ERROR: The view v1 is invalid, please make it valid before operation. +HINT: Please re-add missing table fields. +create table t1 (c1 int); +insert into t1 values(1); +select * from v1; + ?column? +---------- + 3 +(1 row) + +\d v1; +View "test_view_table_depend.v1" + Column | Type | Modifiers +----------+---------+----------- + ?column? | integer | + +\d+ v1; + View "test_view_table_depend.v1" + Column | Type | Modifiers | Storage | Description +----------+---------+-----------+---------+------------- + ?column? | integer | | plain | +View definition: + SELECT t1.c1 + t2.c2 AS "?column?" + FROM t1, t2; + +drop table t1 cascade; +NOTICE: drop cascades to view v1 +drop table t2 cascade; +-- partition table +create table partition_t1 (a int, b int) +partition by range(a) +( +partition p1 values less than (100), +partition p2 values less than (200), +partition p3 values less than (MAXVALUE) +); +insert into partition_t1 values(99,1),(180,2),(300,4); +create view partition_v1 as select * from partition_t1 partition(p1); +select * from partition_v1; + a | b +----+--- + 99 | 1 +(1 row) + +\d+ partition_v1 + View "test_view_table_depend.partition_v1" + Column | Type | Modifiers | Storage | Description +--------+---------+-----------+---------+------------- + a | integer | | plain | + b | integer | | plain | +View definition: + SELECT * + FROM partition_t1 PARTITION(p1); + +drop table partition_t1; +select * from partition_v1; +ERROR: The view partition_v1 is invalid, please make it valid before operation. +HINT: Please re-add missing table fields. +\d+ partition_v1 +WARNING: View partition_v1 references invalid table(s), view(s) or column(s). +CONTEXT: referenced column: pg_get_viewdef + View "test_view_table_depend.partition_v1" + Column | Type | Modifiers | Storage | Description +--------+---------+-----------+---------+------------- + a | integer | | plain | + b | integer | | plain | +View definition: + SELECT * + FROM partition_t1 PARTITION(p1); + +create table partition_t1 (a int, b int) +partition by range(a) +( +partition p1 values less than (100), +partition p2 values less than (200), +partition p3 values less than (MAXVALUE) +); +select * from partition_v1; + a | b +---+--- +(0 rows) + +\d+ partition_v1 + View "test_view_table_depend.partition_v1" + Column | Type | Modifiers | Storage | Description +--------+---------+-----------+---------+------------- + a | integer | | plain | + b | integer | | plain | +View definition: + SELECT partition_t1.a, partition_t1.b + FROM partition_t1 PARTITION(p1); + +-- less partition and different partition type +drop table partition_t1; +create table partition_t1 (a char(20), b char(20)) +partition by list(a) +( +partition p1 values ('100'), +partition p2 values ('200') +); +insert into partition_t1 values('100','1'),('200','2'),('200','3'); +select * from partition_v1; + a | b +----------------------+---------------------- + 100 | 1 +(1 row) + +\d+ partition_v1 + View "test_view_table_depend.partition_v1" + Column | Type | Modifiers | Storage | Description +--------+---------------+-----------+----------+------------- + a | character(20) | | extended | + b | character(20) | | extended | +View definition: + SELECT partition_t1.a, partition_t1.b + FROM partition_t1 PARTITION(p1); + +drop table partition_t1 cascade; +NOTICE: drop cascades to view partition_v1 +-- secondary partition +CREATE TABLE partition_t1 +( + month_code VARCHAR2 ( 30 ) NOT NULL , + dept_code VARCHAR2 ( 30 ) NOT NULL , + user_no VARCHAR2 ( 30 ) NOT NULL , + sales_amt int +) +PARTITION BY LIST (month_code) SUBPARTITION BY LIST (dept_code) +( + PARTITION p_201901 VALUES ( '201901' ) + ( + SUBPARTITION p_201901_a VALUES ( '1' ), + SUBPARTITION p_201901_b VALUES ( '2' ) + ), + PARTITION p_201902 VALUES ( '201902' ) + ( + SUBPARTITION p_201902_a VALUES ( '1' ), + SUBPARTITION p_201902_b VALUES ( '2' ) + ) +); +insert into partition_t1 values('201901', '1', '1', 1); +insert into partition_t1 values('201901', '2', '1', 1); +insert into partition_t1 values('201902', '1', '1', 1); +insert into partition_t1 values('201902', '2', '1', 1); +create view partition_v1 as select * from partition_t1 partition (p_201901); +create view partition_v2 as select * from partition_t1 partition (p_201902); +create view partition_v3 as select * from partition_t1 partition for ('201901'); +create view partition_v4 as select * from partition_t1 subpartition (p_201902_a); +create view partition_v5 as select * from partition_t1 subpartition for ('201902', '2'); +select * from partition_v1; + month_code | dept_code | user_no | sales_amt +------------+-----------+---------+----------- + 201901 | 1 | 1 | 1 + 201901 | 2 | 1 | 1 +(2 rows) + +\d+ partition_v1 + View "test_view_table_depend.partition_v1" + Column | Type | Modifiers | Storage | Description +------------+-----------------------+-----------+----------+------------- + month_code | character varying(30) | | extended | + dept_code | character varying(30) | | extended | + user_no | character varying(30) | | extended | + sales_amt | integer | | plain | +View definition: + SELECT * + FROM partition_t1 PARTITION(p_201901); + +select * from partition_v2; + month_code | dept_code | user_no | sales_amt +------------+-----------+---------+----------- + 201902 | 1 | 1 | 1 + 201902 | 2 | 1 | 1 +(2 rows) + +\d+ partition_v2 + View "test_view_table_depend.partition_v2" + Column | Type | Modifiers | Storage | Description +------------+-----------------------+-----------+----------+------------- + month_code | character varying(30) | | extended | + dept_code | character varying(30) | | extended | + user_no | character varying(30) | | extended | + sales_amt | integer | | plain | +View definition: + SELECT * + FROM partition_t1 PARTITION(p_201902); + +select * from partition_v3; + month_code | dept_code | user_no | sales_amt +------------+-----------+---------+----------- + 201901 | 1 | 1 | 1 + 201901 | 2 | 1 | 1 +(2 rows) + +\d+ partition_v3 + View "test_view_table_depend.partition_v3" + Column | Type | Modifiers | Storage | Description +------------+-----------------------+-----------+----------+------------- + month_code | character varying(30) | | extended | + dept_code | character varying(30) | | extended | + user_no | character varying(30) | | extended | + sales_amt | integer | | plain | +View definition: + SELECT * + FROM partition_t1 PARTITION FOR('201901'::character varying(30)); + +select * from partition_v4; + month_code | dept_code | user_no | sales_amt +------------+-----------+---------+----------- + 201902 | 1 | 1 | 1 +(1 row) + +\d+ partition_v4 + View "test_view_table_depend.partition_v4" + Column | Type | Modifiers | Storage | Description +------------+-----------------------+-----------+----------+------------- + month_code | character varying(30) | | extended | + dept_code | character varying(30) | | extended | + user_no | character varying(30) | | extended | + sales_amt | integer | | plain | +View definition: + SELECT * + FROM partition_t1 SUBPARTITION(p_201902_a); + +select * from partition_v5; + month_code | dept_code | user_no | sales_amt +------------+-----------+---------+----------- + 201902 | 2 | 1 | 1 +(1 row) + +\d+ partition_v5 + View "test_view_table_depend.partition_v5" + Column | Type | Modifiers | Storage | Description +------------+-----------------------+-----------+----------+------------- + month_code | character varying(30) | | extended | + dept_code | character varying(30) | | extended | + user_no | character varying(30) | | extended | + sales_amt | integer | | plain | +View definition: + SELECT * + FROM partition_t1 SUBPARTITION FOR('201902'::character varying(30) ,'2'::character varying(30)); + +drop table partition_t1; +select * from partition_v1; +ERROR: The view partition_v1 is invalid, please make it valid before operation. +HINT: Please re-add missing table fields. +\d+ partition_v1 +WARNING: View partition_v1 references invalid table(s), view(s) or column(s). +CONTEXT: referenced column: pg_get_viewdef + View "test_view_table_depend.partition_v1" + Column | Type | Modifiers | Storage | Description +------------+-----------------------+-----------+----------+------------- + month_code | character varying(30) | | extended | + dept_code | character varying(30) | | extended | + user_no | character varying(30) | | extended | + sales_amt | integer | | plain | +View definition: + SELECT * + FROM partition_t1 PARTITION(p_201901); + +select * from partition_v2; +ERROR: The view partition_v2 is invalid, please make it valid before operation. +HINT: Please re-add missing table fields. +\d+ partition_v2 +WARNING: View partition_v2 references invalid table(s), view(s) or column(s). +CONTEXT: referenced column: pg_get_viewdef + View "test_view_table_depend.partition_v2" + Column | Type | Modifiers | Storage | Description +------------+-----------------------+-----------+----------+------------- + month_code | character varying(30) | | extended | + dept_code | character varying(30) | | extended | + user_no | character varying(30) | | extended | + sales_amt | integer | | plain | +View definition: + SELECT * + FROM partition_t1 PARTITION(p_201902); + +select * from partition_v3; +ERROR: The view partition_v3 is invalid, please make it valid before operation. +HINT: Please re-add missing table fields. +\d+ partition_v3 +WARNING: View partition_v3 references invalid table(s), view(s) or column(s). +CONTEXT: referenced column: pg_get_viewdef + View "test_view_table_depend.partition_v3" + Column | Type | Modifiers | Storage | Description +------------+-----------------------+-----------+----------+------------- + month_code | character varying(30) | | extended | + dept_code | character varying(30) | | extended | + user_no | character varying(30) | | extended | + sales_amt | integer | | plain | +View definition: + SELECT * + FROM partition_t1 PARTITION FOR('201901'::character varying(30)); + +select * from partition_v4; +ERROR: The view partition_v4 is invalid, please make it valid before operation. +HINT: Please re-add missing table fields. +\d+ partition_v4 +WARNING: View partition_v4 references invalid table(s), view(s) or column(s). +CONTEXT: referenced column: pg_get_viewdef + View "test_view_table_depend.partition_v4" + Column | Type | Modifiers | Storage | Description +------------+-----------------------+-----------+----------+------------- + month_code | character varying(30) | | extended | + dept_code | character varying(30) | | extended | + user_no | character varying(30) | | extended | + sales_amt | integer | | plain | +View definition: + SELECT * + FROM partition_t1 SUBPARTITION(p_201902_a); + +select * from partition_v5; +ERROR: The view partition_v5 is invalid, please make it valid before operation. +HINT: Please re-add missing table fields. +\d+ partition_v5 +WARNING: View partition_v5 references invalid table(s), view(s) or column(s). +CONTEXT: referenced column: pg_get_viewdef + View "test_view_table_depend.partition_v5" + Column | Type | Modifiers | Storage | Description +------------+-----------------------+-----------+----------+------------- + month_code | character varying(30) | | extended | + dept_code | character varying(30) | | extended | + user_no | character varying(30) | | extended | + sales_amt | integer | | plain | +View definition: + SELECT * + FROM partition_t1 SUBPARTITION FOR('201902'::character varying(30) ,'2'::character varying(30)); + +CREATE TABLE partition_t1 +( + month_code VARCHAR2 ( 30 ) NOT NULL , + dept_code VARCHAR2 ( 30 ) NOT NULL , + user_no VARCHAR2 ( 30 ) NOT NULL , + sales_amt int +) +PARTITION BY LIST (month_code) SUBPARTITION BY LIST (dept_code) +( + PARTITION p_201901 VALUES ( '201901' ) + ( + SUBPARTITION p_201901_a VALUES ( '1' ), + SUBPARTITION p_201901_b VALUES ( '2' ) + ), + PARTITION p_201902 VALUES ( '201902' ) + ( + SUBPARTITION p_201902_a VALUES ( '1' ), + SUBPARTITION p_201902_b VALUES ( '2' ) + ) +); +insert into partition_t1 values('201901', '1', '1', 1); +insert into partition_t1 values('201901', '2', '1', 1); +insert into partition_t1 values('201902', '1', '1', 1); +insert into partition_t1 values('201902', '2', '1', 1); +select * from partition_v1; + month_code | dept_code | user_no | sales_amt +------------+-----------+---------+----------- + 201901 | 1 | 1 | 1 + 201901 | 2 | 1 | 1 +(2 rows) + +\d+ partition_v1 + View "test_view_table_depend.partition_v1" + Column | Type | Modifiers | Storage | Description +------------+-----------------------+-----------+----------+------------- + month_code | character varying(30) | | extended | + dept_code | character varying(30) | | extended | + user_no | character varying(30) | | extended | + sales_amt | integer | | plain | +View definition: + SELECT partition_t1.month_code, partition_t1.dept_code, partition_t1.user_no, + partition_t1.sales_amt + FROM partition_t1 PARTITION(p_201901); + +select * from partition_v2; + month_code | dept_code | user_no | sales_amt +------------+-----------+---------+----------- + 201902 | 1 | 1 | 1 + 201902 | 2 | 1 | 1 +(2 rows) + +\d+ partition_v2 + View "test_view_table_depend.partition_v2" + Column | Type | Modifiers | Storage | Description +------------+-----------------------+-----------+----------+------------- + month_code | character varying(30) | | extended | + dept_code | character varying(30) | | extended | + user_no | character varying(30) | | extended | + sales_amt | integer | | plain | +View definition: + SELECT partition_t1.month_code, partition_t1.dept_code, partition_t1.user_no, + partition_t1.sales_amt + FROM partition_t1 PARTITION(p_201902); + +select * from partition_v3; + month_code | dept_code | user_no | sales_amt +------------+-----------+---------+----------- + 201901 | 1 | 1 | 1 + 201901 | 2 | 1 | 1 +(2 rows) + +\d+ partition_v3 + View "test_view_table_depend.partition_v3" + Column | Type | Modifiers | Storage | Description +------------+-----------------------+-----------+----------+------------- + month_code | character varying(30) | | extended | + dept_code | character varying(30) | | extended | + user_no | character varying(30) | | extended | + sales_amt | integer | | plain | +View definition: + SELECT partition_t1.month_code, partition_t1.dept_code, partition_t1.user_no, + partition_t1.sales_amt + FROM partition_t1 PARTITION FOR('201901'::character varying(30)); + +select * from partition_v4; + month_code | dept_code | user_no | sales_amt +------------+-----------+---------+----------- + 201902 | 1 | 1 | 1 +(1 row) + +\d+ partition_v4 + View "test_view_table_depend.partition_v4" + Column | Type | Modifiers | Storage | Description +------------+-----------------------+-----------+----------+------------- + month_code | character varying(30) | | extended | + dept_code | character varying(30) | | extended | + user_no | character varying(30) | | extended | + sales_amt | integer | | plain | +View definition: + SELECT partition_t1.month_code, partition_t1.dept_code, partition_t1.user_no, + partition_t1.sales_amt + FROM partition_t1 SUBPARTITION(p_201902_a); + +select * from partition_v5; + month_code | dept_code | user_no | sales_amt +------------+-----------+---------+----------- + 201902 | 2 | 1 | 1 +(1 row) + +\d+ partition_v5 + View "test_view_table_depend.partition_v5" + Column | Type | Modifiers | Storage | Description +------------+-----------------------+-----------+----------+------------- + month_code | character varying(30) | | extended | + dept_code | character varying(30) | | extended | + user_no | character varying(30) | | extended | + sales_amt | integer | | plain | +View definition: + SELECT partition_t1.month_code, partition_t1.dept_code, partition_t1.user_no, + partition_t1.sales_amt + FROM partition_t1 SUBPARTITION FOR('201902'::character varying(30) ,'2'::character varying(30)); + +-- less subpartition and different partition type +drop table partition_t1; +CREATE TABLE partition_t1 +( + month_code int NOT NULL , + dept_code int NOT NULL , + user_no int NOT NULL , + sales_amt varchar( 30 ) +) +PARTITION BY RANGE (month_code) SUBPARTITION BY RANGE (dept_code) +( + PARTITION p_201901 VALUES LESS THAN ( 2019 ) + ( + SUBPARTITION p_201901_a VALUES LESS THAN ( 2 ) + ), + PARTITION p_201902 VALUES LESS THAN ( 2020 ) + ( + SUBPARTITION p_201902_a VALUES LESS THAN ( 3 ) + ) +); +insert into partition_t1 values(2018, 1, 1, 'a'); +insert into partition_t1 values(2019, 2, 1, 'b'); +select * from partition_v1; + month_code | dept_code | user_no | sales_amt +------------+-----------+---------+----------- + 2018 | 1 | 1 | a +(1 row) + +\d+ partition_v1 + View "test_view_table_depend.partition_v1" + Column | Type | Modifiers | Storage | Description +------------+-----------------------+-----------+----------+------------- + month_code | integer | | plain | + dept_code | integer | | plain | + user_no | integer | | plain | + sales_amt | character varying(30) | | extended | +View definition: + SELECT partition_t1.month_code, partition_t1.dept_code, partition_t1.user_no, + partition_t1.sales_amt + FROM partition_t1 PARTITION(p_201901); + +select * from partition_v2; + month_code | dept_code | user_no | sales_amt +------------+-----------+---------+----------- + 2019 | 2 | 1 | b +(1 row) + +\d+ partition_v2 + View "test_view_table_depend.partition_v2" + Column | Type | Modifiers | Storage | Description +------------+-----------------------+-----------+----------+------------- + month_code | integer | | plain | + dept_code | integer | | plain | + user_no | integer | | plain | + sales_amt | character varying(30) | | extended | +View definition: + SELECT partition_t1.month_code, partition_t1.dept_code, partition_t1.user_no, + partition_t1.sales_amt + FROM partition_t1 PARTITION(p_201902); + +select * from partition_v3; +ERROR: The view partition_v3 is invalid, please make it valid before operation. +HINT: Please re-add missing table fields. +\d+ partition_v3 +ERROR: The view partition_v3 is invalid, please make it valid before operation. +HINT: Please re-add missing table fields. +CONTEXT: referenced column: pg_get_viewdef +select * from partition_v4; + month_code | dept_code | user_no | sales_amt +------------+-----------+---------+----------- + 2019 | 2 | 1 | b +(1 row) + +\d+ partition_v4 + View "test_view_table_depend.partition_v4" + Column | Type | Modifiers | Storage | Description +------------+-----------------------+-----------+----------+------------- + month_code | integer | | plain | + dept_code | integer | | plain | + user_no | integer | | plain | + sales_amt | character varying(30) | | extended | +View definition: + SELECT partition_t1.month_code, partition_t1.dept_code, partition_t1.user_no, + partition_t1.sales_amt + FROM partition_t1 SUBPARTITION(p_201902_a); + +select * from partition_v5; +ERROR: The view partition_v5 is invalid, please make it valid before operation. +HINT: Please re-add missing table fields. +\d+ partition_v5 +WARNING: View partition_v5 references invalid table(s), view(s) or column(s). +CONTEXT: referenced column: pg_get_viewdef + View "test_view_table_depend.partition_v5" + Column | Type | Modifiers | Storage | Description +------------+-----------------------+-----------+----------+------------- + month_code | character varying(30) | | extended | + dept_code | character varying(30) | | extended | + user_no | character varying(30) | | extended | + sales_amt | integer | | plain | +View definition: + SELECT partition_t1.month_code, partition_t1.dept_code, partition_t1.user_no, + partition_t1.sales_amt + FROM partition_t1 SUBPARTITION FOR('201902'::character varying(30) ,'2'::character varying(30)); + +drop table partition_t1 cascade; +NOTICE: drop cascades to 4 other objects +DETAIL: drop cascades to view partition_v1 +drop cascades to view partition_v2 +drop cascades to view partition_v4 +drop cascades to view partition_v5 +create table t1 (c1 int, c2 int); +create view v1 as select * from t1; +drop table t1; +create table t1 (c2 int, c3 int, c4 int, c1 int); +insert into t1 values (2, 3, 4, 1); +select * from v1; + c1 | c2 +----+---- + 1 | 2 +(1 row) + +drop table t1 cascade; +NOTICE: drop cascades to view v1 +--test cte +create table t1 (a int); +create view v1 as with tmp as (select * from t1) select * from tmp; +drop table t1; +select * from v1; +ERROR: The view v1 is invalid, please make it valid before operation. +HINT: Please re-add missing table fields. +\d+ v1 +WARNING: View v1 references invalid table(s), view(s) or column(s). +CONTEXT: referenced column: pg_get_viewdef + View "test_view_table_depend.v1" + Column | Type | Modifiers | Storage | Description +--------+---------+-----------+---------+------------- + a | integer | | plain | +View definition: + WITH tmp AS ( + SELECT * + FROM t1 + ) + SELECT * + FROM tmp; + +create table t1 (a int); +\d+ v1 + View "test_view_table_depend.v1" + Column | Type | Modifiers | Storage | Description +--------+---------+-----------+---------+------------- + a | integer | | plain | +View definition: + WITH tmp AS ( + SELECT * + FROM t1 + ) + SELECT * + FROM tmp; + +select * from v1; + a +--- +(0 rows) + +drop table t1 cascade; +NOTICE: drop cascades to view v1 +-- test setop +create table t1 (a int); +create view v1 as select 1 union select a from t1; +drop table t1; +select * from v1; +ERROR: The view v1 is invalid, please make it valid before operation. +HINT: Please re-add missing table fields. +\d+ v1 +WARNING: View v1 references invalid table(s), view(s) or column(s). +CONTEXT: referenced column: pg_get_viewdef + View "test_view_table_depend.v1" + Column | Type | Modifiers | Storage | Description +----------+---------+-----------+---------+------------- + ?column? | integer | | plain | +View definition: + SELECT 1 AS "?column?" +UNION + SELECT t1.a AS "?column?" + FROM t1; + +create table t1 (a int); +\d+ v1 + View "test_view_table_depend.v1" + Column | Type | Modifiers | Storage | Description +----------+---------+-----------+---------+------------- + ?column? | integer | | plain | +View definition: + SELECT 1 AS "?column?" +UNION + SELECT t1.a AS "?column?" + FROM t1; + +select * from v1; + ?column? +---------- + 1 +(1 row) + +drop table t1 cascade; +NOTICE: drop cascades to view v1 +-- test subquery +create table t1 (a int); +create table t2 (a int); +insert into t1 values (1); +insert into t2 values (1); +create view v1 as select * from (select * from t1); +create view v2 as select * from t1 where exists (select * from t1 inner join t2 on t1.a = t2.a); +drop table t1; +select * from v1; +ERROR: The view v1 is invalid, please make it valid before operation. +HINT: Please re-add missing table fields. +\d+ v1 +WARNING: View v1 references invalid table(s), view(s) or column(s). +CONTEXT: referenced column: pg_get_viewdef + View "test_view_table_depend.v1" + Column | Type | Modifiers | Storage | Description +--------+---------+-----------+---------+------------- + a | integer | | plain | +View definition: + SELECT * + FROM ( SELECT * + FROM t1) __unnamed_subquery__; + +select * from v2; +ERROR: The view v2 is invalid, please make it valid before operation. +HINT: Please re-add missing table fields. +\d+ v2 +WARNING: View v2 references invalid table(s), view(s) or column(s). +CONTEXT: referenced column: pg_get_viewdef + View "test_view_table_depend.v2" + Column | Type | Modifiers | Storage | Description +--------+---------+-----------+---------+------------- + a | integer | | plain | +View definition: + SELECT * + FROM t1 + WHERE (EXISTS ( SELECT * + FROM t1 + JOIN t2 ON t1.a = t2.a)); + +create table t1 (a int); +insert into t1 values (1); +\d+ v1 + View "test_view_table_depend.v1" + Column | Type | Modifiers | Storage | Description +--------+---------+-----------+---------+------------- + a | integer | | plain | +View definition: + SELECT * + FROM ( SELECT * + FROM t1) __unnamed_subquery__; + +select * from v1; + a +--- + 1 +(1 row) + +\d+ v2 + View "test_view_table_depend.v2" + Column | Type | Modifiers | Storage | Description +--------+---------+-----------+---------+------------- + a | integer | | plain | +View definition: + SELECT * + FROM t1 + WHERE (EXISTS ( SELECT * + FROM t1 + JOIN t2 ON t1.a = t2.a)); + +select * from v2; + a +--- + 1 +(1 row) + +drop table t2; +\d+ v2 +WARNING: View v2 references invalid table(s), view(s) or column(s). +CONTEXT: referenced column: pg_get_viewdef + View "test_view_table_depend.v2" + Column | Type | Modifiers | Storage | Description +--------+---------+-----------+---------+------------- + a | integer | | plain | +View definition: + SELECT t1.a + FROM t1 + WHERE (EXISTS ( SELECT t1.a, t2.a + FROM t1 + JOIN t2 ON t1.a = t2.a)); + +select * from v2; +ERROR: The view v2 is invalid, please make it valid before operation. +HINT: Please re-add missing table fields. +create table t2 (b int, a int); +insert into t2 values (2, 1); +select * from v2; + a +--- + 1 +(1 row) + +drop view v1; +drop view v2; +drop table t1; +drop table t2; +drop schema test_view_table_depend cascade; +NOTICE: drop cascades to view partition_v3 +reset current_schema; diff --git a/src/test/regress/parallel_schedule0A b/src/test/regress/parallel_schedule0A index 4d0c7b70b7ed346292c01437bae22dd56f612f68..6bb2644166e7955e064eba389ba267007f408195 100644 --- a/src/test/regress/parallel_schedule0A +++ b/src/test/regress/parallel_schedule0A @@ -35,7 +35,7 @@ test: workload_manager test: spm_adaptive_gplan test: smp smp_cursor parallel_enable_function -test: alter_hw_package +test: alter_hw_package dependent_view1 test: hw_grant_package gsc_func gsc_db test: uppercase_attribute_name decode_compatible_with_o outerjoin_bugfix test: replace_func_with_two_args trunc_func_for_date nlssort_pinyin updatable_views dependent_view diff --git a/src/test/regress/pg_regress.cpp b/src/test/regress/pg_regress.cpp index c7724dd17ce10b2c2cdaf6775f16496291b1c746..080fbd601e404c9082f432b4b5f81c2fc86f36d4 100644 --- a/src/test/regress/pg_regress.cpp +++ b/src/test/regress/pg_regress.cpp @@ -5516,7 +5516,7 @@ static void check_global_variables() } } -#define BASE_PGXC_LIKE_MACRO_NUM 1385 +#define BASE_PGXC_LIKE_MACRO_NUM 1386 static void check_pgxc_like_macros() { #ifdef BUILD_BY_CMAKE diff --git a/src/test/regress/sql/dependent_view.sql b/src/test/regress/sql/dependent_view.sql index 87a92fb56521d089448d890554fa1fcf9c7d342b..81f83aef280a6d1435cdbaf3d4170087506072b9 100644 --- a/src/test/regress/sql/dependent_view.sql +++ b/src/test/regress/sql/dependent_view.sql @@ -116,9 +116,6 @@ select * from dependent_view3; select relname, object_type, valid from pg_object join pg_class on object_oid=oid and relnamespace = (select Oid from pg_namespace where nspname='dependent_view') order by object_oid; \d base_table --- 删除整个表,预期报错 -DROP TABLE base_table; --- 删除整个表,预期成功 DROP TABLE base_table CASCADE; -- test2:物化视图 diff --git a/src/test/regress/sql/dependent_view1.sql b/src/test/regress/sql/dependent_view1.sql new file mode 100644 index 0000000000000000000000000000000000000000..79ef8cd98f9453c0eab93daea9bbcfe69f374c1d --- /dev/null +++ b/src/test/regress/sql/dependent_view1.sql @@ -0,0 +1,388 @@ +create schema test_view_table_depend; +set current_schema to 'test_view_table_depend'; + +create table t1 (c1 int); +create view v1 as select * from t1; +drop table t1; +\d+ v1; +create table t1 (c1 int); +\d+ v1; +select valid = true from pg_class join pg_object on oid = object_oid where relname = 'v1'; + +drop table t1 cascade; +create table t1 (c1 int); +create view v1 as select * from t1; +drop table t1; +\d v1; +\d+ v1; +select * from v1; +create table t2 (c1 int); +select * from v1; +drop table t2; +create table t1 (c2 int); +select * from v1; +drop table t1; +create table t1 (c1 int); +insert into t1 values(1); +select * from v1; +\d v1; +\d+ v1; +drop table t1; +create table t1 (c1 varchar); +insert into t1 values('a'); +select * from v1; +\d v1; +\d+ v1; + +drop table t1 cascade; +create table t1 (c1 int); +create view v1 as select * from t1; +insert into t1 values(1); +select * from v1; +\d v1; +\d+ v1; +drop table t1; +create table t1 (c2 int, c3 int, c1 int); +insert into t1 values(2, 3, 1); +select * from v1; +\d v1; +\d+ v1; + +drop table t1 cascade; +create table t1 (c1 int, c2 int, c3 int); +create view v1 as select * from t1; +insert into t1 values(1, 2, 3); +select * from v1; +\d v1; +\d+ v1; +drop table t1; +create table t1 (c2 int); +insert into t1 values(2); +select * from v1; +\d v1; +\d+ v1; + +drop view v1; +drop table t1 cascade; +create table t1 (c1 int); +create view v1 as select * from t1; +create view v2 as select * from v1; +insert into t1 values(1); +select * from v1; +select * from v2; +\d v1; +\d v2; +\d+ v1; +\d+ v2; +drop table t1; +\d v1; +\d v2; +\d+ v1; +\d+ v2; +select * from v1; +select * from v2; +create table t1 (c1 varchar); +insert into t1 values('a'); +select * from v1; +select * from v2; +\d v1; +\d v2; +\d+ v1; +\d+ v2; + +drop table t1 cascade; +create table t1 (c1 int); +create view v1 as select c1 from t1; +create view v2 as select c1 + 1 from v1; +insert into t1 values(1); +select * from v1; +select * from v2; +\d v1; +\d v2; +\d+ v1; +\d+ v2; +drop table t1; +\d v1; +\d v2; +\d+ v1; +\d+ v2; +select * from v1; +select * from v2; +create table t1 (c1 int); +insert into t1 values(1); +select * from v1; +select * from v2; +\d v1; +\d v2; +\d+ v1; +\d+ v2; + +drop table t1 cascade; +create table t1 (c1 int); +create view v1 as select c1 + 1 from t1; +insert into t1 values(1); +select * from v1; +\d v1; +\d+ v1; +drop table t1; +\d v1; +\d+ v1; +select * from v1; +create table t1 (c1 int); +insert into t1 values(1); +select * from v1; +\d v1; +\d+ v1; + +drop table t1 cascade; +create table t1 (c1 int); +create table t2 (c2 int); +create view v1 as select c1 + c2 from t1, t2; +insert into t1 values(1); +insert into t2 values(2); +select * from v1; +\d v1; +\d+ v1; +drop table t1; +\d v1; +\d+ v1; +select * from v1; +create table t1 (c1 int); +insert into t1 values(1); +select * from v1; +\d v1; +\d+ v1; +drop table t1 cascade; +drop table t2 cascade; + +-- partition table +create table partition_t1 (a int, b int) +partition by range(a) +( +partition p1 values less than (100), +partition p2 values less than (200), +partition p3 values less than (MAXVALUE) +); +insert into partition_t1 values(99,1),(180,2),(300,4); +create view partition_v1 as select * from partition_t1 partition(p1); +select * from partition_v1; +\d+ partition_v1 +drop table partition_t1; +select * from partition_v1; +\d+ partition_v1 +create table partition_t1 (a int, b int) +partition by range(a) +( +partition p1 values less than (100), +partition p2 values less than (200), +partition p3 values less than (MAXVALUE) +); +select * from partition_v1; +\d+ partition_v1 + +-- less partition and different partition type +drop table partition_t1; +create table partition_t1 (a char(20), b char(20)) +partition by list(a) +( +partition p1 values ('100'), +partition p2 values ('200') +); +insert into partition_t1 values('100','1'),('200','2'),('200','3'); +select * from partition_v1; +\d+ partition_v1 +drop table partition_t1 cascade; + +-- secondary partition +CREATE TABLE partition_t1 +( + month_code VARCHAR2 ( 30 ) NOT NULL , + dept_code VARCHAR2 ( 30 ) NOT NULL , + user_no VARCHAR2 ( 30 ) NOT NULL , + sales_amt int +) +PARTITION BY LIST (month_code) SUBPARTITION BY LIST (dept_code) +( + PARTITION p_201901 VALUES ( '201901' ) + ( + SUBPARTITION p_201901_a VALUES ( '1' ), + SUBPARTITION p_201901_b VALUES ( '2' ) + ), + PARTITION p_201902 VALUES ( '201902' ) + ( + SUBPARTITION p_201902_a VALUES ( '1' ), + SUBPARTITION p_201902_b VALUES ( '2' ) + ) +); +insert into partition_t1 values('201901', '1', '1', 1); +insert into partition_t1 values('201901', '2', '1', 1); +insert into partition_t1 values('201902', '1', '1', 1); +insert into partition_t1 values('201902', '2', '1', 1); + +create view partition_v1 as select * from partition_t1 partition (p_201901); +create view partition_v2 as select * from partition_t1 partition (p_201902); +create view partition_v3 as select * from partition_t1 partition for ('201901'); +create view partition_v4 as select * from partition_t1 subpartition (p_201902_a); +create view partition_v5 as select * from partition_t1 subpartition for ('201902', '2'); +select * from partition_v1; +\d+ partition_v1 +select * from partition_v2; +\d+ partition_v2 +select * from partition_v3; +\d+ partition_v3 +select * from partition_v4; +\d+ partition_v4 +select * from partition_v5; +\d+ partition_v5 +drop table partition_t1; +select * from partition_v1; +\d+ partition_v1 +select * from partition_v2; +\d+ partition_v2 +select * from partition_v3; +\d+ partition_v3 +select * from partition_v4; +\d+ partition_v4 +select * from partition_v5; +\d+ partition_v5 +CREATE TABLE partition_t1 +( + month_code VARCHAR2 ( 30 ) NOT NULL , + dept_code VARCHAR2 ( 30 ) NOT NULL , + user_no VARCHAR2 ( 30 ) NOT NULL , + sales_amt int +) +PARTITION BY LIST (month_code) SUBPARTITION BY LIST (dept_code) +( + PARTITION p_201901 VALUES ( '201901' ) + ( + SUBPARTITION p_201901_a VALUES ( '1' ), + SUBPARTITION p_201901_b VALUES ( '2' ) + ), + PARTITION p_201902 VALUES ( '201902' ) + ( + SUBPARTITION p_201902_a VALUES ( '1' ), + SUBPARTITION p_201902_b VALUES ( '2' ) + ) +); +insert into partition_t1 values('201901', '1', '1', 1); +insert into partition_t1 values('201901', '2', '1', 1); +insert into partition_t1 values('201902', '1', '1', 1); +insert into partition_t1 values('201902', '2', '1', 1); +select * from partition_v1; +\d+ partition_v1 +select * from partition_v2; +\d+ partition_v2 +select * from partition_v3; +\d+ partition_v3 +select * from partition_v4; +\d+ partition_v4 +select * from partition_v5; +\d+ partition_v5 + +-- less subpartition and different partition type +drop table partition_t1; +CREATE TABLE partition_t1 +( + month_code int NOT NULL , + dept_code int NOT NULL , + user_no int NOT NULL , + sales_amt varchar( 30 ) +) +PARTITION BY RANGE (month_code) SUBPARTITION BY RANGE (dept_code) +( + PARTITION p_201901 VALUES LESS THAN ( 2019 ) + ( + SUBPARTITION p_201901_a VALUES LESS THAN ( 2 ) + ), + PARTITION p_201902 VALUES LESS THAN ( 2020 ) + ( + SUBPARTITION p_201902_a VALUES LESS THAN ( 3 ) + ) +); +insert into partition_t1 values(2018, 1, 1, 'a'); +insert into partition_t1 values(2019, 2, 1, 'b'); + +select * from partition_v1; +\d+ partition_v1 +select * from partition_v2; +\d+ partition_v2 +select * from partition_v3; +\d+ partition_v3 +select * from partition_v4; +\d+ partition_v4 +select * from partition_v5; +\d+ partition_v5 + +drop table partition_t1 cascade; + +create table t1 (c1 int, c2 int); +create view v1 as select * from t1; +drop table t1; +create table t1 (c2 int, c3 int, c4 int, c1 int); +insert into t1 values (2, 3, 4, 1); +select * from v1; + +drop table t1 cascade; + +--test cte +create table t1 (a int); +create view v1 as with tmp as (select * from t1) select * from tmp; +drop table t1; +select * from v1; +\d+ v1 + +create table t1 (a int); +\d+ v1 +select * from v1; + +drop table t1 cascade; + +-- test setop +create table t1 (a int); +create view v1 as select 1 union select a from t1; +drop table t1; +select * from v1; +\d+ v1 + +create table t1 (a int); +\d+ v1 +select * from v1; + +drop table t1 cascade; + +-- test subquery +create table t1 (a int); +create table t2 (a int); +insert into t1 values (1); +insert into t2 values (1); +create view v1 as select * from (select * from t1); +create view v2 as select * from t1 where exists (select * from t1 inner join t2 on t1.a = t2.a); +drop table t1; +select * from v1; +\d+ v1 +select * from v2; +\d+ v2 + +create table t1 (a int); +insert into t1 values (1); +\d+ v1 +select * from v1; +\d+ v2 +select * from v2; + +drop table t2; +\d+ v2 +select * from v2; + +create table t2 (b int, a int); +insert into t2 values (2, 1); +select * from v2; + +drop view v1; +drop view v2; +drop table t1; +drop table t2; + +drop schema test_view_table_depend cascade; +reset current_schema;