deparse: Support CREATE RULE
authorAlvaro Herrera <alvherre@alvh.no-ip.org>
Wed, 26 Feb 2014 20:26:55 +0000 (17:26 -0300)
committerAlvaro Herrera <alvherre@alvh.no-ip.org>
Tue, 7 Apr 2015 17:09:36 +0000 (14:09 -0300)
src/backend/tcop/deparse_utility.c
src/backend/utils/adt/ruleutils.c
src/include/utils/ruleutils.h

index 8fe8ae141b178609ece1aac9c9a7c632b239c5ff..b896fa4b658a1fc60da8afb65f15b3005e57eac0 100644 (file)
@@ -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:
index cb20f52906a226c2e02ef921b57b14d4af503445..ea318bbecb11bb3aed3f7d09b1f472319cae1ff6 100644 (file)
@@ -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)
index 4447af9a0a8741ab257394ac6eb9ce1b8cf21aa4..9989cdd4f5196f1182a235a3e420e6cf8b5c7053 100644 (file)
@@ -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);