prepunion.c
来自「PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统」· C语言 代码 · 共 1,246 行 · 第 1/3 页
C
1,246 行
/* * If all the children were temp tables, pretend it's a non-inheritance * situation. The duplicate RTE we added for the parent table is * harmless. */ if (list_length(inhRTIs) < 2) { /* Clear flag to save repeated tests if called again */ rte->inh = false; return NIL; } /* * The executor will check the parent table's access permissions when it * examines the parent's inheritlist entry. There's no need to check * twice, so turn off access check bits in the original RTE. (If we are * invoked more than once, extra copies of the child RTEs will also not * cause duplicate permission checks.) */ rte->requiredPerms = 0; return inhRTIs;}/* * adjust_inherited_attrs * Copy the specified query or expression and translate Vars referring * to old_rt_index to refer to new_rt_index. * * We also adjust varattno to match the new table by column name, rather * than column number. This hack makes it possible for child tables to have * different column positions for the "same" attribute as a parent, which * is necessary for ALTER TABLE ADD COLUMN. */Node *adjust_inherited_attrs(Node *node, Index old_rt_index, Oid old_relid, Index new_rt_index, Oid new_relid){ Node *result; adjust_inherited_attrs_context context; Relation oldrelation; Relation newrelation; /* Handle simple case simply... */ if (old_rt_index == new_rt_index) { Assert(old_relid == new_relid); return copyObject(node); } /* * We assume that by now the planner has acquired at least AccessShareLock * on both rels, and so we need no additional lock now. */ oldrelation = heap_open(old_relid, NoLock); newrelation = heap_open(new_relid, NoLock); context.old_rt_index = old_rt_index; context.new_rt_index = new_rt_index; context.old_rel_type = oldrelation->rd_rel->reltype; context.new_rel_type = newrelation->rd_rel->reltype; context.old_tupdesc = RelationGetDescr(oldrelation); context.new_tupdesc = RelationGetDescr(newrelation); context.old_rel_name = RelationGetRelationName(oldrelation); context.new_rel_name = RelationGetRelationName(newrelation); /* * Must be prepared to start with a Query or a bare expression tree. */ if (node && IsA(node, Query)) { Query *newnode; newnode = query_tree_mutator((Query *) node, adjust_inherited_attrs_mutator, (void *) &context, QTW_IGNORE_RT_SUBQUERIES); if (newnode->resultRelation == old_rt_index) { newnode->resultRelation = new_rt_index; /* Fix tlist resnos too, if it's inherited UPDATE */ if (newnode->commandType == CMD_UPDATE) newnode->targetList = adjust_inherited_tlist(newnode->targetList, &context); } result = (Node *) newnode; } else result = adjust_inherited_attrs_mutator(node, &context); heap_close(oldrelation, NoLock); heap_close(newrelation, NoLock); return result;}/* * Translate parent's attribute number into child's. * * For paranoia's sake, we match type as well as attribute name. */static AttrNumbertranslate_inherited_attnum(AttrNumber old_attno, adjust_inherited_attrs_context *context){ Form_pg_attribute att; char *attname; Oid atttypid; int32 atttypmod; int newnatts; int i; if (old_attno <= 0 || old_attno > context->old_tupdesc->natts) elog(ERROR, "attribute %d of relation \"%s\" does not exist", (int) old_attno, context->old_rel_name); att = context->old_tupdesc->attrs[old_attno - 1]; if (att->attisdropped) elog(ERROR, "attribute %d of relation \"%s\" does not exist", (int) old_attno, context->old_rel_name); attname = NameStr(att->attname); atttypid = att->atttypid; atttypmod = att->atttypmod; newnatts = context->new_tupdesc->natts; for (i = 0; i < newnatts; i++) { att = context->new_tupdesc->attrs[i]; if (att->attisdropped) continue; if (strcmp(attname, NameStr(att->attname)) == 0) { /* Found it, check type */ if (atttypid != att->atttypid || atttypmod != att->atttypmod) elog(ERROR, "attribute \"%s\" of relation \"%s\" does not match parent's type", attname, context->new_rel_name); return (AttrNumber) (i + 1); } } elog(ERROR, "attribute \"%s\" of relation \"%s\" does not exist", attname, context->new_rel_name); return 0; /* keep compiler quiet */}static Node *adjust_inherited_attrs_mutator(Node *node, adjust_inherited_attrs_context *context){ if (node == NULL) return NULL; if (IsA(node, Var)) { Var *var = (Var *) copyObject(node); if (var->varlevelsup == 0 && var->varno == context->old_rt_index) { var->varno = context->new_rt_index; var->varnoold = context->new_rt_index; if (var->varattno > 0) { var->varattno = translate_inherited_attnum(var->varattno, context); var->varoattno = var->varattno; } else if (var->varattno == 0) { /* * Whole-row Var: we need to insert a coercion step to convert * the tuple layout to the parent's rowtype. */ if (context->old_rel_type != context->new_rel_type) { ConvertRowtypeExpr *r = makeNode(ConvertRowtypeExpr); r->arg = (Expr *) var; r->resulttype = context->old_rel_type; r->convertformat = COERCE_IMPLICIT_CAST; /* Make sure the Var node has the right type ID, too */ Assert(var->vartype == context->old_rel_type); var->vartype = context->new_rel_type; return (Node *) r; } } /* system attributes don't need any translation */ } return (Node *) var; } if (IsA(node, RangeTblRef)) { RangeTblRef *rtr = (RangeTblRef *) copyObject(node); if (rtr->rtindex == context->old_rt_index) rtr->rtindex = context->new_rt_index; return (Node *) rtr; } if (IsA(node, JoinExpr)) { /* Copy the JoinExpr node with correct mutation of subnodes */ JoinExpr *j; j = (JoinExpr *) expression_tree_mutator(node, adjust_inherited_attrs_mutator, (void *) context); /* now fix JoinExpr's rtindex */ if (j->rtindex == context->old_rt_index) j->rtindex = context->new_rt_index; return (Node *) j; } if (IsA(node, InClauseInfo)) { /* Copy the InClauseInfo node with correct mutation of subnodes */ InClauseInfo *ininfo; ininfo = (InClauseInfo *) expression_tree_mutator(node, adjust_inherited_attrs_mutator, (void *) context); /* now fix InClauseInfo's relid sets */ ininfo->lefthand = adjust_relid_set(ininfo->lefthand, context->old_rt_index, context->new_rt_index); ininfo->righthand = adjust_relid_set(ininfo->righthand, context->old_rt_index, context->new_rt_index); return (Node *) ininfo; } /* * We have to process RestrictInfo nodes specially. */ if (IsA(node, RestrictInfo)) { RestrictInfo *oldinfo = (RestrictInfo *) node; RestrictInfo *newinfo = makeNode(RestrictInfo); /* Copy all flat-copiable fields */ memcpy(newinfo, oldinfo, sizeof(RestrictInfo)); /* Recursively fix the clause itself */ newinfo->clause = (Expr *) adjust_inherited_attrs_mutator((Node *) oldinfo->clause, context); /* and the modified version, if an OR clause */ newinfo->orclause = (Expr *) adjust_inherited_attrs_mutator((Node *) oldinfo->orclause, context); /* adjust relid sets too */ newinfo->clause_relids = adjust_relid_set(oldinfo->clause_relids, context->old_rt_index, context->new_rt_index); newinfo->required_relids = adjust_relid_set(oldinfo->required_relids, context->old_rt_index, context->new_rt_index); newinfo->left_relids = adjust_relid_set(oldinfo->left_relids, context->old_rt_index, context->new_rt_index); newinfo->right_relids = adjust_relid_set(oldinfo->right_relids, context->old_rt_index, context->new_rt_index); /* * Reset cached derivative fields, since these might need to have * different values when considering the child relation. */ newinfo->eval_cost.startup = -1; newinfo->this_selec = -1; newinfo->left_pathkey = NIL; newinfo->right_pathkey = NIL; newinfo->left_mergescansel = -1; newinfo->right_mergescansel = -1; newinfo->left_bucketsize = -1; newinfo->right_bucketsize = -1; return (Node *) newinfo; } /* * NOTE: we do not need to recurse into sublinks, because they should * already have been converted to subplans before we see them. */ Assert(!IsA(node, SubLink)); Assert(!IsA(node, Query)); /* * BUT: although we don't need to recurse into subplans, we do need to * make sure that they are copied, not just referenced as * expression_tree_mutator will do by default. Otherwise we'll have the * same subplan node referenced from each arm of the inheritance APPEND * plan, which will cause trouble in the executor. This is a kluge that * should go away when we redesign querytrees. */ if (is_subplan(node)) { SubPlan *subplan; /* Copy the node and process subplan args */ node = expression_tree_mutator(node, adjust_inherited_attrs_mutator, (void *) context); /* Make sure we have separate copies of subplan and its rtable */ subplan = (SubPlan *) node; subplan->plan = copyObject(subplan->plan); subplan->rtable = copyObject(subplan->rtable); return node; } return expression_tree_mutator(node, adjust_inherited_attrs_mutator, (void *) context);}/* * Substitute newrelid for oldrelid in a Relid set */static Relidsadjust_relid_set(Relids relids, Index oldrelid, Index newrelid){ if (bms_is_member(oldrelid, relids)) { /* Ensure we have a modifiable copy */ relids = bms_copy(relids); /* Remove old, add new */ relids = bms_del_member(relids, oldrelid); relids = bms_add_member(relids, newrelid); } return relids;}/* * Adjust the targetlist entries of an inherited UPDATE operation * * The expressions have already been fixed, but we have to make sure that * the target resnos match the child table (they may not, in the case of * a column that was added after-the-fact by ALTER TABLE). In some cases * this can force us to re-order the tlist to preserve resno ordering. * (We do all this work in special cases so that preptlist.c is fast for * the typical case.) * * The given tlist has already been through expression_tree_mutator; * therefore the TargetEntry nodes are fresh copies that it's okay to * scribble on. * * Note that this is not needed for INSERT because INSERT isn't inheritable. */static List *adjust_inherited_tlist(List *tlist, adjust_inherited_attrs_context *context){ bool changed_it = false; ListCell *tl; List *new_tlist; bool more; int attrno; /* Scan tlist and update resnos to match attnums of new_relid */ foreach(tl, tlist) { TargetEntry *tle = (TargetEntry *) lfirst(tl); if (tle->resjunk) continue; /* ignore junk items */ attrno = translate_inherited_attnum(tle->resno, context); if (tle->resno != attrno) { tle->resno = attrno; changed_it = true; } } /* * If we changed anything, re-sort the tlist by resno, and make sure * resjunk entries have resnos above the last real resno. The sort * algorithm is a bit stupid, but for such a seldom-taken path, small is * probably better than fast. */ if (!changed_it) return tlist; new_tlist = NIL; more = true; for (attrno = 1; more; attrno++) { more = false; foreach(tl, tlist) { TargetEntry *tle = (TargetEntry *) lfirst(tl); if (tle->resjunk) continue; /* ignore junk items */ if (tle->resno == attrno) new_tlist = lappend(new_tlist, tle); else if (tle->resno > attrno) more = true; } } foreach(tl, tlist) { TargetEntry *tle = (TargetEntry *) lfirst(tl); if (!tle->resjunk) continue; /* here, ignore non-junk items */ tle->resno = attrno; new_tlist = lappend(new_tlist, tle); attrno++; } return new_tlist;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?