📄 recipe.c
字号:
if (p->param_tlist) { /* * we have a parameter with an attribute like * $N.foo so replace it with a new var node */ /* param tlist can only have one entry in them! */ param_tle = (TargetEntry *) (lfirst(p->param_tlist)); oldVar = (Var *) param_tle->expr; oldVar->varno = rt_ind; oldVar->varnoold = rt_ind; return (Node *) oldVar; } else { /* we have $N without the .foo */ bool defined; bool isRel; /* * TODO here, we need to check to see whether the * type of the tee is a complex type (relation) or * a simple type */ /* * if it is a simple type, then we need to get the * "result" attribute from the tee relation */ isRel = (typeidTypeRelid(p->paramtype) != 0); if (isRel) { newVar = makeVar(rt_ind, 0, /* the whole tuple */ TypeGet(teeRelName, &defined), -1, 0, rt_ind, 0); return (Node *) newVar; } else newVar = makeVar(rt_ind, 1, /* just the first field, * which is 'result' */ TypeGet(teeRelName, &defined), -1, 0, rt_ind, 0); return (Node *) newVar; } } else elog(NOTICE, "tg_replaceNumberedParam: unexpected paramkind value of %d", p->paramkind); } break; case T_Expr: { /* * the node is an expression, we need to recursively call * ourselves until we find parameter nodes */ List *l; Expr *expr = (Expr *) expression; List *newArgs; /* * we have to make a new args lists because Params can be * replaced by Var nodes in tg_replaceNumberedParam() */ newArgs = NIL; /* * we only care about argument to expressions, it doesn't * matter when the opType is */ /* recursively rewrite the arguments of this expression */ foreach(l, expr->args) { newArgs = lappend(newArgs, tg_replaceNumberedParam(lfirst(l), pnum, rt_ind, teeRelName)); } /* change the arguments of the expression */ expr->args = newArgs; } break; default: { /* ignore other expr types */ } } return expression;}/* tg_rewriteParamsInExpr: rewrite the params in expressions by using the targetlist entries from the input parsetrees this procedure recursively calls itself it returns a (possibly modified) Node*.*/static Node *tg_rewriteParamsInExpr(Node *expression, QueryTreeList * inputQlist){ List *tl; TargetEntry *param_tle, *tle; Param *p; int childno; char *resname; if (expression == NULL) return NULL; switch (nodeTag(expression)) { case T_Param: { /* * the node is a parameter, substitute the entry from the * target list of the child that corresponds to the * parameter number */ p = (Param *) expression; /* we only deal with the case of numbered parameters */ if (p->paramkind == PARAM_NUM) { /* paramid's start from 1 */ childno = p->paramid - 1; if (p->param_tlist) { /* * we have a parameter with an attribute like * $N.foo so match the resname "foo" against the * target list of the (N-1)th inputQlist */ /* param tlist can only have one entry in them! */ param_tle = (TargetEntry *) (lfirst(p->param_tlist)); resname = param_tle->resdom->resname; if (inputQlist->qtrees[childno]) { foreach(tl, inputQlist->qtrees[childno]->targetList) { tle = lfirst(tl); if (strcmp(resname, tle->resdom->resname) == 0) return tle->expr; } } else elog(ERROR, "tg_rewriteParamsInExpr:can't substitute for parameter %d when that input is unconnected", p->paramid); } else { /* we have $N without the .foo */ /* use the first resdom in the targetlist of the */ /* appropriate child query */ tl = inputQlist->qtrees[childno]->targetList; tle = lfirst(tl); return tle->expr; } } else elog(NOTICE, "tg_rewriteParamsInExpr: unexpected paramkind value of %d", p->paramkind); } break; case T_Expr: { /* * the node is an expression, we need to recursively call * ourselves until we find parameter nodes */ List *l; Expr *expr = (Expr *) expression; List *newArgs; /* * we have to make a new args lists because Params can be * replaced by Var nodes in tg_rewriteParamsInExpr() */ newArgs = NIL; /* * we only care about argument to expressions, it doesn't * matter when the opType is */ /* recursively rewrite the arguments of this expression */ foreach(l, expr->args) { newArgs = lappend(newArgs, tg_rewriteParamsInExpr(lfirst(l), inputQlist)); } /* change the arguments of the expression */ expr->args = newArgs; } break; default: { /* ignore other expr types */ } } return expression;}/* getParamTypes: given an element, finds its parameter types. the typev array argument is set to the parameter types. the parameterCount is returned this code is very similar to ProcedureDefine() in pg_proc.c*/static intgetParamTypes(TgElement * elem, Oid *typev){ /* this code is similar to ProcedureDefine() */ int16 parameterCount; bool defined; Oid toid; char *t; int i, j; parameterCount = 0; for (i = 0; i < 8; i++) typev[i] = 0; for (j = 0; j < elem->inTypes->num; j++) { if (parameterCount == 8) { elog(ERROR, "getParamTypes: Ingredients cannot take > 8 arguments"); } t = elem->inTypes->val[j]; if (strcmp(t, "opaque") == 0) { elog(ERROR, "getParamTypes: Ingredient functions cannot take type 'opaque'"); } else { toid = TypeGet(elem->inTypes->val[j], &defined); if (!OidIsValid(toid)) elog(ERROR, "getParamTypes: arg type '%s' is not defined", t); if (!defined) elog(NOTICE, "getParamTypes: arg type '%s' is only a shell", t); } typev[parameterCount++] = toid; } return parameterCount;}/* * tg_parseTeeNode * * handles the parsing of the tee node * * */static QueryTreeList *tg_parseTeeNode(TgRecipe * r, TgNode * n, /* the tee node */ int i, /* which input this node is to its parent */ QueryTreeList * qList, TeeInfo * teeInfo){ QueryTreeList *q; char *tt; int rt_ind; Query *orig; /* * the input Node is a tee node, so we need to do the following: we * need to parse the child of the tee node, we add that to our query * tree list we need the name of the tee node table the tee node table * is the table into which the tee node may materialize results. Call * it TT we add a range table to our existing query with TT in it we * need to replace the parameter $i with TT (otherwise the optimizer * won't know to use the table on expression containining $i) After * that rewrite, the optimizer will generate sequential scans of TT * * Later, in the glue phase, we replace all instances of TT sequential * scans with the actual Tee node */ q = tg_parseSubQuery(r, n, teeInfo); /* tt is the name of the tee node table */ tt = n->nodeName; if (q) appendTeeQuery(teeInfo, q, tt); orig = qList->qtrees[0]; rt_ind = RangeTablePosn(orig->rtable, tt); /* * check to see that this table is not part of the range table * already. This usually only happens if multiple inputs are * connected to the same Tee. */ if (rt_ind == 0) { orig->rtable = lappend(orig->rtable, addRangeTableEntry(NULL, tt, tt, FALSE, FALSE)); rt_ind = length(orig->rtable); } orig->qual = tg_replaceNumberedParam(orig->qual, i + 1, /* params start at 1 */ rt_ind, tt); return qList;}/* * tg_parseSubQuery: * go backwards from a node and parse the query * * the result parse tree is passed back * * could return NULL if trying to parse a teeNode * that's already been processed by another parent * */static QueryTreeList *tg_parseSubQuery(TgRecipe * r, TgNode * n, TeeInfo * teeInfo){ TgElement *elem; char *funcName; Oid typev[8], /* eight arguments maximum */ relid; int i, parameterCount; QueryTreeList *qList; /* the parse tree of the nodeElement */ QueryTreeList *inputQlist; /* the list of parse trees for the inputs * to this node */ QueryTreeList *q; TgNode *child; Relation rel; unsigned int len; TupleDesc tupdesc; qList = NULL; if (n->nodeType == TG_INGRED_NODE) { /* parse each ingredient node in turn */ elem = n->nodeElem; switch (elem->srcLang) { case TG_SQL: { /* * for SQL ingredients, the SQL query is contained in * the 'src' field */#ifdef DEBUG_RECIPE elog(NOTICE, "calling parser with %s", elem->src);#endif /* DEBUG_RECIPE */ parameterCount = getParamTypes(elem, typev); qList = parser(elem->src, typev, parameterCount); if (qList->len > 1) { elog(NOTICE, "tg_parseSubQuery: parser produced > 1 query tree"); } } break; case TG_C: { /* C ingredients are registered functions in postgres */ /* * we create a new query string by using the function * name (found in the 'src' field) and adding * parameters to it so if the function was FOOBAR and * took in two arguments, we would create a string * select FOOBAR($1,$2) */ char newquery[1000]; funcName = elem->src; parameterCount = getParamTypes(elem, typev); if (parameterCount > 0) { int i; snprintf(newquery, 1000, "select %s($1", funcName); for (i = 1; i < parameterCount; i++) snprintf(newquery, 1000, "%s,$%d", pstrdup(newquery), i); snprintf(newquery, 1000, "%s)", pstrdup(newquery)); } else snprintf(newquery, 1000, "select %s()", funcName);#ifdef DEBUG_RECIPE elog(NOTICE, "calling parser with %s", newquery);#endif /* DEBUG_RECIPE */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -