📄 ruleutils.c
字号:
return pstrdup(""); buf[0] = '\0'; /* ---------- * Each level of get_rule_expr must return an indivisible term * (parenthesized if necessary) to ensure result is reparsed into * the same expression tree. * * There might be some work left here to support additional node types... * ---------- */ switch (nodeTag(node)) { case T_Const: return get_const_expr((Const *) node); break; case T_Var: { Var *var = (Var *) node; RangeTblEntry *rte = get_rte_for_var(var, qh); if (!strcmp(rte->refname, "*NEW*")) strcat(buf, "new."); else if (!strcmp(rte->refname, "*CURRENT*")) strcat(buf, "old."); else { strcat(buf, "\""); strcat(buf, rte->refname); strcat(buf, "\"."); } strcat(buf, "\""); strcat(buf, get_attribute_name(rte->relid, var->varattno)); strcat(buf, "\""); return pstrdup(buf); } break; case T_Expr: { Expr *expr = (Expr *) node; List *args = expr->args; /* ---------- * Expr nodes have to be handled a bit detailed * ---------- */ switch (expr->opType) { case OP_EXPR: strcat(buf, "("); if (length(args) == 2) { /* binary operator */ strcat(buf, get_rule_expr(qh, rt_index, (Node *) lfirst(args), varprefix)); strcat(buf, " "); strcat(buf, get_opname(((Oper *) expr->oper)->opno)); strcat(buf, " "); strcat(buf, get_rule_expr(qh, rt_index, (Node *) lsecond(args), varprefix)); } else { /* unary operator --- but which side? */ Oid opno = ((Oper *) expr->oper)->opno; HeapTuple tp; Form_pg_operator optup; tp = SearchSysCacheTuple(OPROID, ObjectIdGetDatum(opno), 0, 0, 0); Assert(HeapTupleIsValid(tp)); optup = (Form_pg_operator) GETSTRUCT(tp); switch (optup->oprkind) { case 'l': strcat(buf, get_opname(opno)); strcat(buf, " "); strcat(buf, get_rule_expr(qh, rt_index, (Node *) lfirst(args), varprefix)); break; case 'r': strcat(buf, get_rule_expr(qh, rt_index, (Node *) lfirst(args), varprefix)); strcat(buf, " "); strcat(buf, get_opname(opno)); break; default: elog(ERROR, "get_rule_expr: bogus oprkind"); } } strcat(buf, ")"); return pstrdup(buf); break; case OR_EXPR: strcat(buf, "("); strcat(buf, get_rule_expr(qh, rt_index, (Node *) lfirst(args), varprefix)); /* It's not clear that we can ever see N-argument * OR/AND clauses here, but might as well cope... */ while ((args = lnext(args)) != NIL) { strcat(buf, " OR "); strcat(buf, get_rule_expr(qh, rt_index, (Node *) lfirst(args), varprefix)); } strcat(buf, ")"); return pstrdup(buf); break; case AND_EXPR: strcat(buf, "("); strcat(buf, get_rule_expr(qh, rt_index, (Node *) lfirst(args), varprefix)); while ((args = lnext(args)) != NIL) { strcat(buf, " AND "); strcat(buf, get_rule_expr(qh, rt_index, (Node *) lfirst(args), varprefix)); } strcat(buf, ")"); return pstrdup(buf); break; case NOT_EXPR: strcat(buf, "(NOT "); strcat(buf, get_rule_expr(qh, rt_index, (Node *) get_leftop(expr), varprefix)); strcat(buf, ")"); return pstrdup(buf); break; case FUNC_EXPR: return get_func_expr(qh, rt_index, (Expr *) node, varprefix); break; default: printf("\n%s\n", nodeToString(node)); elog(ERROR, "get_rule_expr: expr type not supported"); } } break; case T_Aggref: { Aggref *aggref = (Aggref *) node; strcat(buf, "\""); strcat(buf, aggref->aggname); strcat(buf, "\"("); strcat(buf, get_rule_expr(qh, rt_index, (Node *) (aggref->target), varprefix)); strcat(buf, ")"); return pstrdup(buf); } break; case T_ArrayRef: { ArrayRef *aref = (ArrayRef *) node; List *lowlist; List *uplist; strcat(buf, get_rule_expr(qh, rt_index, aref->refexpr, varprefix)); lowlist = aref->reflowerindexpr; foreach(uplist, aref->refupperindexpr) { strcat(buf, "["); if (lowlist) { strcat(buf, get_rule_expr(qh, rt_index, (Node *) lfirst(lowlist), varprefix)); strcat(buf, ":"); lowlist = lnext(lowlist); } strcat(buf, get_rule_expr(qh, rt_index, (Node *) lfirst(uplist), varprefix)); strcat(buf, "]"); } /* XXX need to do anything with refassgnexpr? */ return pstrdup(buf); } break; case T_CaseExpr: { CaseExpr *caseexpr = (CaseExpr *) node; List *temp; strcat(buf, "CASE"); foreach(temp, caseexpr->args) { CaseWhen *when = (CaseWhen *) lfirst(temp); strcat(buf, " WHEN "); strcat(buf, get_rule_expr(qh, rt_index, when->expr, varprefix)); strcat(buf, " THEN "); strcat(buf, get_rule_expr(qh, rt_index, when->result, varprefix)); } strcat(buf, " ELSE "); strcat(buf, get_rule_expr(qh, rt_index, caseexpr->defresult, varprefix)); strcat(buf, " END"); return pstrdup(buf); } break; case T_SubLink: return get_sublink_expr(qh, rt_index, node, varprefix); break; default: printf("\n%s\n", nodeToString(node)); elog(ERROR, "get_ruledef of %s: unknown node type %d in get_rule_expr()", rulename, nodeTag(node)); break; } return FALSE;}/* ---------- * get_func_expr - Parse back a Func node * ---------- */static char *get_func_expr(QryHier *qh, int rt_index, Expr *expr, bool varprefix){ char buf[BUFSIZE]; HeapTuple proctup; Form_pg_proc procStruct; List *l; char *sep; Func *func = (Func *) (expr->oper); char *proname; /* ---------- * Get the functions pg_proc tuple * ---------- */ proctup = SearchSysCacheTuple(PROOID, ObjectIdGetDatum(func->funcid), 0, 0, 0); if (!HeapTupleIsValid(proctup)) elog(ERROR, "cache lookup for proc %u failed", func->funcid); procStruct = (Form_pg_proc) GETSTRUCT(proctup); proname = nameout(&(procStruct->proname)); if (procStruct->pronargs == 1 && procStruct->proargtypes[0] == InvalidOid) { if (!strcmp(proname, "nullvalue")) { strcpy(buf, "("); strcat(buf, get_rule_expr(qh, rt_index, lfirst(expr->args), varprefix)); strcat(buf, " ISNULL)"); return pstrdup(buf); } if (!strcmp(proname, "nonnullvalue")) { strcpy(buf, "("); strcat(buf, get_rule_expr(qh, rt_index, lfirst(expr->args), varprefix)); strcat(buf, " NOTNULL)"); return pstrdup(buf); } } /* ---------- * Build a string of proname(args) * ---------- */ strcpy(buf, "\""); strcat(buf, proname); strcat(buf, "\"("); sep = ""; foreach(l, expr->args) { strcat(buf, sep); sep = ", "; strcat(buf, get_rule_expr(qh, rt_index, lfirst(l), varprefix)); } strcat(buf, ")"); /* ---------- * Copy the function call string into allocated space and return it * ---------- */ return pstrdup(buf);}/* ---------- * get_tle_expr - A target list expression is a bit * different from a normal expression. * If the target column has an * an atttypmod, the parser usually * puts a padding-/cut-function call * around the expression itself. We * we must get rid of it, otherwise * dump/reload/dump... would blow up * the expressions. * ---------- */static char *get_tle_expr(QryHier *qh, int rt_index, TargetEntry *tle, bool varprefix){ Expr *expr = (Expr *) (tle->expr); Func *func; HeapTuple tup; Form_pg_proc procStruct; Form_pg_type typeStruct; Const *second_arg; /* ---------- * Check if the result has an atttypmod and if the * expression in the targetlist entry is a function call * ---------- */ if (tle->resdom->restypmod < 0 || ! IsA(expr, Expr) || expr->opType != FUNC_EXPR) return get_rule_expr(qh, rt_index, tle->expr, varprefix); func = (Func *) (expr->oper); /* ---------- * Get the functions pg_proc tuple * ---------- */ tup = SearchSysCacheTuple(PROOID, ObjectIdGetDatum(func->funcid), 0, 0, 0); if (!HeapTupleIsValid(tup)) elog(ERROR, "cache lookup for proc %u failed", func->funcid); procStruct = (Form_pg_proc) GETSTRUCT(tup); /* ---------- * It must be a function with two arguments where the first * is of the same type as the return value and the second is * an int4. * ---------- */ if (procStruct->pronargs != 2 || procStruct->prorettype != procStruct->proargtypes[0] || procStruct->proargtypes[1] != INT4OID) return get_rule_expr(qh, rt_index, tle->expr, varprefix); /* * Furthermore, the name of the function must be the same * as the argument/result type name. */ tup = SearchSysCacheTuple(TYPOID, ObjectIdGetDatum(procStruct->prorettype), 0, 0, 0); if (!HeapTupleIsValid(tup)) elog(ERROR, "cache lookup for type %u failed", procStruct->prorettype); typeStruct = (Form_pg_type) GETSTRUCT(tup); if (strncmp(procStruct->proname.data, typeStruct->typname.data, NAMEDATALEN) != 0) return get_rule_expr(qh, rt_index, tle->expr, varprefix); /* ---------- * Finally (to be totally safe) the second argument must be a * const and match the value in the results atttypmod. * ---------- */ second_arg = (Const *) nth(1, expr->args); if (! IsA(second_arg, Const) || ((int4) second_arg->constvalue) != tle->resdom->restypmod) return get_rule_expr(qh, rt_index, tle->expr, varprefix); /* ---------- * Whow - got it. Now get rid of the padding function * ---------- */ return get_rule_expr(qh, rt_index, lfirst(expr->args), varprefix);}/* ---------- * get_const_expr - Make a string representation * with the type cast out of a Const * ---------- */static char *get_const_expr(Const *constval){ HeapTuple typetup; Form_pg_type typeStruct; FmgrInfo finfo_output; char *extval; bool isnull = FALSE; char buf[BUFSIZE]; char namebuf[64]; if (constval->constisnull) return pstrdup("NULL"); typetup = SearchSysCacheTuple(TYPOID, ObjectIdGetDatum(constval->consttype), 0, 0, 0); if (!HeapTupleIsValid(typetup)) elog(ERROR, "cache lookup of type %u failed", constval->consttype); typeStruct = (Form_pg_type) GETSTRUCT(typetup); fmgr_info(typeStruct->typoutput, &finfo_output); extval = (char *) (*fmgr_faddr(&finfo_output)) (constval->constvalue, &isnull, -1); sprintf(namebuf, "::\"%s\"", nameout(&(typeStruct->typname))); if (strcmp(namebuf, "::unknown") == 0) namebuf[0] = '\0'; sprintf(buf, "'%s'%s", extval, namebuf); return pstrdup(buf);}/* ---------- * get_sublink_expr - Parse back a sublink * ---------- */static char *get_sublink_expr(QryHier *qh, int rt_index, Node *node, bool varprefix){ SubLink *sublink = (SubLink *) node; Query *query = (Query *) (sublink->subselect); Expr *expr; List *l; char *sep; char buf[BUFSIZE]; buf[0] = '\0'; strcat(buf, "("); if (sublink->lefthand != NULL) { if (length(sublink->lefthand) > 1) strcat(buf, "("); sep = ""; foreach(l, sublink->lefthand) { strcat(buf, sep); sep = ", "; strcat(buf, get_rule_expr(qh, rt_index, lfirst(l), varprefix)); } if (length(sublink->lefthand) > 1) strcat(buf, ") "); else strcat(buf, " "); } switch (sublink->subLinkType) { case EXISTS_SUBLINK: strcat(buf, "EXISTS "); break; case ANY_SUBLINK: expr = (Expr *) lfirst(sublink->oper); strcat(buf, get_opname(((Oper *) (expr->oper))->opno)); strcat(buf, " ANY "); break; case ALL_SUBLINK: expr = (Expr *) lfirst(sublink->oper); strcat(buf, get_opname(((Oper *) (expr->oper))->opno)); strcat(buf, " ALL "); break; case EXPR_SUBLINK: expr = (Expr *) lfirst(sublink->oper); strcat(buf, get_opname(((Oper *) (expr->oper))->opno)); strcat(buf, " "); break; default: elog(ERROR, "unupported sublink type %d", sublink->subLinkType); break; } strcat(buf, "("); strcat(buf, get_query_def(query, qh)); strcat(buf, "))"); return pstrdup(buf);}/* ---------- * get_relation_name - Get a relation name by Oid * ---------- */static char *get_relation_name(Oid relid){ HeapTuple classtup; Form_pg_class classStruct; classtup = SearchSysCacheTuple(RELOID, ObjectIdGetDatum(relid), 0, 0, 0); if (!HeapTupleIsValid(classtup)) elog(ERROR, "cache lookup of relation %u failed", relid); classStruct = (Form_pg_class) GETSTRUCT(classtup); return nameout(&(classStruct->relname));}/* ---------- * get_attribute_name - Get an attribute name by it's * relations Oid and it's attnum * ---------- */static char *get_attribute_name(Oid relid, int2 attnum){ HeapTuple atttup; Form_pg_attribute attStruct; atttup = SearchSysCacheTuple(ATTNUM, ObjectIdGetDatum(relid), (Datum) attnum, 0, 0); if (!HeapTupleIsValid(atttup)) elog(ERROR, "cache lookup of attribute %d in relation %u failed", attnum, relid); attStruct = (Form_pg_attribute) GETSTRUCT(atttup); return nameout(&(attStruct->attname));}/* ---------- * check_if_rte_used * Check a targetlist or qual to see if a given rangetable entry * is used in it * ---------- */static boolcheck_if_rte_used(Node *node, Index rt_index, int levelsup){ check_if_rte_used_context context; context.rt_index = rt_index; context.levelsup = levelsup; return check_if_rte_used_walker(node, &context);}static boolcheck_if_rte_used_walker(Node *node, check_if_rte_used_context *context){ if (node == NULL) return false; if (IsA(node, Var)) { Var *var = (Var *) node; return var->varno == context->rt_index && var->varlevelsup == context->levelsup; } if (IsA(node, SubLink)) { SubLink *sublink = (SubLink *) node; Query *query = (Query *) sublink->subselect; /* Recurse into subquery; expression_tree_walker will not */ if (check_if_rte_used((Node *) (query->targetList), context->rt_index, context->levelsup + 1) || check_if_rte_used(query->qual, context->rt_index, context->levelsup + 1) || check_if_rte_used(query->havingQual, context->rt_index, context->levelsup + 1)) return true; /* fall through to let expression_tree_walker examine lefthand args */ } return expression_tree_walker(node, check_if_rte_used_walker, (void *) context);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -