]> granicus.if.org Git - postgresql/commitdiff
Make ruleutils.c schema-aware. Displayed names are schema-qualified
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 3 May 2002 20:15:02 +0000 (20:15 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 3 May 2002 20:15:02 +0000 (20:15 +0000)
only if they would not be found without qualification given the current
search path, as per idea from Peter Eisentraut.

src/backend/parser/parse_func.c
src/backend/utils/adt/ruleutils.c

index 2ab9c9a689868cd8dbc9756514d6e30768f9d176..f74f5be2f7bec4637c3a209bbfb37546e4325cdf 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.126 2002/04/11 20:00:01 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.127 2002/05/03 20:15:02 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -686,6 +686,11 @@ func_select_candidate(int nargs,
  *      b) if the answer is one, we have our function
  *      c) if the answer is more than one, attempt to resolve the conflict
  *      d) if the answer is zero, try the next array from vector #1
+ *
+ * Note: we rely primarily on nargs/argtypes as the argument description.
+ * The actual expression node list is passed in fargs so that we can check
+ * for type coercion of a constant.  Some callers pass fargs == NIL
+ * indicating they don't want that check made.
  */
 FuncDetailCode
 func_get_detail(List *funcname,
@@ -740,7 +745,7 @@ func_get_detail(List *funcname,
                 * that result for something coerce_type can't handle, we'll cause
                 * infinite recursion between this module and coerce_type!
                 */
-               if (nargs == 1)
+               if (nargs == 1 && fargs != NIL)
                {
                        Oid                     targetType;
                        TypeName   *tn = makeNode(TypeName);
index 1e4b5713514f2ad5c7ca8217f451bd76be9080f2..b1f012d4d9d85434a58d52e949b0c397ca28b67a 100644 (file)
@@ -3,7 +3,7 @@
  *                             back to source text
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.101 2002/05/02 18:44:11 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.102 2002/05/03 20:15:02 tgl Exp $
  *
  *       This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -54,6 +54,8 @@
 #include "optimizer/tlist.h"
 #include "parser/keywords.h"
 #include "parser/parse_expr.h"
+#include "parser/parse_func.h"
+#include "parser/parse_oper.h"
 #include "parser/parsetree.h"
 #include "rewrite/rewriteManip.h"
 #include "rewrite/rewriteSupport.h"
@@ -124,12 +126,13 @@ static void get_utility_query_def(Query *query, deparse_context *context);
 static void get_basic_select_query(Query *query, deparse_context *context);
 static void get_setop_query(Node *setOp, Query *query,
                                                        deparse_context *context);
-static void get_rule_sortgroupclause(SortClause *srt, List *tlist,
+static Node *get_rule_sortgroupclause(SortClause *srt, List *tlist,
                                                 bool force_colno,
                                                 deparse_context *context);
 static void get_names_for_var(Var *var, deparse_context *context,
                                  char **refname, char **attname);
 static void get_rule_expr(Node *node, deparse_context *context);
+static void get_oper_expr(Expr *expr, deparse_context *context);
 static void get_func_expr(Expr *expr, deparse_context *context);
 static void get_agg_expr(Aggref *aggref, deparse_context *context);
 static Node *strip_type_coercion(Node *expr, Oid resultType);
@@ -142,6 +145,9 @@ static void get_from_clause_item(Node *jtnode, Query *query,
 static void get_opclass_name(Oid opclass, Oid actual_datatype,
                                 StringInfo buf);
 static bool tleIsArrayAssign(TargetEntry *tle);
+static char *generate_relation_name(Oid relid);
+static char *generate_function_name(Oid funcid, int nargs, Oid *argtypes);
+static char *generate_operator_name(Oid operid, Oid arg1, Oid arg2);
 static char *get_relid_attribute_name(Oid relid, AttrNumber attnum);
 
 #define only_marker(rte)  ((rte)->inh ? "" : "ONLY ")
@@ -281,7 +287,6 @@ pg_do_getviewdef(Oid viewoid)
        TupleDesc       rulettc;
        StringInfoData buf;
        int                     len;
-       char       *viewname;
 
        /*
         * Connect to SPI manager
@@ -310,14 +315,13 @@ pg_do_getviewdef(Oid viewoid)
        /*
         * Get the pg_rewrite tuple for the view's SELECT rule
         */
-       viewname = get_rel_name(viewoid);
        args[0] = ObjectIdGetDatum(viewoid);
        args[1] = PointerGetDatum(ViewSelectRuleName);
        nulls[0] = ' ';
        nulls[1] = ' ';
        spirc = SPI_execp(plan_getviewrule, args, nulls, 2);
        if (spirc != SPI_OK_SELECT)
-               elog(ERROR, "failed to get pg_rewrite tuple for view %s", viewname);
+               elog(ERROR, "failed to get pg_rewrite tuple for view %u", viewoid);
        initStringInfo(&buf);
        if (SPI_processed != 1)
                appendStringInfo(&buf, "Not a view");
@@ -357,14 +361,14 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
        text       *indexdef;
        HeapTuple       ht_idx;
        HeapTuple       ht_idxrel;
-       HeapTuple       ht_indrel;
        HeapTuple       ht_am;
        Form_pg_index idxrec;
        Form_pg_class idxrelrec;
-       Form_pg_class indrelrec;
        Form_pg_am      amrec;
+       Oid                     indrelid;
        int                     len;
        int                     keyno;
+       Oid                     keycoltypes[INDEX_MAX_KEYS];
        StringInfoData buf;
        StringInfoData keybuf;
        char       *sep;
@@ -379,26 +383,19 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
                elog(ERROR, "syscache lookup for index %u failed", indexrelid);
        idxrec = (Form_pg_index) GETSTRUCT(ht_idx);
 
+       indrelid = idxrec->indrelid;
+       Assert(indexrelid == idxrec->indexrelid);
+
        /*
         * Fetch the pg_class tuple of the index relation
         */
        ht_idxrel = SearchSysCache(RELOID,
-                                                          ObjectIdGetDatum(idxrec->indexrelid),
+                                                          ObjectIdGetDatum(indexrelid),
                                                           0, 0, 0);
        if (!HeapTupleIsValid(ht_idxrel))
-               elog(ERROR, "syscache lookup for relid %u failed", idxrec->indexrelid);
+               elog(ERROR, "syscache lookup for relid %u failed", indexrelid);
        idxrelrec = (Form_pg_class) GETSTRUCT(ht_idxrel);
 
-       /*
-        * Fetch the pg_class tuple of the indexed relation
-        */
-       ht_indrel = SearchSysCache(RELOID,
-                                                          ObjectIdGetDatum(idxrec->indrelid),
-                                                          0, 0, 0);
-       if (!HeapTupleIsValid(ht_indrel))
-               elog(ERROR, "syscache lookup for relid %u failed", idxrec->indrelid);
-       indrelrec = (Form_pg_class) GETSTRUCT(ht_indrel);
-
        /*
         * Fetch the pg_am tuple of the index' access method
         */
@@ -410,13 +407,14 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
        amrec = (Form_pg_am) GETSTRUCT(ht_am);
 
        /*
-        * Start the index definition
+        * Start the index definition.  Note that the index's name should never
+        * be schema-qualified, but the indexed rel's name may be.
         */
        initStringInfo(&buf);
        appendStringInfo(&buf, "CREATE %sINDEX %s ON %s USING %s (",
                                         idxrec->indisunique ? "UNIQUE " : "",
                                         quote_identifier(NameStr(idxrelrec->relname)),
-                                        quote_identifier(NameStr(indrelrec->relname)),
+                                        generate_relation_name(indrelid),
                                         quote_identifier(NameStr(amrec->amname)));
 
        /*
@@ -427,26 +425,28 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
        for (keyno = 0; keyno < INDEX_MAX_KEYS; keyno++)
        {
                AttrNumber      attnum = idxrec->indkey[keyno];
+               char       *attname;
 
                if (attnum == InvalidAttrNumber)
                        break;
 
+               attname = get_relid_attribute_name(indrelid, attnum);
+               keycoltypes[keyno] = get_atttype(indrelid, attnum);
+
                appendStringInfo(&keybuf, sep);
                sep = ", ";
 
                /*
                 * Add the indexed field name
                 */
-               appendStringInfo(&keybuf, "%s",
-                         quote_identifier(get_relid_attribute_name(idxrec->indrelid,
-                                                                                                               attnum)));
+               appendStringInfo(&keybuf, "%s", quote_identifier(attname));
 
                /*
                 * If not a functional index, add the operator class name
                 */
                if (idxrec->indproc == InvalidOid)
                        get_opclass_name(idxrec->indclass[keyno],
-                                                        get_atttype(idxrec->indrelid, attnum),
+                                                        keycoltypes[keyno],
                                                         &keybuf);
        }
 
@@ -455,22 +455,13 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
                /*
                 * For functional index say 'func (attrs) opclass'
                 */
-               HeapTuple       proctup;
-               Form_pg_proc procStruct;
-
-               proctup = SearchSysCache(PROCOID,
-                                                                ObjectIdGetDatum(idxrec->indproc),
-                                                                0, 0, 0);
-               if (!HeapTupleIsValid(proctup))
-                       elog(ERROR, "cache lookup for proc %u failed", idxrec->indproc);
-               procStruct = (Form_pg_proc) GETSTRUCT(proctup);
-
                appendStringInfo(&buf, "%s(%s)",
-                                                quote_identifier(NameStr(procStruct->proname)),
+                                                generate_function_name(idxrec->indproc,
+                                                                                               keyno, keycoltypes),
                                                 keybuf.data);
-               get_opclass_name(idxrec->indclass[0], procStruct->prorettype, &buf);
-
-               ReleaseSysCache(proctup);
+               get_opclass_name(idxrec->indclass[0],
+                                                get_func_rettype(idxrec->indproc),
+                                                &buf);
        }
        else
        {
@@ -480,7 +471,7 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
                appendStringInfo(&buf, "%s", keybuf.data);
        }
 
-       appendStringInfo(&buf, ")");
+       appendStringInfoChar(&buf, ')');
 
        /*
         * If it's a partial index, decompile and append the predicate
@@ -506,8 +497,7 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
                if (node && IsA(node, List))
                        node = (Node *) make_ands_explicit((List *) node);
                /* Deparse */
-               context = deparse_context_for(NameStr(indrelrec->relname),
-                                                                         idxrec->indrelid);
+               context = deparse_context_for(get_rel_name(indrelid), indrelid);
                str = deparse_expression(node, context, false);
                appendStringInfo(&buf, " WHERE %s", str);
        }
@@ -525,7 +515,6 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
 
        ReleaseSysCache(ht_idx);
        ReleaseSysCache(ht_idxrel);
-       ReleaseSysCache(ht_indrel);
        ReleaseSysCache(ht_am);
 
        PG_RETURN_TEXT_P(indexdef);
@@ -856,7 +845,6 @@ make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
        if (ev_action != NULL)
                actions = (List *) stringToNode(ev_action);
 
-
        /*
         * Build the rules definition text
         */
@@ -889,8 +877,7 @@ make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
        }
 
        /* The relation the rule is fired on */
-       appendStringInfo(buf, " TO %s",
-                                        quote_identifier(get_rel_name(ev_class)));
+       appendStringInfo(buf, " TO %s", generate_relation_name(ev_class));
        if (ev_attr > 0)
                appendStringInfo(buf, ".%s",
                                          quote_identifier(get_relid_attribute_name(ev_class,
@@ -1126,12 +1113,16 @@ get_select_query_def(Query *query, deparse_context *context)
                foreach(l, query->sortClause)
                {
                        SortClause *srt = (SortClause *) lfirst(l);
+                       Node       *sortexpr;
+                       Oid                     sortcoltype;
                        char       *opname;
 
                        appendStringInfo(buf, sep);
-                       get_rule_sortgroupclause(srt, query->targetList,
-                                                                        force_colno, context);
-                       opname = get_opname(srt->sortop);
+                       sortexpr = get_rule_sortgroupclause(srt, query->targetList,
+                                                                                               force_colno, context);
+                       sortcoltype = exprType(sortexpr);
+                       opname = generate_operator_name(srt->sortop,
+                                                                                       sortcoltype, sortcoltype);
                        if (strcmp(opname, "<") != 0)
                        {
                                if (strcmp(opname, ">") == 0)
@@ -1315,8 +1306,10 @@ get_setop_query(Node *setOp, Query *query, deparse_context *context)
 
 /*
  * Display a sort/group clause.
+ *
+ * Also returns the expression tree, so caller need not find it again.
  */
-static void
+static Node *
 get_rule_sortgroupclause(SortClause *srt, List *tlist, bool force_colno,
                                                 deparse_context *context)
 {
@@ -1339,6 +1332,8 @@ get_rule_sortgroupclause(SortClause *srt, List *tlist, bool force_colno,
        }
        else
                get_rule_expr(expr, context);
+
+       return expr;
 }
 
 /* ----------
@@ -1361,7 +1356,7 @@ get_insert_query_def(Query *query, deparse_context *context)
        foreach(l, query->rtable)
        {
                rte = (RangeTblEntry *) lfirst(l);
-               if (rte->subquery == NULL)
+               if (rte->rtekind != RTE_SUBQUERY)
                        continue;
                if (select_rte)
                        elog(ERROR, "get_insert_query_def: too many RTEs in INSERT!");
@@ -1372,8 +1367,9 @@ get_insert_query_def(Query *query, deparse_context *context)
         * Start the query with INSERT INTO relname
         */
        rte = rt_fetch(query->resultRelation, query->rtable);
+       Assert(rte->rtekind == RTE_RELATION);
        appendStringInfo(buf, "INSERT INTO %s",
-                                        quote_identifier(rte->eref->aliasname));
+                                        generate_relation_name(rte->relid));
 
        /* Add the insert-column-names list */
        sep = " (";
@@ -1429,9 +1425,10 @@ get_update_query_def(Query *query, deparse_context *context)
         * Start the query with UPDATE relname SET
         */
        rte = rt_fetch(query->resultRelation, query->rtable);
+       Assert(rte->rtekind == RTE_RELATION);
        appendStringInfo(buf, "UPDATE %s%s SET ",
                                         only_marker(rte),
-                                        quote_identifier(rte->eref->aliasname));
+                                        generate_relation_name(rte->relid));
 
        /* Add the comma separated list of 'attname = value' */
        sep = "";
@@ -1482,9 +1479,10 @@ get_delete_query_def(Query *query, deparse_context *context)
         * Start the query with DELETE FROM relname
         */
        rte = rt_fetch(query->resultRelation, query->rtable);
+       Assert(rte->rtekind == RTE_RELATION);
        appendStringInfo(buf, "DELETE FROM %s%s",
                                         only_marker(rte),
-                                        quote_identifier(rte->eref->aliasname));
+                                        generate_relation_name(rte->relid));
 
        /* Add a WHERE clause if given */
        if (query->jointree->quals != NULL)
@@ -1509,7 +1507,8 @@ get_utility_query_def(Query *query, deparse_context *context)
                NotifyStmt *stmt = (NotifyStmt *) query->utilityStmt;
 
                appendStringInfo(buf, "NOTIFY %s",
-                                                quote_identifier(stmt->relation->relname));
+                                                quote_qualified_identifier(stmt->relation->schemaname,
+                                                                                                       stmt->relation->relname));
        }
        else
                elog(ERROR, "get_utility_query_def: unexpected statement type");
@@ -1628,52 +1627,11 @@ get_rule_expr(Node *node, deparse_context *context)
                                switch (expr->opType)
                                {
                                        case OP_EXPR:
-                                               appendStringInfoChar(buf, '(');
-                                               if (length(args) == 2)
-                                               {
-                                                       /* binary operator */
-                                                       get_rule_expr((Node *) lfirst(args), context);
-                                                       appendStringInfo(buf, " %s ",
-                                                               get_opname(((Oper *) expr->oper)->opno));
-                                                       get_rule_expr((Node *) lsecond(args), context);
-                                               }
-                                               else
-                                               {
-                                                       /* unary operator --- but which side? */
-                                                       Oid                     opno = ((Oper *) expr->oper)->opno;
-                                                       HeapTuple       tp;
-                                                       Form_pg_operator optup;
-
-                                                       tp = SearchSysCache(OPEROID,
-                                                                                               ObjectIdGetDatum(opno),
-                                                                                               0, 0, 0);
-                                                       if (!HeapTupleIsValid(tp))
-                                                               elog(ERROR, "cache lookup for operator %u failed", opno);
-                                                       optup = (Form_pg_operator) GETSTRUCT(tp);
-                                                       switch (optup->oprkind)
-                                                       {
-                                                               case 'l':
-                                                                       appendStringInfo(buf, "%s ",
-                                                                                                        get_opname(opno));
-                                                                       get_rule_expr((Node *) lfirst(args),
-                                                                                                 context);
-                                                                       break;
-                                                               case 'r':
-                                                                       get_rule_expr((Node *) lfirst(args),
-                                                                                                 context);
-                                                                       appendStringInfo(buf, " %s",
-                                                                                                        get_opname(opno));
-                                                                       break;
-                                                               default:
-                                                                       elog(ERROR, "get_rule_expr: bogus oprkind");
-                                                       }
-                                                       ReleaseSysCache(tp);
-                                               }
-                                               appendStringInfoChar(buf, ')');
+                                               get_oper_expr(expr, context);
                                                break;
 
                                        case FUNC_EXPR:
-                                               get_func_expr((Expr *) node, context);
+                                               get_func_expr(expr, context);
                                                break;
 
                                        case OR_EXPR:
@@ -1922,9 +1880,69 @@ get_rule_expr(Node *node, deparse_context *context)
 }
 
 
-/* ----------
+/*
+ * get_oper_expr                       - Parse back an Oper node
+ */
+static void
+get_oper_expr(Expr *expr, deparse_context *context)
+{
+       StringInfo      buf = context->buf;
+       Oid                     opno = ((Oper *) expr->oper)->opno;
+       List       *args = expr->args;
+
+       appendStringInfoChar(buf, '(');
+       if (length(args) == 2)
+       {
+               /* binary operator */
+               Node   *arg1 = (Node *) lfirst(args);
+               Node   *arg2 = (Node *) lsecond(args);
+
+               get_rule_expr(arg1, context);
+               appendStringInfo(buf, " %s ",
+                                                generate_operator_name(opno,
+                                                                                               exprType(arg1),
+                                                                                               exprType(arg2)));
+               get_rule_expr(arg2, context);
+       }
+       else
+       {
+               /* unary operator --- but which side? */
+               Node       *arg = (Node *) lfirst(args);
+               HeapTuple       tp;
+               Form_pg_operator optup;
+
+               tp = SearchSysCache(OPEROID,
+                                                       ObjectIdGetDatum(opno),
+                                                       0, 0, 0);
+               if (!HeapTupleIsValid(tp))
+                       elog(ERROR, "cache lookup for operator %u failed", opno);
+               optup = (Form_pg_operator) GETSTRUCT(tp);
+               switch (optup->oprkind)
+               {
+                       case 'l':
+                               appendStringInfo(buf, "%s ",
+                                                                generate_operator_name(opno,
+                                                                                                               InvalidOid,
+                                                                                                               exprType(arg)));
+                               get_rule_expr(arg, context);
+                               break;
+                       case 'r':
+                               get_rule_expr(arg, context);
+                               appendStringInfo(buf, " %s",
+                                                                generate_operator_name(opno,
+                                                                                                               exprType(arg),
+                                                                                                               InvalidOid));
+                               break;
+                       default:
+                               elog(ERROR, "get_rule_expr: bogus oprkind");
+               }
+               ReleaseSysCache(tp);
+       }
+       appendStringInfoChar(buf, ')');
+}
+
+/*
  * get_func_expr                       - Parse back a Func node
- * ----------
  */
 static void
 get_func_expr(Expr *expr, deparse_context *context)
@@ -1932,25 +1950,12 @@ get_func_expr(Expr *expr, deparse_context *context)
        StringInfo      buf = context->buf;
        Func       *func = (Func *) (expr->oper);
        Oid                     funcoid = func->funcid;
-       HeapTuple       proctup;
-       Form_pg_proc procStruct;
-       char       *proname;
        int32           coercedTypmod;
+       Oid                     argtypes[FUNC_MAX_ARGS];
+       int                     nargs;
        List       *l;
        char       *sep;
 
-       /*
-        * Get the functions pg_proc tuple
-        */
-       proctup = SearchSysCache(PROCOID,
-                                                        ObjectIdGetDatum(funcoid),
-                                                        0, 0, 0);
-       if (!HeapTupleIsValid(proctup))
-               elog(ERROR, "cache lookup for proc %u failed", funcoid);
-
-       procStruct = (Form_pg_proc) GETSTRUCT(proctup);
-       proname = NameStr(procStruct->proname);
-
        /*
         * Check to see if function is a length-coercion function for some
         * datatype.  If so, display the operation as a type cast.
@@ -1958,6 +1963,7 @@ get_func_expr(Expr *expr, deparse_context *context)
        if (exprIsLengthCoercion((Node *) expr, &coercedTypmod))
        {
                Node       *arg = lfirst(expr->args);
+               Oid                     rettype = get_func_rettype(funcoid);
                char       *typdesc;
 
                /*
@@ -1966,7 +1972,7 @@ get_func_expr(Expr *expr, deparse_context *context)
                 *
                 * XXX Are there any cases where this is a bad idea?
                 */
-               arg = strip_type_coercion(arg, procStruct->prorettype);
+               arg = strip_type_coercion(arg, rettype);
 
                appendStringInfoChar(buf, '(');
                get_rule_expr(arg, context);
@@ -1978,19 +1984,28 @@ get_func_expr(Expr *expr, deparse_context *context)
                 * to quote the result of format_type_with_typemod: it takes
                 * care of double-quoting any identifier that needs it.
                 */
-               typdesc = format_type_with_typemod(procStruct->prorettype,
-                                                                                  coercedTypmod);
+               typdesc = format_type_with_typemod(rettype, coercedTypmod);
                appendStringInfo(buf, ")::%s", typdesc);
                pfree(typdesc);
 
-               ReleaseSysCache(proctup);
                return;
        }
 
        /*
-        * Normal function: display as proname(args)
+        * Normal function: display as proname(args).  First we need to extract
+        * the argument datatypes.
         */
-       appendStringInfo(buf, "%s(", quote_identifier(proname));
+       nargs = 0;
+       foreach(l, expr->args)
+       {
+               Assert(nargs < FUNC_MAX_ARGS);
+               argtypes[nargs] = exprType((Node *) lfirst(l));
+               nargs++;
+       }
+       
+       appendStringInfo(buf, "%s(",
+                                        generate_function_name(funcoid, nargs, argtypes));
+
        sep = "";
        foreach(l, expr->args)
        {
@@ -1999,47 +2014,25 @@ get_func_expr(Expr *expr, deparse_context *context)
                get_rule_expr((Node *) lfirst(l), context);
        }
        appendStringInfoChar(buf, ')');
-
-       ReleaseSysCache(proctup);
 }
 
-/* ----------
+/*
  * get_agg_expr                        - Parse back an Aggref node
- * ----------
  */
 static void
 get_agg_expr(Aggref *aggref, deparse_context *context)
 {
        StringInfo      buf = context->buf;
-       HeapTuple       proctup;
-       Form_pg_proc procStruct;
-       char       *proname;
+       Oid                     argtype = exprType(aggref->target);
 
-       /*
-        * Get the aggregate's pg_proc tuple
-        */
-       proctup = SearchSysCache(PROCOID,
-                                                        ObjectIdGetDatum(aggref->aggfnoid),
-                                                        0, 0, 0);
-       if (!HeapTupleIsValid(proctup))
-               elog(ERROR, "cache lookup for proc %u failed", aggref->aggfnoid);
-
-       procStruct = (Form_pg_proc) GETSTRUCT(proctup);
-       proname = NameStr(procStruct->proname);
-
-       /*
-        * Display it
-        */
        appendStringInfo(buf, "%s(%s",
-                                        quote_identifier(proname),
+                                        generate_function_name(aggref->aggfnoid, 1, &argtype),
                                         aggref->aggdistinct ? "DISTINCT " : "");
        if (aggref->aggstar)
                appendStringInfo(buf, "*");
        else
                get_rule_expr(aggref->target, context);
        appendStringInfoChar(buf, ')');
-
-       ReleaseSysCache(proctup);
 }
 
 
@@ -2064,7 +2057,8 @@ strip_type_coercion(Node *expr, Oid resultType)
        if (IsA(expr, RelabelType))
                return strip_type_coercion(((RelabelType *) expr)->arg, resultType);
 
-       if (IsA(expr, Expr) &&((Expr *) expr)->opType == FUNC_EXPR)
+       if (IsA(expr, Expr) &&
+               ((Expr *) expr)->opType == FUNC_EXPR)
        {
                Func       *func;
                HeapTuple       procTuple;
@@ -2173,9 +2167,8 @@ get_const_expr(Const *constval, deparse_context *context)
        if (constval->constisnull)
        {
                /*
-                * Always label the type of a NULL constant.  This not only
-                * prevents misdecisions about the type, but it ensures that our
-                * output is a valid b_expr.
+                * Always label the type of a NULL constant to prevent misdecisions
+                * about type when reparsing.
                 */
                appendStringInfo(buf, "NULL::%s",
                                                 format_type_with_typemod(constval->consttype, -1));
@@ -2201,7 +2194,7 @@ get_const_expr(Const *constval, deparse_context *context)
                case INT4OID:
                case OIDOID:                    /* int types */
                case FLOAT4OID:
-               case FLOAT8OID: /* float types */
+               case FLOAT8OID:                 /* float types */
                        /* These types are printed without quotes */
                        appendStringInfo(buf, extval);
                        break;
@@ -2289,6 +2282,12 @@ get_sublink_expr(Node *node, deparse_context *context)
 
        need_paren = true;
 
+       /*
+        * XXX we assume here that we can get away without qualifying the
+        * operator name.  Since the name may imply multiple physical operators
+        * it's rather difficult to do otherwise --- in fact, if the operators
+        * are in different namespaces any attempt to qualify would surely fail.
+        */
        switch (sublink->subLinkType)
        {
                case EXISTS_SUBLINK:
@@ -2391,7 +2390,7 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
                                /* Normal relation RTE */
                                appendStringInfo(buf, "%s%s",
                                                                 only_marker(rte),
-                                                                quote_identifier(get_rel_name(rte->relid)));
+                                                                generate_relation_name(rte->relid));
                                break;
                        case RTE_SUBQUERY:
                                /* Subquery RTE */
@@ -2506,7 +2505,7 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
                         nodeTag(jtnode));
 }
 
-/* ----------
+/*
  * get_opclass_name                    - fetch name of an index operator class
  *
  * The opclass name is appended (after a space) to buf.
@@ -2514,7 +2513,6 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
  * Output is suppressed if the opclass is the default for the given
  * actual_datatype.  (If you don't want this behavior, just pass
  * InvalidOid for actual_datatype.)
- * ----------
  */
 static void
 get_opclass_name(Oid opclass, Oid actual_datatype,
@@ -2522,6 +2520,8 @@ get_opclass_name(Oid opclass, Oid actual_datatype,
 {
        HeapTuple       ht_opc;
        Form_pg_opclass opcrec;
+       char       *opcname;
+       char       *nspname;
 
        ht_opc = SearchSysCache(CLAOID,
                                                        ObjectIdGetDatum(opclass),
@@ -2530,14 +2530,24 @@ get_opclass_name(Oid opclass, Oid actual_datatype,
                elog(ERROR, "cache lookup failed for opclass %u", opclass);
        opcrec = (Form_pg_opclass) GETSTRUCT(ht_opc);
        if (actual_datatype != opcrec->opcintype || !opcrec->opcdefault)
-               appendStringInfo(buf, " %s",
-                                                quote_identifier(NameStr(opcrec->opcname)));
+       {
+               /* Okay, we need the opclass name.  Do we need to qualify it? */
+               opcname = NameStr(opcrec->opcname);
+               if (OpclassIsVisible(opclass))
+                       appendStringInfo(buf, " %s", quote_identifier(opcname));
+               else
+               {
+                       nspname = get_namespace_name(opcrec->opcnamespace);
+                       appendStringInfo(buf, " %s.%s",
+                                                        quote_identifier(nspname),
+                                                        quote_identifier(opcname));
+               }
+       }
        ReleaseSysCache(ht_opc);
 }
 
-/* ----------
+/*
  * tleIsArrayAssign                    - check for array assignment
- * ----------
  */
 static bool
 tleIsArrayAssign(TargetEntry *tle)
@@ -2561,12 +2571,11 @@ tleIsArrayAssign(TargetEntry *tle)
        return true;
 }
 
-/* ----------
+/*
  * quote_identifier                    - Quote an identifier only if needed
  *
  * When quotes are needed, we palloc the required space; slightly
  * space-wasteful but well worth it for notational simplicity.
- * ----------
  */
 const char *
 quote_identifier(const char *ident)
@@ -2623,12 +2632,11 @@ quote_identifier(const char *ident)
        return result;
 }
 
-/* ----------
+/*
  * quote_qualified_identifier  - Quote a possibly-qualified identifier
  *
  * Return a name of the form namespace.ident, or just ident if namespace
  * is NULL, quoting each component if necessary.  The result is palloc'd.
- * ----------
  */
 char *
 quote_qualified_identifier(const char *namespace,
@@ -2643,13 +2651,173 @@ quote_qualified_identifier(const char *namespace,
        return buf.data;
 }
 
-/* ----------
+/*
+ * generate_relation_name
+ *             Compute the name to display for a relation specified by OID
+ *
+ * The result includes all necessary quoting and schema-prefixing.
+ */
+static char *
+generate_relation_name(Oid relid)
+{
+       HeapTuple       tp;
+       Form_pg_class reltup;
+       char       *nspname;
+       char       *result;
+
+       tp = SearchSysCache(RELOID,
+                                               ObjectIdGetDatum(relid),
+                                               0, 0, 0);
+       if (!HeapTupleIsValid(tp))
+               elog(ERROR, "cache lookup of relation %u failed", relid);
+       reltup = (Form_pg_class) GETSTRUCT(tp);
+
+       /* Qualify the name if not visible in search path */
+       if (RelationIsVisible(relid))
+               nspname = NULL;
+       else
+               nspname = get_namespace_name(reltup->relnamespace);
+
+       result = quote_qualified_identifier(nspname, NameStr(reltup->relname));
+
+       ReleaseSysCache(tp);
+
+       return result;
+}
+
+/*
+ * generate_function_name
+ *             Compute the name to display for a function specified by OID,
+ *             given that it is being called with the specified actual arg types.
+ *             (Arg types matter because of ambiguous-function resolution rules.)
+ *
+ * The result includes all necessary quoting and schema-prefixing.
+ */
+static char *
+generate_function_name(Oid funcid, int nargs, Oid *argtypes)
+{
+       HeapTuple       proctup;
+       Form_pg_proc procform;
+       char       *proname;
+       char       *nspname;
+       char       *result;
+       FuncDetailCode p_result;
+       Oid                     p_funcid;
+       Oid                     p_rettype;
+       bool            p_retset;
+       Oid                *p_true_typeids;
+
+       proctup = SearchSysCache(PROCOID,
+                                                        ObjectIdGetDatum(funcid),
+                                                        0, 0, 0);
+       if (!HeapTupleIsValid(proctup))
+               elog(ERROR, "cache lookup of function %u failed", funcid);
+       procform = (Form_pg_proc) GETSTRUCT(proctup);
+       proname = NameStr(procform->proname);
+       Assert(nargs == procform->pronargs);
+
+       /*
+        * The idea here is to schema-qualify only if the parser would fail to
+        * resolve the correct function given the unqualified func name
+        * with the specified argtypes.
+        */
+       p_result = func_get_detail(makeList1(makeString(proname)),
+                                                          NIL, nargs, argtypes,
+                                                          &p_funcid, &p_rettype,
+                                                          &p_retset, &p_true_typeids);
+       if (p_result != FUNCDETAIL_NOTFOUND && p_funcid == funcid)
+               nspname = NULL;
+       else
+               nspname = get_namespace_name(procform->pronamespace);
+
+       result = quote_qualified_identifier(nspname, proname);
+
+       ReleaseSysCache(proctup);
+
+       return result;
+}
+
+/*
+ * generate_operator_name
+ *             Compute the name to display for an operator specified by OID,
+ *             given that it is being called with the specified actual arg types.
+ *             (Arg types matter because of ambiguous-operator resolution rules.
+ *             Pass InvalidOid for unused arg of a unary operator.)
+ *
+ * The result includes all necessary quoting and schema-prefixing,
+ * plus the OPERATOR() decoration needed to use a qualified operator name
+ * in an expression.
+ */
+static char *
+generate_operator_name(Oid operid, Oid arg1, Oid arg2)
+{
+       StringInfoData buf;
+       HeapTuple       opertup;
+       Form_pg_operator operform;
+       char       *oprname;
+       char       *nspname;
+       Operator        p_result;
+
+       initStringInfo(&buf);
+
+       opertup = SearchSysCache(OPEROID,
+                                                        ObjectIdGetDatum(operid),
+                                                        0, 0, 0);
+       if (!HeapTupleIsValid(opertup))
+               elog(ERROR, "cache lookup of operator %u failed", operid);
+       operform = (Form_pg_operator) GETSTRUCT(opertup);
+       oprname = NameStr(operform->oprname);
+
+       /*
+        * The idea here is to schema-qualify only if the parser would fail to
+        * resolve the correct operator given the unqualified op name
+        * with the specified argtypes.
+        */
+       switch (operform->oprkind)
+       {
+               case 'b':
+                       p_result = oper(makeList1(makeString(oprname)), arg1, arg2, true);
+                       break;
+               case 'l':
+                       p_result = left_oper(makeList1(makeString(oprname)), arg2, true);
+                       break;
+               case 'r':
+                       p_result = right_oper(makeList1(makeString(oprname)), arg1, true);
+                       break;
+               default:
+                       elog(ERROR, "unexpected oprkind %c for operator %u",
+                                operform->oprkind, operid);
+                       p_result = NULL;        /* keep compiler quiet */
+                       break;
+       }
+
+       if (p_result != NULL && oprid(p_result) == operid)
+               nspname = NULL;
+       else
+       {
+               nspname = get_namespace_name(operform->oprnamespace);
+               appendStringInfo(&buf, "OPERATOR(%s.", quote_identifier(nspname));
+       }
+
+       appendStringInfo(&buf, "%s", oprname);
+
+       if (nspname)
+               appendStringInfoChar(&buf, ')');
+
+       if (p_result != NULL)
+               ReleaseSysCache(p_result);
+
+       ReleaseSysCache(opertup);
+
+       return buf.data;
+}
+
+/*
  * get_relid_attribute_name
  *             Get an attribute name by its relations Oid and its attnum
  *
  * Same as underlying syscache routine get_attname(), except that error
  * is handled by elog() instead of returning NULL.
- * ----------
  */
 static char *
 get_relid_attribute_name(Oid relid, AttrNumber attnum)