From 0d28eb88f178e2e4602eaf1874d685faf1988d35 Mon Sep 17 00:00:00 2001 From: Alvaro Herrera Date: Wed, 26 Feb 2014 17:26:55 -0300 Subject: [PATCH] deparse: Support CREATE RULE --- src/backend/tcop/deparse_utility.c | 91 +++++++++++++++++++++++++++++- src/backend/utils/adt/ruleutils.c | 71 +++++++++++++++++++++++ src/include/utils/ruleutils.h | 2 + 3 files changed, 163 insertions(+), 1 deletion(-) diff --git a/src/backend/tcop/deparse_utility.c b/src/backend/tcop/deparse_utility.c index 8fe8ae141b..b896fa4b65 100644 --- a/src/backend/tcop/deparse_utility.c +++ b/src/backend/tcop/deparse_utility.c @@ -2196,6 +2196,95 @@ deparse_IndexStmt(Oid objectId, Node *parsetree) return indexStmt; } +static ObjTree * +deparse_RuleStmt(Oid objectId, Node *parsetree) +{ + RuleStmt *node = (RuleStmt *) parsetree; + ObjTree *ruleStmt; + ObjTree *tmp; + Relation pg_rewrite; + Form_pg_rewrite rewrForm; + HeapTuple rewrTup; + SysScanDesc scan; + ScanKeyData key; + Datum ev_qual; + Datum ev_actions; + bool isnull; + char *qual; + List *actions; + List *list; + ListCell *cell; + + pg_rewrite = heap_open(RewriteRelationId, AccessShareLock); + ScanKeyInit(&key, + ObjectIdAttributeNumber, + BTEqualStrategyNumber, + F_OIDEQ, ObjectIdGetDatum(objectId)); + + scan = systable_beginscan(pg_rewrite, RewriteOidIndexId, true, + NULL, 1, &key); + rewrTup = systable_getnext(scan); + if (!HeapTupleIsValid(rewrTup)) + elog(ERROR, "cache lookup failed for rewrite rule with oid %u", + objectId); + + rewrForm = (Form_pg_rewrite) GETSTRUCT(rewrTup); + + ruleStmt = + new_objtree_VA("CREATE %{or_replace}s RULE %{identity}I " + "AS ON %{event}s TO %{table}D %{where_clause}s " + "DO %{instead}s (%{actions:; }s)", 2, + "identity", ObjTypeString, node->rulename, + "or_replace", ObjTypeString, + node->replace ? "OR REPLACE" : ""); + append_string_object(ruleStmt, "event", + node->event == CMD_SELECT ? "SELECT" : + node->event == CMD_UPDATE ? "UPDATE" : + node->event == CMD_DELETE ? "DELETE" : + node->event == CMD_INSERT ? "INSERT" : "XXX"); + append_object_object(ruleStmt, "table", + new_objtree_for_qualname_id(RelationRelationId, + rewrForm->ev_class)); + + append_string_object(ruleStmt, "instead", + node->instead ? "INSTEAD" : "ALSO"); + + ev_qual = heap_getattr(rewrTup, Anum_pg_rewrite_ev_qual, + RelationGetDescr(pg_rewrite), &isnull); + ev_actions = heap_getattr(rewrTup, Anum_pg_rewrite_ev_action, + RelationGetDescr(pg_rewrite), &isnull); + + pg_get_ruledef_details(ev_qual, ev_actions, &qual, &actions); + + tmp = new_objtree_VA("WHERE %{clause}s", 0); + + if (qual) + append_string_object(tmp, "clause", qual); + else + { + append_null_object(tmp, "clause"); + append_bool_object(tmp, "present", false); + } + + append_object_object(ruleStmt, "where_clause", tmp); + + list = NIL; + foreach(cell, actions) + { + char *action = lfirst(cell); + + list = lappend(list, new_string_object(action)); + } + append_array_object(ruleStmt, "actions", list); + + systable_endscan(scan); + heap_close(pg_rewrite, AccessShareLock); + + return ruleStmt; +} + + + /* * deparse_CreateSchemaStmt * deparse a CreateSchemaStmt @@ -2364,7 +2453,7 @@ deparse_simple_command(StashedCommand *cmd) break; case T_RuleStmt: - elog(ERROR, "unimplemented deparse of %s", CreateCommandTag(parsetree)); + command = deparse_RuleStmt(objectId, parsetree); break; case T_CreateSeqStmt: diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index cb20f52906..ea318bbecb 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -449,6 +449,77 @@ pg_get_ruledef_ext(PG_FUNCTION_ARGS) PG_RETURN_TEXT_P(string_to_text(pg_get_ruledef_worker(ruleoid, prettyFlags))); } +/* + * Given a pair of Datum corresponding to a rule's pg_rewrite.ev_qual and + * ev_action columns, return their text representation; ev_qual as a single + * string in whereClause and ev_action as a List of strings (which might be + * NIL, signalling NOTHING) in actions. + */ +void +pg_get_ruledef_details(Datum ev_qual, Datum ev_action, + char **whereClause, List **actions) +{ + int prettyFlags = 0; + char *qualstr = TextDatumGetCString(ev_qual); + char *actionstr = TextDatumGetCString(ev_action); + List *actionNodeList = (List *) stringToNode(actionstr); + StringInfoData buf; + + initStringInfo(&buf); + if (strlen(qualstr) > 0 && strcmp(qualstr, "<>") != 0) + { + Node *qual; + Query *query; + deparse_context context; + deparse_namespace dpns; + + qual = stringToNode(qualstr); + + query = (Query *) linitial(actionNodeList); + query = getInsertSelectQuery(query, NULL); + + AcquireRewriteLocks(query, false, false); + + context.buf = &buf; + context.namespaces = list_make1(&dpns); + context.windowClause = NIL; + context.windowTList = NIL; + context.varprefix = (list_length(query->rtable) != 1); + context.prettyFlags = prettyFlags; + context.wrapColumn = WRAP_COLUMN_DEFAULT; + context.indentLevel = PRETTYINDENT_STD; + + set_deparse_for_query(&dpns, query, NIL); + + get_rule_expr(qual, &context, false); + + *whereClause = pstrdup(buf.data); + } + else + *whereClause = NULL; + + if (list_length(actionNodeList) == 0) + *actions = NIL; + else + { + ListCell *cell; + List *output = NIL; + + foreach(cell, actionNodeList) + { + Query *query = (Query *) lfirst(cell); + + if (query->commandType == CMD_NOTHING) + continue; + + resetStringInfo(&buf); + get_query_def(query, &buf, NIL, NULL, + prettyFlags, WRAP_COLUMN_DEFAULT, 0); + output = lappend(output, pstrdup(buf.data)); + } + *actions = output; + } +} static char * pg_get_ruledef_worker(Oid ruleoid, int prettyFlags) diff --git a/src/include/utils/ruleutils.h b/src/include/utils/ruleutils.h index 4447af9a0a..9989cdd4f5 100644 --- a/src/include/utils/ruleutils.h +++ b/src/include/utils/ruleutils.h @@ -30,6 +30,8 @@ extern void pg_get_indexdef_detailed(Oid indexrelid, extern char *pg_get_trigger_whenclause(Form_pg_trigger trigrec, Node *whenClause, bool pretty); extern char *pg_get_constraintdef_string(Oid constraintId, bool fullCommand); +extern void pg_get_ruledef_details(Datum ev_qual, Datum ev_action, + char **whereClause, List **actions); extern char *deparse_expression(Node *expr, List *dpcontext, bool forceprefix, bool showimplicit); -- 2.39.5