📄 ruleutils.c
字号:
fno = SPI_fnumber(rulettc, "is_instead"); is_instead = (bool) SPI_getbinval(ruletup, rulettc, fno, &isnull); fno = SPI_fnumber(rulettc, "ev_qual"); ev_qual = SPI_getvalue(ruletup, rulettc, fno); fno = SPI_fnumber(rulettc, "ev_action"); ev_action = SPI_getvalue(ruletup, rulettc, fno); if (ev_action != NULL) actions = (List *) stringToNode(ev_action); /* ---------- * Build the rules definition text * ---------- */ strcpy(buf, "CREATE RULE \""); /* The rule name */ strcat(buf, rulename); strcat(buf, "\" AS ON "); /* The event the rule is fired for */ switch (ev_type) { case '1': strcat(buf, "SELECT TO \""); break; case '2': strcat(buf, "UPDATE TO \""); break; case '3': strcat(buf, "INSERT TO \""); break; case '4': strcat(buf, "DELETE TO \""); break; default: elog(ERROR, "get_ruledef: rule %s has unsupported event type %d", rulename, ev_type); break; } /* The relation the rule is fired on */ strcat(buf, get_relation_name(ev_class)); strcat(buf, "\""); if (ev_attr > 0) { strcat(buf, ".\""); strcat(buf, get_attribute_name(ev_class, ev_attr)); strcat(buf, "\""); } /* If the rule has an event qualification, add it */ if (ev_qual == NULL) ev_qual = ""; if (strlen(ev_qual) > 0 && strcmp(ev_qual, "<>") != 0) { Node *qual; Query *query; QryHier qh; qual = stringToNode(ev_qual); query = (Query *) lfirst(actions); qh.parent = NULL; qh.query = query; strcat(buf, " WHERE "); strcat(buf, get_rule_expr(&qh, 0, qual, TRUE)); } strcat(buf, " DO "); /* The INSTEAD keyword (if so) */ if (is_instead) strcat(buf, "INSTEAD "); /* Finally the rules actions */ if (length(actions) > 1) { List *action; Query *query; strcat(buf, "("); foreach(action, actions) { query = (Query *) lfirst(action); strcat(buf, get_query_def(query, NULL)); strcat(buf, "; "); } strcat(buf, ");"); } else { if (length(actions) == 0) { strcat(buf, "NOTHING;"); } else { Query *query; query = (Query *) lfirst(actions); strcat(buf, get_query_def(query, NULL)); strcat(buf, ";"); } } /* ---------- * That's it * ---------- */ return buf;}/* ---------- * make_viewdef - reconstruct the SELECT part of a * view rewrite rule * ---------- */static char *make_viewdef(HeapTuple ruletup, TupleDesc rulettc){ char buf[BUFSIZE]; Query *query; char ev_type; Oid ev_class; int2 ev_attr; bool is_instead; char *ev_qual; char *ev_action; List *actions = NIL; int fno; bool isnull; /* ---------- * Get the attribute values from the rules tuple * ---------- */ fno = SPI_fnumber(rulettc, "ev_type"); ev_type = (char) SPI_getbinval(ruletup, rulettc, fno, &isnull); fno = SPI_fnumber(rulettc, "ev_class"); ev_class = (Oid) SPI_getbinval(ruletup, rulettc, fno, &isnull); fno = SPI_fnumber(rulettc, "ev_attr"); ev_attr = (int2) SPI_getbinval(ruletup, rulettc, fno, &isnull); fno = SPI_fnumber(rulettc, "is_instead"); is_instead = (bool) SPI_getbinval(ruletup, rulettc, fno, &isnull); fno = SPI_fnumber(rulettc, "ev_qual"); ev_qual = SPI_getvalue(ruletup, rulettc, fno); fno = SPI_fnumber(rulettc, "ev_action"); ev_action = SPI_getvalue(ruletup, rulettc, fno); if (ev_action != NULL) actions = (List *) stringToNode(ev_action); if (length(actions) != 1) return "Not a view"; query = (Query *) lfirst(actions); if (ev_type != '1' || ev_attr >= 0 || !is_instead || strcmp(ev_qual, "<>")) return "Not a view"; strcpy(buf, get_query_def(query, NULL)); strcat(buf, ";"); /* ---------- * That's it * ---------- */ return pstrdup(buf);}/* ---------- * get_query_def - Parse back one action from * the parsetree in the actions * list * ---------- */static char *get_query_def(Query *query, QryHier *parentqh){ QryHier qh; qh.parent = parentqh; qh.query = query; switch (query->commandType) { case CMD_SELECT: return get_select_query_def(query, &qh); break; case CMD_UPDATE: return get_update_query_def(query, &qh); break; case CMD_INSERT: return get_insert_query_def(query, &qh); break; case CMD_DELETE: return get_delete_query_def(query, &qh); break; case CMD_NOTHING: return "NOTHING"; break; default: elog(ERROR, "get_ruledef of %s: query command type %d not implemented yet", rulename, query->commandType); break; } return NULL;}/* ---------- * get_select_query_def - Parse back a SELECT parsetree * ---------- */static char *get_select_query_def(Query *query, QryHier *qh){ char buf[BUFSIZE]; char *sep; TargetEntry *tle; RangeTblEntry *rte; bool *rt_used; int rt_length; int rt_numused = 0; bool rt_constonly = TRUE; int i; List *l; /* ---------- * First we need to know which and how many of the * range table entries in the query are used in the target list * or queries qualification * ---------- */ rt_length = length(query->rtable); rt_used = palloc(sizeof(bool) * rt_length); for (i = 0; i < rt_length; i++) { if (check_if_rte_used((Node *) (query->targetList), i + 1, 0) || check_if_rte_used(query->qual, i + 1, 0) || check_if_rte_used(query->havingQual, i + 1, 0)) { rt_used[i] = TRUE; rt_numused++; } else rt_used[i] = FALSE; } /* ---------- * Now check if any of the used rangetable entries is different * from *NEW* and *CURRENT*. If so we must omit the FROM clause * later. * ---------- */ i = 0; foreach(l, query->rtable) { if (!rt_used[i++]) continue; rte = (RangeTblEntry *) lfirst(l); if (!strcmp(rte->refname, "*NEW*")) continue; if (!strcmp(rte->refname, "*CURRENT*")) continue; rt_constonly = FALSE; break; } /* ---------- * Build up the query string - first we say SELECT * ---------- */ strcpy(buf, "SELECT"); /* Then we tell what to select (the targetlist) */ sep = " "; foreach(l, query->targetList) { bool tell_as = FALSE; tle = (TargetEntry *) lfirst(l); strcat(buf, sep); sep = ", "; strcat(buf, get_tle_expr(qh, 0, tle, (rt_numused > 1))); /* Check if we must say AS ... */ if (! IsA(tle->expr, Var)) tell_as = strcmp(tle->resdom->resname, "?column?"); else { Var *var = (Var *) (tle->expr); char *attname; rte = get_rte_for_var(var, qh); attname = get_attribute_name(rte->relid, var->varattno); if (strcmp(attname, tle->resdom->resname)) tell_as = TRUE; } /* and do if so */ if (tell_as) { strcat(buf, " AS \""); strcat(buf, tle->resdom->resname); strcat(buf, "\""); } } /* If we need other tables that *NEW* or *CURRENT* add the FROM clause */ if (!rt_constonly && rt_numused > 0) { strcat(buf, " FROM"); i = 0; sep = " "; foreach(l, query->rtable) { if (rt_used[i++]) { rte = (RangeTblEntry *) lfirst(l); if (!strcmp(rte->refname, "*NEW*")) continue; if (!strcmp(rte->refname, "*CURRENT*")) continue; strcat(buf, sep); sep = ", "; strcat(buf, "\""); strcat(buf, rte->relname); strcat(buf, "\""); if (strcmp(rte->relname, rte->refname) != 0) { strcat(buf, " \""); strcat(buf, rte->refname); strcat(buf, "\""); } } } } /* Add the WHERE clause if given */ if (query->qual != NULL) { strcat(buf, " WHERE "); strcat(buf, get_rule_expr(qh, 0, query->qual, (rt_numused > 1))); } /* Add the GROUP BY CLAUSE */ if (query->groupClause != NULL) { strcat(buf, " GROUP BY "); sep = ""; foreach(l, query->groupClause) { GroupClause *grp = (GroupClause *) lfirst(l); Node *groupexpr; groupexpr = (Node *) get_groupclause_expr(grp, query->targetList); strcat(buf, sep); strcat(buf, get_rule_expr(qh, 0, groupexpr, (rt_numused > 1))); sep = ", "; } } /* ---------- * Copy the query string into allocated space and return it * ---------- */ return pstrdup(buf);}/* ---------- * get_insert_query_def - Parse back an INSERT parsetree * ---------- */static char *get_insert_query_def(Query *query, QryHier *qh){ char buf[BUFSIZE]; char *sep; TargetEntry *tle; RangeTblEntry *rte; bool *rt_used; int rt_length; int rt_numused = 0; bool rt_constonly = TRUE; int i; List *l; /* ---------- * We need to know if other tables than *NEW* or *CURRENT* * are used in the query. If not, it's an INSERT ... VALUES, * otherwise an INSERT ... SELECT. * ---------- */ rt_length = length(query->rtable); rt_used = palloc(sizeof(bool) * rt_length); for (i = 0; i < rt_length; i++) { if (check_if_rte_used((Node *) (query->targetList), i + 1, 0) || check_if_rte_used(query->qual, i + 1, 0) || check_if_rte_used(query->havingQual, i + 1, 0)) { rt_used[i] = TRUE; rt_numused++; } else rt_used[i] = FALSE; } i = 0; foreach(l, query->rtable) { if (!rt_used[i++]) continue; rte = (RangeTblEntry *) lfirst(l); if (!strcmp(rte->refname, "*NEW*")) continue; if (!strcmp(rte->refname, "*CURRENT*")) continue; rt_constonly = FALSE; break; } /* ---------- * Start the query with INSERT INTO relname * ---------- */ rte = (RangeTblEntry *) nth(query->resultRelation - 1, query->rtable); strcpy(buf, "INSERT INTO \""); strcat(buf, rte->relname); strcat(buf, "\""); /* Add the target list */ sep = " ("; foreach(l, query->targetList) { tle = (TargetEntry *) lfirst(l); strcat(buf, sep); sep = ", "; strcat(buf, "\""); strcat(buf, tle->resdom->resname); strcat(buf, "\""); } strcat(buf, ") "); /* Add the VALUES or the SELECT */ if (rt_constonly && query->qual == NULL) { strcat(buf, "VALUES ("); sep = ""; foreach(l, query->targetList) { tle = (TargetEntry *) lfirst(l); strcat(buf, sep); sep = ", "; strcat(buf, get_tle_expr(qh, 0, tle, (rt_numused > 1))); } strcat(buf, ")"); } else strcat(buf, get_select_query_def(query, qh)); /* ---------- * Copy the query string into allocated space and return it * ---------- */ return pstrdup(buf);}/* ---------- * get_update_query_def - Parse back an UPDATE parsetree * ---------- */static char *get_update_query_def(Query *query, QryHier *qh){ char buf[BUFSIZE]; char *sep; TargetEntry *tle; RangeTblEntry *rte; List *l; /* ---------- * Start the query with UPDATE relname SET * ---------- */ rte = (RangeTblEntry *) nth(query->resultRelation - 1, query->rtable); strcpy(buf, "UPDATE "); strcat(buf, rte->relname); strcat(buf, " SET "); /* Add the comma separated list of 'attname = value' */ sep = ""; foreach(l, query->targetList) { tle = (TargetEntry *) lfirst(l); strcat(buf, sep); sep = ", "; strcat(buf, "\""); strcat(buf, tle->resdom->resname); strcat(buf, "\" = "); strcat(buf, get_tle_expr(qh, query->resultRelation, tle, TRUE)); } /* Finally add a WHERE clause if given */ if (query->qual != NULL) { strcat(buf, " WHERE "); strcat(buf, get_rule_expr(qh, query->resultRelation, query->qual, TRUE)); } /* ---------- * Copy the query string into allocated space and return it * ---------- */ return pstrdup(buf);}/* ---------- * get_delete_query_def - Parse back a DELETE parsetree * ---------- */static char *get_delete_query_def(Query *query, QryHier *qh){ char buf[BUFSIZE]; RangeTblEntry *rte; /* ---------- * Start the query with DELETE FROM relname * ---------- */ rte = (RangeTblEntry *) nth(query->resultRelation - 1, query->rtable); strcpy(buf, "DELETE FROM \""); strcat(buf, rte->relname); strcat(buf, "\""); /* Add a WHERE clause if given */ if (query->qual != NULL) { strcat(buf, " WHERE "); strcat(buf, get_rule_expr(qh, 0, query->qual, FALSE)); } /* ---------- * Copy the query string into allocated space and return it * ---------- */ return pstrdup(buf);}/* * Find the RTE referenced by a (possibly nonlocal) Var. */static RangeTblEntry *get_rte_for_var(Var *var, QryHier *qh){ int sup = var->varlevelsup; while (sup-- > 0) qh = qh->parent; return (RangeTblEntry *) nth(var->varno - 1, qh->query->rtable);}/* ---------- * get_rule_expr - Parse back an expression * ---------- */static char *get_rule_expr(QryHier *qh, int rt_index, Node *node, bool varprefix){ char buf[BUFSIZE]; if (node == NULL)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -