📄 recipe.c
字号:
qList = parser(newquery, typev, parameterCount); if (qList->len > 1) { elog(NOTICE, "tg_parseSubQuery: parser produced > 1 query tree"); } } break; case TG_RECIPE_GRAPH: elog(NOTICE, "tg_parseSubQuery: can't parse recipe graph ingredients yet!"); break; case TG_COMPILED: elog(NOTICE, "tg_parseSubQuery: can't parse compiled ingredients yet!"); break; default: elog(NOTICE, "tg_parseSubQuery: unknown srcLang: %d", elem->srcLang); } /* parse each of the subrecipes that are input to this node */ if (n->inNodes->num > 0) { inputQlist = malloc(sizeof(QueryTreeList)); inputQlist->len = n->inNodes->num + 1; inputQlist->qtrees = (Query **) malloc(inputQlist->len * sizeof(Query *)); for (i = 0; i < n->inNodes->num; i++) { inputQlist->qtrees[i] = NULL; if (n->inNodes->val[i]) { if (n->inNodes->val[i]->nodeType == TG_TEE_NODE) { qList = tg_parseTeeNode(r, n->inNodes->val[i], i, qList, teeInfo); } else { /* input node is not a Tee */ q = tg_parseSubQuery(r, n->inNodes->val[i], teeInfo); Assert(q->len == 1); inputQlist->qtrees[i] = q->qtrees[0]; } } } /* now, we have all the query trees from our input nodes */ /* transform the original parse tree appropriately */ tg_rewriteQuery(r, n, qList, inputQlist); } } else if (n->nodeType == TG_EYE_NODE) { /* * if we hit an eye, we need to stop and make what we have into a * subrecipe query block */ elog(NOTICE, "tg_parseSubQuery: can't handle eye nodes yet"); } else if (n->nodeType == TG_TEE_NODE) { /* * if we hit a tee, check to see if the parsing has been done for * this tee already by the other parent */ rel = RelationNameGetRelation(n->nodeName); if (RelationIsValid(rel)) { /* * this tee has already been visited, no need to do any * further processing */ return NULL; } else { /* we need to process the child of the tee first, */ child = n->inNodes->val[0]; if (child->nodeType == TG_TEE_NODE) { /* nested Tee nodes */ qList = tg_parseTeeNode(r, child, 0, qList, teeInfo); return qList; } Assert(child != NULL); /* parse the input node */ q = tg_parseSubQuery(r, child, teeInfo); Assert(q->len == 1); /* add the parsed query to the main list of queries */ qList = appendQlist(qList, q); /* need to create the tee table here */ /* * the tee table created is used both for materializing the * values at the tee node, and for parsing and optimization. * The optimization needs to have a real table before it will * consider scans on it */ /* * first, find the type of the tuples being produced by the * tee. The type is the same as the output type of the child * node. * * NOTE: we are assuming that the child node only has a single * output here! */ getParamTypes(child->nodeElem, typev); /* * the output type is either a complex type, (and is thus a * relation) or is a simple type */ rel = RelationNameGetRelation(child->nodeElem->outTypes->val[0]); if (RelationIsValid(rel)) { /* * for complex types, create new relation with the same * tuple descriptor as the output table type */ len = length(q->qtrees[0]->targetList); tupdesc = rel->rd_att; relid = heap_create_with_catalog( child->nodeElem->outTypes->val[0], tupdesc, RELKIND_RELATION, false); } else { /* * we have to create a relation with one attribute of the * simple base type. That attribute will have an attr * name of "result" */ /* NOTE: ignore array types for the time being */ len = 1; tupdesc = CreateTemplateTupleDesc(len); if (!TupleDescInitEntry(tupdesc, 1, "result", InvalidOid, -1, 0, false)) elog(NOTICE, "tg_parseSubQuery: unexpected result from TupleDescInitEntry"); else { relid = heap_create_with_catalog( child->nodeElem->outTypes->val[0], tupdesc, RELKIND_RELATION, false); } } } } else if (n->nodeType == TG_RECIPE_NODE) elog(NOTICE, "tg_parseSubQuery: can't handle embedded recipes yet!"); else elog(NOTICE, "unknown nodeType: %d", n->nodeType); return qList;}/* * OffsetVarAttno - * recursively find all the var nodes with the specified varno * and offset their varattno with the offset * * code is similar to OffsetVarNodes in rewriteManip.c */voidOffsetVarAttno(Node *node, int varno, int offset){ if (node == NULL) return; switch (nodeTag(node)) { case T_TargetEntry: { TargetEntry *tle = (TargetEntry *) node; OffsetVarAttno(tle->expr, varno, offset); } break; case T_Expr: { Expr *expr = (Expr *) node; OffsetVarAttno((Node *) expr->args, varno, offset); } break; case T_Var: { Var *var = (Var *) node; if (var->varno == varno) var->varattno += offset; } break; case T_List: { List *l; foreach(l, (List *) node) OffsetVarAttno(lfirst(l), varno, offset); } break; default: /* ignore the others */ break; }}/* * appendQlist * add the contents of a QueryTreeList q2 to the end of the QueryTreeList * q1 * * returns a new querytree list */QueryTreeList *appendQlist(QueryTreeList * q1, QueryTreeList * q2){ QueryTreeList *newq; int i, j; int newlen; if (q1 == NULL) return q2; if (q2 == NULL) return q1; newlen = q1->len + q2->len; newq = (QueryTreeList *) malloc(sizeof(QueryTreeList)); newq->len = newlen; newq->qtrees = (Query **) malloc(newlen * sizeof(Query *)); for (i = 0; i < q1->len; i++) newq->qtrees[i] = q1->qtrees[i]; for (j = 0; j < q2->len; j++) newq->qtrees[i + j] = q2->qtrees[j]; return newq;}/* * appendTeeQuery * * modify the query field of the teeInfo list of the particular tee node */static voidappendTeeQuery(TeeInfo * teeInfo, QueryTreeList * q, char *teeNodeName){ int i; Assert(teeInfo); for (i = 0; i < teeInfo->num; i++) { if (strcmp(teeInfo->val[i].tpi_relName, teeNodeName) == 0) { Assert(q->len == 1); teeInfo->val[i].tpi_parsetree = q->qtrees[0]; return; } } elog(NOTICE, "appendTeeQuery: teeNodeName '%s' not found in teeInfo");}/* * replaceSeqScan * replaces sequential scans of a specified relation with the tee plan * the relation is specified by its index in the range table, rt_ind * * returns the modified plan * the offset_attno is the offset that needs to be added to the parent's * qual or targetlist because the child plan has been replaced with a tee node */static voidreplaceSeqScan(Plan *plan, Plan *parent, int rt_ind, Plan *tplan){ Scan *snode; Tee *teePlan; Result *newPlan; if (plan == NULL) return; if (plan->type == T_SeqScan) { snode = (Scan *) plan; if (snode->scanrelid == rt_ind) { /* * found the sequential scan that should be replaced with the * tplan. */ /* we replace the plan, but we also need to modify its parent */ /* * replace the sequential scan with a Result node the reason * we use a result node is so that we get the proper * projection behavior. The Result node is simply (ab)used as * a projection node */ newPlan = makeNode(Result); newPlan->plan.cost = 0.0; newPlan->plan.state = (EState *) NULL; newPlan->plan.targetlist = plan->targetlist; newPlan->plan.lefttree = tplan; newPlan->plan.righttree = NULL; newPlan->resconstantqual = NULL; newPlan->resstate = NULL; /* change all the varno's to 1 */ ChangeVarNodes((Node *) newPlan->plan.targetlist, snode->scanrelid, 1); if (parent) { teePlan = (Tee *) tplan; if (parent->lefttree == plan) parent->lefttree = (Plan *) newPlan; else parent->righttree = (Plan *) newPlan; if (teePlan->leftParent == NULL) teePlan->leftParent = (Plan *) newPlan; else teePlan->rightParent = (Plan *) newPlan;/* comment for now to test out executor-stuff if (parent->state) { ExecInitNode((Plan*)newPlan, parent->state, (Plan*)newPlan); }*/ } } } else { if (plan->lefttree) replaceSeqScan(plan->lefttree, plan, rt_ind, tplan); if (plan->righttree) replaceSeqScan(plan->righttree, plan, rt_ind, tplan); }}/* * replaceTeeScans * places the sequential scans of the Tee table with * a connection to the actual tee plan node */static Plan *replaceTeeScans(Plan *plan, Query *parsetree, TeeInfo * teeInfo){ int i; List *rtable; RangeTblEntry *rte; char prefix[5]; int rt_ind; Plan *tplan; rtable = parsetree->rtable; if (rtable == NULL) return plan; /* * look through the range table for the tee relation entry, that will * give use the varno we need to detect which sequential scans need to * be replaced with tee nodes */ rt_ind = 0; while (rtable != NIL) { rte = lfirst(rtable); rtable = lnext(rtable); rt_ind++; /* range table references in varno fields * start w/ 1 */ /* * look for the "tee_" prefix in the refname, also check to see * that the relname and the refname are the same this should * eliminate any user-specified table and leave us with the tee * table entries only */ if ((strlen(rte->refname) < 4) || (strcmp(rte->relname, rte->refname) != 0)) continue; StrNCpy(prefix, rte->refname, 5); if (strcmp(prefix, "tee_") == 0) { /* okay, we found a tee node entry in the range table */ /* find the appropriate plan in the teeInfo list */ tplan = NULL; for (i = 0; i < teeInfo->num; i++) { if (strcmp(teeInfo->val[i].tpi_relName, rte->refname) == 0) tplan = teeInfo->val[i].tpi_plan; } if (tplan == NULL) elog(NOTICE, "replaceTeeScans didn't find the corresponding tee plan"); /* * replace the sequential scan node with that var number with * the tee plan node */ replaceSeqScan(plan, NULL, rt_ind, tplan); } } return plan;}#endif /* TIOGA */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -