Header And Logo

PostgreSQL
| The world's most advanced open source database.

ruleutils.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * ruleutils.c
00004  *    Functions to convert stored expressions/querytrees back to
00005  *    source text
00006  *
00007  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00008  * Portions Copyright (c) 1994, Regents of the University of California
00009  *
00010  *
00011  * IDENTIFICATION
00012  *    src/backend/utils/adt/ruleutils.c
00013  *
00014  *-------------------------------------------------------------------------
00015  */
00016 #include "postgres.h"
00017 
00018 #include <unistd.h>
00019 #include <fcntl.h>
00020 
00021 #include "access/htup_details.h"
00022 #include "access/sysattr.h"
00023 #include "catalog/dependency.h"
00024 #include "catalog/indexing.h"
00025 #include "catalog/pg_authid.h"
00026 #include "catalog/pg_collation.h"
00027 #include "catalog/pg_constraint.h"
00028 #include "catalog/pg_depend.h"
00029 #include "catalog/pg_language.h"
00030 #include "catalog/pg_opclass.h"
00031 #include "catalog/pg_operator.h"
00032 #include "catalog/pg_proc.h"
00033 #include "catalog/pg_trigger.h"
00034 #include "catalog/pg_type.h"
00035 #include "commands/defrem.h"
00036 #include "commands/tablespace.h"
00037 #include "executor/spi.h"
00038 #include "funcapi.h"
00039 #include "nodes/makefuncs.h"
00040 #include "nodes/nodeFuncs.h"
00041 #include "optimizer/clauses.h"
00042 #include "optimizer/tlist.h"
00043 #include "parser/keywords.h"
00044 #include "parser/parse_func.h"
00045 #include "parser/parse_oper.h"
00046 #include "parser/parser.h"
00047 #include "parser/parsetree.h"
00048 #include "rewrite/rewriteHandler.h"
00049 #include "rewrite/rewriteManip.h"
00050 #include "rewrite/rewriteSupport.h"
00051 #include "utils/array.h"
00052 #include "utils/builtins.h"
00053 #include "utils/fmgroids.h"
00054 #include "utils/lsyscache.h"
00055 #include "utils/rel.h"
00056 #include "utils/syscache.h"
00057 #include "utils/tqual.h"
00058 #include "utils/typcache.h"
00059 #include "utils/xml.h"
00060 
00061 
00062 /* ----------
00063  * Pretty formatting constants
00064  * ----------
00065  */
00066 
00067 /* Indent counts */
00068 #define PRETTYINDENT_STD        8
00069 #define PRETTYINDENT_JOIN      13
00070 #define PRETTYINDENT_JOIN_ON    (PRETTYINDENT_JOIN-PRETTYINDENT_STD)
00071 #define PRETTYINDENT_VAR        4
00072 
00073 /* Pretty flags */
00074 #define PRETTYFLAG_PAREN        1
00075 #define PRETTYFLAG_INDENT       2
00076 
00077 /* Default line length for pretty-print wrapping: 0 means wrap always */
00078 #define WRAP_COLUMN_DEFAULT     0
00079 
00080 /* macro to test if pretty action needed */
00081 #define PRETTY_PAREN(context)   ((context)->prettyFlags & PRETTYFLAG_PAREN)
00082 #define PRETTY_INDENT(context)  ((context)->prettyFlags & PRETTYFLAG_INDENT)
00083 
00084 
00085 /* ----------
00086  * Local data types
00087  * ----------
00088  */
00089 
00090 /* Context info needed for invoking a recursive querytree display routine */
00091 typedef struct
00092 {
00093     StringInfo  buf;            /* output buffer to append to */
00094     List       *namespaces;     /* List of deparse_namespace nodes */
00095     List       *windowClause;   /* Current query level's WINDOW clause */
00096     List       *windowTList;    /* targetlist for resolving WINDOW clause */
00097     int         prettyFlags;    /* enabling of pretty-print functions */
00098     int         wrapColumn;     /* max line length, or -1 for no limit */
00099     int         indentLevel;    /* current indent level for prettyprint */
00100     bool        varprefix;      /* TRUE to print prefixes on Vars */
00101 } deparse_context;
00102 
00103 /*
00104  * Each level of query context around a subtree needs a level of Var namespace.
00105  * A Var having varlevelsup=N refers to the N'th item (counting from 0) in
00106  * the current context's namespaces list.
00107  *
00108  * The rangetable is the list of actual RTEs from the query tree, and the
00109  * cte list is the list of actual CTEs.
00110  *
00111  * rtable_names holds the alias name to be used for each RTE (either a C
00112  * string, or NULL for nameless RTEs such as unnamed joins).
00113  * rtable_columns holds the column alias names to be used for each RTE.
00114  *
00115  * In some cases we need to make names of merged JOIN USING columns unique
00116  * across the whole query, not only per-RTE.  If so, unique_using is TRUE
00117  * and using_names is a list of C strings representing names already assigned
00118  * to USING columns.
00119  *
00120  * When deparsing plan trees, there is always just a single item in the
00121  * deparse_namespace list (since a plan tree never contains Vars with
00122  * varlevelsup > 0).  We store the PlanState node that is the immediate
00123  * parent of the expression to be deparsed, as well as a list of that
00124  * PlanState's ancestors.  In addition, we store its outer and inner subplan
00125  * state nodes, as well as their plan nodes' targetlists, and the indextlist
00126  * if the current PlanState is an IndexOnlyScanState.  (These fields could
00127  * be derived on-the-fly from the current PlanState, but it seems notationally
00128  * clearer to set them up as separate fields.)
00129  */
00130 typedef struct
00131 {
00132     List       *rtable;         /* List of RangeTblEntry nodes */
00133     List       *rtable_names;   /* Parallel list of names for RTEs */
00134     List       *rtable_columns; /* Parallel list of deparse_columns structs */
00135     List       *ctes;           /* List of CommonTableExpr nodes */
00136     /* Workspace for column alias assignment: */
00137     bool        unique_using;   /* Are we making USING names globally unique */
00138     List       *using_names;    /* List of assigned names for USING columns */
00139     /* Remaining fields are used only when deparsing a Plan tree: */
00140     PlanState  *planstate;      /* immediate parent of current expression */
00141     List       *ancestors;      /* ancestors of planstate */
00142     PlanState  *outer_planstate;    /* outer subplan state, or NULL if none */
00143     PlanState  *inner_planstate;    /* inner subplan state, or NULL if none */
00144     List       *outer_tlist;    /* referent for OUTER_VAR Vars */
00145     List       *inner_tlist;    /* referent for INNER_VAR Vars */
00146     List       *index_tlist;    /* referent for INDEX_VAR Vars */
00147 } deparse_namespace;
00148 
00149 /*
00150  * Per-relation data about column alias names.
00151  *
00152  * Selecting aliases is unreasonably complicated because of the need to dump
00153  * rules/views whose underlying tables may have had columns added, deleted, or
00154  * renamed since the query was parsed.  We must nonetheless print the rule/view
00155  * in a form that can be reloaded and will produce the same results as before.
00156  *
00157  * For each RTE used in the query, we must assign column aliases that are
00158  * unique within that RTE.  SQL does not require this of the original query,
00159  * but due to factors such as *-expansion we need to be able to uniquely
00160  * reference every column in a decompiled query.  As long as we qualify all
00161  * column references, per-RTE uniqueness is sufficient for that.
00162  *
00163  * However, we can't ensure per-column name uniqueness for unnamed join RTEs,
00164  * since they just inherit column names from their input RTEs, and we can't
00165  * rename the columns at the join level.  Most of the time this isn't an issue
00166  * because we don't need to reference the join's output columns as such; we
00167  * can reference the input columns instead.  That approach fails for merged
00168  * FULL JOIN USING columns, however, so when we have one of those in an
00169  * unnamed join, we have to make that column's alias globally unique across
00170  * the whole query to ensure it can be referenced unambiguously.
00171  *
00172  * Another problem is that a JOIN USING clause requires the columns to be
00173  * merged to have the same aliases in both input RTEs.  To handle that, we do
00174  * USING-column alias assignment in a recursive traversal of the query's
00175  * jointree.  When descending through a JOIN with USING, we preassign the
00176  * USING column names to the child columns, overriding other rules for column
00177  * alias assignment.
00178  *
00179  * Another problem is that if a JOIN's input tables have had columns added or
00180  * deleted since the query was parsed, we must generate a column alias list
00181  * for the join that matches the current set of input columns --- otherwise, a
00182  * change in the number of columns in the left input would throw off matching
00183  * of aliases to columns of the right input.  Thus, positions in the printable
00184  * column alias list are not necessarily one-for-one with varattnos of the
00185  * JOIN, so we need a separate new_colnames[] array for printing purposes.
00186  */
00187 typedef struct
00188 {
00189     /*
00190      * colnames is an array containing column aliases to use for columns that
00191      * existed when the query was parsed.  Dropped columns have NULL entries.
00192      * This array can be directly indexed by varattno to get a Var's name.
00193      *
00194      * Non-NULL entries are guaranteed unique within the RTE, *except* when
00195      * this is for an unnamed JOIN RTE.  In that case we merely copy up names
00196      * from the two input RTEs.
00197      *
00198      * During the recursive descent in set_using_names(), forcible assignment
00199      * of a child RTE's column name is represented by pre-setting that element
00200      * of the child's colnames array.  So at that stage, NULL entries in this
00201      * array just mean that no name has been preassigned, not necessarily that
00202      * the column is dropped.
00203      */
00204     int         num_cols;       /* length of colnames[] array */
00205     char      **colnames;       /* array of C strings and NULLs */
00206 
00207     /*
00208      * new_colnames is an array containing column aliases to use for columns
00209      * that would exist if the query was re-parsed against the current
00210      * definitions of its base tables.  This is what to print as the column
00211      * alias list for the RTE.  This array does not include dropped columns,
00212      * but it will include columns added since original parsing.  Indexes in
00213      * it therefore have little to do with current varattno values.  As above,
00214      * entries are unique unless this is for an unnamed JOIN RTE.  (In such an
00215      * RTE, we never actually print this array, but we must compute it anyway
00216      * for possible use in computing column names of upper joins.) The
00217      * parallel array is_new_col marks which of these columns are new since
00218      * original parsing.  Entries with is_new_col false must match the
00219      * non-NULL colnames entries one-for-one.
00220      */
00221     int         num_new_cols;   /* length of new_colnames[] array */
00222     char      **new_colnames;   /* array of C strings */
00223     bool       *is_new_col;     /* array of bool flags */
00224 
00225     /* This flag tells whether we should actually print a column alias list */
00226     bool        printaliases;
00227 
00228     /*
00229      * If this struct is for a JOIN RTE, we fill these fields during the
00230      * set_using_names() pass to describe its relationship to its child RTEs.
00231      *
00232      * leftattnos and rightattnos are arrays with one entry per existing
00233      * output column of the join (hence, indexable by join varattno).  For a
00234      * simple reference to a column of the left child, leftattnos[i] is the
00235      * child RTE's attno and rightattnos[i] is zero; and conversely for a
00236      * column of the right child.  But for merged columns produced by JOIN
00237      * USING/NATURAL JOIN, both leftattnos[i] and rightattnos[i] are nonzero.
00238      *
00239      * If it's a JOIN USING, usingNames holds the alias names selected for the
00240      * merged columns (these might be different from the original USING list,
00241      * if we had to modify names to achieve uniqueness).
00242      */
00243     int         leftrti;        /* rangetable index of left child */
00244     int         rightrti;       /* rangetable index of right child */
00245     int        *leftattnos;     /* left-child varattnos of join cols, or 0 */
00246     int        *rightattnos;    /* right-child varattnos of join cols, or 0 */
00247     List       *usingNames;     /* names assigned to merged columns */
00248 } deparse_columns;
00249 
00250 /* This macro is analogous to rt_fetch(), but for deparse_columns structs */
00251 #define deparse_columns_fetch(rangetable_index, dpns) \
00252     ((deparse_columns *) list_nth((dpns)->rtable_columns, (rangetable_index)-1))
00253 
00254 
00255 /* ----------
00256  * Global data
00257  * ----------
00258  */
00259 static SPIPlanPtr plan_getrulebyoid = NULL;
00260 static const char *query_getrulebyoid = "SELECT * FROM pg_catalog.pg_rewrite WHERE oid = $1";
00261 static SPIPlanPtr plan_getviewrule = NULL;
00262 static const char *query_getviewrule = "SELECT * FROM pg_catalog.pg_rewrite WHERE ev_class = $1 AND rulename = $2";
00263 
00264 /* GUC parameters */
00265 bool        quote_all_identifiers = false;
00266 
00267 
00268 /* ----------
00269  * Local functions
00270  *
00271  * Most of these functions used to use fixed-size buffers to build their
00272  * results.  Now, they take an (already initialized) StringInfo object
00273  * as a parameter, and append their text output to its contents.
00274  * ----------
00275  */
00276 static char *deparse_expression_pretty(Node *expr, List *dpcontext,
00277                           bool forceprefix, bool showimplicit,
00278                           int prettyFlags, int startIndent);
00279 static char *pg_get_viewdef_worker(Oid viewoid,
00280                       int prettyFlags, int wrapColumn);
00281 static char *pg_get_triggerdef_worker(Oid trigid, bool pretty);
00282 static void decompile_column_index_array(Datum column_index_array, Oid relId,
00283                              StringInfo buf);
00284 static char *pg_get_ruledef_worker(Oid ruleoid, int prettyFlags);
00285 static char *pg_get_indexdef_worker(Oid indexrelid, int colno,
00286                        const Oid *excludeOps,
00287                        bool attrsOnly, bool showTblSpc,
00288                        int prettyFlags);
00289 static char *pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
00290                             int prettyFlags);
00291 static text *pg_get_expr_worker(text *expr, Oid relid, const char *relname,
00292                    int prettyFlags);
00293 static int print_function_arguments(StringInfo buf, HeapTuple proctup,
00294                          bool print_table_args, bool print_defaults);
00295 static void print_function_rettype(StringInfo buf, HeapTuple proctup);
00296 static void set_rtable_names(deparse_namespace *dpns, List *parent_namespaces,
00297                  Bitmapset *rels_used);
00298 static bool refname_is_unique(char *refname, deparse_namespace *dpns,
00299                   List *parent_namespaces);
00300 static void set_deparse_for_query(deparse_namespace *dpns, Query *query,
00301                       List *parent_namespaces);
00302 static void set_simple_column_names(deparse_namespace *dpns);
00303 static bool has_unnamed_full_join_using(Node *jtnode);
00304 static void set_using_names(deparse_namespace *dpns, Node *jtnode);
00305 static void set_relation_column_names(deparse_namespace *dpns,
00306                           RangeTblEntry *rte,
00307                           deparse_columns *colinfo);
00308 static void set_join_column_names(deparse_namespace *dpns, RangeTblEntry *rte,
00309                       deparse_columns *colinfo);
00310 static bool colname_is_unique(char *colname, deparse_namespace *dpns,
00311                   deparse_columns *colinfo);
00312 static char *make_colname_unique(char *colname, deparse_namespace *dpns,
00313                     deparse_columns *colinfo);
00314 static void expand_colnames_array_to(deparse_columns *colinfo, int n);
00315 static void identify_join_columns(JoinExpr *j, RangeTblEntry *jrte,
00316                       deparse_columns *colinfo);
00317 static void flatten_join_using_qual(Node *qual,
00318                         List **leftvars, List **rightvars);
00319 static char *get_rtable_name(int rtindex, deparse_context *context);
00320 static void set_deparse_planstate(deparse_namespace *dpns, PlanState *ps);
00321 static void push_child_plan(deparse_namespace *dpns, PlanState *ps,
00322                 deparse_namespace *save_dpns);
00323 static void pop_child_plan(deparse_namespace *dpns,
00324                deparse_namespace *save_dpns);
00325 static void push_ancestor_plan(deparse_namespace *dpns, ListCell *ancestor_cell,
00326                    deparse_namespace *save_dpns);
00327 static void pop_ancestor_plan(deparse_namespace *dpns,
00328                   deparse_namespace *save_dpns);
00329 static void make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
00330              int prettyFlags);
00331 static void make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
00332              int prettyFlags, int wrapColumn);
00333 static void get_query_def(Query *query, StringInfo buf, List *parentnamespace,
00334               TupleDesc resultDesc,
00335               int prettyFlags, int wrapColumn, int startIndent);
00336 static void get_values_def(List *values_lists, deparse_context *context);
00337 static void get_with_clause(Query *query, deparse_context *context);
00338 static void get_select_query_def(Query *query, deparse_context *context,
00339                      TupleDesc resultDesc);
00340 static void get_insert_query_def(Query *query, deparse_context *context);
00341 static void get_update_query_def(Query *query, deparse_context *context);
00342 static void get_delete_query_def(Query *query, deparse_context *context);
00343 static void get_utility_query_def(Query *query, deparse_context *context);
00344 static void get_basic_select_query(Query *query, deparse_context *context,
00345                        TupleDesc resultDesc);
00346 static void get_target_list(List *targetList, deparse_context *context,
00347                 TupleDesc resultDesc);
00348 static void get_setop_query(Node *setOp, Query *query,
00349                 deparse_context *context,
00350                 TupleDesc resultDesc);
00351 static Node *get_rule_sortgroupclause(SortGroupClause *srt, List *tlist,
00352                          bool force_colno,
00353                          deparse_context *context);
00354 static void get_rule_orderby(List *orderList, List *targetList,
00355                  bool force_colno, deparse_context *context);
00356 static void get_rule_windowclause(Query *query, deparse_context *context);
00357 static void get_rule_windowspec(WindowClause *wc, List *targetList,
00358                     deparse_context *context);
00359 static char *get_variable(Var *var, int levelsup, bool istoplevel,
00360              deparse_context *context);
00361 static Node *find_param_referent(Param *param, deparse_context *context,
00362                     deparse_namespace **dpns_p, ListCell **ancestor_cell_p);
00363 static void get_parameter(Param *param, deparse_context *context);
00364 static const char *get_simple_binary_op_name(OpExpr *expr);
00365 static bool isSimpleNode(Node *node, Node *parentNode, int prettyFlags);
00366 static void appendContextKeyword(deparse_context *context, const char *str,
00367                      int indentBefore, int indentAfter, int indentPlus);
00368 static void get_rule_expr(Node *node, deparse_context *context,
00369               bool showimplicit);
00370 static void get_oper_expr(OpExpr *expr, deparse_context *context);
00371 static void get_func_expr(FuncExpr *expr, deparse_context *context,
00372               bool showimplicit);
00373 static void get_agg_expr(Aggref *aggref, deparse_context *context);
00374 static void get_windowfunc_expr(WindowFunc *wfunc, deparse_context *context);
00375 static void get_coercion_expr(Node *arg, deparse_context *context,
00376                   Oid resulttype, int32 resulttypmod,
00377                   Node *parentNode);
00378 static void get_const_expr(Const *constval, deparse_context *context,
00379                int showtype);
00380 static void get_const_collation(Const *constval, deparse_context *context);
00381 static void simple_quote_literal(StringInfo buf, const char *val);
00382 static void get_sublink_expr(SubLink *sublink, deparse_context *context);
00383 static void get_from_clause(Query *query, const char *prefix,
00384                 deparse_context *context);
00385 static void get_from_clause_item(Node *jtnode, Query *query,
00386                      deparse_context *context);
00387 static void get_column_alias_list(deparse_columns *colinfo,
00388                       deparse_context *context);
00389 static void get_from_clause_coldeflist(deparse_columns *colinfo,
00390                            List *types, List *typmods, List *collations,
00391                            deparse_context *context);
00392 static void get_opclass_name(Oid opclass, Oid actual_datatype,
00393                  StringInfo buf);
00394 static Node *processIndirection(Node *node, deparse_context *context,
00395                    bool printit);
00396 static void printSubscripts(ArrayRef *aref, deparse_context *context);
00397 static char *get_relation_name(Oid relid);
00398 static char *generate_relation_name(Oid relid, List *namespaces);
00399 static char *generate_function_name(Oid funcid, int nargs,
00400                        List *argnames, Oid *argtypes,
00401                        bool was_variadic, bool *use_variadic_p);
00402 static char *generate_operator_name(Oid operid, Oid arg1, Oid arg2);
00403 static text *string_to_text(char *str);
00404 static char *flatten_reloptions(Oid relid);
00405 
00406 #define only_marker(rte)  ((rte)->inh ? "" : "ONLY ")
00407 
00408 
00409 /* ----------
00410  * get_ruledef          - Do it all and return a text
00411  *                that could be used as a statement
00412  *                to recreate the rule
00413  * ----------
00414  */
00415 Datum
00416 pg_get_ruledef(PG_FUNCTION_ARGS)
00417 {
00418     Oid         ruleoid = PG_GETARG_OID(0);
00419     int         prettyFlags;
00420 
00421     prettyFlags = PRETTYFLAG_INDENT;
00422     PG_RETURN_TEXT_P(string_to_text(pg_get_ruledef_worker(ruleoid, prettyFlags)));
00423 }
00424 
00425 
00426 Datum
00427 pg_get_ruledef_ext(PG_FUNCTION_ARGS)
00428 {
00429     Oid         ruleoid = PG_GETARG_OID(0);
00430     bool        pretty = PG_GETARG_BOOL(1);
00431     int         prettyFlags;
00432 
00433     prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : PRETTYFLAG_INDENT;
00434     PG_RETURN_TEXT_P(string_to_text(pg_get_ruledef_worker(ruleoid, prettyFlags)));
00435 }
00436 
00437 
00438 static char *
00439 pg_get_ruledef_worker(Oid ruleoid, int prettyFlags)
00440 {
00441     Datum       args[1];
00442     char        nulls[1];
00443     int         spirc;
00444     HeapTuple   ruletup;
00445     TupleDesc   rulettc;
00446     StringInfoData buf;
00447 
00448     /*
00449      * Do this first so that string is alloc'd in outer context not SPI's.
00450      */
00451     initStringInfo(&buf);
00452 
00453     /*
00454      * Connect to SPI manager
00455      */
00456     if (SPI_connect() != SPI_OK_CONNECT)
00457         elog(ERROR, "SPI_connect failed");
00458 
00459     /*
00460      * On the first call prepare the plan to lookup pg_rewrite. We read
00461      * pg_rewrite over the SPI manager instead of using the syscache to be
00462      * checked for read access on pg_rewrite.
00463      */
00464     if (plan_getrulebyoid == NULL)
00465     {
00466         Oid         argtypes[1];
00467         SPIPlanPtr  plan;
00468 
00469         argtypes[0] = OIDOID;
00470         plan = SPI_prepare(query_getrulebyoid, 1, argtypes);
00471         if (plan == NULL)
00472             elog(ERROR, "SPI_prepare failed for \"%s\"", query_getrulebyoid);
00473         SPI_keepplan(plan);
00474         plan_getrulebyoid = plan;
00475     }
00476 
00477     /*
00478      * Get the pg_rewrite tuple for this rule
00479      */
00480     args[0] = ObjectIdGetDatum(ruleoid);
00481     nulls[0] = ' ';
00482     spirc = SPI_execute_plan(plan_getrulebyoid, args, nulls, true, 1);
00483     if (spirc != SPI_OK_SELECT)
00484         elog(ERROR, "failed to get pg_rewrite tuple for rule %u", ruleoid);
00485     if (SPI_processed != 1)
00486         appendStringInfo(&buf, "-");
00487     else
00488     {
00489         /*
00490          * Get the rule's definition and put it into executor's memory
00491          */
00492         ruletup = SPI_tuptable->vals[0];
00493         rulettc = SPI_tuptable->tupdesc;
00494         make_ruledef(&buf, ruletup, rulettc, prettyFlags);
00495     }
00496 
00497     /*
00498      * Disconnect from SPI manager
00499      */
00500     if (SPI_finish() != SPI_OK_FINISH)
00501         elog(ERROR, "SPI_finish failed");
00502 
00503     return buf.data;
00504 }
00505 
00506 
00507 /* ----------
00508  * get_viewdef          - Mainly the same thing, but we
00509  *                only return the SELECT part of a view
00510  * ----------
00511  */
00512 Datum
00513 pg_get_viewdef(PG_FUNCTION_ARGS)
00514 {
00515     /* By OID */
00516     Oid         viewoid = PG_GETARG_OID(0);
00517     int         prettyFlags;
00518 
00519     prettyFlags = PRETTYFLAG_INDENT;
00520     PG_RETURN_TEXT_P(string_to_text(pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT)));
00521 }
00522 
00523 
00524 Datum
00525 pg_get_viewdef_ext(PG_FUNCTION_ARGS)
00526 {
00527     /* By OID */
00528     Oid         viewoid = PG_GETARG_OID(0);
00529     bool        pretty = PG_GETARG_BOOL(1);
00530     int         prettyFlags;
00531 
00532     prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : PRETTYFLAG_INDENT;
00533     PG_RETURN_TEXT_P(string_to_text(pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT)));
00534 }
00535 
00536 Datum
00537 pg_get_viewdef_wrap(PG_FUNCTION_ARGS)
00538 {
00539     /* By OID */
00540     Oid         viewoid = PG_GETARG_OID(0);
00541     int         wrap = PG_GETARG_INT32(1);
00542     int         prettyFlags;
00543 
00544     /* calling this implies we want pretty printing */
00545     prettyFlags = PRETTYFLAG_PAREN | PRETTYFLAG_INDENT;
00546     PG_RETURN_TEXT_P(string_to_text(pg_get_viewdef_worker(viewoid, prettyFlags, wrap)));
00547 }
00548 
00549 Datum
00550 pg_get_viewdef_name(PG_FUNCTION_ARGS)
00551 {
00552     /* By qualified name */
00553     text       *viewname = PG_GETARG_TEXT_P(0);
00554     int         prettyFlags;
00555     RangeVar   *viewrel;
00556     Oid         viewoid;
00557 
00558     prettyFlags = PRETTYFLAG_INDENT;
00559 
00560     /* Look up view name.  Can't lock it - we might not have privileges. */
00561     viewrel = makeRangeVarFromNameList(textToQualifiedNameList(viewname));
00562     viewoid = RangeVarGetRelid(viewrel, NoLock, false);
00563 
00564     PG_RETURN_TEXT_P(string_to_text(pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT)));
00565 }
00566 
00567 
00568 Datum
00569 pg_get_viewdef_name_ext(PG_FUNCTION_ARGS)
00570 {
00571     /* By qualified name */
00572     text       *viewname = PG_GETARG_TEXT_P(0);
00573     bool        pretty = PG_GETARG_BOOL(1);
00574     int         prettyFlags;
00575     RangeVar   *viewrel;
00576     Oid         viewoid;
00577 
00578     prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : PRETTYFLAG_INDENT;
00579 
00580     /* Look up view name.  Can't lock it - we might not have privileges. */
00581     viewrel = makeRangeVarFromNameList(textToQualifiedNameList(viewname));
00582     viewoid = RangeVarGetRelid(viewrel, NoLock, false);
00583 
00584     PG_RETURN_TEXT_P(string_to_text(pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT)));
00585 }
00586 
00587 /*
00588  * Common code for by-OID and by-name variants of pg_get_viewdef
00589  */
00590 static char *
00591 pg_get_viewdef_worker(Oid viewoid, int prettyFlags, int wrapColumn)
00592 {
00593     Datum       args[2];
00594     char        nulls[2];
00595     int         spirc;
00596     HeapTuple   ruletup;
00597     TupleDesc   rulettc;
00598     StringInfoData buf;
00599 
00600     /*
00601      * Do this first so that string is alloc'd in outer context not SPI's.
00602      */
00603     initStringInfo(&buf);
00604 
00605     /*
00606      * Connect to SPI manager
00607      */
00608     if (SPI_connect() != SPI_OK_CONNECT)
00609         elog(ERROR, "SPI_connect failed");
00610 
00611     /*
00612      * On the first call prepare the plan to lookup pg_rewrite. We read
00613      * pg_rewrite over the SPI manager instead of using the syscache to be
00614      * checked for read access on pg_rewrite.
00615      */
00616     if (plan_getviewrule == NULL)
00617     {
00618         Oid         argtypes[2];
00619         SPIPlanPtr  plan;
00620 
00621         argtypes[0] = OIDOID;
00622         argtypes[1] = NAMEOID;
00623         plan = SPI_prepare(query_getviewrule, 2, argtypes);
00624         if (plan == NULL)
00625             elog(ERROR, "SPI_prepare failed for \"%s\"", query_getviewrule);
00626         SPI_keepplan(plan);
00627         plan_getviewrule = plan;
00628     }
00629 
00630     /*
00631      * Get the pg_rewrite tuple for the view's SELECT rule
00632      */
00633     args[0] = ObjectIdGetDatum(viewoid);
00634     args[1] = PointerGetDatum(ViewSelectRuleName);
00635     nulls[0] = ' ';
00636     nulls[1] = ' ';
00637     spirc = SPI_execute_plan(plan_getviewrule, args, nulls, true, 2);
00638     if (spirc != SPI_OK_SELECT)
00639         elog(ERROR, "failed to get pg_rewrite tuple for view %u", viewoid);
00640     if (SPI_processed != 1)
00641         appendStringInfo(&buf, "Not a view");
00642     else
00643     {
00644         /*
00645          * Get the rule's definition and put it into executor's memory
00646          */
00647         ruletup = SPI_tuptable->vals[0];
00648         rulettc = SPI_tuptable->tupdesc;
00649         make_viewdef(&buf, ruletup, rulettc, prettyFlags, wrapColumn);
00650     }
00651 
00652     /*
00653      * Disconnect from SPI manager
00654      */
00655     if (SPI_finish() != SPI_OK_FINISH)
00656         elog(ERROR, "SPI_finish failed");
00657 
00658     return buf.data;
00659 }
00660 
00661 /* ----------
00662  * get_triggerdef           - Get the definition of a trigger
00663  * ----------
00664  */
00665 Datum
00666 pg_get_triggerdef(PG_FUNCTION_ARGS)
00667 {
00668     Oid         trigid = PG_GETARG_OID(0);
00669 
00670     PG_RETURN_TEXT_P(string_to_text(pg_get_triggerdef_worker(trigid, false)));
00671 }
00672 
00673 Datum
00674 pg_get_triggerdef_ext(PG_FUNCTION_ARGS)
00675 {
00676     Oid         trigid = PG_GETARG_OID(0);
00677     bool        pretty = PG_GETARG_BOOL(1);
00678 
00679     PG_RETURN_TEXT_P(string_to_text(pg_get_triggerdef_worker(trigid, pretty)));
00680 }
00681 
00682 static char *
00683 pg_get_triggerdef_worker(Oid trigid, bool pretty)
00684 {
00685     HeapTuple   ht_trig;
00686     Form_pg_trigger trigrec;
00687     StringInfoData buf;
00688     Relation    tgrel;
00689     ScanKeyData skey[1];
00690     SysScanDesc tgscan;
00691     int         findx = 0;
00692     char       *tgname;
00693     Datum       value;
00694     bool        isnull;
00695 
00696     /*
00697      * Fetch the pg_trigger tuple by the Oid of the trigger
00698      */
00699     tgrel = heap_open(TriggerRelationId, AccessShareLock);
00700 
00701     ScanKeyInit(&skey[0],
00702                 ObjectIdAttributeNumber,
00703                 BTEqualStrategyNumber, F_OIDEQ,
00704                 ObjectIdGetDatum(trigid));
00705 
00706     tgscan = systable_beginscan(tgrel, TriggerOidIndexId, true,
00707                                 SnapshotNow, 1, skey);
00708 
00709     ht_trig = systable_getnext(tgscan);
00710 
00711     if (!HeapTupleIsValid(ht_trig))
00712         elog(ERROR, "could not find tuple for trigger %u", trigid);
00713 
00714     trigrec = (Form_pg_trigger) GETSTRUCT(ht_trig);
00715 
00716     /*
00717      * Start the trigger definition. Note that the trigger's name should never
00718      * be schema-qualified, but the trigger rel's name may be.
00719      */
00720     initStringInfo(&buf);
00721 
00722     tgname = NameStr(trigrec->tgname);
00723     appendStringInfo(&buf, "CREATE %sTRIGGER %s ",
00724                      OidIsValid(trigrec->tgconstraint) ? "CONSTRAINT " : "",
00725                      quote_identifier(tgname));
00726 
00727     if (TRIGGER_FOR_BEFORE(trigrec->tgtype))
00728         appendStringInfo(&buf, "BEFORE");
00729     else if (TRIGGER_FOR_AFTER(trigrec->tgtype))
00730         appendStringInfo(&buf, "AFTER");
00731     else if (TRIGGER_FOR_INSTEAD(trigrec->tgtype))
00732         appendStringInfo(&buf, "INSTEAD OF");
00733     else
00734         elog(ERROR, "unexpected tgtype value: %d", trigrec->tgtype);
00735 
00736     if (TRIGGER_FOR_INSERT(trigrec->tgtype))
00737     {
00738         appendStringInfo(&buf, " INSERT");
00739         findx++;
00740     }
00741     if (TRIGGER_FOR_DELETE(trigrec->tgtype))
00742     {
00743         if (findx > 0)
00744             appendStringInfo(&buf, " OR DELETE");
00745         else
00746             appendStringInfo(&buf, " DELETE");
00747         findx++;
00748     }
00749     if (TRIGGER_FOR_UPDATE(trigrec->tgtype))
00750     {
00751         if (findx > 0)
00752             appendStringInfo(&buf, " OR UPDATE");
00753         else
00754             appendStringInfo(&buf, " UPDATE");
00755         findx++;
00756         /* tgattr is first var-width field, so OK to access directly */
00757         if (trigrec->tgattr.dim1 > 0)
00758         {
00759             int         i;
00760 
00761             appendStringInfoString(&buf, " OF ");
00762             for (i = 0; i < trigrec->tgattr.dim1; i++)
00763             {
00764                 char       *attname;
00765 
00766                 if (i > 0)
00767                     appendStringInfoString(&buf, ", ");
00768                 attname = get_relid_attribute_name(trigrec->tgrelid,
00769                                                    trigrec->tgattr.values[i]);
00770                 appendStringInfoString(&buf, quote_identifier(attname));
00771             }
00772         }
00773     }
00774     if (TRIGGER_FOR_TRUNCATE(trigrec->tgtype))
00775     {
00776         if (findx > 0)
00777             appendStringInfo(&buf, " OR TRUNCATE");
00778         else
00779             appendStringInfo(&buf, " TRUNCATE");
00780         findx++;
00781     }
00782     appendStringInfo(&buf, " ON %s ",
00783                      generate_relation_name(trigrec->tgrelid, NIL));
00784 
00785     if (OidIsValid(trigrec->tgconstraint))
00786     {
00787         if (OidIsValid(trigrec->tgconstrrelid))
00788             appendStringInfo(&buf, "FROM %s ",
00789                         generate_relation_name(trigrec->tgconstrrelid, NIL));
00790         if (!trigrec->tgdeferrable)
00791             appendStringInfo(&buf, "NOT ");
00792         appendStringInfo(&buf, "DEFERRABLE INITIALLY ");
00793         if (trigrec->tginitdeferred)
00794             appendStringInfo(&buf, "DEFERRED ");
00795         else
00796             appendStringInfo(&buf, "IMMEDIATE ");
00797     }
00798 
00799     if (TRIGGER_FOR_ROW(trigrec->tgtype))
00800         appendStringInfo(&buf, "FOR EACH ROW ");
00801     else
00802         appendStringInfo(&buf, "FOR EACH STATEMENT ");
00803 
00804     /* If the trigger has a WHEN qualification, add that */
00805     value = fastgetattr(ht_trig, Anum_pg_trigger_tgqual,
00806                         tgrel->rd_att, &isnull);
00807     if (!isnull)
00808     {
00809         Node       *qual;
00810         char        relkind;
00811         deparse_context context;
00812         deparse_namespace dpns;
00813         RangeTblEntry *oldrte;
00814         RangeTblEntry *newrte;
00815 
00816         appendStringInfoString(&buf, "WHEN (");
00817 
00818         qual = stringToNode(TextDatumGetCString(value));
00819 
00820         relkind = get_rel_relkind(trigrec->tgrelid);
00821 
00822         /* Build minimal OLD and NEW RTEs for the rel */
00823         oldrte = makeNode(RangeTblEntry);
00824         oldrte->rtekind = RTE_RELATION;
00825         oldrte->relid = trigrec->tgrelid;
00826         oldrte->relkind = relkind;
00827         oldrte->alias = makeAlias("old", NIL);
00828         oldrte->eref = oldrte->alias;
00829         oldrte->lateral = false;
00830         oldrte->inh = false;
00831         oldrte->inFromCl = true;
00832 
00833         newrte = makeNode(RangeTblEntry);
00834         newrte->rtekind = RTE_RELATION;
00835         newrte->relid = trigrec->tgrelid;
00836         newrte->relkind = relkind;
00837         newrte->alias = makeAlias("new", NIL);
00838         newrte->eref = newrte->alias;
00839         newrte->lateral = false;
00840         newrte->inh = false;
00841         newrte->inFromCl = true;
00842 
00843         /* Build two-element rtable */
00844         memset(&dpns, 0, sizeof(dpns));
00845         dpns.rtable = list_make2(oldrte, newrte);
00846         dpns.ctes = NIL;
00847         set_rtable_names(&dpns, NIL, NULL);
00848         set_simple_column_names(&dpns);
00849 
00850         /* Set up context with one-deep namespace stack */
00851         context.buf = &buf;
00852         context.namespaces = list_make1(&dpns);
00853         context.windowClause = NIL;
00854         context.windowTList = NIL;
00855         context.varprefix = true;
00856         context.prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : PRETTYFLAG_INDENT;
00857         context.wrapColumn = WRAP_COLUMN_DEFAULT;
00858         context.indentLevel = PRETTYINDENT_STD;
00859 
00860         get_rule_expr(qual, &context, false);
00861 
00862         appendStringInfo(&buf, ") ");
00863     }
00864 
00865     appendStringInfo(&buf, "EXECUTE PROCEDURE %s(",
00866                      generate_function_name(trigrec->tgfoid, 0,
00867                                             NIL, NULL,
00868                                             false, NULL));
00869 
00870     if (trigrec->tgnargs > 0)
00871     {
00872         char       *p;
00873         int         i;
00874 
00875         value = fastgetattr(ht_trig, Anum_pg_trigger_tgargs,
00876                             tgrel->rd_att, &isnull);
00877         if (isnull)
00878             elog(ERROR, "tgargs is null for trigger %u", trigid);
00879         p = (char *) VARDATA(DatumGetByteaP(value));
00880         for (i = 0; i < trigrec->tgnargs; i++)
00881         {
00882             if (i > 0)
00883                 appendStringInfo(&buf, ", ");
00884             simple_quote_literal(&buf, p);
00885             /* advance p to next string embedded in tgargs */
00886             while (*p)
00887                 p++;
00888             p++;
00889         }
00890     }
00891 
00892     /* We deliberately do not put semi-colon at end */
00893     appendStringInfo(&buf, ")");
00894 
00895     /* Clean up */
00896     systable_endscan(tgscan);
00897 
00898     heap_close(tgrel, AccessShareLock);
00899 
00900     return buf.data;
00901 }
00902 
00903 /* ----------
00904  * get_indexdef         - Get the definition of an index
00905  *
00906  * In the extended version, there is a colno argument as well as pretty bool.
00907  *  if colno == 0, we want a complete index definition.
00908  *  if colno > 0, we only want the Nth index key's variable or expression.
00909  *
00910  * Note that the SQL-function versions of this omit any info about the
00911  * index tablespace; this is intentional because pg_dump wants it that way.
00912  * However pg_get_indexdef_string() includes index tablespace if not default.
00913  * ----------
00914  */
00915 Datum
00916 pg_get_indexdef(PG_FUNCTION_ARGS)
00917 {
00918     Oid         indexrelid = PG_GETARG_OID(0);
00919     int         prettyFlags;
00920 
00921     prettyFlags = PRETTYFLAG_INDENT;
00922     PG_RETURN_TEXT_P(string_to_text(pg_get_indexdef_worker(indexrelid, 0,
00923                                                            NULL,
00924                                                            false, false,
00925                                                            prettyFlags)));
00926 }
00927 
00928 Datum
00929 pg_get_indexdef_ext(PG_FUNCTION_ARGS)
00930 {
00931     Oid         indexrelid = PG_GETARG_OID(0);
00932     int32       colno = PG_GETARG_INT32(1);
00933     bool        pretty = PG_GETARG_BOOL(2);
00934     int         prettyFlags;
00935 
00936     prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : PRETTYFLAG_INDENT;
00937     PG_RETURN_TEXT_P(string_to_text(pg_get_indexdef_worker(indexrelid, colno,
00938                                                            NULL,
00939                                                            colno != 0,
00940                                                            false,
00941                                                            prettyFlags)));
00942 }
00943 
00944 /* Internal version that returns a palloc'd C string; no pretty-printing */
00945 char *
00946 pg_get_indexdef_string(Oid indexrelid)
00947 {
00948     return pg_get_indexdef_worker(indexrelid, 0, NULL, false, true, 0);
00949 }
00950 
00951 /* Internal version that just reports the column definitions */
00952 char *
00953 pg_get_indexdef_columns(Oid indexrelid, bool pretty)
00954 {
00955     int         prettyFlags;
00956 
00957     prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : PRETTYFLAG_INDENT;
00958     return pg_get_indexdef_worker(indexrelid, 0, NULL, true, false, prettyFlags);
00959 }
00960 
00961 /*
00962  * Internal workhorse to decompile an index definition.
00963  *
00964  * This is now used for exclusion constraints as well: if excludeOps is not
00965  * NULL then it points to an array of exclusion operator OIDs.
00966  */
00967 static char *
00968 pg_get_indexdef_worker(Oid indexrelid, int colno,
00969                        const Oid *excludeOps,
00970                        bool attrsOnly, bool showTblSpc,
00971                        int prettyFlags)
00972 {
00973     /* might want a separate isConstraint parameter later */
00974     bool        isConstraint = (excludeOps != NULL);
00975     HeapTuple   ht_idx;
00976     HeapTuple   ht_idxrel;
00977     HeapTuple   ht_am;
00978     Form_pg_index idxrec;
00979     Form_pg_class idxrelrec;
00980     Form_pg_am  amrec;
00981     List       *indexprs;
00982     ListCell   *indexpr_item;
00983     List       *context;
00984     Oid         indrelid;
00985     int         keyno;
00986     Datum       indcollDatum;
00987     Datum       indclassDatum;
00988     Datum       indoptionDatum;
00989     bool        isnull;
00990     oidvector  *indcollation;
00991     oidvector  *indclass;
00992     int2vector *indoption;
00993     StringInfoData buf;
00994     char       *str;
00995     char       *sep;
00996 
00997     /*
00998      * Fetch the pg_index tuple by the Oid of the index
00999      */
01000     ht_idx = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexrelid));
01001     if (!HeapTupleIsValid(ht_idx))
01002         elog(ERROR, "cache lookup failed for index %u", indexrelid);
01003     idxrec = (Form_pg_index) GETSTRUCT(ht_idx);
01004 
01005     indrelid = idxrec->indrelid;
01006     Assert(indexrelid == idxrec->indexrelid);
01007 
01008     /* Must get indcollation, indclass, and indoption the hard way */
01009     indcollDatum = SysCacheGetAttr(INDEXRELID, ht_idx,
01010                                    Anum_pg_index_indcollation, &isnull);
01011     Assert(!isnull);
01012     indcollation = (oidvector *) DatumGetPointer(indcollDatum);
01013 
01014     indclassDatum = SysCacheGetAttr(INDEXRELID, ht_idx,
01015                                     Anum_pg_index_indclass, &isnull);
01016     Assert(!isnull);
01017     indclass = (oidvector *) DatumGetPointer(indclassDatum);
01018 
01019     indoptionDatum = SysCacheGetAttr(INDEXRELID, ht_idx,
01020                                      Anum_pg_index_indoption, &isnull);
01021     Assert(!isnull);
01022     indoption = (int2vector *) DatumGetPointer(indoptionDatum);
01023 
01024     /*
01025      * Fetch the pg_class tuple of the index relation
01026      */
01027     ht_idxrel = SearchSysCache1(RELOID, ObjectIdGetDatum(indexrelid));
01028     if (!HeapTupleIsValid(ht_idxrel))
01029         elog(ERROR, "cache lookup failed for relation %u", indexrelid);
01030     idxrelrec = (Form_pg_class) GETSTRUCT(ht_idxrel);
01031 
01032     /*
01033      * Fetch the pg_am tuple of the index' access method
01034      */
01035     ht_am = SearchSysCache1(AMOID, ObjectIdGetDatum(idxrelrec->relam));
01036     if (!HeapTupleIsValid(ht_am))
01037         elog(ERROR, "cache lookup failed for access method %u",
01038              idxrelrec->relam);
01039     amrec = (Form_pg_am) GETSTRUCT(ht_am);
01040 
01041     /*
01042      * Get the index expressions, if any.  (NOTE: we do not use the relcache
01043      * versions of the expressions and predicate, because we want to display
01044      * non-const-folded expressions.)
01045      */
01046     if (!heap_attisnull(ht_idx, Anum_pg_index_indexprs))
01047     {
01048         Datum       exprsDatum;
01049         bool        isnull;
01050         char       *exprsString;
01051 
01052         exprsDatum = SysCacheGetAttr(INDEXRELID, ht_idx,
01053                                      Anum_pg_index_indexprs, &isnull);
01054         Assert(!isnull);
01055         exprsString = TextDatumGetCString(exprsDatum);
01056         indexprs = (List *) stringToNode(exprsString);
01057         pfree(exprsString);
01058     }
01059     else
01060         indexprs = NIL;
01061 
01062     indexpr_item = list_head(indexprs);
01063 
01064     context = deparse_context_for(get_relation_name(indrelid), indrelid);
01065 
01066     /*
01067      * Start the index definition.  Note that the index's name should never be
01068      * schema-qualified, but the indexed rel's name may be.
01069      */
01070     initStringInfo(&buf);
01071 
01072     if (!attrsOnly)
01073     {
01074         if (!isConstraint)
01075             appendStringInfo(&buf, "CREATE %sINDEX %s ON %s USING %s (",
01076                              idxrec->indisunique ? "UNIQUE " : "",
01077                              quote_identifier(NameStr(idxrelrec->relname)),
01078                              generate_relation_name(indrelid, NIL),
01079                              quote_identifier(NameStr(amrec->amname)));
01080         else    /* currently, must be EXCLUDE constraint */
01081             appendStringInfo(&buf, "EXCLUDE USING %s (",
01082                              quote_identifier(NameStr(amrec->amname)));
01083     }
01084 
01085     /*
01086      * Report the indexed attributes
01087      */
01088     sep = "";
01089     for (keyno = 0; keyno < idxrec->indnatts; keyno++)
01090     {
01091         AttrNumber  attnum = idxrec->indkey.values[keyno];
01092         int16       opt = indoption->values[keyno];
01093         Oid         keycoltype;
01094         Oid         keycolcollation;
01095 
01096         if (!colno)
01097             appendStringInfoString(&buf, sep);
01098         sep = ", ";
01099 
01100         if (attnum != 0)
01101         {
01102             /* Simple index column */
01103             char       *attname;
01104             int32       keycoltypmod;
01105 
01106             attname = get_relid_attribute_name(indrelid, attnum);
01107             if (!colno || colno == keyno + 1)
01108                 appendStringInfoString(&buf, quote_identifier(attname));
01109             get_atttypetypmodcoll(indrelid, attnum,
01110                                   &keycoltype, &keycoltypmod,
01111                                   &keycolcollation);
01112         }
01113         else
01114         {
01115             /* expressional index */
01116             Node       *indexkey;
01117 
01118             if (indexpr_item == NULL)
01119                 elog(ERROR, "too few entries in indexprs list");
01120             indexkey = (Node *) lfirst(indexpr_item);
01121             indexpr_item = lnext(indexpr_item);
01122             /* Deparse */
01123             str = deparse_expression_pretty(indexkey, context, false, false,
01124                                             prettyFlags, 0);
01125             if (!colno || colno == keyno + 1)
01126             {
01127                 /* Need parens if it's not a bare function call */
01128                 if (indexkey && IsA(indexkey, FuncExpr) &&
01129                  ((FuncExpr *) indexkey)->funcformat == COERCE_EXPLICIT_CALL)
01130                     appendStringInfoString(&buf, str);
01131                 else
01132                     appendStringInfo(&buf, "(%s)", str);
01133             }
01134             keycoltype = exprType(indexkey);
01135             keycolcollation = exprCollation(indexkey);
01136         }
01137 
01138         if (!attrsOnly && (!colno || colno == keyno + 1))
01139         {
01140             Oid         indcoll;
01141 
01142             /* Add collation, if not default for column */
01143             indcoll = indcollation->values[keyno];
01144             if (OidIsValid(indcoll) && indcoll != keycolcollation)
01145                 appendStringInfo(&buf, " COLLATE %s",
01146                                  generate_collation_name((indcoll)));
01147 
01148             /* Add the operator class name, if not default */
01149             get_opclass_name(indclass->values[keyno], keycoltype, &buf);
01150 
01151             /* Add options if relevant */
01152             if (amrec->amcanorder)
01153             {
01154                 /* if it supports sort ordering, report DESC and NULLS opts */
01155                 if (opt & INDOPTION_DESC)
01156                 {
01157                     appendStringInfo(&buf, " DESC");
01158                     /* NULLS FIRST is the default in this case */
01159                     if (!(opt & INDOPTION_NULLS_FIRST))
01160                         appendStringInfo(&buf, " NULLS LAST");
01161                 }
01162                 else
01163                 {
01164                     if (opt & INDOPTION_NULLS_FIRST)
01165                         appendStringInfo(&buf, " NULLS FIRST");
01166                 }
01167             }
01168 
01169             /* Add the exclusion operator if relevant */
01170             if (excludeOps != NULL)
01171                 appendStringInfo(&buf, " WITH %s",
01172                                  generate_operator_name(excludeOps[keyno],
01173                                                         keycoltype,
01174                                                         keycoltype));
01175         }
01176     }
01177 
01178     if (!attrsOnly)
01179     {
01180         appendStringInfoChar(&buf, ')');
01181 
01182         /*
01183          * If it has options, append "WITH (options)"
01184          */
01185         str = flatten_reloptions(indexrelid);
01186         if (str)
01187         {
01188             appendStringInfo(&buf, " WITH (%s)", str);
01189             pfree(str);
01190         }
01191 
01192         /*
01193          * If it's in a nondefault tablespace, say so, but only if requested
01194          */
01195         if (showTblSpc)
01196         {
01197             Oid         tblspc;
01198 
01199             tblspc = get_rel_tablespace(indexrelid);
01200             if (OidIsValid(tblspc))
01201             {
01202                 if (isConstraint)
01203                     appendStringInfoString(&buf, " USING INDEX");
01204                 appendStringInfo(&buf, " TABLESPACE %s",
01205                               quote_identifier(get_tablespace_name(tblspc)));
01206             }
01207         }
01208 
01209         /*
01210          * If it's a partial index, decompile and append the predicate
01211          */
01212         if (!heap_attisnull(ht_idx, Anum_pg_index_indpred))
01213         {
01214             Node       *node;
01215             Datum       predDatum;
01216             bool        isnull;
01217             char       *predString;
01218 
01219             /* Convert text string to node tree */
01220             predDatum = SysCacheGetAttr(INDEXRELID, ht_idx,
01221                                         Anum_pg_index_indpred, &isnull);
01222             Assert(!isnull);
01223             predString = TextDatumGetCString(predDatum);
01224             node = (Node *) stringToNode(predString);
01225             pfree(predString);
01226 
01227             /* Deparse */
01228             str = deparse_expression_pretty(node, context, false, false,
01229                                             prettyFlags, 0);
01230             if (isConstraint)
01231                 appendStringInfo(&buf, " WHERE (%s)", str);
01232             else
01233                 appendStringInfo(&buf, " WHERE %s", str);
01234         }
01235     }
01236 
01237     /* Clean up */
01238     ReleaseSysCache(ht_idx);
01239     ReleaseSysCache(ht_idxrel);
01240     ReleaseSysCache(ht_am);
01241 
01242     return buf.data;
01243 }
01244 
01245 
01246 /*
01247  * pg_get_constraintdef
01248  *
01249  * Returns the definition for the constraint, ie, everything that needs to
01250  * appear after "ALTER TABLE ... ADD CONSTRAINT <constraintname>".
01251  */
01252 Datum
01253 pg_get_constraintdef(PG_FUNCTION_ARGS)
01254 {
01255     Oid         constraintId = PG_GETARG_OID(0);
01256     int         prettyFlags;
01257 
01258     prettyFlags = PRETTYFLAG_INDENT;
01259     PG_RETURN_TEXT_P(string_to_text(pg_get_constraintdef_worker(constraintId,
01260                                                                 false,
01261                                                                 prettyFlags)));
01262 }
01263 
01264 Datum
01265 pg_get_constraintdef_ext(PG_FUNCTION_ARGS)
01266 {
01267     Oid         constraintId = PG_GETARG_OID(0);
01268     bool        pretty = PG_GETARG_BOOL(1);
01269     int         prettyFlags;
01270 
01271     prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : PRETTYFLAG_INDENT;
01272     PG_RETURN_TEXT_P(string_to_text(pg_get_constraintdef_worker(constraintId,
01273                                                                 false,
01274                                                                 prettyFlags)));
01275 }
01276 
01277 /* Internal version that returns a palloc'd C string; no pretty-printing */
01278 char *
01279 pg_get_constraintdef_string(Oid constraintId)
01280 {
01281     return pg_get_constraintdef_worker(constraintId, true, 0);
01282 }
01283 
01284 static char *
01285 pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
01286                             int prettyFlags)
01287 {
01288     HeapTuple   tup;
01289     Form_pg_constraint conForm;
01290     StringInfoData buf;
01291 
01292     tup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(constraintId));
01293     if (!HeapTupleIsValid(tup)) /* should not happen */
01294         elog(ERROR, "cache lookup failed for constraint %u", constraintId);
01295     conForm = (Form_pg_constraint) GETSTRUCT(tup);
01296 
01297     initStringInfo(&buf);
01298 
01299     if (fullCommand && OidIsValid(conForm->conrelid))
01300     {
01301         appendStringInfo(&buf, "ALTER TABLE ONLY %s ADD CONSTRAINT %s ",
01302                          generate_relation_name(conForm->conrelid, NIL),
01303                          quote_identifier(NameStr(conForm->conname)));
01304     }
01305 
01306     switch (conForm->contype)
01307     {
01308         case CONSTRAINT_FOREIGN:
01309             {
01310                 Datum       val;
01311                 bool        isnull;
01312                 const char *string;
01313 
01314                 /* Start off the constraint definition */
01315                 appendStringInfo(&buf, "FOREIGN KEY (");
01316 
01317                 /* Fetch and build referencing-column list */
01318                 val = SysCacheGetAttr(CONSTROID, tup,
01319                                       Anum_pg_constraint_conkey, &isnull);
01320                 if (isnull)
01321                     elog(ERROR, "null conkey for constraint %u",
01322                          constraintId);
01323 
01324                 decompile_column_index_array(val, conForm->conrelid, &buf);
01325 
01326                 /* add foreign relation name */
01327                 appendStringInfo(&buf, ") REFERENCES %s(",
01328                                  generate_relation_name(conForm->confrelid,
01329                                                         NIL));
01330 
01331                 /* Fetch and build referenced-column list */
01332                 val = SysCacheGetAttr(CONSTROID, tup,
01333                                       Anum_pg_constraint_confkey, &isnull);
01334                 if (isnull)
01335                     elog(ERROR, "null confkey for constraint %u",
01336                          constraintId);
01337 
01338                 decompile_column_index_array(val, conForm->confrelid, &buf);
01339 
01340                 appendStringInfo(&buf, ")");
01341 
01342                 /* Add match type */
01343                 switch (conForm->confmatchtype)
01344                 {
01345                     case FKCONSTR_MATCH_FULL:
01346                         string = " MATCH FULL";
01347                         break;
01348                     case FKCONSTR_MATCH_PARTIAL:
01349                         string = " MATCH PARTIAL";
01350                         break;
01351                     case FKCONSTR_MATCH_SIMPLE:
01352                         string = "";
01353                         break;
01354                     default:
01355                         elog(ERROR, "unrecognized confmatchtype: %d",
01356                              conForm->confmatchtype);
01357                         string = "";    /* keep compiler quiet */
01358                         break;
01359                 }
01360                 appendStringInfoString(&buf, string);
01361 
01362                 /* Add ON UPDATE and ON DELETE clauses, if needed */
01363                 switch (conForm->confupdtype)
01364                 {
01365                     case FKCONSTR_ACTION_NOACTION:
01366                         string = NULL;  /* suppress default */
01367                         break;
01368                     case FKCONSTR_ACTION_RESTRICT:
01369                         string = "RESTRICT";
01370                         break;
01371                     case FKCONSTR_ACTION_CASCADE:
01372                         string = "CASCADE";
01373                         break;
01374                     case FKCONSTR_ACTION_SETNULL:
01375                         string = "SET NULL";
01376                         break;
01377                     case FKCONSTR_ACTION_SETDEFAULT:
01378                         string = "SET DEFAULT";
01379                         break;
01380                     default:
01381                         elog(ERROR, "unrecognized confupdtype: %d",
01382                              conForm->confupdtype);
01383                         string = NULL;  /* keep compiler quiet */
01384                         break;
01385                 }
01386                 if (string)
01387                     appendStringInfo(&buf, " ON UPDATE %s", string);
01388 
01389                 switch (conForm->confdeltype)
01390                 {
01391                     case FKCONSTR_ACTION_NOACTION:
01392                         string = NULL;  /* suppress default */
01393                         break;
01394                     case FKCONSTR_ACTION_RESTRICT:
01395                         string = "RESTRICT";
01396                         break;
01397                     case FKCONSTR_ACTION_CASCADE:
01398                         string = "CASCADE";
01399                         break;
01400                     case FKCONSTR_ACTION_SETNULL:
01401                         string = "SET NULL";
01402                         break;
01403                     case FKCONSTR_ACTION_SETDEFAULT:
01404                         string = "SET DEFAULT";
01405                         break;
01406                     default:
01407                         elog(ERROR, "unrecognized confdeltype: %d",
01408                              conForm->confdeltype);
01409                         string = NULL;  /* keep compiler quiet */
01410                         break;
01411                 }
01412                 if (string)
01413                     appendStringInfo(&buf, " ON DELETE %s", string);
01414 
01415                 break;
01416             }
01417         case CONSTRAINT_PRIMARY:
01418         case CONSTRAINT_UNIQUE:
01419             {
01420                 Datum       val;
01421                 bool        isnull;
01422                 Oid         indexId;
01423 
01424                 /* Start off the constraint definition */
01425                 if (conForm->contype == CONSTRAINT_PRIMARY)
01426                     appendStringInfo(&buf, "PRIMARY KEY (");
01427                 else
01428                     appendStringInfo(&buf, "UNIQUE (");
01429 
01430                 /* Fetch and build target column list */
01431                 val = SysCacheGetAttr(CONSTROID, tup,
01432                                       Anum_pg_constraint_conkey, &isnull);
01433                 if (isnull)
01434                     elog(ERROR, "null conkey for constraint %u",
01435                          constraintId);
01436 
01437                 decompile_column_index_array(val, conForm->conrelid, &buf);
01438 
01439                 appendStringInfo(&buf, ")");
01440 
01441                 indexId = get_constraint_index(constraintId);
01442 
01443                 /* XXX why do we only print these bits if fullCommand? */
01444                 if (fullCommand && OidIsValid(indexId))
01445                 {
01446                     char       *options = flatten_reloptions(indexId);
01447                     Oid         tblspc;
01448 
01449                     if (options)
01450                     {
01451                         appendStringInfo(&buf, " WITH (%s)", options);
01452                         pfree(options);
01453                     }
01454 
01455                     tblspc = get_rel_tablespace(indexId);
01456                     if (OidIsValid(tblspc))
01457                         appendStringInfo(&buf, " USING INDEX TABLESPACE %s",
01458                               quote_identifier(get_tablespace_name(tblspc)));
01459                 }
01460 
01461                 break;
01462             }
01463         case CONSTRAINT_CHECK:
01464             {
01465                 Datum       val;
01466                 bool        isnull;
01467                 char       *conbin;
01468                 char       *consrc;
01469                 Node       *expr;
01470                 List       *context;
01471 
01472                 /* Fetch constraint expression in parsetree form */
01473                 val = SysCacheGetAttr(CONSTROID, tup,
01474                                       Anum_pg_constraint_conbin, &isnull);
01475                 if (isnull)
01476                     elog(ERROR, "null conbin for constraint %u",
01477                          constraintId);
01478 
01479                 conbin = TextDatumGetCString(val);
01480                 expr = stringToNode(conbin);
01481 
01482                 /* Set up deparsing context for Var nodes in constraint */
01483                 if (conForm->conrelid != InvalidOid)
01484                 {
01485                     /* relation constraint */
01486                     context = deparse_context_for(get_relation_name(conForm->conrelid),
01487                                                   conForm->conrelid);
01488                 }
01489                 else
01490                 {
01491                     /* domain constraint --- can't have Vars */
01492                     context = NIL;
01493                 }
01494 
01495                 consrc = deparse_expression_pretty(expr, context, false, false,
01496                                                    prettyFlags, 0);
01497 
01498                 /*
01499                  * Now emit the constraint definition, adding NO INHERIT if
01500                  * necessary.
01501                  *
01502                  * There are cases where the constraint expression will be
01503                  * fully parenthesized and we don't need the outer parens ...
01504                  * but there are other cases where we do need 'em.  Be
01505                  * conservative for now.
01506                  *
01507                  * Note that simply checking for leading '(' and trailing ')'
01508                  * would NOT be good enough, consider "(x > 0) AND (y > 0)".
01509                  */
01510                 appendStringInfo(&buf, "CHECK (%s)%s",
01511                                  consrc,
01512                                  conForm->connoinherit ? " NO INHERIT" : "");
01513                 break;
01514             }
01515         case CONSTRAINT_TRIGGER:
01516 
01517             /*
01518              * There isn't an ALTER TABLE syntax for creating a user-defined
01519              * constraint trigger, but it seems better to print something than
01520              * throw an error; if we throw error then this function couldn't
01521              * safely be applied to all rows of pg_constraint.
01522              */
01523             appendStringInfo(&buf, "TRIGGER");
01524             break;
01525         case CONSTRAINT_EXCLUSION:
01526             {
01527                 Oid         indexOid = conForm->conindid;
01528                 Datum       val;
01529                 bool        isnull;
01530                 Datum      *elems;
01531                 int         nElems;
01532                 int         i;
01533                 Oid        *operators;
01534 
01535                 /* Extract operator OIDs from the pg_constraint tuple */
01536                 val = SysCacheGetAttr(CONSTROID, tup,
01537                                       Anum_pg_constraint_conexclop,
01538                                       &isnull);
01539                 if (isnull)
01540                     elog(ERROR, "null conexclop for constraint %u",
01541                          constraintId);
01542 
01543                 deconstruct_array(DatumGetArrayTypeP(val),
01544                                   OIDOID, sizeof(Oid), true, 'i',
01545                                   &elems, NULL, &nElems);
01546 
01547                 operators = (Oid *) palloc(nElems * sizeof(Oid));
01548                 for (i = 0; i < nElems; i++)
01549                     operators[i] = DatumGetObjectId(elems[i]);
01550 
01551                 /* pg_get_indexdef_worker does the rest */
01552                 /* suppress tablespace because pg_dump wants it that way */
01553                 appendStringInfoString(&buf,
01554                                        pg_get_indexdef_worker(indexOid,
01555                                                               0,
01556                                                               operators,
01557                                                               false,
01558                                                               false,
01559                                                               prettyFlags));
01560                 break;
01561             }
01562         default:
01563             elog(ERROR, "invalid constraint type \"%c\"", conForm->contype);
01564             break;
01565     }
01566 
01567     if (conForm->condeferrable)
01568         appendStringInfo(&buf, " DEFERRABLE");
01569     if (conForm->condeferred)
01570         appendStringInfo(&buf, " INITIALLY DEFERRED");
01571     if (!conForm->convalidated)
01572         appendStringInfoString(&buf, " NOT VALID");
01573 
01574     /* Cleanup */
01575     ReleaseSysCache(tup);
01576 
01577     return buf.data;
01578 }
01579 
01580 
01581 /*
01582  * Convert an int16[] Datum into a comma-separated list of column names
01583  * for the indicated relation; append the list to buf.
01584  */
01585 static void
01586 decompile_column_index_array(Datum column_index_array, Oid relId,
01587                              StringInfo buf)
01588 {
01589     Datum      *keys;
01590     int         nKeys;
01591     int         j;
01592 
01593     /* Extract data from array of int16 */
01594     deconstruct_array(DatumGetArrayTypeP(column_index_array),
01595                       INT2OID, 2, true, 's',
01596                       &keys, NULL, &nKeys);
01597 
01598     for (j = 0; j < nKeys; j++)
01599     {
01600         char       *colName;
01601 
01602         colName = get_relid_attribute_name(relId, DatumGetInt16(keys[j]));
01603 
01604         if (j == 0)
01605             appendStringInfoString(buf, quote_identifier(colName));
01606         else
01607             appendStringInfo(buf, ", %s", quote_identifier(colName));
01608     }
01609 }
01610 
01611 
01612 /* ----------
01613  * get_expr         - Decompile an expression tree
01614  *
01615  * Input: an expression tree in nodeToString form, and a relation OID
01616  *
01617  * Output: reverse-listed expression
01618  *
01619  * Currently, the expression can only refer to a single relation, namely
01620  * the one specified by the second parameter.  This is sufficient for
01621  * partial indexes, column default expressions, etc.  We also support
01622  * Var-free expressions, for which the OID can be InvalidOid.
01623  * ----------
01624  */
01625 Datum
01626 pg_get_expr(PG_FUNCTION_ARGS)
01627 {
01628     text       *expr = PG_GETARG_TEXT_P(0);
01629     Oid         relid = PG_GETARG_OID(1);
01630     int         prettyFlags;
01631     char       *relname;
01632 
01633     prettyFlags = PRETTYFLAG_INDENT;
01634 
01635     if (OidIsValid(relid))
01636     {
01637         /* Get the name for the relation */
01638         relname = get_rel_name(relid);
01639 
01640         /*
01641          * If the OID isn't actually valid, don't throw an error, just return
01642          * NULL.  This is a bit questionable, but it's what we've done
01643          * historically, and it can help avoid unwanted failures when
01644          * examining catalog entries for just-deleted relations.
01645          */
01646         if (relname == NULL)
01647             PG_RETURN_NULL();
01648     }
01649     else
01650         relname = NULL;
01651 
01652     PG_RETURN_TEXT_P(pg_get_expr_worker(expr, relid, relname, prettyFlags));
01653 }
01654 
01655 Datum
01656 pg_get_expr_ext(PG_FUNCTION_ARGS)
01657 {
01658     text       *expr = PG_GETARG_TEXT_P(0);
01659     Oid         relid = PG_GETARG_OID(1);
01660     bool        pretty = PG_GETARG_BOOL(2);
01661     int         prettyFlags;
01662     char       *relname;
01663 
01664     prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : PRETTYFLAG_INDENT;
01665 
01666     if (OidIsValid(relid))
01667     {
01668         /* Get the name for the relation */
01669         relname = get_rel_name(relid);
01670         /* See notes above */
01671         if (relname == NULL)
01672             PG_RETURN_NULL();
01673     }
01674     else
01675         relname = NULL;
01676 
01677     PG_RETURN_TEXT_P(pg_get_expr_worker(expr, relid, relname, prettyFlags));
01678 }
01679 
01680 static text *
01681 pg_get_expr_worker(text *expr, Oid relid, const char *relname, int prettyFlags)
01682 {
01683     Node       *node;
01684     List       *context;
01685     char       *exprstr;
01686     char       *str;
01687 
01688     /* Convert input TEXT object to C string */
01689     exprstr = text_to_cstring(expr);
01690 
01691     /* Convert expression to node tree */
01692     node = (Node *) stringToNode(exprstr);
01693 
01694     pfree(exprstr);
01695 
01696     /* Prepare deparse context if needed */
01697     if (OidIsValid(relid))
01698         context = deparse_context_for(relname, relid);
01699     else
01700         context = NIL;
01701 
01702     /* Deparse */
01703     str = deparse_expression_pretty(node, context, false, false,
01704                                     prettyFlags, 0);
01705 
01706     return string_to_text(str);
01707 }
01708 
01709 
01710 /* ----------
01711  * get_userbyid         - Get a user name by roleid and
01712  *                fallback to 'unknown (OID=n)'
01713  * ----------
01714  */
01715 Datum
01716 pg_get_userbyid(PG_FUNCTION_ARGS)
01717 {
01718     Oid         roleid = PG_GETARG_OID(0);
01719     Name        result;
01720     HeapTuple   roletup;
01721     Form_pg_authid role_rec;
01722 
01723     /*
01724      * Allocate space for the result
01725      */
01726     result = (Name) palloc(NAMEDATALEN);
01727     memset(NameStr(*result), 0, NAMEDATALEN);
01728 
01729     /*
01730      * Get the pg_authid entry and print the result
01731      */
01732     roletup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
01733     if (HeapTupleIsValid(roletup))
01734     {
01735         role_rec = (Form_pg_authid) GETSTRUCT(roletup);
01736         StrNCpy(NameStr(*result), NameStr(role_rec->rolname), NAMEDATALEN);
01737         ReleaseSysCache(roletup);
01738     }
01739     else
01740         sprintf(NameStr(*result), "unknown (OID=%u)", roleid);
01741 
01742     PG_RETURN_NAME(result);
01743 }
01744 
01745 
01746 /*
01747  * pg_get_serial_sequence
01748  *      Get the name of the sequence used by a serial column,
01749  *      formatted suitably for passing to setval, nextval or currval.
01750  *      First parameter is not treated as double-quoted, second parameter
01751  *      is --- see documentation for reason.
01752  */
01753 Datum
01754 pg_get_serial_sequence(PG_FUNCTION_ARGS)
01755 {
01756     text       *tablename = PG_GETARG_TEXT_P(0);
01757     text       *columnname = PG_GETARG_TEXT_PP(1);
01758     RangeVar   *tablerv;
01759     Oid         tableOid;
01760     char       *column;
01761     AttrNumber  attnum;
01762     Oid         sequenceId = InvalidOid;
01763     Relation    depRel;
01764     ScanKeyData key[3];
01765     SysScanDesc scan;
01766     HeapTuple   tup;
01767 
01768     /* Look up table name.  Can't lock it - we might not have privileges. */
01769     tablerv = makeRangeVarFromNameList(textToQualifiedNameList(tablename));
01770     tableOid = RangeVarGetRelid(tablerv, NoLock, false);
01771 
01772     /* Get the number of the column */
01773     column = text_to_cstring(columnname);
01774 
01775     attnum = get_attnum(tableOid, column);
01776     if (attnum == InvalidAttrNumber)
01777         ereport(ERROR,
01778                 (errcode(ERRCODE_UNDEFINED_COLUMN),
01779                  errmsg("column \"%s\" of relation \"%s\" does not exist",
01780                         column, tablerv->relname)));
01781 
01782     /* Search the dependency table for the dependent sequence */
01783     depRel = heap_open(DependRelationId, AccessShareLock);
01784 
01785     ScanKeyInit(&key[0],
01786                 Anum_pg_depend_refclassid,
01787                 BTEqualStrategyNumber, F_OIDEQ,
01788                 ObjectIdGetDatum(RelationRelationId));
01789     ScanKeyInit(&key[1],
01790                 Anum_pg_depend_refobjid,
01791                 BTEqualStrategyNumber, F_OIDEQ,
01792                 ObjectIdGetDatum(tableOid));
01793     ScanKeyInit(&key[2],
01794                 Anum_pg_depend_refobjsubid,
01795                 BTEqualStrategyNumber, F_INT4EQ,
01796                 Int32GetDatum(attnum));
01797 
01798     scan = systable_beginscan(depRel, DependReferenceIndexId, true,
01799                               SnapshotNow, 3, key);
01800 
01801     while (HeapTupleIsValid(tup = systable_getnext(scan)))
01802     {
01803         Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
01804 
01805         /*
01806          * We assume any auto dependency of a sequence on a column must be
01807          * what we are looking for.  (We need the relkind test because indexes
01808          * can also have auto dependencies on columns.)
01809          */
01810         if (deprec->classid == RelationRelationId &&
01811             deprec->objsubid == 0 &&
01812             deprec->deptype == DEPENDENCY_AUTO &&
01813             get_rel_relkind(deprec->objid) == RELKIND_SEQUENCE)
01814         {
01815             sequenceId = deprec->objid;
01816             break;
01817         }
01818     }
01819 
01820     systable_endscan(scan);
01821     heap_close(depRel, AccessShareLock);
01822 
01823     if (OidIsValid(sequenceId))
01824     {
01825         HeapTuple   classtup;
01826         Form_pg_class classtuple;
01827         char       *nspname;
01828         char       *result;
01829 
01830         /* Get the sequence's pg_class entry */
01831         classtup = SearchSysCache1(RELOID, ObjectIdGetDatum(sequenceId));
01832         if (!HeapTupleIsValid(classtup))
01833             elog(ERROR, "cache lookup failed for relation %u", sequenceId);
01834         classtuple = (Form_pg_class) GETSTRUCT(classtup);
01835 
01836         /* Get the namespace */
01837         nspname = get_namespace_name(classtuple->relnamespace);
01838         if (!nspname)
01839             elog(ERROR, "cache lookup failed for namespace %u",
01840                  classtuple->relnamespace);
01841 
01842         /* And construct the result string */
01843         result = quote_qualified_identifier(nspname,
01844                                             NameStr(classtuple->relname));
01845 
01846         ReleaseSysCache(classtup);
01847 
01848         PG_RETURN_TEXT_P(string_to_text(result));
01849     }
01850 
01851     PG_RETURN_NULL();
01852 }
01853 
01854 
01855 /*
01856  * pg_get_functiondef
01857  *      Returns the complete "CREATE OR REPLACE FUNCTION ..." statement for
01858  *      the specified function.
01859  *
01860  * Note: if you change the output format of this function, be careful not
01861  * to break psql's rules (in \ef and \sf) for identifying the start of the
01862  * function body.  To wit: the function body starts on a line that begins
01863  * with "AS ", and no preceding line will look like that.
01864  */
01865 Datum
01866 pg_get_functiondef(PG_FUNCTION_ARGS)
01867 {
01868     Oid         funcid = PG_GETARG_OID(0);
01869     StringInfoData buf;
01870     StringInfoData dq;
01871     HeapTuple   proctup;
01872     HeapTuple   langtup;
01873     Form_pg_proc proc;
01874     Form_pg_language lang;
01875     Datum       tmp;
01876     bool        isnull;
01877     const char *prosrc;
01878     const char *name;
01879     const char *nsp;
01880     float4      procost;
01881     int         oldlen;
01882 
01883     initStringInfo(&buf);
01884 
01885     /* Look up the function */
01886     proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
01887     if (!HeapTupleIsValid(proctup))
01888         elog(ERROR, "cache lookup failed for function %u", funcid);
01889     proc = (Form_pg_proc) GETSTRUCT(proctup);
01890     name = NameStr(proc->proname);
01891 
01892     if (proc->proisagg)
01893         ereport(ERROR,
01894                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
01895                  errmsg("\"%s\" is an aggregate function", name)));
01896 
01897     /* Need its pg_language tuple for the language name */
01898     langtup = SearchSysCache1(LANGOID, ObjectIdGetDatum(proc->prolang));
01899     if (!HeapTupleIsValid(langtup))
01900         elog(ERROR, "cache lookup failed for language %u", proc->prolang);
01901     lang = (Form_pg_language) GETSTRUCT(langtup);
01902 
01903     /*
01904      * We always qualify the function name, to ensure the right function gets
01905      * replaced.
01906      */
01907     nsp = get_namespace_name(proc->pronamespace);
01908     appendStringInfo(&buf, "CREATE OR REPLACE FUNCTION %s(",
01909                      quote_qualified_identifier(nsp, name));
01910     (void) print_function_arguments(&buf, proctup, false, true);
01911     appendStringInfoString(&buf, ")\n RETURNS ");
01912     print_function_rettype(&buf, proctup);
01913     appendStringInfo(&buf, "\n LANGUAGE %s\n",
01914                      quote_identifier(NameStr(lang->lanname)));
01915 
01916     /* Emit some miscellaneous options on one line */
01917     oldlen = buf.len;
01918 
01919     if (proc->proiswindow)
01920         appendStringInfoString(&buf, " WINDOW");
01921     switch (proc->provolatile)
01922     {
01923         case PROVOLATILE_IMMUTABLE:
01924             appendStringInfoString(&buf, " IMMUTABLE");
01925             break;
01926         case PROVOLATILE_STABLE:
01927             appendStringInfoString(&buf, " STABLE");
01928             break;
01929         case PROVOLATILE_VOLATILE:
01930             break;
01931     }
01932     if (proc->proisstrict)
01933         appendStringInfoString(&buf, " STRICT");
01934     if (proc->prosecdef)
01935         appendStringInfoString(&buf, " SECURITY DEFINER");
01936 
01937     /* This code for the default cost and rows should match functioncmds.c */
01938     if (proc->prolang == INTERNALlanguageId ||
01939         proc->prolang == ClanguageId)
01940         procost = 1;
01941     else
01942         procost = 100;
01943     if (proc->procost != procost)
01944         appendStringInfo(&buf, " COST %g", proc->procost);
01945 
01946     if (proc->prorows > 0 && proc->prorows != 1000)
01947         appendStringInfo(&buf, " ROWS %g", proc->prorows);
01948 
01949     if (oldlen != buf.len)
01950         appendStringInfoChar(&buf, '\n');
01951 
01952     /* Emit any proconfig options, one per line */
01953     tmp = SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_proconfig, &isnull);
01954     if (!isnull)
01955     {
01956         ArrayType  *a = DatumGetArrayTypeP(tmp);
01957         int         i;
01958 
01959         Assert(ARR_ELEMTYPE(a) == TEXTOID);
01960         Assert(ARR_NDIM(a) == 1);
01961         Assert(ARR_LBOUND(a)[0] == 1);
01962 
01963         for (i = 1; i <= ARR_DIMS(a)[0]; i++)
01964         {
01965             Datum       d;
01966 
01967             d = array_ref(a, 1, &i,
01968                           -1 /* varlenarray */ ,
01969                           -1 /* TEXT's typlen */ ,
01970                           false /* TEXT's typbyval */ ,
01971                           'i' /* TEXT's typalign */ ,
01972                           &isnull);
01973             if (!isnull)
01974             {
01975                 char       *configitem = TextDatumGetCString(d);
01976                 char       *pos;
01977 
01978                 pos = strchr(configitem, '=');
01979                 if (pos == NULL)
01980                     continue;
01981                 *pos++ = '\0';
01982 
01983                 appendStringInfo(&buf, " SET %s TO ",
01984                                  quote_identifier(configitem));
01985 
01986                 /*
01987                  * Some GUC variable names are 'LIST' type and hence must not
01988                  * be quoted.
01989                  */
01990                 if (pg_strcasecmp(configitem, "DateStyle") == 0
01991                     || pg_strcasecmp(configitem, "search_path") == 0)
01992                     appendStringInfoString(&buf, pos);
01993                 else
01994                     simple_quote_literal(&buf, pos);
01995                 appendStringInfoChar(&buf, '\n');
01996             }
01997         }
01998     }
01999 
02000     /* And finally the function definition ... */
02001     appendStringInfoString(&buf, "AS ");
02002 
02003     tmp = SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_probin, &isnull);
02004     if (!isnull)
02005     {
02006         simple_quote_literal(&buf, TextDatumGetCString(tmp));
02007         appendStringInfoString(&buf, ", ");     /* assume prosrc isn't null */
02008     }
02009 
02010     tmp = SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_prosrc, &isnull);
02011     if (isnull)
02012         elog(ERROR, "null prosrc");
02013     prosrc = TextDatumGetCString(tmp);
02014 
02015     /*
02016      * We always use dollar quoting.  Figure out a suitable delimiter.
02017      *
02018      * Since the user is likely to be editing the function body string, we
02019      * shouldn't use a short delimiter that he might easily create a conflict
02020      * with.  Hence prefer "$function$", but extend if needed.
02021      */
02022     initStringInfo(&dq);
02023     appendStringInfoString(&dq, "$function");
02024     while (strstr(prosrc, dq.data) != NULL)
02025         appendStringInfoChar(&dq, 'x');
02026     appendStringInfoChar(&dq, '$');
02027 
02028     appendStringInfoString(&buf, dq.data);
02029     appendStringInfoString(&buf, prosrc);
02030     appendStringInfoString(&buf, dq.data);
02031 
02032     appendStringInfoString(&buf, "\n");
02033 
02034     ReleaseSysCache(langtup);
02035     ReleaseSysCache(proctup);
02036 
02037     PG_RETURN_TEXT_P(string_to_text(buf.data));
02038 }
02039 
02040 /*
02041  * pg_get_function_arguments
02042  *      Get a nicely-formatted list of arguments for a function.
02043  *      This is everything that would go between the parentheses in
02044  *      CREATE FUNCTION.
02045  */
02046 Datum
02047 pg_get_function_arguments(PG_FUNCTION_ARGS)
02048 {
02049     Oid         funcid = PG_GETARG_OID(0);
02050     StringInfoData buf;
02051     HeapTuple   proctup;
02052 
02053     initStringInfo(&buf);
02054 
02055     proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
02056     if (!HeapTupleIsValid(proctup))
02057         elog(ERROR, "cache lookup failed for function %u", funcid);
02058 
02059     (void) print_function_arguments(&buf, proctup, false, true);
02060 
02061     ReleaseSysCache(proctup);
02062 
02063     PG_RETURN_TEXT_P(string_to_text(buf.data));
02064 }
02065 
02066 /*
02067  * pg_get_function_identity_arguments
02068  *      Get a formatted list of arguments for a function.
02069  *      This is everything that would go between the parentheses in
02070  *      ALTER FUNCTION, etc.  In particular, don't print defaults.
02071  */
02072 Datum
02073 pg_get_function_identity_arguments(PG_FUNCTION_ARGS)
02074 {
02075     Oid         funcid = PG_GETARG_OID(0);
02076     StringInfoData buf;
02077     HeapTuple   proctup;
02078 
02079     initStringInfo(&buf);
02080 
02081     proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
02082     if (!HeapTupleIsValid(proctup))
02083         elog(ERROR, "cache lookup failed for function %u", funcid);
02084 
02085     (void) print_function_arguments(&buf, proctup, false, false);
02086 
02087     ReleaseSysCache(proctup);
02088 
02089     PG_RETURN_TEXT_P(string_to_text(buf.data));
02090 }
02091 
02092 /*
02093  * pg_get_function_result
02094  *      Get a nicely-formatted version of the result type of a function.
02095  *      This is what would appear after RETURNS in CREATE FUNCTION.
02096  */
02097 Datum
02098 pg_get_function_result(PG_FUNCTION_ARGS)
02099 {
02100     Oid         funcid = PG_GETARG_OID(0);
02101     StringInfoData buf;
02102     HeapTuple   proctup;
02103 
02104     initStringInfo(&buf);
02105 
02106     proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
02107     if (!HeapTupleIsValid(proctup))
02108         elog(ERROR, "cache lookup failed for function %u", funcid);
02109 
02110     print_function_rettype(&buf, proctup);
02111 
02112     ReleaseSysCache(proctup);
02113 
02114     PG_RETURN_TEXT_P(string_to_text(buf.data));
02115 }
02116 
02117 /*
02118  * Guts of pg_get_function_result: append the function's return type
02119  * to the specified buffer.
02120  */
02121 static void
02122 print_function_rettype(StringInfo buf, HeapTuple proctup)
02123 {
02124     Form_pg_proc proc = (Form_pg_proc) GETSTRUCT(proctup);
02125     int         ntabargs = 0;
02126     StringInfoData rbuf;
02127 
02128     initStringInfo(&rbuf);
02129 
02130     if (proc->proretset)
02131     {
02132         /* It might be a table function; try to print the arguments */
02133         appendStringInfoString(&rbuf, "TABLE(");
02134         ntabargs = print_function_arguments(&rbuf, proctup, true, false);
02135         if (ntabargs > 0)
02136             appendStringInfoString(&rbuf, ")");
02137         else
02138             resetStringInfo(&rbuf);
02139     }
02140 
02141     if (ntabargs == 0)
02142     {
02143         /* Not a table function, so do the normal thing */
02144         if (proc->proretset)
02145             appendStringInfoString(&rbuf, "SETOF ");
02146         appendStringInfoString(&rbuf, format_type_be(proc->prorettype));
02147     }
02148 
02149     appendStringInfoString(buf, rbuf.data);
02150 }
02151 
02152 /*
02153  * Common code for pg_get_function_arguments and pg_get_function_result:
02154  * append the desired subset of arguments to buf.  We print only TABLE
02155  * arguments when print_table_args is true, and all the others when it's false.
02156  * We print argument defaults only if print_defaults is true.
02157  * Function return value is the number of arguments printed.
02158  */
02159 static int
02160 print_function_arguments(StringInfo buf, HeapTuple proctup,
02161                          bool print_table_args, bool print_defaults)
02162 {
02163     Form_pg_proc proc = (Form_pg_proc) GETSTRUCT(proctup);
02164     int         numargs;
02165     Oid        *argtypes;
02166     char      **argnames;
02167     char       *argmodes;
02168     int         argsprinted;
02169     int         inputargno;
02170     int         nlackdefaults;
02171     ListCell   *nextargdefault = NULL;
02172     int         i;
02173 
02174     numargs = get_func_arg_info(proctup,
02175                                 &argtypes, &argnames, &argmodes);
02176 
02177     nlackdefaults = numargs;
02178     if (print_defaults && proc->pronargdefaults > 0)
02179     {
02180         Datum       proargdefaults;
02181         bool        isnull;
02182 
02183         proargdefaults = SysCacheGetAttr(PROCOID, proctup,
02184                                          Anum_pg_proc_proargdefaults,
02185                                          &isnull);
02186         if (!isnull)
02187         {
02188             char       *str;
02189             List       *argdefaults;
02190 
02191             str = TextDatumGetCString(proargdefaults);
02192             argdefaults = (List *) stringToNode(str);
02193             Assert(IsA(argdefaults, List));
02194             pfree(str);
02195             nextargdefault = list_head(argdefaults);
02196             /* nlackdefaults counts only *input* arguments lacking defaults */
02197             nlackdefaults = proc->pronargs - list_length(argdefaults);
02198         }
02199     }
02200 
02201     argsprinted = 0;
02202     inputargno = 0;
02203     for (i = 0; i < numargs; i++)
02204     {
02205         Oid         argtype = argtypes[i];
02206         char       *argname = argnames ? argnames[i] : NULL;
02207         char        argmode = argmodes ? argmodes[i] : PROARGMODE_IN;
02208         const char *modename;
02209         bool        isinput;
02210 
02211         switch (argmode)
02212         {
02213             case PROARGMODE_IN:
02214                 modename = "";
02215                 isinput = true;
02216                 break;
02217             case PROARGMODE_INOUT:
02218                 modename = "INOUT ";
02219                 isinput = true;
02220                 break;
02221             case PROARGMODE_OUT:
02222                 modename = "OUT ";
02223                 isinput = false;
02224                 break;
02225             case PROARGMODE_VARIADIC:
02226                 modename = "VARIADIC ";
02227                 isinput = true;
02228                 break;
02229             case PROARGMODE_TABLE:
02230                 modename = "";
02231                 isinput = false;
02232                 break;
02233             default:
02234                 elog(ERROR, "invalid parameter mode '%c'", argmode);
02235                 modename = NULL;    /* keep compiler quiet */
02236                 isinput = false;
02237                 break;
02238         }
02239         if (isinput)
02240             inputargno++;       /* this is a 1-based counter */
02241 
02242         if (print_table_args != (argmode == PROARGMODE_TABLE))
02243             continue;
02244 
02245         if (argsprinted)
02246             appendStringInfoString(buf, ", ");
02247         appendStringInfoString(buf, modename);
02248         if (argname && argname[0])
02249             appendStringInfo(buf, "%s ", quote_identifier(argname));
02250         appendStringInfoString(buf, format_type_be(argtype));
02251         if (print_defaults && isinput && inputargno > nlackdefaults)
02252         {
02253             Node       *expr;
02254 
02255             Assert(nextargdefault != NULL);
02256             expr = (Node *) lfirst(nextargdefault);
02257             nextargdefault = lnext(nextargdefault);
02258 
02259             appendStringInfo(buf, " DEFAULT %s",
02260                              deparse_expression(expr, NIL, false, false));
02261         }
02262         argsprinted++;
02263     }
02264 
02265     return argsprinted;
02266 }
02267 
02268 
02269 /*
02270  * deparse_expression           - General utility for deparsing expressions
02271  *
02272  * calls deparse_expression_pretty with all prettyPrinting disabled
02273  */
02274 char *
02275 deparse_expression(Node *expr, List *dpcontext,
02276                    bool forceprefix, bool showimplicit)
02277 {
02278     return deparse_expression_pretty(expr, dpcontext, forceprefix,
02279                                      showimplicit, 0, 0);
02280 }
02281 
02282 /* ----------
02283  * deparse_expression_pretty    - General utility for deparsing expressions
02284  *
02285  * expr is the node tree to be deparsed.  It must be a transformed expression
02286  * tree (ie, not the raw output of gram.y).
02287  *
02288  * dpcontext is a list of deparse_namespace nodes representing the context
02289  * for interpreting Vars in the node tree.  It can be NIL if no Vars are
02290  * expected.
02291  *
02292  * forceprefix is TRUE to force all Vars to be prefixed with their table names.
02293  *
02294  * showimplicit is TRUE to force all implicit casts to be shown explicitly.
02295  *
02296  * Tries to pretty up the output according to prettyFlags and startIndent.
02297  *
02298  * The result is a palloc'd string.
02299  * ----------
02300  */
02301 static char *
02302 deparse_expression_pretty(Node *expr, List *dpcontext,
02303                           bool forceprefix, bool showimplicit,
02304                           int prettyFlags, int startIndent)
02305 {
02306     StringInfoData buf;
02307     deparse_context context;
02308 
02309     initStringInfo(&buf);
02310     context.buf = &buf;
02311     context.namespaces = dpcontext;
02312     context.windowClause = NIL;
02313     context.windowTList = NIL;
02314     context.varprefix = forceprefix;
02315     context.prettyFlags = prettyFlags;
02316     context.wrapColumn = WRAP_COLUMN_DEFAULT;
02317     context.indentLevel = startIndent;
02318 
02319     get_rule_expr(expr, &context, showimplicit);
02320 
02321     return buf.data;
02322 }
02323 
02324 /* ----------
02325  * deparse_context_for          - Build deparse context for a single relation
02326  *
02327  * Given the reference name (alias) and OID of a relation, build deparsing
02328  * context for an expression referencing only that relation (as varno 1,
02329  * varlevelsup 0).  This is sufficient for many uses of deparse_expression.
02330  * ----------
02331  */
02332 List *
02333 deparse_context_for(const char *aliasname, Oid relid)
02334 {
02335     deparse_namespace *dpns;
02336     RangeTblEntry *rte;
02337 
02338     dpns = (deparse_namespace *) palloc0(sizeof(deparse_namespace));
02339 
02340     /* Build a minimal RTE for the rel */
02341     rte = makeNode(RangeTblEntry);
02342     rte->rtekind = RTE_RELATION;
02343     rte->relid = relid;
02344     rte->relkind = RELKIND_RELATION;    /* no need for exactness here */
02345     rte->alias = makeAlias(aliasname, NIL);
02346     rte->eref = rte->alias;
02347     rte->lateral = false;
02348     rte->inh = false;
02349     rte->inFromCl = true;
02350 
02351     /* Build one-element rtable */
02352     dpns->rtable = list_make1(rte);
02353     dpns->ctes = NIL;
02354     set_rtable_names(dpns, NIL, NULL);
02355     set_simple_column_names(dpns);
02356 
02357     /* Return a one-deep namespace stack */
02358     return list_make1(dpns);
02359 }
02360 
02361 /*
02362  * deparse_context_for_planstate    - Build deparse context for a plan
02363  *
02364  * When deparsing an expression in a Plan tree, we might have to resolve
02365  * OUTER_VAR, INNER_VAR, or INDEX_VAR references.  To do this, the caller must
02366  * provide the parent PlanState node.  Then OUTER_VAR and INNER_VAR references
02367  * can be resolved by drilling down into the left and right child plans.
02368  * Similarly, INDEX_VAR references can be resolved by reference to the
02369  * indextlist given in the parent IndexOnlyScan node.  (Note that we don't
02370  * currently support deparsing of indexquals in regular IndexScan or
02371  * BitmapIndexScan nodes; for those, we can only deparse the indexqualorig
02372  * fields, which won't contain INDEX_VAR Vars.)
02373  *
02374  * Note: planstate really ought to be declared as "PlanState *", but we use
02375  * "Node *" to avoid having to include execnodes.h in builtins.h.
02376  *
02377  * The ancestors list is a list of the PlanState's parent PlanStates, the
02378  * most-closely-nested first.  This is needed to resolve PARAM_EXEC Params.
02379  * Note we assume that all the PlanStates share the same rtable.
02380  *
02381  * The plan's rangetable list must also be passed, along with the per-RTE
02382  * alias names assigned by a previous call to select_rtable_names_for_explain.
02383  * (We use the rangetable to resolve simple Vars, but the plan inputs are
02384  * necessary for Vars with special varnos.)
02385  */
02386 List *
02387 deparse_context_for_planstate(Node *planstate, List *ancestors,
02388                               List *rtable, List *rtable_names)
02389 {
02390     deparse_namespace *dpns;
02391 
02392     dpns = (deparse_namespace *) palloc0(sizeof(deparse_namespace));
02393 
02394     /* Initialize fields that stay the same across the whole plan tree */
02395     dpns->rtable = rtable;
02396     dpns->rtable_names = rtable_names;
02397     dpns->ctes = NIL;
02398 
02399     /*
02400      * Set up column name aliases.  We will get rather bogus results for join
02401      * RTEs, but that doesn't matter because plan trees don't contain any join
02402      * alias Vars.
02403      */
02404     set_simple_column_names(dpns);
02405 
02406     /* Set our attention on the specific plan node passed in */
02407     set_deparse_planstate(dpns, (PlanState *) planstate);
02408     dpns->ancestors = ancestors;
02409 
02410     /* Return a one-deep namespace stack */
02411     return list_make1(dpns);
02412 }
02413 
02414 /*
02415  * select_rtable_names_for_explain  - Select RTE aliases for EXPLAIN
02416  *
02417  * Determine the relation aliases we'll use during an EXPLAIN operation.
02418  * This is just a frontend to set_rtable_names.  We have to expose the aliases
02419  * to EXPLAIN because EXPLAIN needs to know the right alias names to print.
02420  */
02421 List *
02422 select_rtable_names_for_explain(List *rtable, Bitmapset *rels_used)
02423 {
02424     deparse_namespace dpns;
02425 
02426     memset(&dpns, 0, sizeof(dpns));
02427     dpns.rtable = rtable;
02428     dpns.ctes = NIL;
02429     set_rtable_names(&dpns, NIL, rels_used);
02430     /* We needn't bother computing column aliases yet */
02431 
02432     return dpns.rtable_names;
02433 }
02434 
02435 /*
02436  * set_rtable_names: select RTE aliases to be used in printing a query
02437  *
02438  * We fill in dpns->rtable_names with a list of names that is one-for-one with
02439  * the already-filled dpns->rtable list.  Each RTE name is unique among those
02440  * in the new namespace plus any ancestor namespaces listed in
02441  * parent_namespaces.
02442  *
02443  * If rels_used isn't NULL, only RTE indexes listed in it are given aliases.
02444  *
02445  * Note that this function is only concerned with relation names, not column
02446  * names.
02447  */
02448 static void
02449 set_rtable_names(deparse_namespace *dpns, List *parent_namespaces,
02450                  Bitmapset *rels_used)
02451 {
02452     ListCell   *lc;
02453     int         rtindex = 1;
02454 
02455     dpns->rtable_names = NIL;
02456     foreach(lc, dpns->rtable)
02457     {
02458         RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
02459         char       *refname;
02460 
02461         if (rels_used && !bms_is_member(rtindex, rels_used))
02462         {
02463             /* Ignore unreferenced RTE */
02464             refname = NULL;
02465         }
02466         else if (rte->alias)
02467         {
02468             /* If RTE has a user-defined alias, prefer that */
02469             refname = rte->alias->aliasname;
02470         }
02471         else if (rte->rtekind == RTE_RELATION)
02472         {
02473             /* Use the current actual name of the relation */
02474             refname = get_rel_name(rte->relid);
02475         }
02476         else if (rte->rtekind == RTE_JOIN)
02477         {
02478             /* Unnamed join has no refname */
02479             refname = NULL;
02480         }
02481         else
02482         {
02483             /* Otherwise use whatever the parser assigned */
02484             refname = rte->eref->aliasname;
02485         }
02486 
02487         /*
02488          * If the selected name isn't unique, append digits to make it so
02489          */
02490         if (refname &&
02491             !refname_is_unique(refname, dpns, parent_namespaces))
02492         {
02493             char       *modname = (char *) palloc(strlen(refname) + 32);
02494             int         i = 0;
02495 
02496             do
02497             {
02498                 sprintf(modname, "%s_%d", refname, ++i);
02499             } while (!refname_is_unique(modname, dpns, parent_namespaces));
02500             refname = modname;
02501         }
02502 
02503         dpns->rtable_names = lappend(dpns->rtable_names, refname);
02504         rtindex++;
02505     }
02506 }
02507 
02508 /*
02509  * refname_is_unique: is refname distinct from all already-chosen RTE names?
02510  */
02511 static bool
02512 refname_is_unique(char *refname, deparse_namespace *dpns,
02513                   List *parent_namespaces)
02514 {
02515     ListCell   *lc;
02516 
02517     foreach(lc, dpns->rtable_names)
02518     {
02519         char       *oldname = (char *) lfirst(lc);
02520 
02521         if (oldname && strcmp(oldname, refname) == 0)
02522             return false;
02523     }
02524     foreach(lc, parent_namespaces)
02525     {
02526         deparse_namespace *olddpns = (deparse_namespace *) lfirst(lc);
02527         ListCell   *lc2;
02528 
02529         foreach(lc2, olddpns->rtable_names)
02530         {
02531             char       *oldname = (char *) lfirst(lc2);
02532 
02533             if (oldname && strcmp(oldname, refname) == 0)
02534                 return false;
02535         }
02536     }
02537     return true;
02538 }
02539 
02540 /*
02541  * set_deparse_for_query: set up deparse_namespace for deparsing a Query tree
02542  *
02543  * For convenience, this is defined to initialize the deparse_namespace struct
02544  * from scratch.
02545  */
02546 static void
02547 set_deparse_for_query(deparse_namespace *dpns, Query *query,
02548                       List *parent_namespaces)
02549 {
02550     ListCell   *lc;
02551     ListCell   *lc2;
02552 
02553     /* Initialize *dpns and fill rtable/ctes links */
02554     memset(dpns, 0, sizeof(deparse_namespace));
02555     dpns->rtable = query->rtable;
02556     dpns->ctes = query->cteList;
02557 
02558     /* Assign a unique relation alias to each RTE */
02559     set_rtable_names(dpns, parent_namespaces, NULL);
02560 
02561     /* Initialize dpns->rtable_columns to contain zeroed structs */
02562     dpns->rtable_columns = NIL;
02563     while (list_length(dpns->rtable_columns) < list_length(dpns->rtable))
02564         dpns->rtable_columns = lappend(dpns->rtable_columns,
02565                                        palloc0(sizeof(deparse_columns)));
02566 
02567     /* Detect whether global uniqueness of USING names is needed */
02568     dpns->unique_using = has_unnamed_full_join_using((Node *) query->jointree);
02569 
02570     /*
02571      * Select names for columns merged by USING, via a recursive pass over the
02572      * query jointree.
02573      */
02574     set_using_names(dpns, (Node *) query->jointree);
02575 
02576     /*
02577      * Now assign remaining column aliases for each RTE.  We do this in a
02578      * linear scan of the rtable, so as to process RTEs whether or not they
02579      * are in the jointree (we mustn't miss NEW.*, INSERT target relations,
02580      * etc).  JOIN RTEs must be processed after their children, but this is
02581      * okay because they appear later in the rtable list than their children
02582      * (cf Asserts in identify_join_columns()).
02583      */
02584     forboth(lc, dpns->rtable, lc2, dpns->rtable_columns)
02585     {
02586         RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
02587         deparse_columns *colinfo = (deparse_columns *) lfirst(lc2);
02588 
02589         if (rte->rtekind == RTE_JOIN)
02590             set_join_column_names(dpns, rte, colinfo);
02591         else
02592             set_relation_column_names(dpns, rte, colinfo);
02593     }
02594 }
02595 
02596 /*
02597  * set_simple_column_names: fill in column aliases for non-query situations
02598  *
02599  * This handles EXPLAIN and cases where we only have relation RTEs.  Without
02600  * a join tree, we can't do anything smart about join RTEs, but we don't
02601  * need to (note that EXPLAIN should never see join alias Vars anyway).
02602  * If we do hit a join RTE we'll just process it like a non-table base RTE.
02603  */
02604 static void
02605 set_simple_column_names(deparse_namespace *dpns)
02606 {
02607     ListCell   *lc;
02608     ListCell   *lc2;
02609 
02610     /* Initialize dpns->rtable_columns to contain zeroed structs */
02611     dpns->rtable_columns = NIL;
02612     while (list_length(dpns->rtable_columns) < list_length(dpns->rtable))
02613         dpns->rtable_columns = lappend(dpns->rtable_columns,
02614                                        palloc0(sizeof(deparse_columns)));
02615 
02616     /* Assign unique column aliases within each RTE */
02617     forboth(lc, dpns->rtable, lc2, dpns->rtable_columns)
02618     {
02619         RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
02620         deparse_columns *colinfo = (deparse_columns *) lfirst(lc2);
02621 
02622         set_relation_column_names(dpns, rte, colinfo);
02623     }
02624 }
02625 
02626 /*
02627  * has_unnamed_full_join_using: search jointree for unnamed FULL JOIN USING
02628  *
02629  * Merged columns of a FULL JOIN USING act differently from either of the
02630  * input columns, so they have to be referenced as columns of the JOIN not
02631  * as columns of either input.  And this is problematic if the join is
02632  * unnamed (alias-less): we cannot qualify the column's name with an RTE
02633  * name, since there is none.  (Forcibly assigning an alias to the join is
02634  * not a solution, since that will prevent legal references to tables below
02635  * the join.)  To ensure that every column in the query is unambiguously
02636  * referenceable, we must assign such merged columns names that are globally
02637  * unique across the whole query, aliasing other columns out of the way as
02638  * necessary.
02639  *
02640  * Because the ensuing re-aliasing is fairly damaging to the readability of
02641  * the query, we don't do this unless we have to.  So, we must pre-scan
02642  * the join tree to see if we have to, before starting set_using_names().
02643  */
02644 static bool
02645 has_unnamed_full_join_using(Node *jtnode)
02646 {
02647     if (IsA(jtnode, RangeTblRef))
02648     {
02649         /* nothing to do here */
02650     }
02651     else if (IsA(jtnode, FromExpr))
02652     {
02653         FromExpr   *f = (FromExpr *) jtnode;
02654         ListCell   *lc;
02655 
02656         foreach(lc, f->fromlist)
02657         {
02658             if (has_unnamed_full_join_using((Node *) lfirst(lc)))
02659                 return true;
02660         }
02661     }
02662     else if (IsA(jtnode, JoinExpr))
02663     {
02664         JoinExpr   *j = (JoinExpr *) jtnode;
02665 
02666         /* Is it an unnamed FULL JOIN with USING? */
02667         if (j->alias == NULL &&
02668             j->jointype == JOIN_FULL &&
02669             j->usingClause)
02670             return true;
02671 
02672         /* Nope, but inspect children */
02673         if (has_unnamed_full_join_using(j->larg))
02674             return true;
02675         if (has_unnamed_full_join_using(j->rarg))
02676             return true;
02677     }
02678     else
02679         elog(ERROR, "unrecognized node type: %d",
02680              (int) nodeTag(jtnode));
02681     return false;
02682 }
02683 
02684 /*
02685  * set_using_names: select column aliases to be used for merged USING columns
02686  *
02687  * We do this during a recursive descent of the query jointree.
02688  * dpns->unique_using must already be set to determine the global strategy.
02689  *
02690  * Column alias info is saved in the dpns->rtable_columns list, which is
02691  * assumed to be filled with pre-zeroed deparse_columns structs.
02692  */
02693 static void
02694 set_using_names(deparse_namespace *dpns, Node *jtnode)
02695 {
02696     if (IsA(jtnode, RangeTblRef))
02697     {
02698         /* nothing to do now */
02699     }
02700     else if (IsA(jtnode, FromExpr))
02701     {
02702         FromExpr   *f = (FromExpr *) jtnode;
02703         ListCell   *lc;
02704 
02705         foreach(lc, f->fromlist)
02706             set_using_names(dpns, (Node *) lfirst(lc));
02707     }
02708     else if (IsA(jtnode, JoinExpr))
02709     {
02710         JoinExpr   *j = (JoinExpr *) jtnode;
02711         RangeTblEntry *rte = rt_fetch(j->rtindex, dpns->rtable);
02712         deparse_columns *colinfo = deparse_columns_fetch(j->rtindex, dpns);
02713         int        *leftattnos;
02714         int        *rightattnos;
02715         deparse_columns *leftcolinfo;
02716         deparse_columns *rightcolinfo;
02717         int         i;
02718         ListCell   *lc;
02719 
02720         /* Get info about the shape of the join */
02721         identify_join_columns(j, rte, colinfo);
02722         leftattnos = colinfo->leftattnos;
02723         rightattnos = colinfo->rightattnos;
02724 
02725         /* Look up the not-yet-filled-in child deparse_columns structs */
02726         leftcolinfo = deparse_columns_fetch(colinfo->leftrti, dpns);
02727         rightcolinfo = deparse_columns_fetch(colinfo->rightrti, dpns);
02728 
02729         /*
02730          * If this join is unnamed, then we cannot substitute new aliases at
02731          * this level, so any name requirements pushed down to here must be
02732          * pushed down again to the children.
02733          */
02734         if (rte->alias == NULL)
02735         {
02736             for (i = 0; i < colinfo->num_cols; i++)
02737             {
02738                 char       *colname = colinfo->colnames[i];
02739 
02740                 if (colname == NULL)
02741                     continue;
02742 
02743                 /* Push down to left column, unless it's a system column */
02744                 if (leftattnos[i] > 0)
02745                 {
02746                     expand_colnames_array_to(leftcolinfo, leftattnos[i]);
02747                     leftcolinfo->colnames[leftattnos[i] - 1] = colname;
02748                 }
02749 
02750                 /* Same on the righthand side */
02751                 if (rightattnos[i] > 0)
02752                 {
02753                     expand_colnames_array_to(rightcolinfo, rightattnos[i]);
02754                     rightcolinfo->colnames[rightattnos[i] - 1] = colname;
02755                 }
02756             }
02757         }
02758 
02759         /*
02760          * If there's a USING clause, select the USING column names and push
02761          * those names down to the children.  We have two strategies:
02762          *
02763          * If dpns->unique_using is TRUE, we force all USING names to be
02764          * unique across the whole query level.  In principle we'd only need
02765          * the names of USING columns in unnamed full joins to be globally
02766          * unique, but to safely assign all USING names in a single pass, we
02767          * have to enforce the same uniqueness rule for all of them.  However,
02768          * if a USING column's name has been pushed down from the parent, we
02769          * should use it as-is rather than making a uniqueness adjustment.
02770          * This is necessary when we're at an unnamed join, and it creates no
02771          * risk of ambiguity.  Also, if there's a user-written output alias
02772          * for a merged column, we prefer to use that rather than the input
02773          * name; this simplifies the logic and seems likely to lead to less
02774          * aliasing overall.
02775          *
02776          * If dpns->unique_using is FALSE, we only need USING names to be
02777          * unique within their own join RTE.  We still need to honor
02778          * pushed-down names, though.
02779          *
02780          * Though significantly different in results, these two strategies are
02781          * implemented by the same code, with only the difference of whether
02782          * to put assigned names into dpns->using_names.
02783          */
02784         if (j->usingClause)
02785         {
02786             /* USING names must correspond to the first join output columns */
02787             expand_colnames_array_to(colinfo, list_length(j->usingClause));
02788             i = 0;
02789             foreach(lc, j->usingClause)
02790             {
02791                 char       *colname = strVal(lfirst(lc));
02792 
02793                 /* Assert it's a merged column */
02794                 Assert(leftattnos[i] != 0 && rightattnos[i] != 0);
02795 
02796                 /* Adopt passed-down name if any, else select unique name */
02797                 if (colinfo->colnames[i] != NULL)
02798                     colname = colinfo->colnames[i];
02799                 else
02800                 {
02801                     /* Prefer user-written output alias if any */
02802                     if (rte->alias && i < list_length(rte->alias->colnames))
02803                         colname = strVal(list_nth(rte->alias->colnames, i));
02804                     /* Make it appropriately unique */
02805                     colname = make_colname_unique(colname, dpns, colinfo);
02806                     if (dpns->unique_using)
02807                         dpns->using_names = lappend(dpns->using_names,
02808                                                     colname);
02809                     /* Save it as output column name, too */
02810                     colinfo->colnames[i] = colname;
02811                 }
02812 
02813                 /* Remember selected names for use later */
02814                 colinfo->usingNames = lappend(colinfo->usingNames, colname);
02815 
02816                 /* Push down to left column, unless it's a system column */
02817                 if (leftattnos[i] > 0)
02818                 {
02819                     expand_colnames_array_to(leftcolinfo, leftattnos[i]);
02820                     leftcolinfo->colnames[leftattnos[i] - 1] = colname;
02821                 }
02822 
02823                 /* Same on the righthand side */
02824                 if (rightattnos[i] > 0)
02825                 {
02826                     expand_colnames_array_to(rightcolinfo, rightattnos[i]);
02827                     rightcolinfo->colnames[rightattnos[i] - 1] = colname;
02828                 }
02829 
02830                 i++;
02831             }
02832         }
02833 
02834         /* Now recursively assign USING column names in children */
02835         set_using_names(dpns, j->larg);
02836         set_using_names(dpns, j->rarg);
02837     }
02838     else
02839         elog(ERROR, "unrecognized node type: %d",
02840              (int) nodeTag(jtnode));
02841 }
02842 
02843 /*
02844  * set_relation_column_names: select column aliases for a non-join RTE
02845  *
02846  * Column alias info is saved in *colinfo, which is assumed to be pre-zeroed.
02847  * If any colnames entries are already filled in, those override local
02848  * choices.
02849  */
02850 static void
02851 set_relation_column_names(deparse_namespace *dpns, RangeTblEntry *rte,
02852                           deparse_columns *colinfo)
02853 {
02854     int         ncolumns;
02855     char      **real_colnames;
02856     bool        changed_any;
02857     int         noldcolumns;
02858     int         i;
02859     int         j;
02860 
02861     /*
02862      * Extract the RTE's "real" column names.  This is comparable to
02863      * get_rte_attribute_name, except that it's important to disregard dropped
02864      * columns.  We put NULL into the array for a dropped column.
02865      */
02866     if (rte->rtekind == RTE_RELATION)
02867     {
02868         /* Relation --- look to the system catalogs for up-to-date info */
02869         Relation    rel;
02870         TupleDesc   tupdesc;
02871 
02872         rel = relation_open(rte->relid, AccessShareLock);
02873         tupdesc = RelationGetDescr(rel);
02874 
02875         ncolumns = tupdesc->natts;
02876         real_colnames = (char **) palloc(ncolumns * sizeof(char *));
02877 
02878         for (i = 0; i < ncolumns; i++)
02879         {
02880             if (tupdesc->attrs[i]->attisdropped)
02881                 real_colnames[i] = NULL;
02882             else
02883                 real_colnames[i] = pstrdup(NameStr(tupdesc->attrs[i]->attname));
02884         }
02885         relation_close(rel, AccessShareLock);
02886     }
02887     else
02888     {
02889         /* Otherwise use the column names from eref */
02890         ListCell   *lc;
02891 
02892         ncolumns = list_length(rte->eref->colnames);
02893         real_colnames = (char **) palloc(ncolumns * sizeof(char *));
02894 
02895         i = 0;
02896         foreach(lc, rte->eref->colnames)
02897         {
02898             real_colnames[i] = strVal(lfirst(lc));
02899             i++;
02900         }
02901     }
02902 
02903     /*
02904      * Ensure colinfo->colnames has a slot for each column.  (It could be long
02905      * enough already, if we pushed down a name for the last column.)  Note:
02906      * it's possible that there are now more columns than there were when the
02907      * query was parsed, ie colnames could be longer than rte->eref->colnames.
02908      * We must assign unique aliases to the new columns too, else there could
02909      * be unresolved conflicts when the view/rule is reloaded.
02910      */
02911     expand_colnames_array_to(colinfo, ncolumns);
02912     Assert(colinfo->num_cols == ncolumns);
02913 
02914     /*
02915      * Make sufficiently large new_colnames and is_new_col arrays, too.
02916      *
02917      * Note: because we leave colinfo->num_new_cols zero until after the loop,
02918      * colname_is_unique will not consult that array, which is fine because it
02919      * would only be duplicate effort.
02920      */
02921     colinfo->new_colnames = (char **) palloc(ncolumns * sizeof(char *));
02922     colinfo->is_new_col = (bool *) palloc(ncolumns * sizeof(bool));
02923 
02924     /*
02925      * Scan the columns, select a unique alias for each one, and store it in
02926      * colinfo->colnames and colinfo->new_colnames.  The former array has NULL
02927      * entries for dropped columns, the latter omits them.  Also mark
02928      * new_colnames entries as to whether they are new since parse time; this
02929      * is the case for entries beyond the length of rte->eref->colnames.
02930      */
02931     noldcolumns = list_length(rte->eref->colnames);
02932     changed_any = false;
02933     j = 0;
02934     for (i = 0; i < ncolumns; i++)
02935     {
02936         char       *real_colname = real_colnames[i];
02937         char       *colname = colinfo->colnames[i];
02938 
02939         /* Skip dropped columns */
02940         if (real_colname == NULL)
02941         {
02942             Assert(colname == NULL);    /* colnames[i] is already NULL */
02943             continue;
02944         }
02945 
02946         /* If alias already assigned, that's what to use */
02947         if (colname == NULL)
02948         {
02949             /* If user wrote an alias, prefer that over real column name */
02950             if (rte->alias && i < list_length(rte->alias->colnames))
02951                 colname = strVal(list_nth(rte->alias->colnames, i));
02952             else
02953                 colname = real_colname;
02954 
02955             /* Unique-ify and insert into colinfo */
02956             colname = make_colname_unique(colname, dpns, colinfo);
02957 
02958             colinfo->colnames[i] = colname;
02959         }
02960 
02961         /* Put names of non-dropped columns in new_colnames[] too */
02962         colinfo->new_colnames[j] = colname;
02963         /* And mark them as new or not */
02964         colinfo->is_new_col[j] = (i >= noldcolumns);
02965         j++;
02966 
02967         /* Remember if any assigned aliases differ from "real" name */
02968         if (!changed_any && strcmp(colname, real_colname) != 0)
02969             changed_any = true;
02970     }
02971 
02972     /*
02973      * Set correct length for new_colnames[] array.  (Note: if columns have
02974      * been added, colinfo->num_cols includes them, which is not really quite
02975      * right but is harmless, since any new columns must be at the end where
02976      * they won't affect varattnos of pre-existing columns.)
02977      */
02978     colinfo->num_new_cols = j;
02979 
02980     /*
02981      * For a relation RTE, we need only print the alias column names if any
02982      * are different from the underlying "real" names.  For a function RTE,
02983      * always emit a complete column alias list; this is to protect against
02984      * possible instability of the default column names (eg, from altering
02985      * parameter names).  For other RTE types, print if we changed anything OR
02986      * if there were user-written column aliases (since the latter would be
02987      * part of the underlying "reality").
02988      */
02989     if (rte->rtekind == RTE_RELATION)
02990         colinfo->printaliases = changed_any;
02991     else if (rte->rtekind == RTE_FUNCTION)
02992         colinfo->printaliases = true;
02993     else if (rte->alias && rte->alias->colnames != NIL)
02994         colinfo->printaliases = true;
02995     else
02996         colinfo->printaliases = changed_any;
02997 }
02998 
02999 /*
03000  * set_join_column_names: select column aliases for a join RTE
03001  *
03002  * Column alias info is saved in *colinfo, which is assumed to be pre-zeroed.
03003  * If any colnames entries are already filled in, those override local
03004  * choices.  Also, names for USING columns were already chosen by
03005  * set_using_names().  We further expect that column alias selection has been
03006  * completed for both input RTEs.
03007  */
03008 static void
03009 set_join_column_names(deparse_namespace *dpns, RangeTblEntry *rte,
03010                       deparse_columns *colinfo)
03011 {
03012     deparse_columns *leftcolinfo;
03013     deparse_columns *rightcolinfo;
03014     bool        changed_any;
03015     int         noldcolumns;
03016     int         nnewcolumns;
03017     Bitmapset  *leftmerged = NULL;
03018     Bitmapset  *rightmerged = NULL;
03019     int         i;
03020     int         j;
03021     int         ic;
03022     int         jc;
03023 
03024     /* Look up the previously-filled-in child deparse_columns structs */
03025     leftcolinfo = deparse_columns_fetch(colinfo->leftrti, dpns);
03026     rightcolinfo = deparse_columns_fetch(colinfo->rightrti, dpns);
03027 
03028     /*
03029      * Ensure colinfo->colnames has a slot for each column.  (It could be long
03030      * enough already, if we pushed down a name for the last column.)  Note:
03031      * it's possible that one or both inputs now have more columns than there
03032      * were when the query was parsed, but we'll deal with that below.  We
03033      * only need entries in colnames for pre-existing columns.
03034      */
03035     noldcolumns = list_length(rte->eref->colnames);
03036     expand_colnames_array_to(colinfo, noldcolumns);
03037     Assert(colinfo->num_cols == noldcolumns);
03038 
03039     /*
03040      * Scan the join output columns, select an alias for each one, and store
03041      * it in colinfo->colnames.  If there are USING columns, set_using_names()
03042      * already selected their names, so we can start the loop at the first
03043      * non-merged column.
03044      */
03045     changed_any = false;
03046     for (i = list_length(colinfo->usingNames); i < noldcolumns; i++)
03047     {
03048         char       *colname = colinfo->colnames[i];
03049         char       *real_colname;
03050 
03051         /* Get the child column name */
03052         if (colinfo->leftattnos[i] > 0)
03053             real_colname = leftcolinfo->colnames[colinfo->leftattnos[i] - 1];
03054         else if (colinfo->rightattnos[i] > 0)
03055             real_colname = rightcolinfo->colnames[colinfo->rightattnos[i] - 1];
03056         else
03057         {
03058             /* We're joining system columns --- use eref name */
03059             real_colname = (char *) list_nth(rte->eref->colnames, i);
03060         }
03061 
03062         /* Ignore dropped columns (only possible for non-merged column) */
03063         if (real_colname == NULL)
03064         {
03065             Assert(colname == NULL);
03066             continue;
03067         }
03068 
03069         /* In an unnamed join, just report child column names as-is */
03070         if (rte->alias == NULL)
03071         {
03072             colinfo->colnames[i] = real_colname;
03073             continue;
03074         }
03075 
03076         /* If alias already assigned, that's what to use */
03077         if (colname == NULL)
03078         {
03079             /* If user wrote an alias, prefer that over real column name */
03080             if (rte->alias && i < list_length(rte->alias->colnames))
03081                 colname = strVal(list_nth(rte->alias->colnames, i));
03082             else
03083                 colname = real_colname;
03084 
03085             /* Unique-ify and insert into colinfo */
03086             colname = make_colname_unique(colname, dpns, colinfo);
03087 
03088             colinfo->colnames[i] = colname;
03089         }
03090 
03091         /* Remember if any assigned aliases differ from "real" name */
03092         if (!changed_any && strcmp(colname, real_colname) != 0)
03093             changed_any = true;
03094     }
03095 
03096     /*
03097      * Calculate number of columns the join would have if it were re-parsed
03098      * now, and create storage for the new_colnames and is_new_col arrays.
03099      *
03100      * Note: colname_is_unique will be consulting new_colnames[] during the
03101      * loops below, so its not-yet-filled entries must be zeroes.
03102      */
03103     nnewcolumns = leftcolinfo->num_new_cols + rightcolinfo->num_new_cols -
03104         list_length(colinfo->usingNames);
03105     colinfo->num_new_cols = nnewcolumns;
03106     colinfo->new_colnames = (char **) palloc0(nnewcolumns * sizeof(char *));
03107     colinfo->is_new_col = (bool *) palloc0(nnewcolumns * sizeof(bool));
03108 
03109     /*
03110      * Generating the new_colnames array is a bit tricky since any new columns
03111      * added since parse time must be inserted in the right places.  This code
03112      * must match the parser, which will order a join's columns as merged
03113      * columns first (in USING-clause order), then non-merged columns from the
03114      * left input (in attnum order), then non-merged columns from the right
03115      * input (ditto).  If one of the inputs is itself a join, its columns will
03116      * be ordered according to the same rule, which means newly-added columns
03117      * might not be at the end.  We can figure out what's what by consulting
03118      * the leftattnos and rightattnos arrays plus the input is_new_col arrays.
03119      *
03120      * In these loops, i indexes leftattnos/rightattnos (so it's join varattno
03121      * less one), j indexes new_colnames/is_new_col, and ic/jc have similar
03122      * meanings for the current child RTE.
03123      */
03124 
03125     /* Handle merged columns; they are first and can't be new */
03126     i = j = 0;
03127     while (i < noldcolumns &&
03128            colinfo->leftattnos[i] != 0 &&
03129            colinfo->rightattnos[i] != 0)
03130     {
03131         /* column name is already determined and known unique */
03132         colinfo->new_colnames[j] = colinfo->colnames[i];
03133         colinfo->is_new_col[j] = false;
03134 
03135         /* build bitmapsets of child attnums of merged columns */
03136         if (colinfo->leftattnos[i] > 0)
03137             leftmerged = bms_add_member(leftmerged, colinfo->leftattnos[i]);
03138         if (colinfo->rightattnos[i] > 0)
03139             rightmerged = bms_add_member(rightmerged, colinfo->rightattnos[i]);
03140 
03141         i++, j++;
03142     }
03143 
03144     /* Handle non-merged left-child columns */
03145     ic = 0;
03146     for (jc = 0; jc < leftcolinfo->num_new_cols; jc++)
03147     {
03148         char       *child_colname = leftcolinfo->new_colnames[jc];
03149 
03150         if (!leftcolinfo->is_new_col[jc])
03151         {
03152             /* Advance ic to next non-dropped old column of left child */
03153             while (ic < leftcolinfo->num_cols &&
03154                    leftcolinfo->colnames[ic] == NULL)
03155                 ic++;
03156             Assert(ic < leftcolinfo->num_cols);
03157             ic++;
03158             /* If it is a merged column, we already processed it */
03159             if (bms_is_member(ic, leftmerged))
03160                 continue;
03161             /* Else, advance i to the corresponding existing join column */
03162             while (i < colinfo->num_cols &&
03163                    colinfo->colnames[i] == NULL)
03164                 i++;
03165             Assert(i < colinfo->num_cols);
03166             Assert(ic == colinfo->leftattnos[i]);
03167             /* Use the already-assigned name of this column */
03168             colinfo->new_colnames[j] = colinfo->colnames[i];
03169             i++;
03170         }
03171         else
03172         {
03173             /*
03174              * Unique-ify the new child column name and assign, unless we're
03175              * in an unnamed join, in which case just copy
03176              */
03177             if (rte->alias != NULL)
03178             {
03179                 colinfo->new_colnames[j] =
03180                     make_colname_unique(child_colname, dpns, colinfo);
03181                 if (!changed_any &&
03182                     strcmp(colinfo->new_colnames[j], child_colname) != 0)
03183                     changed_any = true;
03184             }
03185             else
03186                 colinfo->new_colnames[j] = child_colname;
03187         }
03188 
03189         colinfo->is_new_col[j] = leftcolinfo->is_new_col[jc];
03190         j++;
03191     }
03192 
03193     /* Handle non-merged right-child columns in exactly the same way */
03194     ic = 0;
03195     for (jc = 0; jc < rightcolinfo->num_new_cols; jc++)
03196     {
03197         char       *child_colname = rightcolinfo->new_colnames[jc];
03198 
03199         if (!rightcolinfo->is_new_col[jc])
03200         {
03201             /* Advance ic to next non-dropped old column of right child */
03202             while (ic < rightcolinfo->num_cols &&
03203                    rightcolinfo->colnames[ic] == NULL)
03204                 ic++;
03205             Assert(ic < rightcolinfo->num_cols);
03206             ic++;
03207             /* If it is a merged column, we already processed it */
03208             if (bms_is_member(ic, rightmerged))
03209                 continue;
03210             /* Else, advance i to the corresponding existing join column */
03211             while (i < colinfo->num_cols &&
03212                    colinfo->colnames[i] == NULL)
03213                 i++;
03214             Assert(i < colinfo->num_cols);
03215             Assert(ic == colinfo->rightattnos[i]);
03216             /* Use the already-assigned name of this column */
03217             colinfo->new_colnames[j] = colinfo->colnames[i];
03218             i++;
03219         }
03220         else
03221         {
03222             /*
03223              * Unique-ify the new child column name and assign, unless we're
03224              * in an unnamed join, in which case just copy
03225              */
03226             if (rte->alias != NULL)
03227             {
03228                 colinfo->new_colnames[j] =
03229                     make_colname_unique(child_colname, dpns, colinfo);
03230                 if (!changed_any &&
03231                     strcmp(colinfo->new_colnames[j], child_colname) != 0)
03232                     changed_any = true;
03233             }
03234             else
03235                 colinfo->new_colnames[j] = child_colname;
03236         }
03237 
03238         colinfo->is_new_col[j] = rightcolinfo->is_new_col[jc];
03239         j++;
03240     }
03241 
03242     /* Assert we processed the right number of columns */
03243 #ifdef USE_ASSERT_CHECKING
03244     while (i < colinfo->num_cols && colinfo->colnames[i] == NULL)
03245         i++;
03246     Assert(i == colinfo->num_cols);
03247     Assert(j == nnewcolumns);
03248 #endif
03249 
03250     /*
03251      * For a named join, print column aliases if we changed any from the child
03252      * names.  Unnamed joins cannot print aliases.
03253      */
03254     if (rte->alias != NULL)
03255         colinfo->printaliases = changed_any;
03256     else
03257         colinfo->printaliases = false;
03258 }
03259 
03260 /*
03261  * colname_is_unique: is colname distinct from already-chosen column names?
03262  *
03263  * dpns is query-wide info, colinfo is for the column's RTE
03264  */
03265 static bool
03266 colname_is_unique(char *colname, deparse_namespace *dpns,
03267                   deparse_columns *colinfo)
03268 {
03269     int         i;
03270     ListCell   *lc;
03271 
03272     /* Check against already-assigned column aliases within RTE */
03273     for (i = 0; i < colinfo->num_cols; i++)
03274     {
03275         char       *oldname = colinfo->colnames[i];
03276 
03277         if (oldname && strcmp(oldname, colname) == 0)
03278             return false;
03279     }
03280 
03281     /*
03282      * If we're building a new_colnames array, check that too (this will be
03283      * partially but not completely redundant with the previous checks)
03284      */
03285     for (i = 0; i < colinfo->num_new_cols; i++)
03286     {
03287         char       *oldname = colinfo->new_colnames[i];
03288 
03289         if (oldname && strcmp(oldname, colname) == 0)
03290             return false;
03291     }
03292 
03293     /* Also check against USING-column names that must be globally unique */
03294     foreach(lc, dpns->using_names)
03295     {
03296         char       *oldname = (char *) lfirst(lc);
03297 
03298         if (strcmp(oldname, colname) == 0)
03299             return false;
03300     }
03301 
03302     return true;
03303 }
03304 
03305 /*
03306  * make_colname_unique: modify colname if necessary to make it unique
03307  *
03308  * dpns is query-wide info, colinfo is for the column's RTE
03309  */
03310 static char *
03311 make_colname_unique(char *colname, deparse_namespace *dpns,
03312                     deparse_columns *colinfo)
03313 {
03314     /*
03315      * If the selected name isn't unique, append digits to make it so
03316      */
03317     if (!colname_is_unique(colname, dpns, colinfo))
03318     {
03319         char       *modname = (char *) palloc(strlen(colname) + 32);
03320         int         i = 0;
03321 
03322         do
03323         {
03324             sprintf(modname, "%s_%d", colname, ++i);
03325         } while (!colname_is_unique(modname, dpns, colinfo));
03326         colname = modname;
03327     }
03328     return colname;
03329 }
03330 
03331 /*
03332  * expand_colnames_array_to: make colinfo->colnames at least n items long
03333  *
03334  * Any added array entries are initialized to zero.
03335  */
03336 static void
03337 expand_colnames_array_to(deparse_columns *colinfo, int n)
03338 {
03339     if (n > colinfo->num_cols)
03340     {
03341         if (colinfo->colnames == NULL)
03342             colinfo->colnames = (char **) palloc0(n * sizeof(char *));
03343         else
03344         {
03345             colinfo->colnames = (char **) repalloc(colinfo->colnames,
03346                                                    n * sizeof(char *));
03347             memset(colinfo->colnames + colinfo->num_cols, 0,
03348                    (n - colinfo->num_cols) * sizeof(char *));
03349         }
03350         colinfo->num_cols = n;
03351     }
03352 }
03353 
03354 /*
03355  * identify_join_columns: figure out where columns of a join come from
03356  *
03357  * Fills the join-specific fields of the colinfo struct, except for
03358  * usingNames which is filled later.
03359  */
03360 static void
03361 identify_join_columns(JoinExpr *j, RangeTblEntry *jrte,
03362                       deparse_columns *colinfo)
03363 {
03364     int         numjoincols;
03365     int         i;
03366     ListCell   *lc;
03367 
03368     /* Extract left/right child RT indexes */
03369     if (IsA(j->larg, RangeTblRef))
03370         colinfo->leftrti = ((RangeTblRef *) j->larg)->rtindex;
03371     else if (IsA(j->larg, JoinExpr))
03372         colinfo->leftrti = ((JoinExpr *) j->larg)->rtindex;
03373     else
03374         elog(ERROR, "unrecognized node type in jointree: %d",
03375              (int) nodeTag(j->larg));
03376     if (IsA(j->rarg, RangeTblRef))
03377         colinfo->rightrti = ((RangeTblRef *) j->rarg)->rtindex;
03378     else if (IsA(j->rarg, JoinExpr))
03379         colinfo->rightrti = ((JoinExpr *) j->rarg)->rtindex;
03380     else
03381         elog(ERROR, "unrecognized node type in jointree: %d",
03382              (int) nodeTag(j->rarg));
03383 
03384     /* Assert children will be processed earlier than join in second pass */
03385     Assert(colinfo->leftrti < j->rtindex);
03386     Assert(colinfo->rightrti < j->rtindex);
03387 
03388     /* Initialize result arrays with zeroes */
03389     numjoincols = list_length(jrte->joinaliasvars);
03390     Assert(numjoincols == list_length(jrte->eref->colnames));
03391     colinfo->leftattnos = (int *) palloc0(numjoincols * sizeof(int));
03392     colinfo->rightattnos = (int *) palloc0(numjoincols * sizeof(int));
03393 
03394     /* Scan the joinaliasvars list to identify simple column references */
03395     i = 0;
03396     foreach(lc, jrte->joinaliasvars)
03397     {
03398         Var        *aliasvar = (Var *) lfirst(lc);
03399 
03400         if (IsA(aliasvar, Var))
03401         {
03402             Assert(aliasvar->varlevelsup == 0);
03403             Assert(aliasvar->varattno != 0);
03404             if (aliasvar->varno == colinfo->leftrti)
03405                 colinfo->leftattnos[i] = aliasvar->varattno;
03406             else if (aliasvar->varno == colinfo->rightrti)
03407                 colinfo->rightattnos[i] = aliasvar->varattno;
03408             else
03409                 elog(ERROR, "unexpected varno %d in JOIN RTE",
03410                      aliasvar->varno);
03411         }
03412         else if (IsA(aliasvar, CoalesceExpr))
03413         {
03414             /*
03415              * It's a merged column in FULL JOIN USING.  Ignore it for now and
03416              * let the code below identify the merged columns.
03417              */
03418         }
03419         else
03420         {
03421             /*
03422              * Although NULL constants can appear in joinaliasvars lists
03423              * during planning, we shouldn't see any here, since the Query
03424              * tree hasn't been through AcquireRewriteLocks().
03425              */
03426             elog(ERROR, "unrecognized node type in join alias vars: %d",
03427                  (int) nodeTag(aliasvar));
03428         }
03429 
03430         i++;
03431     }
03432 
03433     /*
03434      * If there's a USING clause, deconstruct the join quals to identify the
03435      * merged columns.  This is a tad painful but if we cannot rely on the
03436      * column names, there is no other representation of which columns were
03437      * joined by USING.  (Unless the join type is FULL, we can't tell from the
03438      * joinaliasvars list which columns are merged.)  Note: we assume that the
03439      * merged columns are the first output column(s) of the join.
03440      */
03441     if (j->usingClause)
03442     {
03443         List       *leftvars = NIL;
03444         List       *rightvars = NIL;
03445         ListCell   *lc2;
03446 
03447         /* Extract left- and right-side Vars from the qual expression */
03448         flatten_join_using_qual(j->quals, &leftvars, &rightvars);
03449         Assert(list_length(leftvars) == list_length(j->usingClause));
03450         Assert(list_length(rightvars) == list_length(j->usingClause));
03451 
03452         /* Mark the output columns accordingly */
03453         i = 0;
03454         forboth(lc, leftvars, lc2, rightvars)
03455         {
03456             Var        *leftvar = (Var *) lfirst(lc);
03457             Var        *rightvar = (Var *) lfirst(lc2);
03458 
03459             Assert(leftvar->varlevelsup == 0);
03460             Assert(leftvar->varattno != 0);
03461             if (leftvar->varno != colinfo->leftrti)
03462                 elog(ERROR, "unexpected varno %d in JOIN USING qual",
03463                      leftvar->varno);
03464             colinfo->leftattnos[i] = leftvar->varattno;
03465 
03466             Assert(rightvar->varlevelsup == 0);
03467             Assert(rightvar->varattno != 0);
03468             if (rightvar->varno != colinfo->rightrti)
03469                 elog(ERROR, "unexpected varno %d in JOIN USING qual",
03470                      rightvar->varno);
03471             colinfo->rightattnos[i] = rightvar->varattno;
03472 
03473             i++;
03474         }
03475     }
03476 }
03477 
03478 /*
03479  * flatten_join_using_qual: extract Vars being joined from a JOIN/USING qual
03480  *
03481  * We assume that transformJoinUsingClause won't have produced anything except
03482  * AND nodes, equality operator nodes, and possibly implicit coercions, and
03483  * that the AND node inputs match left-to-right with the original USING list.
03484  *
03485  * Caller must initialize the result lists to NIL.
03486  */
03487 static void
03488 flatten_join_using_qual(Node *qual, List **leftvars, List **rightvars)
03489 {
03490     if (IsA(qual, BoolExpr))
03491     {
03492         /* Handle AND nodes by recursion */
03493         BoolExpr   *b = (BoolExpr *) qual;
03494         ListCell   *lc;
03495 
03496         Assert(b->boolop == AND_EXPR);
03497         foreach(lc, b->args)
03498         {
03499             flatten_join_using_qual((Node *) lfirst(lc),
03500                                     leftvars, rightvars);
03501         }
03502     }
03503     else if (IsA(qual, OpExpr))
03504     {
03505         /* Otherwise we should have an equality operator */
03506         OpExpr     *op = (OpExpr *) qual;
03507         Var        *var;
03508 
03509         if (list_length(op->args) != 2)
03510             elog(ERROR, "unexpected unary operator in JOIN/USING qual");
03511         /* Arguments should be Vars with perhaps implicit coercions */
03512         var = (Var *) strip_implicit_coercions((Node *) linitial(op->args));
03513         if (!IsA(var, Var))
03514             elog(ERROR, "unexpected node type in JOIN/USING qual: %d",
03515                  (int) nodeTag(var));
03516         *leftvars = lappend(*leftvars, var);
03517         var = (Var *) strip_implicit_coercions((Node *) lsecond(op->args));
03518         if (!IsA(var, Var))
03519             elog(ERROR, "unexpected node type in JOIN/USING qual: %d",
03520                  (int) nodeTag(var));
03521         *rightvars = lappend(*rightvars, var);
03522     }
03523     else
03524     {
03525         /* Perhaps we have an implicit coercion to boolean? */
03526         Node       *q = strip_implicit_coercions(qual);
03527 
03528         if (q != qual)
03529             flatten_join_using_qual(q, leftvars, rightvars);
03530         else
03531             elog(ERROR, "unexpected node type in JOIN/USING qual: %d",
03532                  (int) nodeTag(qual));
03533     }
03534 }
03535 
03536 /*
03537  * get_rtable_name: convenience function to get a previously assigned RTE alias
03538  *
03539  * The RTE must belong to the topmost namespace level in "context".
03540  */
03541 static char *
03542 get_rtable_name(int rtindex, deparse_context *context)
03543 {
03544     deparse_namespace *dpns = (deparse_namespace *) linitial(context->namespaces);
03545 
03546     Assert(rtindex > 0 && rtindex <= list_length(dpns->rtable_names));
03547     return (char *) list_nth(dpns->rtable_names, rtindex - 1);
03548 }
03549 
03550 /*
03551  * set_deparse_planstate: set up deparse_namespace to parse subexpressions
03552  * of a given PlanState node
03553  *
03554  * This sets the planstate, outer_planstate, inner_planstate, outer_tlist,
03555  * inner_tlist, and index_tlist fields.  Caller is responsible for adjusting
03556  * the ancestors list if necessary.  Note that the rtable and ctes fields do
03557  * not need to change when shifting attention to different plan nodes in a
03558  * single plan tree.
03559  */
03560 static void
03561 set_deparse_planstate(deparse_namespace *dpns, PlanState *ps)
03562 {
03563     dpns->planstate = ps;
03564 
03565     /*
03566      * We special-case Append and MergeAppend to pretend that the first child
03567      * plan is the OUTER referent; we have to interpret OUTER Vars in their
03568      * tlists according to one of the children, and the first one is the most
03569      * natural choice.  Likewise special-case ModifyTable to pretend that the
03570      * first child plan is the OUTER referent; this is to support RETURNING
03571      * lists containing references to non-target relations.
03572      */
03573     if (IsA(ps, AppendState))
03574         dpns->outer_planstate = ((AppendState *) ps)->appendplans[0];
03575     else if (IsA(ps, MergeAppendState))
03576         dpns->outer_planstate = ((MergeAppendState *) ps)->mergeplans[0];
03577     else if (IsA(ps, ModifyTableState))
03578         dpns->outer_planstate = ((ModifyTableState *) ps)->mt_plans[0];
03579     else
03580         dpns->outer_planstate = outerPlanState(ps);
03581 
03582     if (dpns->outer_planstate)
03583         dpns->outer_tlist = dpns->outer_planstate->plan->targetlist;
03584     else
03585         dpns->outer_tlist = NIL;
03586 
03587     /*
03588      * For a SubqueryScan, pretend the subplan is INNER referent.  (We don't
03589      * use OUTER because that could someday conflict with the normal meaning.)
03590      * Likewise, for a CteScan, pretend the subquery's plan is INNER referent.
03591      */
03592     if (IsA(ps, SubqueryScanState))
03593         dpns->inner_planstate = ((SubqueryScanState *) ps)->subplan;
03594     else if (IsA(ps, CteScanState))
03595         dpns->inner_planstate = ((CteScanState *) ps)->cteplanstate;
03596     else
03597         dpns->inner_planstate = innerPlanState(ps);
03598 
03599     if (dpns->inner_planstate)
03600         dpns->inner_tlist = dpns->inner_planstate->plan->targetlist;
03601     else
03602         dpns->inner_tlist = NIL;
03603 
03604     /* index_tlist is set only if it's an IndexOnlyScan */
03605     if (IsA(ps->plan, IndexOnlyScan))
03606         dpns->index_tlist = ((IndexOnlyScan *) ps->plan)->indextlist;
03607     else
03608         dpns->index_tlist = NIL;
03609 }
03610 
03611 /*
03612  * push_child_plan: temporarily transfer deparsing attention to a child plan
03613  *
03614  * When expanding an OUTER_VAR or INNER_VAR reference, we must adjust the
03615  * deparse context in case the referenced expression itself uses
03616  * OUTER_VAR/INNER_VAR.  We modify the top stack entry in-place to avoid
03617  * affecting levelsup issues (although in a Plan tree there really shouldn't
03618  * be any).
03619  *
03620  * Caller must provide a local deparse_namespace variable to save the
03621  * previous state for pop_child_plan.
03622  */
03623 static void
03624 push_child_plan(deparse_namespace *dpns, PlanState *ps,
03625                 deparse_namespace *save_dpns)
03626 {
03627     /* Save state for restoration later */
03628     *save_dpns = *dpns;
03629 
03630     /* Link current plan node into ancestors list */
03631     dpns->ancestors = lcons(dpns->planstate, dpns->ancestors);
03632 
03633     /* Set attention on selected child */
03634     set_deparse_planstate(dpns, ps);
03635 }
03636 
03637 /*
03638  * pop_child_plan: undo the effects of push_child_plan
03639  */
03640 static void
03641 pop_child_plan(deparse_namespace *dpns, deparse_namespace *save_dpns)
03642 {
03643     List       *ancestors;
03644 
03645     /* Get rid of ancestors list cell added by push_child_plan */
03646     ancestors = list_delete_first(dpns->ancestors);
03647 
03648     /* Restore fields changed by push_child_plan */
03649     *dpns = *save_dpns;
03650 
03651     /* Make sure dpns->ancestors is right (may be unnecessary) */
03652     dpns->ancestors = ancestors;
03653 }
03654 
03655 /*
03656  * push_ancestor_plan: temporarily transfer deparsing attention to an
03657  * ancestor plan
03658  *
03659  * When expanding a Param reference, we must adjust the deparse context
03660  * to match the plan node that contains the expression being printed;
03661  * otherwise we'd fail if that expression itself contains a Param or
03662  * OUTER_VAR/INNER_VAR/INDEX_VAR variable.
03663  *
03664  * The target ancestor is conveniently identified by the ListCell holding it
03665  * in dpns->ancestors.
03666  *
03667  * Caller must provide a local deparse_namespace variable to save the
03668  * previous state for pop_ancestor_plan.
03669  */
03670 static void
03671 push_ancestor_plan(deparse_namespace *dpns, ListCell *ancestor_cell,
03672                    deparse_namespace *save_dpns)
03673 {
03674     PlanState  *ps = (PlanState *) lfirst(ancestor_cell);
03675     List       *ancestors;
03676 
03677     /* Save state for restoration later */
03678     *save_dpns = *dpns;
03679 
03680     /* Build a new ancestor list with just this node's ancestors */
03681     ancestors = NIL;
03682     while ((ancestor_cell = lnext(ancestor_cell)) != NULL)
03683         ancestors = lappend(ancestors, lfirst(ancestor_cell));
03684     dpns->ancestors = ancestors;
03685 
03686     /* Set attention on selected ancestor */
03687     set_deparse_planstate(dpns, ps);
03688 }
03689 
03690 /*
03691  * pop_ancestor_plan: undo the effects of push_ancestor_plan
03692  */
03693 static void
03694 pop_ancestor_plan(deparse_namespace *dpns, deparse_namespace *save_dpns)
03695 {
03696     /* Free the ancestor list made in push_ancestor_plan */
03697     list_free(dpns->ancestors);
03698 
03699     /* Restore fields changed by push_ancestor_plan */
03700     *dpns = *save_dpns;
03701 }
03702 
03703 
03704 /* ----------
03705  * make_ruledef         - reconstruct the CREATE RULE command
03706  *                for a given pg_rewrite tuple
03707  * ----------
03708  */
03709 static void
03710 make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
03711              int prettyFlags)
03712 {
03713     char       *rulename;
03714     char        ev_type;
03715     Oid         ev_class;
03716     int16       ev_attr;
03717     bool        is_instead;
03718     char       *ev_qual;
03719     char       *ev_action;
03720     List       *actions = NIL;
03721     int         fno;
03722     Datum       dat;
03723     bool        isnull;
03724 
03725     /*
03726      * Get the attribute values from the rules tuple
03727      */
03728     fno = SPI_fnumber(rulettc, "rulename");
03729     dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
03730     Assert(!isnull);
03731     rulename = NameStr(*(DatumGetName(dat)));
03732 
03733     fno = SPI_fnumber(rulettc, "ev_type");
03734     dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
03735     Assert(!isnull);
03736     ev_type = DatumGetChar(dat);
03737 
03738     fno = SPI_fnumber(rulettc, "ev_class");
03739     dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
03740     Assert(!isnull);
03741     ev_class = DatumGetObjectId(dat);
03742 
03743     fno = SPI_fnumber(rulettc, "ev_attr");
03744     dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
03745     Assert(!isnull);
03746     ev_attr = DatumGetInt16(dat);
03747 
03748     fno = SPI_fnumber(rulettc, "is_instead");
03749     dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
03750     Assert(!isnull);
03751     is_instead = DatumGetBool(dat);
03752 
03753     /* these could be nulls */
03754     fno = SPI_fnumber(rulettc, "ev_qual");
03755     ev_qual = SPI_getvalue(ruletup, rulettc, fno);
03756 
03757     fno = SPI_fnumber(rulettc, "ev_action");
03758     ev_action = SPI_getvalue(ruletup, rulettc, fno);
03759     if (ev_action != NULL)
03760         actions = (List *) stringToNode(ev_action);
03761 
03762     /*
03763      * Build the rules definition text
03764      */
03765     appendStringInfo(buf, "CREATE RULE %s AS",
03766                      quote_identifier(rulename));
03767 
03768     if (prettyFlags & PRETTYFLAG_INDENT)
03769         appendStringInfoString(buf, "\n    ON ");
03770     else
03771         appendStringInfoString(buf, " ON ");
03772 
03773     /* The event the rule is fired for */
03774     switch (ev_type)
03775     {
03776         case '1':
03777             appendStringInfo(buf, "SELECT");
03778             break;
03779 
03780         case '2':
03781             appendStringInfo(buf, "UPDATE");
03782             break;
03783 
03784         case '3':
03785             appendStringInfo(buf, "INSERT");
03786             break;
03787 
03788         case '4':
03789             appendStringInfo(buf, "DELETE");
03790             break;
03791 
03792         default:
03793             ereport(ERROR,
03794                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
03795                      errmsg("rule \"%s\" has unsupported event type %d",
03796                             rulename, ev_type)));
03797             break;
03798     }
03799 
03800     /* The relation the rule is fired on */
03801     appendStringInfo(buf, " TO %s", generate_relation_name(ev_class, NIL));
03802     if (ev_attr > 0)
03803         appendStringInfo(buf, ".%s",
03804                          quote_identifier(get_relid_attribute_name(ev_class,
03805                                                                    ev_attr)));
03806 
03807     /* If the rule has an event qualification, add it */
03808     if (ev_qual == NULL)
03809         ev_qual = "";
03810     if (strlen(ev_qual) > 0 && strcmp(ev_qual, "<>") != 0)
03811     {
03812         Node       *qual;
03813         Query      *query;
03814         deparse_context context;
03815         deparse_namespace dpns;
03816 
03817         if (prettyFlags & PRETTYFLAG_INDENT)
03818             appendStringInfoString(buf, "\n  ");
03819         appendStringInfo(buf, " WHERE ");
03820 
03821         qual = stringToNode(ev_qual);
03822 
03823         /*
03824          * We need to make a context for recognizing any Vars in the qual
03825          * (which can only be references to OLD and NEW).  Use the rtable of
03826          * the first query in the action list for this purpose.
03827          */
03828         query = (Query *) linitial(actions);
03829 
03830         /*
03831          * If the action is INSERT...SELECT, OLD/NEW have been pushed down
03832          * into the SELECT, and that's what we need to look at. (Ugly kluge
03833          * ... try to fix this when we redesign querytrees.)
03834          */
03835         query = getInsertSelectQuery(query, NULL);
03836 
03837         /* Must acquire locks right away; see notes in get_query_def() */
03838         AcquireRewriteLocks(query, false);
03839 
03840         context.buf = buf;
03841         context.namespaces = list_make1(&dpns);
03842         context.windowClause = NIL;
03843         context.windowTList = NIL;
03844         context.varprefix = (list_length(query->rtable) != 1);
03845         context.prettyFlags = prettyFlags;
03846         context.wrapColumn = WRAP_COLUMN_DEFAULT;
03847         context.indentLevel = PRETTYINDENT_STD;
03848 
03849         set_deparse_for_query(&dpns, query, NIL);
03850 
03851         get_rule_expr(qual, &context, false);
03852     }
03853 
03854     appendStringInfo(buf, " DO ");
03855 
03856     /* The INSTEAD keyword (if so) */
03857     if (is_instead)
03858         appendStringInfo(buf, "INSTEAD ");
03859 
03860     /* Finally the rules actions */
03861     if (list_length(actions) > 1)
03862     {
03863         ListCell   *action;
03864         Query      *query;
03865 
03866         appendStringInfo(buf, "(");
03867         foreach(action, actions)
03868         {
03869             query = (Query *) lfirst(action);
03870             get_query_def(query, buf, NIL, NULL,
03871                           prettyFlags, WRAP_COLUMN_DEFAULT, 0);
03872             if (prettyFlags)
03873                 appendStringInfo(buf, ";\n");
03874             else
03875                 appendStringInfo(buf, "; ");
03876         }
03877         appendStringInfo(buf, ");");
03878     }
03879     else if (list_length(actions) == 0)
03880     {
03881         appendStringInfo(buf, "NOTHING;");
03882     }
03883     else
03884     {
03885         Query      *query;
03886 
03887         query = (Query *) linitial(actions);
03888         get_query_def(query, buf, NIL, NULL,
03889                       prettyFlags, WRAP_COLUMN_DEFAULT, 0);
03890         appendStringInfo(buf, ";");
03891     }
03892 }
03893 
03894 
03895 /* ----------
03896  * make_viewdef         - reconstruct the SELECT part of a
03897  *                view rewrite rule
03898  * ----------
03899  */
03900 static void
03901 make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
03902              int prettyFlags, int wrapColumn)
03903 {
03904     Query      *query;
03905     char        ev_type;
03906     Oid         ev_class;
03907     int16       ev_attr;
03908     bool        is_instead;
03909     char       *ev_qual;
03910     char       *ev_action;
03911     List       *actions = NIL;
03912     Relation    ev_relation;
03913     int         fno;
03914     bool        isnull;
03915 
03916     /*
03917      * Get the attribute values from the rules tuple
03918      */
03919     fno = SPI_fnumber(rulettc, "ev_type");
03920     ev_type = (char) SPI_getbinval(ruletup, rulettc, fno, &isnull);
03921 
03922     fno = SPI_fnumber(rulettc, "ev_class");
03923     ev_class = (Oid) SPI_getbinval(ruletup, rulettc, fno, &isnull);
03924 
03925     fno = SPI_fnumber(rulettc, "ev_attr");
03926     ev_attr = (int16) SPI_getbinval(ruletup, rulettc, fno, &isnull);
03927 
03928     fno = SPI_fnumber(rulettc, "is_instead");
03929     is_instead = (bool) SPI_getbinval(ruletup, rulettc, fno, &isnull);
03930 
03931     fno = SPI_fnumber(rulettc, "ev_qual");
03932     ev_qual = SPI_getvalue(ruletup, rulettc, fno);
03933 
03934     fno = SPI_fnumber(rulettc, "ev_action");
03935     ev_action = SPI_getvalue(ruletup, rulettc, fno);
03936     if (ev_action != NULL)
03937         actions = (List *) stringToNode(ev_action);
03938 
03939     if (list_length(actions) != 1)
03940     {
03941         appendStringInfo(buf, "Not a view");
03942         return;
03943     }
03944 
03945     query = (Query *) linitial(actions);
03946 
03947     if (ev_type != '1' || ev_attr >= 0 || !is_instead ||
03948         strcmp(ev_qual, "<>") != 0 || query->commandType != CMD_SELECT)
03949     {
03950         appendStringInfo(buf, "Not a view");
03951         return;
03952     }
03953 
03954     ev_relation = heap_open(ev_class, AccessShareLock);
03955 
03956     get_query_def(query, buf, NIL, RelationGetDescr(ev_relation),
03957                   prettyFlags, wrapColumn, 0);
03958     appendStringInfo(buf, ";");
03959 
03960     heap_close(ev_relation, AccessShareLock);
03961 }
03962 
03963 
03964 /* ----------
03965  * get_query_def            - Parse back one query parsetree
03966  *
03967  * If resultDesc is not NULL, then it is the output tuple descriptor for
03968  * the view represented by a SELECT query.
03969  * ----------
03970  */
03971 static void
03972 get_query_def(Query *query, StringInfo buf, List *parentnamespace,
03973               TupleDesc resultDesc,
03974               int prettyFlags, int wrapColumn, int startIndent)
03975 {
03976     deparse_context context;
03977     deparse_namespace dpns;
03978 
03979     /*
03980      * Before we begin to examine the query, acquire locks on referenced
03981      * relations, and fix up deleted columns in JOIN RTEs.  This ensures
03982      * consistent results.  Note we assume it's OK to scribble on the passed
03983      * querytree!
03984      */
03985     AcquireRewriteLocks(query, false);
03986 
03987     context.buf = buf;
03988     context.namespaces = lcons(&dpns, list_copy(parentnamespace));
03989     context.windowClause = NIL;
03990     context.windowTList = NIL;
03991     context.varprefix = (parentnamespace != NIL ||
03992                          list_length(query->rtable) != 1);
03993     context.prettyFlags = prettyFlags;
03994     context.wrapColumn = wrapColumn;
03995     context.indentLevel = startIndent;
03996 
03997     set_deparse_for_query(&dpns, query, parentnamespace);
03998 
03999     switch (query->commandType)
04000     {
04001         case CMD_SELECT:
04002             get_select_query_def(query, &context, resultDesc);
04003             break;
04004 
04005         case CMD_UPDATE:
04006             get_update_query_def(query, &context);
04007             break;
04008 
04009         case CMD_INSERT:
04010             get_insert_query_def(query, &context);
04011             break;
04012 
04013         case CMD_DELETE:
04014             get_delete_query_def(query, &context);
04015             break;
04016 
04017         case CMD_NOTHING:
04018             appendStringInfo(buf, "NOTHING");
04019             break;
04020 
04021         case CMD_UTILITY:
04022             get_utility_query_def(query, &context);
04023             break;
04024 
04025         default:
04026             elog(ERROR, "unrecognized query command type: %d",
04027                  query->commandType);
04028             break;
04029     }
04030 }
04031 
04032 /* ----------
04033  * get_values_def           - Parse back a VALUES list
04034  * ----------
04035  */
04036 static void
04037 get_values_def(List *values_lists, deparse_context *context)
04038 {
04039     StringInfo  buf = context->buf;
04040     bool        first_list = true;
04041     ListCell   *vtl;
04042 
04043     appendStringInfoString(buf, "VALUES ");
04044 
04045     foreach(vtl, values_lists)
04046     {
04047         List       *sublist = (List *) lfirst(vtl);
04048         bool        first_col = true;
04049         ListCell   *lc;
04050 
04051         if (first_list)
04052             first_list = false;
04053         else
04054             appendStringInfoString(buf, ", ");
04055 
04056         appendStringInfoChar(buf, '(');
04057         foreach(lc, sublist)
04058         {
04059             Node       *col = (Node *) lfirst(lc);
04060 
04061             if (first_col)
04062                 first_col = false;
04063             else
04064                 appendStringInfoChar(buf, ',');
04065 
04066             /*
04067              * Strip any top-level nodes representing indirection assignments,
04068              * then print the result.
04069              */
04070             get_rule_expr(processIndirection(col, context, false),
04071                           context, false);
04072         }
04073         appendStringInfoChar(buf, ')');
04074     }
04075 }
04076 
04077 /* ----------
04078  * get_with_clause          - Parse back a WITH clause
04079  * ----------
04080  */
04081 static void
04082 get_with_clause(Query *query, deparse_context *context)
04083 {
04084     StringInfo  buf = context->buf;
04085     const char *sep;
04086     ListCell   *l;
04087 
04088     if (query->cteList == NIL)
04089         return;
04090 
04091     if (PRETTY_INDENT(context))
04092     {
04093         context->indentLevel += PRETTYINDENT_STD;
04094         appendStringInfoChar(buf, ' ');
04095     }
04096 
04097     if (query->hasRecursive)
04098         sep = "WITH RECURSIVE ";
04099     else
04100         sep = "WITH ";
04101     foreach(l, query->cteList)
04102     {
04103         CommonTableExpr *cte = (CommonTableExpr *) lfirst(l);
04104 
04105         appendStringInfoString(buf, sep);
04106         appendStringInfoString(buf, quote_identifier(cte->ctename));
04107         if (cte->aliascolnames)
04108         {
04109             bool        first = true;
04110             ListCell   *col;
04111 
04112             appendStringInfoChar(buf, '(');
04113             foreach(col, cte->aliascolnames)
04114             {
04115                 if (first)
04116                     first = false;
04117                 else
04118                     appendStringInfoString(buf, ", ");
04119                 appendStringInfoString(buf,
04120                                        quote_identifier(strVal(lfirst(col))));
04121             }
04122             appendStringInfoChar(buf, ')');
04123         }
04124         appendStringInfoString(buf, " AS (");
04125         if (PRETTY_INDENT(context))
04126             appendContextKeyword(context, "", 0, 0, 0);
04127         get_query_def((Query *) cte->ctequery, buf, context->namespaces, NULL,
04128                       context->prettyFlags, context->wrapColumn,
04129                       context->indentLevel);
04130         if (PRETTY_INDENT(context))
04131             appendContextKeyword(context, "", 0, 0, 0);
04132         appendStringInfoChar(buf, ')');
04133         sep = ", ";
04134     }
04135 
04136     if (PRETTY_INDENT(context))
04137     {
04138         context->indentLevel -= PRETTYINDENT_STD;
04139         appendContextKeyword(context, "", 0, 0, 0);
04140     }
04141     else
04142         appendStringInfoChar(buf, ' ');
04143 }
04144 
04145 /* ----------
04146  * get_select_query_def         - Parse back a SELECT parsetree
04147  * ----------
04148  */
04149 static void
04150 get_select_query_def(Query *query, deparse_context *context,
04151                      TupleDesc resultDesc)
04152 {
04153     StringInfo  buf = context->buf;
04154     List       *save_windowclause;
04155     List       *save_windowtlist;
04156     bool        force_colno;
04157     ListCell   *l;
04158 
04159     /* Insert the WITH clause if given */
04160     get_with_clause(query, context);
04161 
04162     /* Set up context for possible window functions */
04163     save_windowclause = context->windowClause;
04164     context->windowClause = query->windowClause;
04165     save_windowtlist = context->windowTList;
04166     context->windowTList = query->targetList;
04167 
04168     /*
04169      * If the Query node has a setOperations tree, then it's the top level of
04170      * a UNION/INTERSECT/EXCEPT query; only the WITH, ORDER BY and LIMIT
04171      * fields are interesting in the top query itself.
04172      */
04173     if (query->setOperations)
04174     {
04175         get_setop_query(query->setOperations, query, context, resultDesc);
04176         /* ORDER BY clauses must be simple in this case */
04177         force_colno = true;
04178     }
04179     else
04180     {
04181         get_basic_select_query(query, context, resultDesc);
04182         force_colno = false;
04183     }
04184 
04185     /* Add the ORDER BY clause if given */
04186     if (query->sortClause != NIL)
04187     {
04188         appendContextKeyword(context, " ORDER BY ",
04189                              -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
04190         get_rule_orderby(query->sortClause, query->targetList,
04191                          force_colno, context);
04192     }
04193 
04194     /* Add the LIMIT clause if given */
04195     if (query->limitOffset != NULL)
04196     {
04197         appendContextKeyword(context, " OFFSET ",
04198                              -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
04199         get_rule_expr(query->limitOffset, context, false);
04200     }
04201     if (query->limitCount != NULL)
04202     {
04203         appendContextKeyword(context, " LIMIT ",
04204                              -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
04205         if (IsA(query->limitCount, Const) &&
04206             ((Const *) query->limitCount)->constisnull)
04207             appendStringInfo(buf, "ALL");
04208         else
04209             get_rule_expr(query->limitCount, context, false);
04210     }
04211 
04212     /* Add FOR [KEY] UPDATE/SHARE clauses if present */
04213     if (query->hasForUpdate)
04214     {
04215         foreach(l, query->rowMarks)
04216         {
04217             RowMarkClause *rc = (RowMarkClause *) lfirst(l);
04218 
04219             /* don't print implicit clauses */
04220             if (rc->pushedDown)
04221                 continue;
04222 
04223             switch (rc->strength)
04224             {
04225                 case LCS_FORKEYSHARE:
04226                     appendContextKeyword(context, " FOR KEY SHARE",
04227                                          -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
04228                     break;
04229                 case LCS_FORSHARE:
04230                     appendContextKeyword(context, " FOR SHARE",
04231                                          -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
04232                     break;
04233                 case LCS_FORNOKEYUPDATE:
04234                     appendContextKeyword(context, " FOR NO KEY UPDATE",
04235                                          -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
04236                     break;
04237                 case LCS_FORUPDATE:
04238                     appendContextKeyword(context, " FOR UPDATE",
04239                                          -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
04240                     break;
04241             }
04242 
04243             appendStringInfo(buf, " OF %s",
04244                              quote_identifier(get_rtable_name(rc->rti,
04245                                                               context)));
04246             if (rc->noWait)
04247                 appendStringInfo(buf, " NOWAIT");
04248         }
04249     }
04250 
04251     context->windowClause = save_windowclause;
04252     context->windowTList = save_windowtlist;
04253 }
04254 
04255 /*
04256  * Detect whether query looks like SELECT ... FROM VALUES();
04257  * if so, return the VALUES RTE.  Otherwise return NULL.
04258  */
04259 static RangeTblEntry *
04260 get_simple_values_rte(Query *query)
04261 {
04262     RangeTblEntry *result = NULL;
04263     ListCell   *lc;
04264 
04265     /*
04266      * We want to return TRUE even if the Query also contains OLD or NEW rule
04267      * RTEs.  So the idea is to scan the rtable and see if there is only one
04268      * inFromCl RTE that is a VALUES RTE.  We don't look at the targetlist at
04269      * all.  This is okay because parser/analyze.c will never generate a
04270      * "bare" VALUES RTE --- they only appear inside auto-generated
04271      * sub-queries with very restricted structure.
04272      */
04273     foreach(lc, query->rtable)
04274     {
04275         RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
04276 
04277         if (rte->rtekind == RTE_VALUES && rte->inFromCl)
04278         {
04279             if (result)
04280                 return NULL;    /* multiple VALUES (probably not possible) */
04281             result = rte;
04282         }
04283         else if (rte->rtekind == RTE_RELATION && !rte->inFromCl)
04284             continue;           /* ignore rule entries */
04285         else
04286             return NULL;        /* something else -> not simple VALUES */
04287     }
04288     return result;
04289 }
04290 
04291 static void
04292 get_basic_select_query(Query *query, deparse_context *context,
04293                        TupleDesc resultDesc)
04294 {
04295     StringInfo  buf = context->buf;
04296     RangeTblEntry *values_rte;
04297     char       *sep;
04298     ListCell   *l;
04299 
04300     if (PRETTY_INDENT(context))
04301     {
04302         context->indentLevel += PRETTYINDENT_STD;
04303         appendStringInfoChar(buf, ' ');
04304     }
04305 
04306     /*
04307      * If the query looks like SELECT * FROM (VALUES ...), then print just the
04308      * VALUES part.  This reverses what transformValuesClause() did at parse
04309      * time.
04310      */
04311     values_rte = get_simple_values_rte(query);
04312     if (values_rte)
04313     {
04314         get_values_def(values_rte->values_lists, context);
04315         return;
04316     }
04317 
04318     /*
04319      * Build up the query string - first we say SELECT
04320      */
04321     appendStringInfo(buf, "SELECT");
04322 
04323     /* Add the DISTINCT clause if given */
04324     if (query->distinctClause != NIL)
04325     {
04326         if (query->hasDistinctOn)
04327         {
04328             appendStringInfo(buf, " DISTINCT ON (");
04329             sep = "";
04330             foreach(l, query->distinctClause)
04331             {
04332                 SortGroupClause *srt = (SortGroupClause *) lfirst(l);
04333 
04334                 appendStringInfoString(buf, sep);
04335                 get_rule_sortgroupclause(srt, query->targetList,
04336                                          false, context);
04337                 sep = ", ";
04338             }
04339             appendStringInfo(buf, ")");
04340         }
04341         else
04342             appendStringInfo(buf, " DISTINCT");
04343     }
04344 
04345     /* Then we tell what to select (the targetlist) */
04346     get_target_list(query->targetList, context, resultDesc);
04347 
04348     /* Add the FROM clause if needed */
04349     get_from_clause(query, " FROM ", context);
04350 
04351     /* Add the WHERE clause if given */
04352     if (query->jointree->quals != NULL)
04353     {
04354         appendContextKeyword(context, " WHERE ",
04355                              -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
04356         get_rule_expr(query->jointree->quals, context, false);
04357     }
04358 
04359     /* Add the GROUP BY clause if given */
04360     if (query->groupClause != NULL)
04361     {
04362         appendContextKeyword(context, " GROUP BY ",
04363                              -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
04364         sep = "";
04365         foreach(l, query->groupClause)
04366         {
04367             SortGroupClause *grp = (SortGroupClause *) lfirst(l);
04368 
04369             appendStringInfoString(buf, sep);
04370             get_rule_sortgroupclause(grp, query->targetList,
04371                                      false, context);
04372             sep = ", ";
04373         }
04374     }
04375 
04376     /* Add the HAVING clause if given */
04377     if (query->havingQual != NULL)
04378     {
04379         appendContextKeyword(context, " HAVING ",
04380                              -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
04381         get_rule_expr(query->havingQual, context, false);
04382     }
04383 
04384     /* Add the WINDOW clause if needed */
04385     if (query->windowClause != NIL)
04386         get_rule_windowclause(query, context);
04387 }
04388 
04389 /* ----------
04390  * get_target_list          - Parse back a SELECT target list
04391  *
04392  * This is also used for RETURNING lists in INSERT/UPDATE/DELETE.
04393  * ----------
04394  */
04395 static void
04396 get_target_list(List *targetList, deparse_context *context,
04397                 TupleDesc resultDesc)
04398 {
04399     StringInfo  buf = context->buf;
04400     StringInfoData targetbuf;
04401     bool        last_was_multiline = false;
04402     char       *sep;
04403     int         colno;
04404     ListCell   *l;
04405 
04406     /* we use targetbuf to hold each TLE's text temporarily */
04407     initStringInfo(&targetbuf);
04408 
04409     sep = " ";
04410     colno = 0;
04411     foreach(l, targetList)
04412     {
04413         TargetEntry *tle = (TargetEntry *) lfirst(l);
04414         char       *colname;
04415         char       *attname;
04416 
04417         if (tle->resjunk)
04418             continue;           /* ignore junk entries */
04419 
04420         appendStringInfoString(buf, sep);
04421         sep = ", ";
04422         colno++;
04423 
04424         /*
04425          * Put the new field text into targetbuf so we can decide after we've
04426          * got it whether or not it needs to go on a new line.
04427          */
04428         resetStringInfo(&targetbuf);
04429         context->buf = &targetbuf;
04430 
04431         /*
04432          * We special-case Var nodes rather than using get_rule_expr. This is
04433          * needed because get_rule_expr will display a whole-row Var as
04434          * "foo.*", which is the preferred notation in most contexts, but at
04435          * the top level of a SELECT list it's not right (the parser will
04436          * expand that notation into multiple columns, yielding behavior
04437          * different from a whole-row Var).  We need to call get_variable
04438          * directly so that we can tell it to do the right thing.
04439          */
04440         if (tle->expr && IsA(tle->expr, Var))
04441         {
04442             attname = get_variable((Var *) tle->expr, 0, true, context);
04443         }
04444         else
04445         {
04446             get_rule_expr((Node *) tle->expr, context, true);
04447             /* We'll show the AS name unless it's this: */
04448             attname = "?column?";
04449         }
04450 
04451         /*
04452          * Figure out what the result column should be called.  In the context
04453          * of a view, use the view's tuple descriptor (so as to pick up the
04454          * effects of any column RENAME that's been done on the view).
04455          * Otherwise, just use what we can find in the TLE.
04456          */
04457         if (resultDesc && colno <= resultDesc->natts)
04458             colname = NameStr(resultDesc->attrs[colno - 1]->attname);
04459         else
04460             colname = tle->resname;
04461 
04462         /* Show AS unless the column's name is correct as-is */
04463         if (colname)            /* resname could be NULL */
04464         {
04465             if (attname == NULL || strcmp(attname, colname) != 0)
04466                 appendStringInfo(&targetbuf, " AS %s", quote_identifier(colname));
04467         }
04468 
04469         /* Restore context's output buffer */
04470         context->buf = buf;
04471 
04472         /* Consider line-wrapping if enabled */
04473         if (PRETTY_INDENT(context) && context->wrapColumn >= 0)
04474         {
04475             int         leading_nl_pos = -1;
04476             char       *trailing_nl;
04477             int         pos;
04478 
04479             /* Does the new field start with whitespace plus a new line? */
04480             for (pos = 0; pos < targetbuf.len; pos++)
04481             {
04482                 if (targetbuf.data[pos] == '\n')
04483                 {
04484                     leading_nl_pos = pos;
04485                     break;
04486                 }
04487                 if (targetbuf.data[pos] != ' ')
04488                     break;
04489             }
04490 
04491             /* Locate the start of the current line in the output buffer */
04492             trailing_nl = strrchr(buf->data, '\n');
04493             if (trailing_nl == NULL)
04494                 trailing_nl = buf->data;
04495             else
04496                 trailing_nl++;
04497 
04498             /*
04499              * If the field we're adding is the first in the list, or it
04500              * already has a leading newline, don't add anything. Otherwise,
04501              * add a newline, plus some indentation, if either the new field
04502              * would cause an overflow or the last field used more than one
04503              * line.
04504              */
04505             if (colno > 1 &&
04506                 leading_nl_pos == -1 &&
04507                 ((strlen(trailing_nl) + strlen(targetbuf.data) > context->wrapColumn) ||
04508                  last_was_multiline))
04509                 appendContextKeyword(context, "", -PRETTYINDENT_STD,
04510                                      PRETTYINDENT_STD, PRETTYINDENT_VAR);
04511 
04512             /* Remember this field's multiline status for next iteration */
04513             last_was_multiline =
04514                 (strchr(targetbuf.data + leading_nl_pos + 1, '\n') != NULL);
04515         }
04516 
04517         /* Add the new field */
04518         appendStringInfoString(buf, targetbuf.data);
04519     }
04520 
04521     /* clean up */
04522     pfree(targetbuf.data);
04523 }
04524 
04525 static void
04526 get_setop_query(Node *setOp, Query *query, deparse_context *context,
04527                 TupleDesc resultDesc)
04528 {
04529     StringInfo  buf = context->buf;
04530     bool        need_paren;
04531 
04532     if (IsA(setOp, RangeTblRef))
04533     {
04534         RangeTblRef *rtr = (RangeTblRef *) setOp;
04535         RangeTblEntry *rte = rt_fetch(rtr->rtindex, query->rtable);
04536         Query      *subquery = rte->subquery;
04537 
04538         Assert(subquery != NULL);
04539         Assert(subquery->setOperations == NULL);
04540         /* Need parens if WITH, ORDER BY, FOR UPDATE, or LIMIT; see gram.y */
04541         need_paren = (subquery->cteList ||
04542                       subquery->sortClause ||
04543                       subquery->rowMarks ||
04544                       subquery->limitOffset ||
04545                       subquery->limitCount);
04546         if (need_paren)
04547             appendStringInfoChar(buf, '(');
04548         get_query_def(subquery, buf, context->namespaces, resultDesc,
04549                       context->prettyFlags, context->wrapColumn,
04550                       context->indentLevel);
04551         if (need_paren)
04552             appendStringInfoChar(buf, ')');
04553     }
04554     else if (IsA(setOp, SetOperationStmt))
04555     {
04556         SetOperationStmt *op = (SetOperationStmt *) setOp;
04557 
04558         if (PRETTY_INDENT(context))
04559         {
04560             context->indentLevel += PRETTYINDENT_STD;
04561             appendStringInfoSpaces(buf, PRETTYINDENT_STD);
04562         }
04563 
04564         /*
04565          * We force parens whenever nesting two SetOperationStmts. There are
04566          * some cases in which parens are needed around a leaf query too, but
04567          * those are more easily handled at the next level down (see code
04568          * above).
04569          */
04570         need_paren = !IsA(op->larg, RangeTblRef);
04571 
04572         if (need_paren)
04573             appendStringInfoChar(buf, '(');
04574         get_setop_query(op->larg, query, context, resultDesc);
04575         if (need_paren)
04576             appendStringInfoChar(buf, ')');
04577 
04578         if (!PRETTY_INDENT(context))
04579             appendStringInfoChar(buf, ' ');
04580         switch (op->op)
04581         {
04582             case SETOP_UNION:
04583                 appendContextKeyword(context, "UNION ",
04584                                      -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
04585                 break;
04586             case SETOP_INTERSECT:
04587                 appendContextKeyword(context, "INTERSECT ",
04588                                      -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
04589                 break;
04590             case SETOP_EXCEPT:
04591                 appendContextKeyword(context, "EXCEPT ",
04592                                      -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
04593                 break;
04594             default:
04595                 elog(ERROR, "unrecognized set op: %d",
04596                      (int) op->op);
04597         }
04598         if (op->all)
04599             appendStringInfo(buf, "ALL ");
04600 
04601         if (PRETTY_INDENT(context))
04602             appendContextKeyword(context, "", 0, 0, 0);
04603 
04604         need_paren = !IsA(op->rarg, RangeTblRef);
04605 
04606         if (need_paren)
04607             appendStringInfoChar(buf, '(');
04608         get_setop_query(op->rarg, query, context, resultDesc);
04609         if (need_paren)
04610             appendStringInfoChar(buf, ')');
04611 
04612         if (PRETTY_INDENT(context))
04613             context->indentLevel -= PRETTYINDENT_STD;
04614     }
04615     else
04616     {
04617         elog(ERROR, "unrecognized node type: %d",
04618              (int) nodeTag(setOp));
04619     }
04620 }
04621 
04622 /*
04623  * Display a sort/group clause.
04624  *
04625  * Also returns the expression tree, so caller need not find it again.
04626  */
04627 static Node *
04628 get_rule_sortgroupclause(SortGroupClause *srt, List *tlist, bool force_colno,
04629                          deparse_context *context)
04630 {
04631     StringInfo  buf = context->buf;
04632     TargetEntry *tle;
04633     Node       *expr;
04634 
04635     tle = get_sortgroupclause_tle(srt, tlist);
04636     expr = (Node *) tle->expr;
04637 
04638     /*
04639      * Use column-number form if requested by caller.  Otherwise, if
04640      * expression is a constant, force it to be dumped with an explicit cast
04641      * as decoration --- this is because a simple integer constant is
04642      * ambiguous (and will be misinterpreted by findTargetlistEntry()) if we
04643      * dump it without any decoration.  Otherwise, just dump the expression
04644      * normally.
04645      */
04646     if (force_colno)
04647     {
04648         Assert(!tle->resjunk);
04649         appendStringInfo(buf, "%d", tle->resno);
04650     }
04651     else if (expr && IsA(expr, Const))
04652         get_const_expr((Const *) expr, context, 1);
04653     else
04654         get_rule_expr(expr, context, true);
04655 
04656     return expr;
04657 }
04658 
04659 /*
04660  * Display an ORDER BY list.
04661  */
04662 static void
04663 get_rule_orderby(List *orderList, List *targetList,
04664                  bool force_colno, deparse_context *context)
04665 {
04666     StringInfo  buf = context->buf;
04667     const char *sep;
04668     ListCell   *l;
04669 
04670     sep = "";
04671     foreach(l, orderList)
04672     {
04673         SortGroupClause *srt = (SortGroupClause *) lfirst(l);
04674         Node       *sortexpr;
04675         Oid         sortcoltype;
04676         TypeCacheEntry *typentry;
04677 
04678         appendStringInfoString(buf, sep);
04679         sortexpr = get_rule_sortgroupclause(srt, targetList,
04680                                             force_colno, context);
04681         sortcoltype = exprType(sortexpr);
04682         /* See whether operator is default < or > for datatype */
04683         typentry = lookup_type_cache(sortcoltype,
04684                                      TYPECACHE_LT_OPR | TYPECACHE_GT_OPR);
04685         if (srt->sortop == typentry->lt_opr)
04686         {
04687             /* ASC is default, so emit nothing for it */
04688             if (srt->nulls_first)
04689                 appendStringInfo(buf, " NULLS FIRST");
04690         }
04691         else if (srt->sortop == typentry->gt_opr)
04692         {
04693             appendStringInfo(buf, " DESC");
04694             /* DESC defaults to NULLS FIRST */
04695             if (!srt->nulls_first)
04696                 appendStringInfo(buf, " NULLS LAST");
04697         }
04698         else
04699         {
04700             appendStringInfo(buf, " USING %s",
04701                              generate_operator_name(srt->sortop,
04702                                                     sortcoltype,
04703                                                     sortcoltype));
04704             /* be specific to eliminate ambiguity */
04705             if (srt->nulls_first)
04706                 appendStringInfo(buf, " NULLS FIRST");
04707             else
04708                 appendStringInfo(buf, " NULLS LAST");
04709         }
04710         sep = ", ";
04711     }
04712 }
04713 
04714 /*
04715  * Display a WINDOW clause.
04716  *
04717  * Note that the windowClause list might contain only anonymous window
04718  * specifications, in which case we should print nothing here.
04719  */
04720 static void
04721 get_rule_windowclause(Query *query, deparse_context *context)
04722 {
04723     StringInfo  buf = context->buf;
04724     const char *sep;
04725     ListCell   *l;
04726 
04727     sep = NULL;
04728     foreach(l, query->windowClause)
04729     {
04730         WindowClause *wc = (WindowClause *) lfirst(l);
04731 
04732         if (wc->name == NULL)
04733             continue;           /* ignore anonymous windows */
04734 
04735         if (sep == NULL)
04736             appendContextKeyword(context, " WINDOW ",
04737                                  -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
04738         else
04739             appendStringInfoString(buf, sep);
04740 
04741         appendStringInfo(buf, "%s AS ", quote_identifier(wc->name));
04742 
04743         get_rule_windowspec(wc, query->targetList, context);
04744 
04745         sep = ", ";
04746     }
04747 }
04748 
04749 /*
04750  * Display a window definition
04751  */
04752 static void
04753 get_rule_windowspec(WindowClause *wc, List *targetList,
04754                     deparse_context *context)
04755 {
04756     StringInfo  buf = context->buf;
04757     bool        needspace = false;
04758     const char *sep;
04759     ListCell   *l;
04760 
04761     appendStringInfoChar(buf, '(');
04762     if (wc->refname)
04763     {
04764         appendStringInfoString(buf, quote_identifier(wc->refname));
04765         needspace = true;
04766     }
04767     /* partition clauses are always inherited, so only print if no refname */
04768     if (wc->partitionClause && !wc->refname)
04769     {
04770         if (needspace)
04771             appendStringInfoChar(buf, ' ');
04772         appendStringInfoString(buf, "PARTITION BY ");
04773         sep = "";
04774         foreach(l, wc->partitionClause)
04775         {
04776             SortGroupClause *grp = (SortGroupClause *) lfirst(l);
04777 
04778             appendStringInfoString(buf, sep);
04779             get_rule_sortgroupclause(grp, targetList,
04780                                      false, context);
04781             sep = ", ";
04782         }
04783         needspace = true;
04784     }
04785     /* print ordering clause only if not inherited */
04786     if (wc->orderClause && !wc->copiedOrder)
04787     {
04788         if (needspace)
04789             appendStringInfoChar(buf, ' ');
04790         appendStringInfoString(buf, "ORDER BY ");
04791         get_rule_orderby(wc->orderClause, targetList, false, context);
04792         needspace = true;
04793     }
04794     /* framing clause is never inherited, so print unless it's default */
04795     if (wc->frameOptions & FRAMEOPTION_NONDEFAULT)
04796     {
04797         if (needspace)
04798             appendStringInfoChar(buf, ' ');
04799         if (wc->frameOptions & FRAMEOPTION_RANGE)
04800             appendStringInfoString(buf, "RANGE ");
04801         else if (wc->frameOptions & FRAMEOPTION_ROWS)
04802             appendStringInfoString(buf, "ROWS ");
04803         else
04804             Assert(false);
04805         if (wc->frameOptions & FRAMEOPTION_BETWEEN)
04806             appendStringInfoString(buf, "BETWEEN ");
04807         if (wc->frameOptions & FRAMEOPTION_START_UNBOUNDED_PRECEDING)
04808             appendStringInfoString(buf, "UNBOUNDED PRECEDING ");
04809         else if (wc->frameOptions & FRAMEOPTION_START_CURRENT_ROW)
04810             appendStringInfoString(buf, "CURRENT ROW ");
04811         else if (wc->frameOptions & FRAMEOPTION_START_VALUE)
04812         {
04813             get_rule_expr(wc->startOffset, context, false);
04814             if (wc->frameOptions & FRAMEOPTION_START_VALUE_PRECEDING)
04815                 appendStringInfoString(buf, " PRECEDING ");
04816             else if (wc->frameOptions & FRAMEOPTION_START_VALUE_FOLLOWING)
04817                 appendStringInfoString(buf, " FOLLOWING ");
04818             else
04819                 Assert(false);
04820         }
04821         else
04822             Assert(false);
04823         if (wc->frameOptions & FRAMEOPTION_BETWEEN)
04824         {
04825             appendStringInfoString(buf, "AND ");
04826             if (wc->frameOptions & FRAMEOPTION_END_UNBOUNDED_FOLLOWING)
04827                 appendStringInfoString(buf, "UNBOUNDED FOLLOWING ");
04828             else if (wc->frameOptions & FRAMEOPTION_END_CURRENT_ROW)
04829                 appendStringInfoString(buf, "CURRENT ROW ");
04830             else if (wc->frameOptions & FRAMEOPTION_END_VALUE)
04831             {
04832                 get_rule_expr(wc->endOffset, context, false);
04833                 if (wc->frameOptions & FRAMEOPTION_END_VALUE_PRECEDING)
04834                     appendStringInfoString(buf, " PRECEDING ");
04835                 else if (wc->frameOptions & FRAMEOPTION_END_VALUE_FOLLOWING)
04836                     appendStringInfoString(buf, " FOLLOWING ");
04837                 else
04838                     Assert(false);
04839             }
04840             else
04841                 Assert(false);
04842         }
04843         /* we will now have a trailing space; remove it */
04844         buf->len--;
04845     }
04846     appendStringInfoChar(buf, ')');
04847 }
04848 
04849 /* ----------
04850  * get_insert_query_def         - Parse back an INSERT parsetree
04851  * ----------
04852  */
04853 static void
04854 get_insert_query_def(Query *query, deparse_context *context)
04855 {
04856     StringInfo  buf = context->buf;
04857     RangeTblEntry *select_rte = NULL;
04858     RangeTblEntry *values_rte = NULL;
04859     RangeTblEntry *rte;
04860     char       *sep;
04861     ListCell   *values_cell;
04862     ListCell   *l;
04863     List       *strippedexprs;
04864 
04865     /* Insert the WITH clause if given */
04866     get_with_clause(query, context);
04867 
04868     /*
04869      * If it's an INSERT ... SELECT or multi-row VALUES, there will be a
04870      * single RTE for the SELECT or VALUES.  Plain VALUES has neither.
04871      */
04872     foreach(l, query->rtable)
04873     {
04874         rte = (RangeTblEntry *) lfirst(l);
04875 
04876         if (rte->rtekind == RTE_SUBQUERY)
04877         {
04878             if (select_rte)
04879                 elog(ERROR, "too many subquery RTEs in INSERT");
04880             select_rte = rte;
04881         }
04882 
04883         if (rte->rtekind == RTE_VALUES)
04884         {
04885             if (values_rte)
04886                 elog(ERROR, "too many values RTEs in INSERT");
04887             values_rte = rte;
04888         }
04889     }
04890     if (select_rte && values_rte)
04891         elog(ERROR, "both subquery and values RTEs in INSERT");
04892 
04893     /*
04894      * Start the query with INSERT INTO relname
04895      */
04896     rte = rt_fetch(query->resultRelation, query->rtable);
04897     Assert(rte->rtekind == RTE_RELATION);
04898 
04899     if (PRETTY_INDENT(context))
04900     {
04901         context->indentLevel += PRETTYINDENT_STD;
04902         appendStringInfoChar(buf, ' ');
04903     }
04904     appendStringInfo(buf, "INSERT INTO %s ",
04905                      generate_relation_name(rte->relid, NIL));
04906 
04907     /*
04908      * Add the insert-column-names list.  To handle indirection properly, we
04909      * need to look for indirection nodes in the top targetlist (if it's
04910      * INSERT ... SELECT or INSERT ... single VALUES), or in the first
04911      * expression list of the VALUES RTE (if it's INSERT ... multi VALUES). We
04912      * assume that all the expression lists will have similar indirection in
04913      * the latter case.
04914      */
04915     if (values_rte)
04916         values_cell = list_head((List *) linitial(values_rte->values_lists));
04917     else
04918         values_cell = NULL;
04919     strippedexprs = NIL;
04920     sep = "";
04921     if (query->targetList)
04922         appendStringInfoChar(buf, '(');
04923     foreach(l, query->targetList)
04924     {
04925         TargetEntry *tle = (TargetEntry *) lfirst(l);
04926 
04927         if (tle->resjunk)
04928             continue;           /* ignore junk entries */
04929 
04930         appendStringInfoString(buf, sep);
04931         sep = ", ";
04932 
04933         /*
04934          * Put out name of target column; look in the catalogs, not at
04935          * tle->resname, since resname will fail to track RENAME.
04936          */
04937         appendStringInfoString(buf,
04938                         quote_identifier(get_relid_attribute_name(rte->relid,
04939                                                                tle->resno)));
04940 
04941         /*
04942          * Print any indirection needed (subfields or subscripts), and strip
04943          * off the top-level nodes representing the indirection assignments.
04944          */
04945         if (values_cell)
04946         {
04947             /* we discard the stripped expression in this case */
04948             processIndirection((Node *) lfirst(values_cell), context, true);
04949             values_cell = lnext(values_cell);
04950         }
04951         else
04952         {
04953             /* we keep a list of the stripped expressions in this case */
04954             strippedexprs = lappend(strippedexprs,
04955                                     processIndirection((Node *) tle->expr,
04956                                                        context, true));
04957         }
04958     }
04959     if (query->targetList)
04960         appendStringInfo(buf, ") ");
04961 
04962     if (select_rte)
04963     {
04964         /* Add the SELECT */
04965         get_query_def(select_rte->subquery, buf, NIL, NULL,
04966                       context->prettyFlags, context->wrapColumn,
04967                       context->indentLevel);
04968     }
04969     else if (values_rte)
04970     {
04971         /* Add the multi-VALUES expression lists */
04972         get_values_def(values_rte->values_lists, context);
04973     }
04974     else if (strippedexprs)
04975     {
04976         /* Add the single-VALUES expression list */
04977         appendContextKeyword(context, "VALUES (",
04978                              -PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
04979         get_rule_expr((Node *) strippedexprs, context, false);
04980         appendStringInfoChar(buf, ')');
04981     }
04982     else
04983     {
04984         /* No expressions, so it must be DEFAULT VALUES */
04985         appendStringInfo(buf, "DEFAULT VALUES");
04986     }
04987 
04988     /* Add RETURNING if present */
04989     if (query->returningList)
04990     {
04991         appendContextKeyword(context, " RETURNING",
04992                              -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
04993         get_target_list(query->returningList, context, NULL);
04994     }
04995 }
04996 
04997 
04998 /* ----------
04999  * get_update_query_def         - Parse back an UPDATE parsetree
05000  * ----------
05001  */
05002 static void
05003 get_update_query_def(Query *query, deparse_context *context)
05004 {
05005     StringInfo  buf = context->buf;
05006     char       *sep;
05007     RangeTblEntry *rte;
05008     ListCell   *l;
05009 
05010     /* Insert the WITH clause if given */
05011     get_with_clause(query, context);
05012 
05013     /*
05014      * Start the query with UPDATE relname SET
05015      */
05016     rte = rt_fetch(query->resultRelation, query->rtable);
05017     Assert(rte->rtekind == RTE_RELATION);
05018     if (PRETTY_INDENT(context))
05019     {
05020         appendStringInfoChar(buf, ' ');
05021         context->indentLevel += PRETTYINDENT_STD;
05022     }
05023     appendStringInfo(buf, "UPDATE %s%s",
05024                      only_marker(rte),
05025                      generate_relation_name(rte->relid, NIL));
05026     if (rte->alias != NULL)
05027         appendStringInfo(buf, " %s",
05028                          quote_identifier(rte->alias->aliasname));
05029     appendStringInfoString(buf, " SET ");
05030 
05031     /* Add the comma separated list of 'attname = value' */
05032     sep = "";
05033     foreach(l, query->targetList)
05034     {
05035         TargetEntry *tle = (TargetEntry *) lfirst(l);
05036         Node       *expr;
05037 
05038         if (tle->resjunk)
05039             continue;           /* ignore junk entries */
05040 
05041         appendStringInfoString(buf, sep);
05042         sep = ", ";
05043 
05044         /*
05045          * Put out name of target column; look in the catalogs, not at
05046          * tle->resname, since resname will fail to track RENAME.
05047          */
05048         appendStringInfoString(buf,
05049                         quote_identifier(get_relid_attribute_name(rte->relid,
05050                                                                tle->resno)));
05051 
05052         /*
05053          * Print any indirection needed (subfields or subscripts), and strip
05054          * off the top-level nodes representing the indirection assignments.
05055          */
05056         expr = processIndirection((Node *) tle->expr, context, true);
05057 
05058         appendStringInfo(buf, " = ");
05059 
05060         get_rule_expr(expr, context, false);
05061     }
05062 
05063     /* Add the FROM clause if needed */
05064     get_from_clause(query, " FROM ", context);
05065 
05066     /* Add a WHERE clause if given */
05067     if (query->jointree->quals != NULL)
05068     {
05069         appendContextKeyword(context, " WHERE ",
05070                              -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
05071         get_rule_expr(query->jointree->quals, context, false);
05072     }
05073 
05074     /* Add RETURNING if present */
05075     if (query->returningList)
05076     {
05077         appendContextKeyword(context, " RETURNING",
05078                              -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
05079         get_target_list(query->returningList, context, NULL);
05080     }
05081 }
05082 
05083 
05084 /* ----------
05085  * get_delete_query_def         - Parse back a DELETE parsetree
05086  * ----------
05087  */
05088 static void
05089 get_delete_query_def(Query *query, deparse_context *context)
05090 {
05091     StringInfo  buf = context->buf;
05092     RangeTblEntry *rte;
05093 
05094     /* Insert the WITH clause if given */
05095     get_with_clause(query, context);
05096 
05097     /*
05098      * Start the query with DELETE FROM relname
05099      */
05100     rte = rt_fetch(query->resultRelation, query->rtable);
05101     Assert(rte->rtekind == RTE_RELATION);
05102     if (PRETTY_INDENT(context))
05103     {
05104         appendStringInfoChar(buf, ' ');
05105         context->indentLevel += PRETTYINDENT_STD;
05106     }
05107     appendStringInfo(buf, "DELETE FROM %s%s",
05108                      only_marker(rte),
05109                      generate_relation_name(rte->relid, NIL));
05110     if (rte->alias != NULL)
05111         appendStringInfo(buf, " %s",
05112                          quote_identifier(rte->alias->aliasname));
05113 
05114     /* Add the USING clause if given */
05115     get_from_clause(query, " USING ", context);
05116 
05117     /* Add a WHERE clause if given */
05118     if (query->jointree->quals != NULL)
05119     {
05120         appendContextKeyword(context, " WHERE ",
05121                              -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
05122         get_rule_expr(query->jointree->quals, context, false);
05123     }
05124 
05125     /* Add RETURNING if present */
05126     if (query->returningList)
05127     {
05128         appendContextKeyword(context, " RETURNING",
05129                              -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
05130         get_target_list(query->returningList, context, NULL);
05131     }
05132 }
05133 
05134 
05135 /* ----------
05136  * get_utility_query_def            - Parse back a UTILITY parsetree
05137  * ----------
05138  */
05139 static void
05140 get_utility_query_def(Query *query, deparse_context *context)
05141 {
05142     StringInfo  buf = context->buf;
05143 
05144     if (query->utilityStmt && IsA(query->utilityStmt, NotifyStmt))
05145     {
05146         NotifyStmt *stmt = (NotifyStmt *) query->utilityStmt;
05147 
05148         appendContextKeyword(context, "",
05149                              0, PRETTYINDENT_STD, 1);
05150         appendStringInfo(buf, "NOTIFY %s",
05151                          quote_identifier(stmt->conditionname));
05152         if (stmt->payload)
05153         {
05154             appendStringInfoString(buf, ", ");
05155             simple_quote_literal(buf, stmt->payload);
05156         }
05157     }
05158     else
05159     {
05160         /* Currently only NOTIFY utility commands can appear in rules */
05161         elog(ERROR, "unexpected utility statement type");
05162     }
05163 }
05164 
05165 
05166 /*
05167  * Display a Var appropriately.
05168  *
05169  * In some cases (currently only when recursing into an unnamed join)
05170  * the Var's varlevelsup has to be interpreted with respect to a context
05171  * above the current one; levelsup indicates the offset.
05172  *
05173  * If istoplevel is TRUE, the Var is at the top level of a SELECT's
05174  * targetlist, which means we need special treatment of whole-row Vars.
05175  * Instead of the normal "tab.*", we'll print "tab.*::typename", which is a
05176  * dirty hack to prevent "tab.*" from being expanded into multiple columns.
05177  * (The parser will strip the useless coercion, so no inefficiency is added in
05178  * dump and reload.)  We used to print just "tab" in such cases, but that is
05179  * ambiguous and will yield the wrong result if "tab" is also a plain column
05180  * name in the query.
05181  *
05182  * Returns the attname of the Var, or NULL if the Var has no attname (because
05183  * it is a whole-row Var or a subplan output reference).
05184  */
05185 static char *
05186 get_variable(Var *var, int levelsup, bool istoplevel, deparse_context *context)
05187 {
05188     StringInfo  buf = context->buf;
05189     RangeTblEntry *rte;
05190     AttrNumber  attnum;
05191     int         netlevelsup;
05192     deparse_namespace *dpns;
05193     deparse_columns *colinfo;
05194     char       *refname;
05195     char       *attname;
05196 
05197     /* Find appropriate nesting depth */
05198     netlevelsup = var->varlevelsup + levelsup;
05199     if (netlevelsup >= list_length(context->namespaces))
05200         elog(ERROR, "bogus varlevelsup: %d offset %d",
05201              var->varlevelsup, levelsup);
05202     dpns = (deparse_namespace *) list_nth(context->namespaces,
05203                                           netlevelsup);
05204 
05205     /*
05206      * Try to find the relevant RTE in this rtable.  In a plan tree, it's
05207      * likely that varno is OUTER_VAR or INNER_VAR, in which case we must dig
05208      * down into the subplans, or INDEX_VAR, which is resolved similarly. Also
05209      * find the aliases previously assigned for this RTE.
05210      */
05211     if (var->varno >= 1 && var->varno <= list_length(dpns->rtable))
05212     {
05213         rte = rt_fetch(var->varno, dpns->rtable);
05214         refname = (char *) list_nth(dpns->rtable_names, var->varno - 1);
05215         colinfo = deparse_columns_fetch(var->varno, dpns);
05216         attnum = var->varattno;
05217     }
05218     else if (var->varno == OUTER_VAR && dpns->outer_tlist)
05219     {
05220         TargetEntry *tle;
05221         deparse_namespace save_dpns;
05222 
05223         tle = get_tle_by_resno(dpns->outer_tlist, var->varattno);
05224         if (!tle)
05225             elog(ERROR, "bogus varattno for OUTER_VAR var: %d", var->varattno);
05226 
05227         Assert(netlevelsup == 0);
05228         push_child_plan(dpns, dpns->outer_planstate, &save_dpns);
05229 
05230         /*
05231          * Force parentheses because our caller probably assumed a Var is a
05232          * simple expression.
05233          */
05234         if (!IsA(tle->expr, Var))
05235             appendStringInfoChar(buf, '(');
05236         get_rule_expr((Node *) tle->expr, context, true);
05237         if (!IsA(tle->expr, Var))
05238             appendStringInfoChar(buf, ')');
05239 
05240         pop_child_plan(dpns, &save_dpns);
05241         return NULL;
05242     }
05243     else if (var->varno == INNER_VAR && dpns->inner_tlist)
05244     {
05245         TargetEntry *tle;
05246         deparse_namespace save_dpns;
05247 
05248         tle = get_tle_by_resno(dpns->inner_tlist, var->varattno);
05249         if (!tle)
05250             elog(ERROR, "bogus varattno for INNER_VAR var: %d", var->varattno);
05251 
05252         Assert(netlevelsup == 0);
05253         push_child_plan(dpns, dpns->inner_planstate, &save_dpns);
05254 
05255         /*
05256          * Force parentheses because our caller probably assumed a Var is a
05257          * simple expression.
05258          */
05259         if (!IsA(tle->expr, Var))
05260             appendStringInfoChar(buf, '(');
05261         get_rule_expr((Node *) tle->expr, context, true);
05262         if (!IsA(tle->expr, Var))
05263             appendStringInfoChar(buf, ')');
05264 
05265         pop_child_plan(dpns, &save_dpns);
05266         return NULL;
05267     }
05268     else if (var->varno == INDEX_VAR && dpns->index_tlist)
05269     {
05270         TargetEntry *tle;
05271 
05272         tle = get_tle_by_resno(dpns->index_tlist, var->varattno);
05273         if (!tle)
05274             elog(ERROR, "bogus varattno for INDEX_VAR var: %d", var->varattno);
05275 
05276         Assert(netlevelsup == 0);
05277 
05278         /*
05279          * Force parentheses because our caller probably assumed a Var is a
05280          * simple expression.
05281          */
05282         if (!IsA(tle->expr, Var))
05283             appendStringInfoChar(buf, '(');
05284         get_rule_expr((Node *) tle->expr, context, true);
05285         if (!IsA(tle->expr, Var))
05286             appendStringInfoChar(buf, ')');
05287 
05288         return NULL;
05289     }
05290     else
05291     {
05292         elog(ERROR, "bogus varno: %d", var->varno);
05293         return NULL;            /* keep compiler quiet */
05294     }
05295 
05296     /*
05297      * The planner will sometimes emit Vars referencing resjunk elements of a
05298      * subquery's target list (this is currently only possible if it chooses
05299      * to generate a "physical tlist" for a SubqueryScan or CteScan node).
05300      * Although we prefer to print subquery-referencing Vars using the
05301      * subquery's alias, that's not possible for resjunk items since they have
05302      * no alias.  So in that case, drill down to the subplan and print the
05303      * contents of the referenced tlist item.  This works because in a plan
05304      * tree, such Vars can only occur in a SubqueryScan or CteScan node, and
05305      * we'll have set dpns->inner_planstate to reference the child plan node.
05306      */
05307     if ((rte->rtekind == RTE_SUBQUERY || rte->rtekind == RTE_CTE) &&
05308         attnum > list_length(rte->eref->colnames) &&
05309         dpns->inner_planstate)
05310     {
05311         TargetEntry *tle;
05312         deparse_namespace save_dpns;
05313 
05314         tle = get_tle_by_resno(dpns->inner_tlist, var->varattno);
05315         if (!tle)
05316             elog(ERROR, "bogus varattno for subquery var: %d", var->varattno);
05317 
05318         Assert(netlevelsup == 0);
05319         push_child_plan(dpns, dpns->inner_planstate, &save_dpns);
05320 
05321         /*
05322          * Force parentheses because our caller probably assumed a Var is a
05323          * simple expression.
05324          */
05325         if (!IsA(tle->expr, Var))
05326             appendStringInfoChar(buf, '(');
05327         get_rule_expr((Node *) tle->expr, context, true);
05328         if (!IsA(tle->expr, Var))
05329             appendStringInfoChar(buf, ')');
05330 
05331         pop_child_plan(dpns, &save_dpns);
05332         return NULL;
05333     }
05334 
05335     /*
05336      * If it's an unnamed join, look at the expansion of the alias variable.
05337      * If it's a simple reference to one of the input vars, then recursively
05338      * print the name of that var instead.  When it's not a simple reference,
05339      * we have to just print the unqualified join column name.  (This can only
05340      * happen with columns that were merged by USING or NATURAL clauses in a
05341      * FULL JOIN; we took pains previously to make the unqualified column name
05342      * unique in such cases.)
05343      *
05344      * This wouldn't work in decompiling plan trees, because we don't store
05345      * joinaliasvars lists after planning; but a plan tree should never
05346      * contain a join alias variable.
05347      */
05348     if (rte->rtekind == RTE_JOIN && rte->alias == NULL)
05349     {
05350         if (rte->joinaliasvars == NIL)
05351             elog(ERROR, "cannot decompile join alias var in plan tree");
05352         if (attnum > 0)
05353         {
05354             Var        *aliasvar;
05355 
05356             aliasvar = (Var *) list_nth(rte->joinaliasvars, attnum - 1);
05357             if (IsA(aliasvar, Var))
05358             {
05359                 return get_variable(aliasvar, var->varlevelsup + levelsup,
05360                                     istoplevel, context);
05361             }
05362         }
05363 
05364         /*
05365          * Unnamed join has no refname.  (Note: since it's unnamed, there is
05366          * no way the user could have referenced it to create a whole-row Var
05367          * for it.  So we don't have to cover that case below.)
05368          */
05369         Assert(refname == NULL);
05370     }
05371 
05372     if (attnum == InvalidAttrNumber)
05373         attname = NULL;
05374     else if (attnum > 0)
05375     {
05376         /* Get column name to use from the colinfo struct */
05377         Assert(attnum <= colinfo->num_cols);
05378         attname = colinfo->colnames[attnum - 1];
05379         Assert(attname != NULL);
05380     }
05381     else
05382     {
05383         /* System column - name is fixed, get it from the catalog */
05384         attname = get_rte_attribute_name(rte, attnum);
05385     }
05386 
05387     if (refname && (context->varprefix || attname == NULL))
05388     {
05389         appendStringInfoString(buf, quote_identifier(refname));
05390         appendStringInfoChar(buf, '.');
05391     }
05392     if (attname)
05393         appendStringInfoString(buf, quote_identifier(attname));
05394     else
05395     {
05396         appendStringInfoChar(buf, '*');
05397         if (istoplevel)
05398             appendStringInfo(buf, "::%s",
05399                              format_type_with_typemod(var->vartype,
05400                                                       var->vartypmod));
05401     }
05402 
05403     return attname;
05404 }
05405 
05406 
05407 /*
05408  * Get the name of a field of an expression of composite type.  The
05409  * expression is usually a Var, but we handle other cases too.
05410  *
05411  * levelsup is an extra offset to interpret the Var's varlevelsup correctly.
05412  *
05413  * This is fairly straightforward when the expression has a named composite
05414  * type; we need only look up the type in the catalogs.  However, the type
05415  * could also be RECORD.  Since no actual table or view column is allowed to
05416  * have type RECORD, a Var of type RECORD must refer to a JOIN or FUNCTION RTE
05417  * or to a subquery output.  We drill down to find the ultimate defining
05418  * expression and attempt to infer the field name from it.  We ereport if we
05419  * can't determine the name.
05420  *
05421  * Similarly, a PARAM of type RECORD has to refer to some expression of
05422  * a determinable composite type.
05423  */
05424 static const char *
05425 get_name_for_var_field(Var *var, int fieldno,
05426                        int levelsup, deparse_context *context)
05427 {
05428     RangeTblEntry *rte;
05429     AttrNumber  attnum;
05430     int         netlevelsup;
05431     deparse_namespace *dpns;
05432     TupleDesc   tupleDesc;
05433     Node       *expr;
05434 
05435     /*
05436      * If it's a RowExpr that was expanded from a whole-row Var, use the
05437      * column names attached to it.
05438      */
05439     if (IsA(var, RowExpr))
05440     {
05441         RowExpr    *r = (RowExpr *) var;
05442 
05443         if (fieldno > 0 && fieldno <= list_length(r->colnames))
05444             return strVal(list_nth(r->colnames, fieldno - 1));
05445     }
05446 
05447     /*
05448      * If it's a Param of type RECORD, try to find what the Param refers to.
05449      */
05450     if (IsA(var, Param))
05451     {
05452         Param      *param = (Param *) var;
05453         ListCell   *ancestor_cell;
05454 
05455         expr = find_param_referent(param, context, &dpns, &ancestor_cell);
05456         if (expr)
05457         {
05458             /* Found a match, so recurse to decipher the field name */
05459             deparse_namespace save_dpns;
05460             const char *result;
05461 
05462             push_ancestor_plan(dpns, ancestor_cell, &save_dpns);
05463             result = get_name_for_var_field((Var *) expr, fieldno,
05464                                             0, context);
05465             pop_ancestor_plan(dpns, &save_dpns);
05466             return result;
05467         }
05468     }
05469 
05470     /*
05471      * If it's a Var of type RECORD, we have to find what the Var refers to;
05472      * if not, we can use get_expr_result_type. If that fails, we try
05473      * lookup_rowtype_tupdesc, which will probably fail too, but will ereport
05474      * an acceptable message.
05475      */
05476     if (!IsA(var, Var) ||
05477         var->vartype != RECORDOID)
05478     {
05479         if (get_expr_result_type((Node *) var, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE)
05480             tupleDesc = lookup_rowtype_tupdesc_copy(exprType((Node *) var),
05481                                                     exprTypmod((Node *) var));
05482         Assert(tupleDesc);
05483         /* Got the tupdesc, so we can extract the field name */
05484         Assert(fieldno >= 1 && fieldno <= tupleDesc->natts);
05485         return NameStr(tupleDesc->attrs[fieldno - 1]->attname);
05486     }
05487 
05488     /* Find appropriate nesting depth */
05489     netlevelsup = var->varlevelsup + levelsup;
05490     if (netlevelsup >= list_length(context->namespaces))
05491         elog(ERROR, "bogus varlevelsup: %d offset %d",
05492              var->varlevelsup, levelsup);
05493     dpns = (deparse_namespace *) list_nth(context->namespaces,
05494                                           netlevelsup);
05495 
05496     /*
05497      * Try to find the relevant RTE in this rtable.  In a plan tree, it's
05498      * likely that varno is OUTER_VAR or INNER_VAR, in which case we must dig
05499      * down into the subplans, or INDEX_VAR, which is resolved similarly.
05500      */
05501     if (var->varno >= 1 && var->varno <= list_length(dpns->rtable))
05502     {
05503         rte = rt_fetch(var->varno, dpns->rtable);
05504         attnum = var->varattno;
05505     }
05506     else if (var->varno == OUTER_VAR && dpns->outer_tlist)
05507     {
05508         TargetEntry *tle;
05509         deparse_namespace save_dpns;
05510         const char *result;
05511 
05512         tle = get_tle_by_resno(dpns->outer_tlist, var->varattno);
05513         if (!tle)
05514             elog(ERROR, "bogus varattno for OUTER_VAR var: %d", var->varattno);
05515 
05516         Assert(netlevelsup == 0);
05517         push_child_plan(dpns, dpns->outer_planstate, &save_dpns);
05518 
05519         result = get_name_for_var_field((Var *) tle->expr, fieldno,
05520                                         levelsup, context);
05521 
05522         pop_child_plan(dpns, &save_dpns);
05523         return result;
05524     }
05525     else if (var->varno == INNER_VAR && dpns->inner_tlist)
05526     {
05527         TargetEntry *tle;
05528         deparse_namespace save_dpns;
05529         const char *result;
05530 
05531         tle = get_tle_by_resno(dpns->inner_tlist, var->varattno);
05532         if (!tle)
05533             elog(ERROR, "bogus varattno for INNER_VAR var: %d", var->varattno);
05534 
05535         Assert(netlevelsup == 0);
05536         push_child_plan(dpns, dpns->inner_planstate, &save_dpns);
05537 
05538         result = get_name_for_var_field((Var *) tle->expr, fieldno,
05539                                         levelsup, context);
05540 
05541         pop_child_plan(dpns, &save_dpns);
05542         return result;
05543     }
05544     else if (var->varno == INDEX_VAR && dpns->index_tlist)
05545     {
05546         TargetEntry *tle;
05547         const char *result;
05548 
05549         tle = get_tle_by_resno(dpns->index_tlist, var->varattno);
05550         if (!tle)
05551             elog(ERROR, "bogus varattno for INDEX_VAR var: %d", var->varattno);
05552 
05553         Assert(netlevelsup == 0);
05554 
05555         result = get_name_for_var_field((Var *) tle->expr, fieldno,
05556                                         levelsup, context);
05557 
05558         return result;
05559     }
05560     else
05561     {
05562         elog(ERROR, "bogus varno: %d", var->varno);
05563         return NULL;            /* keep compiler quiet */
05564     }
05565 
05566     if (attnum == InvalidAttrNumber)
05567     {
05568         /* Var is whole-row reference to RTE, so select the right field */
05569         return get_rte_attribute_name(rte, fieldno);
05570     }
05571 
05572     /*
05573      * This part has essentially the same logic as the parser's
05574      * expandRecordVariable() function, but we are dealing with a different
05575      * representation of the input context, and we only need one field name
05576      * not a TupleDesc.  Also, we need special cases for finding subquery and
05577      * CTE subplans when deparsing Plan trees.
05578      */
05579     expr = (Node *) var;        /* default if we can't drill down */
05580 
05581     switch (rte->rtekind)
05582     {
05583         case RTE_RELATION:
05584         case RTE_VALUES:
05585 
05586             /*
05587              * This case should not occur: a column of a table or values list
05588              * shouldn't have type RECORD.  Fall through and fail (most
05589              * likely) at the bottom.
05590              */
05591             break;
05592         case RTE_SUBQUERY:
05593             /* Subselect-in-FROM: examine sub-select's output expr */
05594             {
05595                 if (rte->subquery)
05596                 {
05597                     TargetEntry *ste = get_tle_by_resno(rte->subquery->targetList,
05598                                                         attnum);
05599 
05600                     if (ste == NULL || ste->resjunk)
05601                         elog(ERROR, "subquery %s does not have attribute %d",
05602                              rte->eref->aliasname, attnum);
05603                     expr = (Node *) ste->expr;
05604                     if (IsA(expr, Var))
05605                     {
05606                         /*
05607                          * Recurse into the sub-select to see what its Var
05608                          * refers to. We have to build an additional level of
05609                          * namespace to keep in step with varlevelsup in the
05610                          * subselect.
05611                          */
05612                         deparse_namespace mydpns;
05613                         const char *result;
05614 
05615                         set_deparse_for_query(&mydpns, rte->subquery,
05616                                               context->namespaces);
05617 
05618                         context->namespaces = lcons(&mydpns,
05619                                                     context->namespaces);
05620 
05621                         result = get_name_for_var_field((Var *) expr, fieldno,
05622                                                         0, context);
05623 
05624                         context->namespaces =
05625                             list_delete_first(context->namespaces);
05626 
05627                         return result;
05628                     }
05629                     /* else fall through to inspect the expression */
05630                 }
05631                 else
05632                 {
05633                     /*
05634                      * We're deparsing a Plan tree so we don't have complete
05635                      * RTE entries (in particular, rte->subquery is NULL). But
05636                      * the only place we'd see a Var directly referencing a
05637                      * SUBQUERY RTE is in a SubqueryScan plan node, and we can
05638                      * look into the child plan's tlist instead.
05639                      */
05640                     TargetEntry *tle;
05641                     deparse_namespace save_dpns;
05642                     const char *result;
05643 
05644                     if (!dpns->inner_planstate)
05645                         elog(ERROR, "failed to find plan for subquery %s",
05646                              rte->eref->aliasname);
05647                     tle = get_tle_by_resno(dpns->inner_tlist, attnum);
05648                     if (!tle)
05649                         elog(ERROR, "bogus varattno for subquery var: %d",
05650                              attnum);
05651                     Assert(netlevelsup == 0);
05652                     push_child_plan(dpns, dpns->inner_planstate, &save_dpns);
05653 
05654                     result = get_name_for_var_field((Var *) tle->expr, fieldno,
05655                                                     levelsup, context);
05656 
05657                     pop_child_plan(dpns, &save_dpns);
05658                     return result;
05659                 }
05660             }
05661             break;
05662         case RTE_JOIN:
05663             /* Join RTE --- recursively inspect the alias variable */
05664             if (rte->joinaliasvars == NIL)
05665                 elog(ERROR, "cannot decompile join alias var in plan tree");
05666             Assert(attnum > 0 && attnum <= list_length(rte->joinaliasvars));
05667             expr = (Node *) list_nth(rte->joinaliasvars, attnum - 1);
05668             if (IsA(expr, Var))
05669                 return get_name_for_var_field((Var *) expr, fieldno,
05670                                               var->varlevelsup + levelsup,
05671                                               context);
05672             /* else fall through to inspect the expression */
05673             break;
05674         case RTE_FUNCTION:
05675 
05676             /*
05677              * We couldn't get here unless a function is declared with one of
05678              * its result columns as RECORD, which is not allowed.
05679              */
05680             break;
05681         case RTE_CTE:
05682             /* CTE reference: examine subquery's output expr */
05683             {
05684                 CommonTableExpr *cte = NULL;
05685                 Index       ctelevelsup;
05686                 ListCell   *lc;
05687 
05688                 /*
05689                  * Try to find the referenced CTE using the namespace stack.
05690                  */
05691                 ctelevelsup = rte->ctelevelsup + netlevelsup;
05692                 if (ctelevelsup >= list_length(context->namespaces))
05693                     lc = NULL;
05694                 else
05695                 {
05696                     deparse_namespace *ctedpns;
05697 
05698                     ctedpns = (deparse_namespace *)
05699                         list_nth(context->namespaces, ctelevelsup);
05700                     foreach(lc, ctedpns->ctes)
05701                     {
05702                         cte = (CommonTableExpr *) lfirst(lc);
05703                         if (strcmp(cte->ctename, rte->ctename) == 0)
05704                             break;
05705                     }
05706                 }
05707                 if (lc != NULL)
05708                 {
05709                     Query      *ctequery = (Query *) cte->ctequery;
05710                     TargetEntry *ste = get_tle_by_resno(GetCTETargetList(cte),
05711                                                         attnum);
05712 
05713                     if (ste == NULL || ste->resjunk)
05714                         elog(ERROR, "subquery %s does not have attribute %d",
05715                              rte->eref->aliasname, attnum);
05716                     expr = (Node *) ste->expr;
05717                     if (IsA(expr, Var))
05718                     {
05719                         /*
05720                          * Recurse into the CTE to see what its Var refers to.
05721                          * We have to build an additional level of namespace
05722                          * to keep in step with varlevelsup in the CTE.
05723                          * Furthermore it could be an outer CTE, so we may
05724                          * have to delete some levels of namespace.
05725                          */
05726                         List       *save_nslist = context->namespaces;
05727                         List       *new_nslist;
05728                         deparse_namespace mydpns;
05729                         const char *result;
05730 
05731                         set_deparse_for_query(&mydpns, ctequery,
05732                                               context->namespaces);
05733 
05734                         new_nslist = list_copy_tail(context->namespaces,
05735                                                     ctelevelsup);
05736                         context->namespaces = lcons(&mydpns, new_nslist);
05737 
05738                         result = get_name_for_var_field((Var *) expr, fieldno,
05739                                                         0, context);
05740 
05741                         context->namespaces = save_nslist;
05742 
05743                         return result;
05744                     }
05745                     /* else fall through to inspect the expression */
05746                 }
05747                 else
05748                 {
05749                     /*
05750                      * We're deparsing a Plan tree so we don't have a CTE
05751                      * list.  But the only place we'd see a Var directly
05752                      * referencing a CTE RTE is in a CteScan plan node, and we
05753                      * can look into the subplan's tlist instead.
05754                      */
05755                     TargetEntry *tle;
05756                     deparse_namespace save_dpns;
05757                     const char *result;
05758 
05759                     if (!dpns->inner_planstate)
05760                         elog(ERROR, "failed to find plan for CTE %s",
05761                              rte->eref->aliasname);
05762                     tle = get_tle_by_resno(dpns->inner_tlist, attnum);
05763                     if (!tle)
05764                         elog(ERROR, "bogus varattno for subquery var: %d",
05765                              attnum);
05766                     Assert(netlevelsup == 0);
05767                     push_child_plan(dpns, dpns->inner_planstate, &save_dpns);
05768 
05769                     result = get_name_for_var_field((Var *) tle->expr, fieldno,
05770                                                     levelsup, context);
05771 
05772                     pop_child_plan(dpns, &save_dpns);
05773                     return result;
05774                 }
05775             }
05776             break;
05777     }
05778 
05779     /*
05780      * We now have an expression we can't expand any more, so see if
05781      * get_expr_result_type() can do anything with it.  If not, pass to
05782      * lookup_rowtype_tupdesc() which will probably fail, but will give an
05783      * appropriate error message while failing.
05784      */
05785     if (get_expr_result_type(expr, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE)
05786         tupleDesc = lookup_rowtype_tupdesc_copy(exprType(expr),
05787                                                 exprTypmod(expr));
05788     Assert(tupleDesc);
05789     /* Got the tupdesc, so we can extract the field name */
05790     Assert(fieldno >= 1 && fieldno <= tupleDesc->natts);
05791     return NameStr(tupleDesc->attrs[fieldno - 1]->attname);
05792 }
05793 
05794 /*
05795  * Try to find the referenced expression for a PARAM_EXEC Param that might
05796  * reference a parameter supplied by an upper NestLoop or SubPlan plan node.
05797  *
05798  * If successful, return the expression and set *dpns_p and *ancestor_cell_p
05799  * appropriately for calling push_ancestor_plan().  If no referent can be
05800  * found, return NULL.
05801  */
05802 static Node *
05803 find_param_referent(Param *param, deparse_context *context,
05804                     deparse_namespace **dpns_p, ListCell **ancestor_cell_p)
05805 {
05806     /* Initialize output parameters to prevent compiler warnings */
05807     *dpns_p = NULL;
05808     *ancestor_cell_p = NULL;
05809 
05810     /*
05811      * If it's a PARAM_EXEC parameter, look for a matching NestLoopParam or
05812      * SubPlan argument.  This will necessarily be in some ancestor of the
05813      * current expression's PlanState.
05814      */
05815     if (param->paramkind == PARAM_EXEC)
05816     {
05817         deparse_namespace *dpns;
05818         PlanState  *child_ps;
05819         bool        in_same_plan_level;
05820         ListCell   *lc;
05821 
05822         dpns = (deparse_namespace *) linitial(context->namespaces);
05823         child_ps = dpns->planstate;
05824         in_same_plan_level = true;
05825 
05826         foreach(lc, dpns->ancestors)
05827         {
05828             PlanState  *ps = (PlanState *) lfirst(lc);
05829             ListCell   *lc2;
05830 
05831             /*
05832              * NestLoops transmit params to their inner child only; also, once
05833              * we've crawled up out of a subplan, this couldn't possibly be
05834              * the right match.
05835              */
05836             if (IsA(ps, NestLoopState) &&
05837                 child_ps == innerPlanState(ps) &&
05838                 in_same_plan_level)
05839             {
05840                 NestLoop   *nl = (NestLoop *) ps->plan;
05841 
05842                 foreach(lc2, nl->nestParams)
05843                 {
05844                     NestLoopParam *nlp = (NestLoopParam *) lfirst(lc2);
05845 
05846                     if (nlp->paramno == param->paramid)
05847                     {
05848                         /* Found a match, so return it */
05849                         *dpns_p = dpns;
05850                         *ancestor_cell_p = lc;
05851                         return (Node *) nlp->paramval;
05852                     }
05853                 }
05854             }
05855 
05856             /*
05857              * Check to see if we're crawling up from a subplan.
05858              */
05859             foreach(lc2, ps->subPlan)
05860             {
05861                 SubPlanState *sstate = (SubPlanState *) lfirst(lc2);
05862                 SubPlan    *subplan = (SubPlan *) sstate->xprstate.expr;
05863                 ListCell   *lc3;
05864                 ListCell   *lc4;
05865 
05866                 if (child_ps != sstate->planstate)
05867                     continue;
05868 
05869                 /* Matched subplan, so check its arguments */
05870                 forboth(lc3, subplan->parParam, lc4, subplan->args)
05871                 {
05872                     int         paramid = lfirst_int(lc3);
05873                     Node       *arg = (Node *) lfirst(lc4);
05874 
05875                     if (paramid == param->paramid)
05876                     {
05877                         /* Found a match, so return it */
05878                         *dpns_p = dpns;
05879                         *ancestor_cell_p = lc;
05880                         return arg;
05881                     }
05882                 }
05883 
05884                 /* Keep looking, but we are emerging from a subplan. */
05885                 in_same_plan_level = false;
05886                 break;
05887             }
05888 
05889             /*
05890              * Likewise check to see if we're emerging from an initplan.
05891              * Initplans never have any parParams, so no need to search that
05892              * list, but we need to know if we should reset
05893              * in_same_plan_level.
05894              */
05895             foreach(lc2, ps->initPlan)
05896             {
05897                 SubPlanState *sstate = (SubPlanState *) lfirst(lc2);
05898 
05899                 if (child_ps != sstate->planstate)
05900                     continue;
05901 
05902                 /* No parameters to be had here. */
05903                 Assert(((SubPlan *) sstate->xprstate.expr)->parParam == NIL);
05904 
05905                 /* Keep looking, but we are emerging from an initplan. */
05906                 in_same_plan_level = false;
05907                 break;
05908             }
05909 
05910             /* No luck, crawl up to next ancestor */
05911             child_ps = ps;
05912         }
05913     }
05914 
05915     /* No referent found */
05916     return NULL;
05917 }
05918 
05919 /*
05920  * Display a Param appropriately.
05921  */
05922 static void
05923 get_parameter(Param *param, deparse_context *context)
05924 {
05925     Node       *expr;
05926     deparse_namespace *dpns;
05927     ListCell   *ancestor_cell;
05928 
05929     /*
05930      * If it's a PARAM_EXEC parameter, try to locate the expression from which
05931      * the parameter was computed.  Note that failing to find a referent isn't
05932      * an error, since the Param might well be a subplan output rather than an
05933      * input.
05934      */
05935     expr = find_param_referent(param, context, &dpns, &ancestor_cell);
05936     if (expr)
05937     {
05938         /* Found a match, so print it */
05939         deparse_namespace save_dpns;
05940         bool        save_varprefix;
05941         bool        need_paren;
05942 
05943         /* Switch attention to the ancestor plan node */
05944         push_ancestor_plan(dpns, ancestor_cell, &save_dpns);
05945 
05946         /*
05947          * Force prefixing of Vars, since they won't belong to the relation
05948          * being scanned in the original plan node.
05949          */
05950         save_varprefix = context->varprefix;
05951         context->varprefix = true;
05952 
05953         /*
05954          * A Param's expansion is typically a Var, Aggref, or upper-level
05955          * Param, which wouldn't need extra parentheses.  Otherwise, insert
05956          * parens to ensure the expression looks atomic.
05957          */
05958         need_paren = !(IsA(expr, Var) ||
05959                        IsA(expr, Aggref) ||
05960                        IsA(expr, Param));
05961         if (need_paren)
05962             appendStringInfoChar(context->buf, '(');
05963 
05964         get_rule_expr(expr, context, false);
05965 
05966         if (need_paren)
05967             appendStringInfoChar(context->buf, ')');
05968 
05969         context->varprefix = save_varprefix;
05970 
05971         pop_ancestor_plan(dpns, &save_dpns);
05972 
05973         return;
05974     }
05975 
05976     /*
05977      * Not PARAM_EXEC, or couldn't find referent: just print $N.
05978      */
05979     appendStringInfo(context->buf, "$%d", param->paramid);
05980 }
05981 
05982 /*
05983  * get_simple_binary_op_name
05984  *
05985  * helper function for isSimpleNode
05986  * will return single char binary operator name, or NULL if it's not
05987  */
05988 static const char *
05989 get_simple_binary_op_name(OpExpr *expr)
05990 {
05991     List       *args = expr->args;
05992 
05993     if (list_length(args) == 2)
05994     {
05995         /* binary operator */
05996         Node       *arg1 = (Node *) linitial(args);
05997         Node       *arg2 = (Node *) lsecond(args);
05998         const char *op;
05999 
06000         op = generate_operator_name(expr->opno, exprType(arg1), exprType(arg2));
06001         if (strlen(op) == 1)
06002             return op;
06003     }
06004     return NULL;
06005 }
06006 
06007 
06008 /*
06009  * isSimpleNode - check if given node is simple (doesn't need parenthesizing)
06010  *
06011  *  true   : simple in the context of parent node's type
06012  *  false  : not simple
06013  */
06014 static bool
06015 isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
06016 {
06017     if (!node)
06018         return false;
06019 
06020     switch (nodeTag(node))
06021     {
06022         case T_Var:
06023         case T_Const:
06024         case T_Param:
06025         case T_CoerceToDomainValue:
06026         case T_SetToDefault:
06027         case T_CurrentOfExpr:
06028             /* single words: always simple */
06029             return true;
06030 
06031         case T_ArrayRef:
06032         case T_ArrayExpr:
06033         case T_RowExpr:
06034         case T_CoalesceExpr:
06035         case T_MinMaxExpr:
06036         case T_XmlExpr:
06037         case T_NullIfExpr:
06038         case T_Aggref:
06039         case T_WindowFunc:
06040         case T_FuncExpr:
06041             /* function-like: name(..) or name[..] */
06042             return true;
06043 
06044             /* CASE keywords act as parentheses */
06045         case T_CaseExpr:
06046             return true;
06047 
06048         case T_FieldSelect:
06049 
06050             /*
06051              * appears simple since . has top precedence, unless parent is
06052              * T_FieldSelect itself!
06053              */
06054             return (IsA(parentNode, FieldSelect) ? false : true);
06055 
06056         case T_FieldStore:
06057 
06058             /*
06059              * treat like FieldSelect (probably doesn't matter)
06060              */
06061             return (IsA(parentNode, FieldStore) ? false : true);
06062 
06063         case T_CoerceToDomain:
06064             /* maybe simple, check args */
06065             return isSimpleNode((Node *) ((CoerceToDomain *) node)->arg,
06066                                 node, prettyFlags);
06067         case T_RelabelType:
06068             return isSimpleNode((Node *) ((RelabelType *) node)->arg,
06069                                 node, prettyFlags);
06070         case T_CoerceViaIO:
06071             return isSimpleNode((Node *) ((CoerceViaIO *) node)->arg,
06072                                 node, prettyFlags);
06073         case T_ArrayCoerceExpr:
06074             return isSimpleNode((Node *) ((ArrayCoerceExpr *) node)->arg,
06075                                 node, prettyFlags);
06076         case T_ConvertRowtypeExpr:
06077             return isSimpleNode((Node *) ((ConvertRowtypeExpr *) node)->arg,
06078                                 node, prettyFlags);
06079 
06080         case T_OpExpr:
06081             {
06082                 /* depends on parent node type; needs further checking */
06083                 if (prettyFlags & PRETTYFLAG_PAREN && IsA(parentNode, OpExpr))
06084                 {
06085                     const char *op;
06086                     const char *parentOp;
06087                     bool        is_lopriop;
06088                     bool        is_hipriop;
06089                     bool        is_lopriparent;
06090                     bool        is_hipriparent;
06091 
06092                     op = get_simple_binary_op_name((OpExpr *) node);
06093                     if (!op)
06094                         return false;
06095 
06096                     /* We know only the basic operators + - and * / % */
06097                     is_lopriop = (strchr("+-", *op) != NULL);
06098                     is_hipriop = (strchr("*/%", *op) != NULL);
06099                     if (!(is_lopriop || is_hipriop))
06100                         return false;
06101 
06102                     parentOp = get_simple_binary_op_name((OpExpr *) parentNode);
06103                     if (!parentOp)
06104                         return false;
06105 
06106                     is_lopriparent = (strchr("+-", *parentOp) != NULL);
06107                     is_hipriparent = (strchr("*/%", *parentOp) != NULL);
06108                     if (!(is_lopriparent || is_hipriparent))
06109                         return false;
06110 
06111                     if (is_hipriop && is_lopriparent)
06112                         return true;    /* op binds tighter than parent */
06113 
06114                     if (is_lopriop && is_hipriparent)
06115                         return false;
06116 
06117                     /*
06118                      * Operators are same priority --- can skip parens only if
06119                      * we have (a - b) - c, not a - (b - c).
06120                      */
06121                     if (node == (Node *) linitial(((OpExpr *) parentNode)->args))
06122                         return true;
06123 
06124                     return false;
06125                 }
06126                 /* else do the same stuff as for T_SubLink et al. */
06127                 /* FALL THROUGH */
06128             }
06129 
06130         case T_SubLink:
06131         case T_NullTest:
06132         case T_BooleanTest:
06133         case T_DistinctExpr:
06134             switch (nodeTag(parentNode))
06135             {
06136                 case T_FuncExpr:
06137                     {
06138                         /* special handling for casts */
06139                         CoercionForm type = ((FuncExpr *) parentNode)->funcformat;
06140 
06141                         if (type == COERCE_EXPLICIT_CAST ||
06142                             type == COERCE_IMPLICIT_CAST)
06143                             return false;
06144                         return true;    /* own parentheses */
06145                     }
06146                 case T_BoolExpr:        /* lower precedence */
06147                 case T_ArrayRef:        /* other separators */
06148                 case T_ArrayExpr:       /* other separators */
06149                 case T_RowExpr: /* other separators */
06150                 case T_CoalesceExpr:    /* own parentheses */
06151                 case T_MinMaxExpr:      /* own parentheses */
06152                 case T_XmlExpr: /* own parentheses */
06153                 case T_NullIfExpr:      /* other separators */
06154                 case T_Aggref:  /* own parentheses */
06155                 case T_WindowFunc:      /* own parentheses */
06156                 case T_CaseExpr:        /* other separators */
06157                     return true;
06158                 default:
06159                     return false;
06160             }
06161 
06162         case T_BoolExpr:
06163             switch (nodeTag(parentNode))
06164             {
06165                 case T_BoolExpr:
06166                     if (prettyFlags & PRETTYFLAG_PAREN)
06167                     {
06168                         BoolExprType type;
06169                         BoolExprType parentType;
06170 
06171                         type = ((BoolExpr *) node)->boolop;
06172                         parentType = ((BoolExpr *) parentNode)->boolop;
06173                         switch (type)
06174                         {
06175                             case NOT_EXPR:
06176                             case AND_EXPR:
06177                                 if (parentType == AND_EXPR || parentType == OR_EXPR)
06178                                     return true;
06179                                 break;
06180                             case OR_EXPR:
06181                                 if (parentType == OR_EXPR)
06182                                     return true;
06183                                 break;
06184                         }
06185                     }
06186                     return false;
06187                 case T_FuncExpr:
06188                     {
06189                         /* special handling for casts */
06190                         CoercionForm type = ((FuncExpr *) parentNode)->funcformat;
06191 
06192                         if (type == COERCE_EXPLICIT_CAST ||
06193                             type == COERCE_IMPLICIT_CAST)
06194                             return false;
06195                         return true;    /* own parentheses */
06196                     }
06197                 case T_ArrayRef:        /* other separators */
06198                 case T_ArrayExpr:       /* other separators */
06199                 case T_RowExpr: /* other separators */
06200                 case T_CoalesceExpr:    /* own parentheses */
06201                 case T_MinMaxExpr:      /* own parentheses */
06202                 case T_XmlExpr: /* own parentheses */
06203                 case T_NullIfExpr:      /* other separators */
06204                 case T_Aggref:  /* own parentheses */
06205                 case T_WindowFunc:      /* own parentheses */
06206                 case T_CaseExpr:        /* other separators */
06207                     return true;
06208                 default:
06209                     return false;
06210             }
06211 
06212         default:
06213             break;
06214     }
06215     /* those we don't know: in dubio complexo */
06216     return false;
06217 }
06218 
06219 
06220 /*
06221  * appendContextKeyword - append a keyword to buffer
06222  *
06223  * If prettyPrint is enabled, perform a line break, and adjust indentation.
06224  * Otherwise, just append the keyword.
06225  */
06226 static void
06227 appendContextKeyword(deparse_context *context, const char *str,
06228                      int indentBefore, int indentAfter, int indentPlus)
06229 {
06230     if (PRETTY_INDENT(context))
06231     {
06232         context->indentLevel += indentBefore;
06233 
06234         appendStringInfoChar(context->buf, '\n');
06235         appendStringInfoSpaces(context->buf,
06236                                Max(context->indentLevel, 0) + indentPlus);
06237         appendStringInfoString(context->buf, str);
06238 
06239         context->indentLevel += indentAfter;
06240         if (context->indentLevel < 0)
06241             context->indentLevel = 0;
06242     }
06243     else
06244         appendStringInfoString(context->buf, str);
06245 }
06246 
06247 /*
06248  * get_rule_expr_paren  - deparse expr using get_rule_expr,
06249  * embracing the string with parentheses if necessary for prettyPrint.
06250  *
06251  * Never embrace if prettyFlags=0, because it's done in the calling node.
06252  *
06253  * Any node that does *not* embrace its argument node by sql syntax (with
06254  * parentheses, non-operator keywords like CASE/WHEN/ON, or comma etc) should
06255  * use get_rule_expr_paren instead of get_rule_expr so parentheses can be
06256  * added.
06257  */
06258 static void
06259 get_rule_expr_paren(Node *node, deparse_context *context,
06260                     bool showimplicit, Node *parentNode)
06261 {
06262     bool        need_paren;
06263 
06264     need_paren = PRETTY_PAREN(context) &&
06265         !isSimpleNode(node, parentNode, context->prettyFlags);
06266 
06267     if (need_paren)
06268         appendStringInfoChar(context->buf, '(');
06269 
06270     get_rule_expr(node, context, showimplicit);
06271 
06272     if (need_paren)
06273         appendStringInfoChar(context->buf, ')');
06274 }
06275 
06276 
06277 /* ----------
06278  * get_rule_expr            - Parse back an expression
06279  *
06280  * Note: showimplicit determines whether we display any implicit cast that
06281  * is present at the top of the expression tree.  It is a passed argument,
06282  * not a field of the context struct, because we change the value as we
06283  * recurse down into the expression.  In general we suppress implicit casts
06284  * when the result type is known with certainty (eg, the arguments of an
06285  * OR must be boolean).  We display implicit casts for arguments of functions
06286  * and operators, since this is needed to be certain that the same function
06287  * or operator will be chosen when the expression is re-parsed.
06288  * ----------
06289  */
06290 static void
06291 get_rule_expr(Node *node, deparse_context *context,
06292               bool showimplicit)
06293 {
06294     StringInfo  buf = context->buf;
06295 
06296     if (node == NULL)
06297         return;
06298 
06299     /*
06300      * Each level of get_rule_expr must emit an indivisible term
06301      * (parenthesized if necessary) to ensure result is reparsed into the same
06302      * expression tree.  The only exception is that when the input is a List,
06303      * we emit the component items comma-separated with no surrounding
06304      * decoration; this is convenient for most callers.
06305      */
06306     switch (nodeTag(node))
06307     {
06308         case T_Var:
06309             (void) get_variable((Var *) node, 0, false, context);
06310             break;
06311 
06312         case T_Const:
06313             get_const_expr((Const *) node, context, 0);
06314             break;
06315 
06316         case T_Param:
06317             get_parameter((Param *) node, context);
06318             break;
06319 
06320         case T_Aggref:
06321             get_agg_expr((Aggref *) node, context);
06322             break;
06323 
06324         case T_WindowFunc:
06325             get_windowfunc_expr((WindowFunc *) node, context);
06326             break;
06327 
06328         case T_ArrayRef:
06329             {
06330                 ArrayRef   *aref = (ArrayRef *) node;
06331                 bool        need_parens;
06332 
06333                 /*
06334                  * If the argument is a CaseTestExpr, we must be inside a
06335                  * FieldStore, ie, we are assigning to an element of an array
06336                  * within a composite column.  Since we already punted on
06337                  * displaying the FieldStore's target information, just punt
06338                  * here too, and display only the assignment source
06339                  * expression.
06340                  */
06341                 if (IsA(aref->refexpr, CaseTestExpr))
06342                 {
06343                     Assert(aref->refassgnexpr);
06344                     get_rule_expr((Node *) aref->refassgnexpr,
06345                                   context, showimplicit);
06346                     break;
06347                 }
06348 
06349                 /*
06350                  * Parenthesize the argument unless it's a simple Var or a
06351                  * FieldSelect.  (In particular, if it's another ArrayRef, we
06352                  * *must* parenthesize to avoid confusion.)
06353                  */
06354                 need_parens = !IsA(aref->refexpr, Var) &&
06355                     !IsA(aref->refexpr, FieldSelect);
06356                 if (need_parens)
06357                     appendStringInfoChar(buf, '(');
06358                 get_rule_expr((Node *) aref->refexpr, context, showimplicit);
06359                 if (need_parens)
06360                     appendStringInfoChar(buf, ')');
06361 
06362                 /*
06363                  * If there's a refassgnexpr, we want to print the node in the
06364                  * format "array[subscripts] := refassgnexpr".  This is not
06365                  * legal SQL, so decompilation of INSERT or UPDATE statements
06366                  * should always use processIndirection as part of the
06367                  * statement-level syntax.  We should only see this when
06368                  * EXPLAIN tries to print the targetlist of a plan resulting
06369                  * from such a statement.
06370                  */
06371                 if (aref->refassgnexpr)
06372                 {
06373                     Node       *refassgnexpr;
06374 
06375                     /*
06376                      * Use processIndirection to print this node's subscripts
06377                      * as well as any additional field selections or
06378                      * subscripting in immediate descendants.  It returns the
06379                      * RHS expr that is actually being "assigned".
06380                      */
06381                     refassgnexpr = processIndirection(node, context, true);
06382                     appendStringInfoString(buf, " := ");
06383                     get_rule_expr(refassgnexpr, context, showimplicit);
06384                 }
06385                 else
06386                 {
06387                     /* Just an ordinary array fetch, so print subscripts */
06388                     printSubscripts(aref, context);
06389                 }
06390             }
06391             break;
06392 
06393         case T_FuncExpr:
06394             get_func_expr((FuncExpr *) node, context, showimplicit);
06395             break;
06396 
06397         case T_NamedArgExpr:
06398             {
06399                 NamedArgExpr *na = (NamedArgExpr *) node;
06400 
06401                 appendStringInfo(buf, "%s := ", quote_identifier(na->name));
06402                 get_rule_expr((Node *) na->arg, context, showimplicit);
06403             }
06404             break;
06405 
06406         case T_OpExpr:
06407             get_oper_expr((OpExpr *) node, context);
06408             break;
06409 
06410         case T_DistinctExpr:
06411             {
06412                 DistinctExpr *expr = (DistinctExpr *) node;
06413                 List       *args = expr->args;
06414                 Node       *arg1 = (Node *) linitial(args);
06415                 Node       *arg2 = (Node *) lsecond(args);
06416 
06417                 if (!PRETTY_PAREN(context))
06418                     appendStringInfoChar(buf, '(');
06419                 get_rule_expr_paren(arg1, context, true, node);
06420                 appendStringInfo(buf, " IS DISTINCT FROM ");
06421                 get_rule_expr_paren(arg2, context, true, node);
06422                 if (!PRETTY_PAREN(context))
06423                     appendStringInfoChar(buf, ')');
06424             }
06425             break;
06426 
06427         case T_NullIfExpr:
06428             {
06429                 NullIfExpr *nullifexpr = (NullIfExpr *) node;
06430 
06431                 appendStringInfo(buf, "NULLIF(");
06432                 get_rule_expr((Node *) nullifexpr->args, context, true);
06433                 appendStringInfoChar(buf, ')');
06434             }
06435             break;
06436 
06437         case T_ScalarArrayOpExpr:
06438             {
06439                 ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) node;
06440                 List       *args = expr->args;
06441                 Node       *arg1 = (Node *) linitial(args);
06442                 Node       *arg2 = (Node *) lsecond(args);
06443 
06444                 if (!PRETTY_PAREN(context))
06445                     appendStringInfoChar(buf, '(');
06446                 get_rule_expr_paren(arg1, context, true, node);
06447                 appendStringInfo(buf, " %s %s (",
06448                                  generate_operator_name(expr->opno,
06449                                                         exprType(arg1),
06450                                       get_base_element_type(exprType(arg2))),
06451                                  expr->useOr ? "ANY" : "ALL");
06452                 get_rule_expr_paren(arg2, context, true, node);
06453                 appendStringInfoChar(buf, ')');
06454                 if (!PRETTY_PAREN(context))
06455                     appendStringInfoChar(buf, ')');
06456             }
06457             break;
06458 
06459         case T_BoolExpr:
06460             {
06461                 BoolExpr   *expr = (BoolExpr *) node;
06462                 Node       *first_arg = linitial(expr->args);
06463                 ListCell   *arg = lnext(list_head(expr->args));
06464 
06465                 switch (expr->boolop)
06466                 {
06467                     case AND_EXPR:
06468                         if (!PRETTY_PAREN(context))
06469                             appendStringInfoChar(buf, '(');
06470                         get_rule_expr_paren(first_arg, context,
06471                                             false, node);
06472                         while (arg)
06473                         {
06474                             appendStringInfo(buf, " AND ");
06475                             get_rule_expr_paren((Node *) lfirst(arg), context,
06476                                                 false, node);
06477                             arg = lnext(arg);
06478                         }
06479                         if (!PRETTY_PAREN(context))
06480                             appendStringInfoChar(buf, ')');
06481                         break;
06482 
06483                     case OR_EXPR:
06484                         if (!PRETTY_PAREN(context))
06485                             appendStringInfoChar(buf, '(');
06486                         get_rule_expr_paren(first_arg, context,
06487                                             false, node);
06488                         while (arg)
06489                         {
06490                             appendStringInfo(buf, " OR ");
06491                             get_rule_expr_paren((Node *) lfirst(arg), context,
06492                                                 false, node);
06493                             arg = lnext(arg);
06494                         }
06495                         if (!PRETTY_PAREN(context))
06496                             appendStringInfoChar(buf, ')');
06497                         break;
06498 
06499                     case NOT_EXPR:
06500                         if (!PRETTY_PAREN(context))
06501                             appendStringInfoChar(buf, '(');
06502                         appendStringInfo(buf, "NOT ");
06503                         get_rule_expr_paren(first_arg, context,
06504                                             false, node);
06505                         if (!PRETTY_PAREN(context))
06506                             appendStringInfoChar(buf, ')');
06507                         break;
06508 
06509                     default:
06510                         elog(ERROR, "unrecognized boolop: %d",
06511                              (int) expr->boolop);
06512                 }
06513             }
06514             break;
06515 
06516         case T_SubLink:
06517             get_sublink_expr((SubLink *) node, context);
06518             break;
06519 
06520         case T_SubPlan:
06521             {
06522                 SubPlan    *subplan = (SubPlan *) node;
06523 
06524                 /*
06525                  * We cannot see an already-planned subplan in rule deparsing,
06526                  * only while EXPLAINing a query plan.  We don't try to
06527                  * reconstruct the original SQL, just reference the subplan
06528                  * that appears elsewhere in EXPLAIN's result.
06529                  */
06530                 if (subplan->useHashTable)
06531                     appendStringInfo(buf, "(hashed %s)", subplan->plan_name);
06532                 else
06533                     appendStringInfo(buf, "(%s)", subplan->plan_name);
06534             }
06535             break;
06536 
06537         case T_AlternativeSubPlan:
06538             {
06539                 AlternativeSubPlan *asplan = (AlternativeSubPlan *) node;
06540                 ListCell   *lc;
06541 
06542                 /* As above, this can only happen during EXPLAIN */
06543                 appendStringInfo(buf, "(alternatives: ");
06544                 foreach(lc, asplan->subplans)
06545                 {
06546                     SubPlan    *splan = (SubPlan *) lfirst(lc);
06547 
06548                     Assert(IsA(splan, SubPlan));
06549                     if (splan->useHashTable)
06550                         appendStringInfo(buf, "hashed %s", splan->plan_name);
06551                     else
06552                         appendStringInfo(buf, "%s", splan->plan_name);
06553                     if (lnext(lc))
06554                         appendStringInfo(buf, " or ");
06555                 }
06556                 appendStringInfo(buf, ")");
06557             }
06558             break;
06559 
06560         case T_FieldSelect:
06561             {
06562                 FieldSelect *fselect = (FieldSelect *) node;
06563                 Node       *arg = (Node *) fselect->arg;
06564                 int         fno = fselect->fieldnum;
06565                 const char *fieldname;
06566                 bool        need_parens;
06567 
06568                 /*
06569                  * Parenthesize the argument unless it's an ArrayRef or
06570                  * another FieldSelect.  Note in particular that it would be
06571                  * WRONG to not parenthesize a Var argument; simplicity is not
06572                  * the issue here, having the right number of names is.
06573                  */
06574                 need_parens = !IsA(arg, ArrayRef) &&!IsA(arg, FieldSelect);
06575                 if (need_parens)
06576                     appendStringInfoChar(buf, '(');
06577                 get_rule_expr(arg, context, true);
06578                 if (need_parens)
06579                     appendStringInfoChar(buf, ')');
06580 
06581                 /*
06582                  * Get and print the field name.
06583                  */
06584                 fieldname = get_name_for_var_field((Var *) arg, fno,
06585                                                    0, context);
06586                 appendStringInfo(buf, ".%s", quote_identifier(fieldname));
06587             }
06588             break;
06589 
06590         case T_FieldStore:
06591             {
06592                 FieldStore *fstore = (FieldStore *) node;
06593                 bool        need_parens;
06594 
06595                 /*
06596                  * There is no good way to represent a FieldStore as real SQL,
06597                  * so decompilation of INSERT or UPDATE statements should
06598                  * always use processIndirection as part of the
06599                  * statement-level syntax.  We should only get here when
06600                  * EXPLAIN tries to print the targetlist of a plan resulting
06601                  * from such a statement.  The plan case is even harder than
06602                  * ordinary rules would be, because the planner tries to
06603                  * collapse multiple assignments to the same field or subfield
06604                  * into one FieldStore; so we can see a list of target fields
06605                  * not just one, and the arguments could be FieldStores
06606                  * themselves.  We don't bother to try to print the target
06607                  * field names; we just print the source arguments, with a
06608                  * ROW() around them if there's more than one.  This isn't
06609                  * terribly complete, but it's probably good enough for
06610                  * EXPLAIN's purposes; especially since anything more would be
06611                  * either hopelessly confusing or an even poorer
06612                  * representation of what the plan is actually doing.
06613                  */
06614                 need_parens = (list_length(fstore->newvals) != 1);
06615                 if (need_parens)
06616                     appendStringInfoString(buf, "ROW(");
06617                 get_rule_expr((Node *) fstore->newvals, context, showimplicit);
06618                 if (need_parens)
06619                     appendStringInfoChar(buf, ')');
06620             }
06621             break;
06622 
06623         case T_RelabelType:
06624             {
06625                 RelabelType *relabel = (RelabelType *) node;
06626                 Node       *arg = (Node *) relabel->arg;
06627 
06628                 if (relabel->relabelformat == COERCE_IMPLICIT_CAST &&
06629                     !showimplicit)
06630                 {
06631                     /* don't show the implicit cast */
06632                     get_rule_expr_paren(arg, context, false, node);
06633                 }
06634                 else
06635                 {
06636                     get_coercion_expr(arg, context,
06637                                       relabel->resulttype,
06638                                       relabel->resulttypmod,
06639                                       node);
06640                 }
06641             }
06642             break;
06643 
06644         case T_CoerceViaIO:
06645             {
06646                 CoerceViaIO *iocoerce = (CoerceViaIO *) node;
06647                 Node       *arg = (Node *) iocoerce->arg;
06648 
06649                 if (iocoerce->coerceformat == COERCE_IMPLICIT_CAST &&
06650                     !showimplicit)
06651                 {
06652                     /* don't show the implicit cast */
06653                     get_rule_expr_paren(arg, context, false, node);
06654                 }
06655                 else
06656                 {
06657                     get_coercion_expr(arg, context,
06658                                       iocoerce->resulttype,
06659                                       -1,
06660                                       node);
06661                 }
06662             }
06663             break;
06664 
06665         case T_ArrayCoerceExpr:
06666             {
06667                 ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node;
06668                 Node       *arg = (Node *) acoerce->arg;
06669 
06670                 if (acoerce->coerceformat == COERCE_IMPLICIT_CAST &&
06671                     !showimplicit)
06672                 {
06673                     /* don't show the implicit cast */
06674                     get_rule_expr_paren(arg, context, false, node);
06675                 }
06676                 else
06677                 {
06678                     get_coercion_expr(arg, context,
06679                                       acoerce->resulttype,
06680                                       acoerce->resulttypmod,
06681                                       node);
06682                 }
06683             }
06684             break;
06685 
06686         case T_ConvertRowtypeExpr:
06687             {
06688                 ConvertRowtypeExpr *convert = (ConvertRowtypeExpr *) node;
06689                 Node       *arg = (Node *) convert->arg;
06690 
06691                 if (convert->convertformat == COERCE_IMPLICIT_CAST &&
06692                     !showimplicit)
06693                 {
06694                     /* don't show the implicit cast */
06695                     get_rule_expr_paren(arg, context, false, node);
06696                 }
06697                 else
06698                 {
06699                     get_coercion_expr(arg, context,
06700                                       convert->resulttype, -1,
06701                                       node);
06702                 }
06703             }
06704             break;
06705 
06706         case T_CollateExpr:
06707             {
06708                 CollateExpr *collate = (CollateExpr *) node;
06709                 Node       *arg = (Node *) collate->arg;
06710 
06711                 if (!PRETTY_PAREN(context))
06712                     appendStringInfoChar(buf, '(');
06713                 get_rule_expr_paren(arg, context, showimplicit, node);
06714                 appendStringInfo(buf, " COLLATE %s",
06715                                  generate_collation_name(collate->collOid));
06716                 if (!PRETTY_PAREN(context))
06717                     appendStringInfoChar(buf, ')');
06718             }
06719             break;
06720 
06721         case T_CaseExpr:
06722             {
06723                 CaseExpr   *caseexpr = (CaseExpr *) node;
06724                 ListCell   *temp;
06725 
06726                 appendContextKeyword(context, "CASE",
06727                                      0, PRETTYINDENT_VAR, 0);
06728                 if (caseexpr->arg)
06729                 {
06730                     appendStringInfoChar(buf, ' ');
06731                     get_rule_expr((Node *) caseexpr->arg, context, true);
06732                 }
06733                 foreach(temp, caseexpr->args)
06734                 {
06735                     CaseWhen   *when = (CaseWhen *) lfirst(temp);
06736                     Node       *w = (Node *) when->expr;
06737 
06738                     if (caseexpr->arg)
06739                     {
06740                         /*
06741                          * The parser should have produced WHEN clauses of the
06742                          * form "CaseTestExpr = RHS", possibly with an
06743                          * implicit coercion inserted above the CaseTestExpr.
06744                          * For accurate decompilation of rules it's essential
06745                          * that we show just the RHS.  However in an
06746                          * expression that's been through the optimizer, the
06747                          * WHEN clause could be almost anything (since the
06748                          * equality operator could have been expanded into an
06749                          * inline function).  If we don't recognize the form
06750                          * of the WHEN clause, just punt and display it as-is.
06751                          */
06752                         if (IsA(w, OpExpr))
06753                         {
06754                             List       *args = ((OpExpr *) w)->args;
06755 
06756                             if (list_length(args) == 2 &&
06757                                 IsA(strip_implicit_coercions(linitial(args)),
06758                                     CaseTestExpr))
06759                                 w = (Node *) lsecond(args);
06760                         }
06761                     }
06762 
06763                     if (!PRETTY_INDENT(context))
06764                         appendStringInfoChar(buf, ' ');
06765                     appendContextKeyword(context, "WHEN ",
06766                                          0, 0, 0);
06767                     get_rule_expr(w, context, false);
06768                     appendStringInfo(buf, " THEN ");
06769                     get_rule_expr((Node *) when->result, context, true);
06770                 }
06771                 if (!PRETTY_INDENT(context))
06772                     appendStringInfoChar(buf, ' ');
06773                 appendContextKeyword(context, "ELSE ",
06774                                      0, 0, 0);
06775                 get_rule_expr((Node *) caseexpr->defresult, context, true);
06776                 if (!PRETTY_INDENT(context))
06777                     appendStringInfoChar(buf, ' ');
06778                 appendContextKeyword(context, "END",
06779                                      -PRETTYINDENT_VAR, 0, 0);
06780             }
06781             break;
06782 
06783         case T_CaseTestExpr:
06784             {
06785                 /*
06786                  * Normally we should never get here, since for expressions
06787                  * that can contain this node type we attempt to avoid
06788                  * recursing to it.  But in an optimized expression we might
06789                  * be unable to avoid that (see comments for CaseExpr).  If we
06790                  * do see one, print it as CASE_TEST_EXPR.
06791                  */
06792                 appendStringInfo(buf, "CASE_TEST_EXPR");
06793             }
06794             break;
06795 
06796         case T_ArrayExpr:
06797             {
06798                 ArrayExpr  *arrayexpr = (ArrayExpr *) node;
06799 
06800                 appendStringInfo(buf, "ARRAY[");
06801                 get_rule_expr((Node *) arrayexpr->elements, context, true);
06802                 appendStringInfoChar(buf, ']');
06803 
06804                 /*
06805                  * If the array isn't empty, we assume its elements are
06806                  * coerced to the desired type.  If it's empty, though, we
06807                  * need an explicit coercion to the array type.
06808                  */
06809                 if (arrayexpr->elements == NIL)
06810                     appendStringInfo(buf, "::%s",
06811                       format_type_with_typemod(arrayexpr->array_typeid, -1));
06812             }
06813             break;
06814 
06815         case T_RowExpr:
06816             {
06817                 RowExpr    *rowexpr = (RowExpr *) node;
06818                 TupleDesc   tupdesc = NULL;
06819                 ListCell   *arg;
06820                 int         i;
06821                 char       *sep;
06822 
06823                 /*
06824                  * If it's a named type and not RECORD, we may have to skip
06825                  * dropped columns and/or claim there are NULLs for added
06826                  * columns.
06827                  */
06828                 if (rowexpr->row_typeid != RECORDOID)
06829                 {
06830                     tupdesc = lookup_rowtype_tupdesc(rowexpr->row_typeid, -1);
06831                     Assert(list_length(rowexpr->args) <= tupdesc->natts);
06832                 }
06833 
06834                 /*
06835                  * SQL99 allows "ROW" to be omitted when there is more than
06836                  * one column, but for simplicity we always print it.
06837                  */
06838                 appendStringInfo(buf, "ROW(");
06839                 sep = "";
06840                 i = 0;
06841                 foreach(arg, rowexpr->args)
06842                 {
06843                     Node       *e = (Node *) lfirst(arg);
06844 
06845                     if (tupdesc == NULL ||
06846                         !tupdesc->attrs[i]->attisdropped)
06847                     {
06848                         appendStringInfoString(buf, sep);
06849                         get_rule_expr(e, context, true);
06850                         sep = ", ";
06851                     }
06852                     i++;
06853                 }
06854                 if (tupdesc != NULL)
06855                 {
06856                     while (i < tupdesc->natts)
06857                     {
06858                         if (!tupdesc->attrs[i]->attisdropped)
06859                         {
06860                             appendStringInfoString(buf, sep);
06861                             appendStringInfo(buf, "NULL");
06862                             sep = ", ";
06863                         }
06864                         i++;
06865                     }
06866 
06867                     ReleaseTupleDesc(tupdesc);
06868                 }
06869                 appendStringInfo(buf, ")");
06870                 if (rowexpr->row_format == COERCE_EXPLICIT_CAST)
06871                     appendStringInfo(buf, "::%s",
06872                           format_type_with_typemod(rowexpr->row_typeid, -1));
06873             }
06874             break;
06875 
06876         case T_RowCompareExpr:
06877             {
06878                 RowCompareExpr *rcexpr = (RowCompareExpr *) node;
06879                 ListCell   *arg;
06880                 char       *sep;
06881 
06882                 /*
06883                  * SQL99 allows "ROW" to be omitted when there is more than
06884                  * one column, but for simplicity we always print it.
06885                  */
06886                 appendStringInfo(buf, "(ROW(");
06887                 sep = "";
06888                 foreach(arg, rcexpr->largs)
06889                 {
06890                     Node       *e = (Node *) lfirst(arg);
06891 
06892                     appendStringInfoString(buf, sep);
06893                     get_rule_expr(e, context, true);
06894                     sep = ", ";
06895                 }
06896 
06897                 /*
06898                  * We assume that the name of the first-column operator will
06899                  * do for all the rest too.  This is definitely open to
06900                  * failure, eg if some but not all operators were renamed
06901                  * since the construct was parsed, but there seems no way to
06902                  * be perfect.
06903                  */
06904                 appendStringInfo(buf, ") %s ROW(",
06905                           generate_operator_name(linitial_oid(rcexpr->opnos),
06906                                            exprType(linitial(rcexpr->largs)),
06907                                          exprType(linitial(rcexpr->rargs))));
06908                 sep = "";
06909                 foreach(arg, rcexpr->rargs)
06910                 {
06911                     Node       *e = (Node *) lfirst(arg);
06912 
06913                     appendStringInfoString(buf, sep);
06914                     get_rule_expr(e, context, true);
06915                     sep = ", ";
06916                 }
06917                 appendStringInfo(buf, "))");
06918             }
06919             break;
06920 
06921         case T_CoalesceExpr:
06922             {
06923                 CoalesceExpr *coalesceexpr = (CoalesceExpr *) node;
06924 
06925                 appendStringInfo(buf, "COALESCE(");
06926                 get_rule_expr((Node *) coalesceexpr->args, context, true);
06927                 appendStringInfoChar(buf, ')');
06928             }
06929             break;
06930 
06931         case T_MinMaxExpr:
06932             {
06933                 MinMaxExpr *minmaxexpr = (MinMaxExpr *) node;
06934 
06935                 switch (minmaxexpr->op)
06936                 {
06937                     case IS_GREATEST:
06938                         appendStringInfo(buf, "GREATEST(");
06939                         break;
06940                     case IS_LEAST:
06941                         appendStringInfo(buf, "LEAST(");
06942                         break;
06943                 }
06944                 get_rule_expr((Node *) minmaxexpr->args, context, true);
06945                 appendStringInfoChar(buf, ')');
06946             }
06947             break;
06948 
06949         case T_XmlExpr:
06950             {
06951                 XmlExpr    *xexpr = (XmlExpr *) node;
06952                 bool        needcomma = false;
06953                 ListCell   *arg;
06954                 ListCell   *narg;
06955                 Const      *con;
06956 
06957                 switch (xexpr->op)
06958                 {
06959                     case IS_XMLCONCAT:
06960                         appendStringInfoString(buf, "XMLCONCAT(");
06961                         break;
06962                     case IS_XMLELEMENT:
06963                         appendStringInfoString(buf, "XMLELEMENT(");
06964                         break;
06965                     case IS_XMLFOREST:
06966                         appendStringInfoString(buf, "XMLFOREST(");
06967                         break;
06968                     case IS_XMLPARSE:
06969                         appendStringInfoString(buf, "XMLPARSE(");
06970                         break;
06971                     case IS_XMLPI:
06972                         appendStringInfoString(buf, "XMLPI(");
06973                         break;
06974                     case IS_XMLROOT:
06975                         appendStringInfoString(buf, "XMLROOT(");
06976                         break;
06977                     case IS_XMLSERIALIZE:
06978                         appendStringInfoString(buf, "XMLSERIALIZE(");
06979                         break;
06980                     case IS_DOCUMENT:
06981                         break;
06982                 }
06983                 if (xexpr->op == IS_XMLPARSE || xexpr->op == IS_XMLSERIALIZE)
06984                 {
06985                     if (xexpr->xmloption == XMLOPTION_DOCUMENT)
06986                         appendStringInfoString(buf, "DOCUMENT ");
06987                     else
06988                         appendStringInfoString(buf, "CONTENT ");
06989                 }
06990                 if (xexpr->name)
06991                 {
06992                     appendStringInfo(buf, "NAME %s",
06993                                      quote_identifier(map_xml_name_to_sql_identifier(xexpr->name)));
06994                     needcomma = true;
06995                 }
06996                 if (xexpr->named_args)
06997                 {
06998                     if (xexpr->op != IS_XMLFOREST)
06999                     {
07000                         if (needcomma)
07001                             appendStringInfoString(buf, ", ");
07002                         appendStringInfoString(buf, "XMLATTRIBUTES(");
07003                         needcomma = false;
07004                     }
07005                     forboth(arg, xexpr->named_args, narg, xexpr->arg_names)
07006                     {
07007                         Node       *e = (Node *) lfirst(arg);
07008                         char       *argname = strVal(lfirst(narg));
07009 
07010                         if (needcomma)
07011                             appendStringInfoString(buf, ", ");
07012                         get_rule_expr((Node *) e, context, true);
07013                         appendStringInfo(buf, " AS %s",
07014                                          quote_identifier(map_xml_name_to_sql_identifier(argname)));
07015                         needcomma = true;
07016                     }
07017                     if (xexpr->op != IS_XMLFOREST)
07018                         appendStringInfoChar(buf, ')');
07019                 }
07020                 if (xexpr->args)
07021                 {
07022                     if (needcomma)
07023                         appendStringInfoString(buf, ", ");
07024                     switch (xexpr->op)
07025                     {
07026                         case IS_XMLCONCAT:
07027                         case IS_XMLELEMENT:
07028                         case IS_XMLFOREST:
07029                         case IS_XMLPI:
07030                         case IS_XMLSERIALIZE:
07031                             /* no extra decoration needed */
07032                             get_rule_expr((Node *) xexpr->args, context, true);
07033                             break;
07034                         case IS_XMLPARSE:
07035                             Assert(list_length(xexpr->args) == 2);
07036 
07037                             get_rule_expr((Node *) linitial(xexpr->args),
07038                                           context, true);
07039 
07040                             con = (Const *) lsecond(xexpr->args);
07041                             Assert(IsA(con, Const));
07042                             Assert(!con->constisnull);
07043                             if (DatumGetBool(con->constvalue))
07044                                 appendStringInfoString(buf,
07045                                                      " PRESERVE WHITESPACE");
07046                             else
07047                                 appendStringInfoString(buf,
07048                                                        " STRIP WHITESPACE");
07049                             break;
07050                         case IS_XMLROOT:
07051                             Assert(list_length(xexpr->args) == 3);
07052 
07053                             get_rule_expr((Node *) linitial(xexpr->args),
07054                                           context, true);
07055 
07056                             appendStringInfoString(buf, ", VERSION ");
07057                             con = (Const *) lsecond(xexpr->args);
07058                             if (IsA(con, Const) &&
07059                                 con->constisnull)
07060                                 appendStringInfoString(buf, "NO VALUE");
07061                             else
07062                                 get_rule_expr((Node *) con, context, false);
07063 
07064                             con = (Const *) lthird(xexpr->args);
07065                             Assert(IsA(con, Const));
07066                             if (con->constisnull)
07067                                  /* suppress STANDALONE NO VALUE */ ;
07068                             else
07069                             {
07070                                 switch (DatumGetInt32(con->constvalue))
07071                                 {
07072                                     case XML_STANDALONE_YES:
07073                                         appendStringInfoString(buf,
07074                                                          ", STANDALONE YES");
07075                                         break;
07076                                     case XML_STANDALONE_NO:
07077                                         appendStringInfoString(buf,
07078                                                           ", STANDALONE NO");
07079                                         break;
07080                                     case XML_STANDALONE_NO_VALUE:
07081                                         appendStringInfoString(buf,
07082                                                     ", STANDALONE NO VALUE");
07083                                         break;
07084                                     default:
07085                                         break;
07086                                 }
07087                             }
07088                             break;
07089                         case IS_DOCUMENT:
07090                             get_rule_expr_paren((Node *) xexpr->args, context, false, node);
07091                             break;
07092                     }
07093 
07094                 }
07095                 if (xexpr->op == IS_XMLSERIALIZE)
07096                     appendStringInfo(buf, " AS %s",
07097                                      format_type_with_typemod(xexpr->type,
07098                                                               xexpr->typmod));
07099                 if (xexpr->op == IS_DOCUMENT)
07100                     appendStringInfoString(buf, " IS DOCUMENT");
07101                 else
07102                     appendStringInfoChar(buf, ')');
07103             }
07104             break;
07105 
07106         case T_NullTest:
07107             {
07108                 NullTest   *ntest = (NullTest *) node;
07109 
07110                 if (!PRETTY_PAREN(context))
07111                     appendStringInfoChar(buf, '(');
07112                 get_rule_expr_paren((Node *) ntest->arg, context, true, node);
07113                 switch (ntest->nulltesttype)
07114                 {
07115                     case IS_NULL:
07116                         appendStringInfo(buf, " IS NULL");
07117                         break;
07118                     case IS_NOT_NULL:
07119                         appendStringInfo(buf, " IS NOT NULL");
07120                         break;
07121                     default:
07122                         elog(ERROR, "unrecognized nulltesttype: %d",
07123                              (int) ntest->nulltesttype);
07124                 }
07125                 if (!PRETTY_PAREN(context))
07126                     appendStringInfoChar(buf, ')');
07127             }
07128             break;
07129 
07130         case T_BooleanTest:
07131             {
07132                 BooleanTest *btest = (BooleanTest *) node;
07133 
07134                 if (!PRETTY_PAREN(context))
07135                     appendStringInfoChar(buf, '(');
07136                 get_rule_expr_paren((Node *) btest->arg, context, false, node);
07137                 switch (btest->booltesttype)
07138                 {
07139                     case IS_TRUE:
07140                         appendStringInfo(buf, " IS TRUE");
07141                         break;
07142                     case IS_NOT_TRUE:
07143                         appendStringInfo(buf, " IS NOT TRUE");
07144                         break;
07145                     case IS_FALSE:
07146                         appendStringInfo(buf, " IS FALSE");
07147                         break;
07148                     case IS_NOT_FALSE:
07149                         appendStringInfo(buf, " IS NOT FALSE");
07150                         break;
07151                     case IS_UNKNOWN:
07152                         appendStringInfo(buf, " IS UNKNOWN");
07153                         break;
07154                     case IS_NOT_UNKNOWN:
07155                         appendStringInfo(buf, " IS NOT UNKNOWN");
07156                         break;
07157                     default:
07158                         elog(ERROR, "unrecognized booltesttype: %d",
07159                              (int) btest->booltesttype);
07160                 }
07161                 if (!PRETTY_PAREN(context))
07162                     appendStringInfoChar(buf, ')');
07163             }
07164             break;
07165 
07166         case T_CoerceToDomain:
07167             {
07168                 CoerceToDomain *ctest = (CoerceToDomain *) node;
07169                 Node       *arg = (Node *) ctest->arg;
07170 
07171                 if (ctest->coercionformat == COERCE_IMPLICIT_CAST &&
07172                     !showimplicit)
07173                 {
07174                     /* don't show the implicit cast */
07175                     get_rule_expr(arg, context, false);
07176                 }
07177                 else
07178                 {
07179                     get_coercion_expr(arg, context,
07180                                       ctest->resulttype,
07181                                       ctest->resulttypmod,
07182                                       node);
07183                 }
07184             }
07185             break;
07186 
07187         case T_CoerceToDomainValue:
07188             appendStringInfo(buf, "VALUE");
07189             break;
07190 
07191         case T_SetToDefault:
07192             appendStringInfo(buf, "DEFAULT");
07193             break;
07194 
07195         case T_CurrentOfExpr:
07196             {
07197                 CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
07198 
07199                 if (cexpr->cursor_name)
07200                     appendStringInfo(buf, "CURRENT OF %s",
07201                                      quote_identifier(cexpr->cursor_name));
07202                 else
07203                     appendStringInfo(buf, "CURRENT OF $%d",
07204                                      cexpr->cursor_param);
07205             }
07206             break;
07207 
07208         case T_List:
07209             {
07210                 char       *sep;
07211                 ListCell   *l;
07212 
07213                 sep = "";
07214                 foreach(l, (List *) node)
07215                 {
07216                     appendStringInfoString(buf, sep);
07217                     get_rule_expr((Node *) lfirst(l), context, showimplicit);
07218                     sep = ", ";
07219                 }
07220             }
07221             break;
07222 
07223         default:
07224             elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
07225             break;
07226     }
07227 }
07228 
07229 
07230 /*
07231  * get_oper_expr            - Parse back an OpExpr node
07232  */
07233 static void
07234 get_oper_expr(OpExpr *expr, deparse_context *context)
07235 {
07236     StringInfo  buf = context->buf;
07237     Oid         opno = expr->opno;
07238     List       *args = expr->args;
07239 
07240     if (!PRETTY_PAREN(context))
07241         appendStringInfoChar(buf, '(');
07242     if (list_length(args) == 2)
07243     {
07244         /* binary operator */
07245         Node       *arg1 = (Node *) linitial(args);
07246         Node       *arg2 = (Node *) lsecond(args);
07247 
07248         get_rule_expr_paren(arg1, context, true, (Node *) expr);
07249         appendStringInfo(buf, " %s ",
07250                          generate_operator_name(opno,
07251                                                 exprType(arg1),
07252                                                 exprType(arg2)));
07253         get_rule_expr_paren(arg2, context, true, (Node *) expr);
07254     }
07255     else
07256     {
07257         /* unary operator --- but which side? */
07258         Node       *arg = (Node *) linitial(args);
07259         HeapTuple   tp;
07260         Form_pg_operator optup;
07261 
07262         tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
07263         if (!HeapTupleIsValid(tp))
07264             elog(ERROR, "cache lookup failed for operator %u", opno);
07265         optup = (Form_pg_operator) GETSTRUCT(tp);
07266         switch (optup->oprkind)
07267         {
07268             case 'l':
07269                 appendStringInfo(buf, "%s ",
07270                                  generate_operator_name(opno,
07271                                                         InvalidOid,
07272                                                         exprType(arg)));
07273                 get_rule_expr_paren(arg, context, true, (Node *) expr);
07274                 break;
07275             case 'r':
07276                 get_rule_expr_paren(arg, context, true, (Node *) expr);
07277                 appendStringInfo(buf, " %s",
07278                                  generate_operator_name(opno,
07279                                                         exprType(arg),
07280                                                         InvalidOid));
07281                 break;
07282             default:
07283                 elog(ERROR, "bogus oprkind: %d", optup->oprkind);
07284         }
07285         ReleaseSysCache(tp);
07286     }
07287     if (!PRETTY_PAREN(context))
07288         appendStringInfoChar(buf, ')');
07289 }
07290 
07291 /*
07292  * get_func_expr            - Parse back a FuncExpr node
07293  */
07294 static void
07295 get_func_expr(FuncExpr *expr, deparse_context *context,
07296               bool showimplicit)
07297 {
07298     StringInfo  buf = context->buf;
07299     Oid         funcoid = expr->funcid;
07300     Oid         argtypes[FUNC_MAX_ARGS];
07301     int         nargs;
07302     List       *argnames;
07303     bool        use_variadic;
07304     ListCell   *l;
07305 
07306     /*
07307      * If the function call came from an implicit coercion, then just show the
07308      * first argument --- unless caller wants to see implicit coercions.
07309      */
07310     if (expr->funcformat == COERCE_IMPLICIT_CAST && !showimplicit)
07311     {
07312         get_rule_expr_paren((Node *) linitial(expr->args), context,
07313                             false, (Node *) expr);
07314         return;
07315     }
07316 
07317     /*
07318      * If the function call came from a cast, then show the first argument
07319      * plus an explicit cast operation.
07320      */
07321     if (expr->funcformat == COERCE_EXPLICIT_CAST ||
07322         expr->funcformat == COERCE_IMPLICIT_CAST)
07323     {
07324         Node       *arg = linitial(expr->args);
07325         Oid         rettype = expr->funcresulttype;
07326         int32       coercedTypmod;
07327 
07328         /* Get the typmod if this is a length-coercion function */
07329         (void) exprIsLengthCoercion((Node *) expr, &coercedTypmod);
07330 
07331         get_coercion_expr(arg, context,
07332                           rettype, coercedTypmod,
07333                           (Node *) expr);
07334 
07335         return;
07336     }
07337 
07338     /*
07339      * Normal function: display as proname(args).  First we need to extract
07340      * the argument datatypes.
07341      */
07342     if (list_length(expr->args) > FUNC_MAX_ARGS)
07343         ereport(ERROR,
07344                 (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
07345                  errmsg("too many arguments")));
07346     nargs = 0;
07347     argnames = NIL;
07348     foreach(l, expr->args)
07349     {
07350         Node       *arg = (Node *) lfirst(l);
07351 
07352         if (IsA(arg, NamedArgExpr))
07353             argnames = lappend(argnames, ((NamedArgExpr *) arg)->name);
07354         argtypes[nargs] = exprType(arg);
07355         nargs++;
07356     }
07357 
07358     appendStringInfo(buf, "%s(",
07359                      generate_function_name(funcoid, nargs,
07360                                             argnames, argtypes,
07361                                             expr->funcvariadic,
07362                                             &use_variadic));
07363     nargs = 0;
07364     foreach(l, expr->args)
07365     {
07366         if (nargs++ > 0)
07367             appendStringInfoString(buf, ", ");
07368         if (use_variadic && lnext(l) == NULL)
07369             appendStringInfoString(buf, "VARIADIC ");
07370         get_rule_expr((Node *) lfirst(l), context, true);
07371     }
07372     appendStringInfoChar(buf, ')');
07373 }
07374 
07375 /*
07376  * get_agg_expr         - Parse back an Aggref node
07377  */
07378 static void
07379 get_agg_expr(Aggref *aggref, deparse_context *context)
07380 {
07381     StringInfo  buf = context->buf;
07382     Oid         argtypes[FUNC_MAX_ARGS];
07383     List       *arglist;
07384     int         nargs;
07385     ListCell   *l;
07386 
07387     /* Extract the regular arguments, ignoring resjunk stuff for the moment */
07388     arglist = NIL;
07389     nargs = 0;
07390     foreach(l, aggref->args)
07391     {
07392         TargetEntry *tle = (TargetEntry *) lfirst(l);
07393         Node       *arg = (Node *) tle->expr;
07394 
07395         Assert(!IsA(arg, NamedArgExpr));
07396         if (tle->resjunk)
07397             continue;
07398         if (nargs >= FUNC_MAX_ARGS)     /* paranoia */
07399             ereport(ERROR,
07400                     (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
07401                      errmsg("too many arguments")));
07402         argtypes[nargs] = exprType(arg);
07403         arglist = lappend(arglist, arg);
07404         nargs++;
07405     }
07406 
07407     appendStringInfo(buf, "%s(%s",
07408                      generate_function_name(aggref->aggfnoid, nargs,
07409                                             NIL, argtypes,
07410                                             false, NULL),
07411                      (aggref->aggdistinct != NIL) ? "DISTINCT " : "");
07412     /* aggstar can be set only in zero-argument aggregates */
07413     if (aggref->aggstar)
07414         appendStringInfoChar(buf, '*');
07415     else
07416         get_rule_expr((Node *) arglist, context, true);
07417     if (aggref->aggorder != NIL)
07418     {
07419         appendStringInfoString(buf, " ORDER BY ");
07420         get_rule_orderby(aggref->aggorder, aggref->args, false, context);
07421     }
07422     appendStringInfoChar(buf, ')');
07423 }
07424 
07425 /*
07426  * get_windowfunc_expr  - Parse back a WindowFunc node
07427  */
07428 static void
07429 get_windowfunc_expr(WindowFunc *wfunc, deparse_context *context)
07430 {
07431     StringInfo  buf = context->buf;
07432     Oid         argtypes[FUNC_MAX_ARGS];
07433     int         nargs;
07434     ListCell   *l;
07435 
07436     if (list_length(wfunc->args) > FUNC_MAX_ARGS)
07437         ereport(ERROR,
07438                 (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
07439                  errmsg("too many arguments")));
07440     nargs = 0;
07441     foreach(l, wfunc->args)
07442     {
07443         Node       *arg = (Node *) lfirst(l);
07444 
07445         Assert(!IsA(arg, NamedArgExpr));
07446         argtypes[nargs] = exprType(arg);
07447         nargs++;
07448     }
07449 
07450     appendStringInfo(buf, "%s(",
07451                      generate_function_name(wfunc->winfnoid, nargs,
07452                                             NIL, argtypes,
07453                                             false, NULL));
07454     /* winstar can be set only in zero-argument aggregates */
07455     if (wfunc->winstar)
07456         appendStringInfoChar(buf, '*');
07457     else
07458         get_rule_expr((Node *) wfunc->args, context, true);
07459     appendStringInfoString(buf, ") OVER ");
07460 
07461     foreach(l, context->windowClause)
07462     {
07463         WindowClause *wc = (WindowClause *) lfirst(l);
07464 
07465         if (wc->winref == wfunc->winref)
07466         {
07467             if (wc->name)
07468                 appendStringInfoString(buf, quote_identifier(wc->name));
07469             else
07470                 get_rule_windowspec(wc, context->windowTList, context);
07471             break;
07472         }
07473     }
07474     if (l == NULL)
07475     {
07476         if (context->windowClause)
07477             elog(ERROR, "could not find window clause for winref %u",
07478                  wfunc->winref);
07479 
07480         /*
07481          * In EXPLAIN, we don't have window context information available, so
07482          * we have to settle for this:
07483          */
07484         appendStringInfoString(buf, "(?)");
07485     }
07486 }
07487 
07488 /* ----------
07489  * get_coercion_expr
07490  *
07491  *  Make a string representation of a value coerced to a specific type
07492  * ----------
07493  */
07494 static void
07495 get_coercion_expr(Node *arg, deparse_context *context,
07496                   Oid resulttype, int32 resulttypmod,
07497                   Node *parentNode)
07498 {
07499     StringInfo  buf = context->buf;
07500 
07501     /*
07502      * Since parse_coerce.c doesn't immediately collapse application of
07503      * length-coercion functions to constants, what we'll typically see in
07504      * such cases is a Const with typmod -1 and a length-coercion function
07505      * right above it.  Avoid generating redundant output. However, beware of
07506      * suppressing casts when the user actually wrote something like
07507      * 'foo'::text::char(3).
07508      */
07509     if (arg && IsA(arg, Const) &&
07510         ((Const *) arg)->consttype == resulttype &&
07511         ((Const *) arg)->consttypmod == -1)
07512     {
07513         /* Show the constant without normal ::typename decoration */
07514         get_const_expr((Const *) arg, context, -1);
07515     }
07516     else
07517     {
07518         if (!PRETTY_PAREN(context))
07519             appendStringInfoChar(buf, '(');
07520         get_rule_expr_paren(arg, context, false, parentNode);
07521         if (!PRETTY_PAREN(context))
07522             appendStringInfoChar(buf, ')');
07523     }
07524     appendStringInfo(buf, "::%s",
07525                      format_type_with_typemod(resulttype, resulttypmod));
07526 }
07527 
07528 /* ----------
07529  * get_const_expr
07530  *
07531  *  Make a string representation of a Const
07532  *
07533  * showtype can be -1 to never show "::typename" decoration, or +1 to always
07534  * show it, or 0 to show it only if the constant wouldn't be assumed to be
07535  * the right type by default.
07536  *
07537  * If the Const's collation isn't default for its type, show that too.
07538  * This can only happen in trees that have been through constant-folding.
07539  * We assume we don't need to do this when showtype is -1.
07540  * ----------
07541  */
07542 static void
07543 get_const_expr(Const *constval, deparse_context *context, int showtype)
07544 {
07545     StringInfo  buf = context->buf;
07546     Oid         typoutput;
07547     bool        typIsVarlena;
07548     char       *extval;
07549     bool        isfloat = false;
07550     bool        needlabel;
07551 
07552     if (constval->constisnull)
07553     {
07554         /*
07555          * Always label the type of a NULL constant to prevent misdecisions
07556          * about type when reparsing.
07557          */
07558         appendStringInfo(buf, "NULL");
07559         if (showtype >= 0)
07560         {
07561             appendStringInfo(buf, "::%s",
07562                              format_type_with_typemod(constval->consttype,
07563                                                       constval->consttypmod));
07564             get_const_collation(constval, context);
07565         }
07566         return;
07567     }
07568 
07569     getTypeOutputInfo(constval->consttype,
07570                       &typoutput, &typIsVarlena);
07571 
07572     extval = OidOutputFunctionCall(typoutput, constval->constvalue);
07573 
07574     switch (constval->consttype)
07575     {
07576         case INT2OID:
07577         case INT4OID:
07578         case INT8OID:
07579         case OIDOID:
07580         case FLOAT4OID:
07581         case FLOAT8OID:
07582         case NUMERICOID:
07583             {
07584                 /*
07585                  * These types are printed without quotes unless they contain
07586                  * values that aren't accepted by the scanner unquoted (e.g.,
07587                  * 'NaN').  Note that strtod() and friends might accept NaN,
07588                  * so we can't use that to test.
07589                  *
07590                  * In reality we only need to defend against infinity and NaN,
07591                  * so we need not get too crazy about pattern matching here.
07592                  *
07593                  * There is a special-case gotcha: if the constant is signed,
07594                  * we need to parenthesize it, else the parser might see a
07595                  * leading plus/minus as binding less tightly than adjacent
07596                  * operators --- particularly, the cast that we might attach
07597                  * below.
07598                  */
07599                 if (strspn(extval, "0123456789+-eE.") == strlen(extval))
07600                 {
07601                     if (extval[0] == '+' || extval[0] == '-')
07602                         appendStringInfo(buf, "(%s)", extval);
07603                     else
07604                         appendStringInfoString(buf, extval);
07605                     if (strcspn(extval, "eE.") != strlen(extval))
07606                         isfloat = true; /* it looks like a float */
07607                 }
07608                 else
07609                     appendStringInfo(buf, "'%s'", extval);
07610             }
07611             break;
07612 
07613         case BITOID:
07614         case VARBITOID:
07615             appendStringInfo(buf, "B'%s'", extval);
07616             break;
07617 
07618         case BOOLOID:
07619             if (strcmp(extval, "t") == 0)
07620                 appendStringInfo(buf, "true");
07621             else
07622                 appendStringInfo(buf, "false");
07623             break;
07624 
07625         default:
07626             simple_quote_literal(buf, extval);
07627             break;
07628     }
07629 
07630     pfree(extval);
07631 
07632     if (showtype < 0)
07633         return;
07634 
07635     /*
07636      * For showtype == 0, append ::typename unless the constant will be
07637      * implicitly typed as the right type when it is read in.
07638      *
07639      * XXX this code has to be kept in sync with the behavior of the parser,
07640      * especially make_const.
07641      */
07642     switch (constval->consttype)
07643     {
07644         case BOOLOID:
07645         case INT4OID:
07646         case UNKNOWNOID:
07647             /* These types can be left unlabeled */
07648             needlabel = false;
07649             break;
07650         case NUMERICOID:
07651 
07652             /*
07653              * Float-looking constants will be typed as numeric, but if
07654              * there's a specific typmod we need to show it.
07655              */
07656             needlabel = !isfloat || (constval->consttypmod >= 0);
07657             break;
07658         default:
07659             needlabel = true;
07660             break;
07661     }
07662     if (needlabel || showtype > 0)
07663         appendStringInfo(buf, "::%s",
07664                          format_type_with_typemod(constval->consttype,
07665                                                   constval->consttypmod));
07666 
07667     get_const_collation(constval, context);
07668 }
07669 
07670 /*
07671  * helper for get_const_expr: append COLLATE if needed
07672  */
07673 static void
07674 get_const_collation(Const *constval, deparse_context *context)
07675 {
07676     StringInfo  buf = context->buf;
07677 
07678     if (OidIsValid(constval->constcollid))
07679     {
07680         Oid         typcollation = get_typcollation(constval->consttype);
07681 
07682         if (constval->constcollid != typcollation)
07683         {
07684             appendStringInfo(buf, " COLLATE %s",
07685                              generate_collation_name(constval->constcollid));
07686         }
07687     }
07688 }
07689 
07690 /*
07691  * simple_quote_literal - Format a string as a SQL literal, append to buf
07692  */
07693 static void
07694 simple_quote_literal(StringInfo buf, const char *val)
07695 {
07696     const char *valptr;
07697 
07698     /*
07699      * We form the string literal according to the prevailing setting of
07700      * standard_conforming_strings; we never use E''. User is responsible for
07701      * making sure result is used correctly.
07702      */
07703     appendStringInfoChar(buf, '\'');
07704     for (valptr = val; *valptr; valptr++)
07705     {
07706         char        ch = *valptr;
07707 
07708         if (SQL_STR_DOUBLE(ch, !standard_conforming_strings))
07709             appendStringInfoChar(buf, ch);
07710         appendStringInfoChar(buf, ch);
07711     }
07712     appendStringInfoChar(buf, '\'');
07713 }
07714 
07715 
07716 /* ----------
07717  * get_sublink_expr         - Parse back a sublink
07718  * ----------
07719  */
07720 static void
07721 get_sublink_expr(SubLink *sublink, deparse_context *context)
07722 {
07723     StringInfo  buf = context->buf;
07724     Query      *query = (Query *) (sublink->subselect);
07725     char       *opname = NULL;
07726     bool        need_paren;
07727 
07728     if (sublink->subLinkType == ARRAY_SUBLINK)
07729         appendStringInfo(buf, "ARRAY(");
07730     else
07731         appendStringInfoChar(buf, '(');
07732 
07733     /*
07734      * Note that we print the name of only the first operator, when there are
07735      * multiple combining operators.  This is an approximation that could go
07736      * wrong in various scenarios (operators in different schemas, renamed
07737      * operators, etc) but there is not a whole lot we can do about it, since
07738      * the syntax allows only one operator to be shown.
07739      */
07740     if (sublink->testexpr)
07741     {
07742         if (IsA(sublink->testexpr, OpExpr))
07743         {
07744             /* single combining operator */
07745             OpExpr     *opexpr = (OpExpr *) sublink->testexpr;
07746 
07747             get_rule_expr(linitial(opexpr->args), context, true);
07748             opname = generate_operator_name(opexpr->opno,
07749                                             exprType(linitial(opexpr->args)),
07750                                             exprType(lsecond(opexpr->args)));
07751         }
07752         else if (IsA(sublink->testexpr, BoolExpr))
07753         {
07754             /* multiple combining operators, = or <> cases */
07755             char       *sep;
07756             ListCell   *l;
07757 
07758             appendStringInfoChar(buf, '(');
07759             sep = "";
07760             foreach(l, ((BoolExpr *) sublink->testexpr)->args)
07761             {
07762                 OpExpr     *opexpr = (OpExpr *) lfirst(l);
07763 
07764                 Assert(IsA(opexpr, OpExpr));
07765                 appendStringInfoString(buf, sep);
07766                 get_rule_expr(linitial(opexpr->args), context, true);
07767                 if (!opname)
07768                     opname = generate_operator_name(opexpr->opno,
07769                                             exprType(linitial(opexpr->args)),
07770                                             exprType(lsecond(opexpr->args)));
07771                 sep = ", ";
07772             }
07773             appendStringInfoChar(buf, ')');
07774         }
07775         else if (IsA(sublink->testexpr, RowCompareExpr))
07776         {
07777             /* multiple combining operators, < <= > >= cases */
07778             RowCompareExpr *rcexpr = (RowCompareExpr *) sublink->testexpr;
07779 
07780             appendStringInfoChar(buf, '(');
07781             get_rule_expr((Node *) rcexpr->largs, context, true);
07782             opname = generate_operator_name(linitial_oid(rcexpr->opnos),
07783                                             exprType(linitial(rcexpr->largs)),
07784                                           exprType(linitial(rcexpr->rargs)));
07785             appendStringInfoChar(buf, ')');
07786         }
07787         else
07788             elog(ERROR, "unrecognized testexpr type: %d",
07789                  (int) nodeTag(sublink->testexpr));
07790     }
07791 
07792     need_paren = true;
07793 
07794     switch (sublink->subLinkType)
07795     {
07796         case EXISTS_SUBLINK:
07797             appendStringInfo(buf, "EXISTS ");
07798             break;
07799 
07800         case ANY_SUBLINK:
07801             if (strcmp(opname, "=") == 0)       /* Represent = ANY as IN */
07802                 appendStringInfo(buf, " IN ");
07803             else
07804                 appendStringInfo(buf, " %s ANY ", opname);
07805             break;
07806 
07807         case ALL_SUBLINK:
07808             appendStringInfo(buf, " %s ALL ", opname);
07809             break;
07810 
07811         case ROWCOMPARE_SUBLINK:
07812             appendStringInfo(buf, " %s ", opname);
07813             break;
07814 
07815         case EXPR_SUBLINK:
07816         case ARRAY_SUBLINK:
07817             need_paren = false;
07818             break;
07819 
07820         case CTE_SUBLINK:       /* shouldn't occur in a SubLink */
07821         default:
07822             elog(ERROR, "unrecognized sublink type: %d",
07823                  (int) sublink->subLinkType);
07824             break;
07825     }
07826 
07827     if (need_paren)
07828         appendStringInfoChar(buf, '(');
07829 
07830     get_query_def(query, buf, context->namespaces, NULL,
07831                   context->prettyFlags, context->wrapColumn,
07832                   context->indentLevel);
07833 
07834     if (need_paren)
07835         appendStringInfo(buf, "))");
07836     else
07837         appendStringInfoChar(buf, ')');
07838 }
07839 
07840 
07841 /* ----------
07842  * get_from_clause          - Parse back a FROM clause
07843  *
07844  * "prefix" is the keyword that denotes the start of the list of FROM
07845  * elements. It is FROM when used to parse back SELECT and UPDATE, but
07846  * is USING when parsing back DELETE.
07847  * ----------
07848  */
07849 static void
07850 get_from_clause(Query *query, const char *prefix, deparse_context *context)
07851 {
07852     StringInfo  buf = context->buf;
07853     bool        first = true;
07854     ListCell   *l;
07855 
07856     /*
07857      * We use the query's jointree as a guide to what to print.  However, we
07858      * must ignore auto-added RTEs that are marked not inFromCl. (These can
07859      * only appear at the top level of the jointree, so it's sufficient to
07860      * check here.)  This check also ensures we ignore the rule pseudo-RTEs
07861      * for NEW and OLD.
07862      */
07863     foreach(l, query->jointree->fromlist)
07864     {
07865         Node       *jtnode = (Node *) lfirst(l);
07866 
07867         if (IsA(jtnode, RangeTblRef))
07868         {
07869             int         varno = ((RangeTblRef *) jtnode)->rtindex;
07870             RangeTblEntry *rte = rt_fetch(varno, query->rtable);
07871 
07872             if (!rte->inFromCl)
07873                 continue;
07874         }
07875 
07876         if (first)
07877         {
07878             appendContextKeyword(context, prefix,
07879                                  -PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
07880             first = false;
07881 
07882             get_from_clause_item(jtnode, query, context);
07883         }
07884         else
07885         {
07886             StringInfoData itembuf;
07887 
07888             appendStringInfoString(buf, ", ");
07889 
07890             /*
07891              * Put the new FROM item's text into itembuf so we can decide
07892              * after we've got it whether or not it needs to go on a new line.
07893              */
07894             initStringInfo(&itembuf);
07895             context->buf = &itembuf;
07896 
07897             get_from_clause_item(jtnode, query, context);
07898 
07899             /* Restore context's output buffer */
07900             context->buf = buf;
07901 
07902             /* Consider line-wrapping if enabled */
07903             if (PRETTY_INDENT(context) && context->wrapColumn >= 0)
07904             {
07905                 char       *trailing_nl;
07906 
07907                 /* Locate the start of the current line in the buffer */
07908                 trailing_nl = strrchr(buf->data, '\n');
07909                 if (trailing_nl == NULL)
07910                     trailing_nl = buf->data;
07911                 else
07912                     trailing_nl++;
07913 
07914                 /*
07915                  * Add a newline, plus some indentation, if the new item would
07916                  * cause an overflow.
07917                  */
07918                 if (strlen(trailing_nl) + strlen(itembuf.data) > context->wrapColumn)
07919                     appendContextKeyword(context, "", -PRETTYINDENT_STD,
07920                                          PRETTYINDENT_STD, PRETTYINDENT_VAR);
07921             }
07922 
07923             /* Add the new item */
07924             appendStringInfoString(buf, itembuf.data);
07925 
07926             /* clean up */
07927             pfree(itembuf.data);
07928         }
07929     }
07930 }
07931 
07932 static void
07933 get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
07934 {
07935     StringInfo  buf = context->buf;
07936     deparse_namespace *dpns = (deparse_namespace *) linitial(context->namespaces);
07937 
07938     if (IsA(jtnode, RangeTblRef))
07939     {
07940         int         varno = ((RangeTblRef *) jtnode)->rtindex;
07941         RangeTblEntry *rte = rt_fetch(varno, query->rtable);
07942         char       *refname = get_rtable_name(varno, context);
07943         deparse_columns *colinfo = deparse_columns_fetch(varno, dpns);
07944         bool        printalias;
07945 
07946         if (rte->lateral)
07947             appendStringInfoString(buf, "LATERAL ");
07948 
07949         /* Print the FROM item proper */
07950         switch (rte->rtekind)
07951         {
07952             case RTE_RELATION:
07953                 /* Normal relation RTE */
07954                 appendStringInfo(buf, "%s%s",
07955                                  only_marker(rte),
07956                                  generate_relation_name(rte->relid,
07957                                                         context->namespaces));
07958                 break;
07959             case RTE_SUBQUERY:
07960                 /* Subquery RTE */
07961                 appendStringInfoChar(buf, '(');
07962                 get_query_def(rte->subquery, buf, context->namespaces, NULL,
07963                               context->prettyFlags, context->wrapColumn,
07964                               context->indentLevel);
07965                 appendStringInfoChar(buf, ')');
07966                 break;
07967             case RTE_FUNCTION:
07968                 /* Function RTE */
07969                 get_rule_expr(rte->funcexpr, context, true);
07970                 break;
07971             case RTE_VALUES:
07972                 /* Values list RTE */
07973                 get_values_def(rte->values_lists, context);
07974                 break;
07975             case RTE_CTE:
07976                 appendStringInfoString(buf, quote_identifier(rte->ctename));
07977                 break;
07978             default:
07979                 elog(ERROR, "unrecognized RTE kind: %d", (int) rte->rtekind);
07980                 break;
07981         }
07982 
07983         /* Print the relation alias, if needed */
07984         printalias = false;
07985         if (rte->alias != NULL)
07986         {
07987             /* Always print alias if user provided one */
07988             printalias = true;
07989         }
07990         else if (colinfo->printaliases)
07991         {
07992             /* Always print alias if we need to print column aliases */
07993             printalias = true;
07994         }
07995         else if (rte->rtekind == RTE_RELATION)
07996         {
07997             /*
07998              * No need to print alias if it's same as relation name (this
07999              * would normally be the case, but not if set_rtable_names had to
08000              * resolve a conflict).
08001              */
08002             if (strcmp(refname, get_relation_name(rte->relid)) != 0)
08003                 printalias = true;
08004         }
08005         else if (rte->rtekind == RTE_FUNCTION)
08006         {
08007             /*
08008              * For a function RTE, always print alias.  This covers possible
08009              * renaming of the function and/or instability of the
08010              * FigureColname rules for things that aren't simple functions.
08011              * Also note we'd need to force it anyway for the RECORD case.
08012              */
08013             printalias = true;
08014         }
08015         else if (rte->rtekind == RTE_CTE)
08016         {
08017             /*
08018              * No need to print alias if it's same as CTE name (this would
08019              * normally be the case, but not if set_rtable_names had to
08020              * resolve a conflict).
08021              */
08022             if (strcmp(refname, rte->ctename) != 0)
08023                 printalias = true;
08024         }
08025         if (printalias)
08026             appendStringInfo(buf, " %s", quote_identifier(refname));
08027 
08028         /* Print the column definitions or aliases, if needed */
08029         if (rte->rtekind == RTE_FUNCTION && rte->funccoltypes != NIL)
08030         {
08031             /* Function returning RECORD, reconstruct the columndefs */
08032             get_from_clause_coldeflist(colinfo,
08033                                        rte->funccoltypes,
08034                                        rte->funccoltypmods,
08035                                        rte->funccolcollations,
08036                                        context);
08037         }
08038         else
08039         {
08040             /* Else print column aliases as needed */
08041             get_column_alias_list(colinfo, context);
08042         }
08043     }
08044     else if (IsA(jtnode, JoinExpr))
08045     {
08046         JoinExpr   *j = (JoinExpr *) jtnode;
08047         deparse_columns *colinfo = deparse_columns_fetch(j->rtindex, dpns);
08048         bool        need_paren_on_right;
08049 
08050         need_paren_on_right = PRETTY_PAREN(context) &&
08051             !IsA(j->rarg, RangeTblRef) &&
08052             !(IsA(j->rarg, JoinExpr) &&((JoinExpr *) j->rarg)->alias != NULL);
08053 
08054         if (!PRETTY_PAREN(context) || j->alias != NULL)
08055             appendStringInfoChar(buf, '(');
08056 
08057         get_from_clause_item(j->larg, query, context);
08058 
08059         switch (j->jointype)
08060         {
08061             case JOIN_INNER:
08062                 if (j->quals)
08063                     appendContextKeyword(context, " JOIN ",
08064                                          -PRETTYINDENT_JOIN,
08065                                          PRETTYINDENT_JOIN, 2);
08066                 else
08067                     appendContextKeyword(context, " CROSS JOIN ",
08068                                          -PRETTYINDENT_JOIN,
08069                                          PRETTYINDENT_JOIN, 1);
08070                 break;
08071             case JOIN_LEFT:
08072                 appendContextKeyword(context, " LEFT JOIN ",
08073                                      -PRETTYINDENT_JOIN,
08074                                      PRETTYINDENT_JOIN, 2);
08075                 break;
08076             case JOIN_FULL:
08077                 appendContextKeyword(context, " FULL JOIN ",
08078                                      -PRETTYINDENT_JOIN,
08079                                      PRETTYINDENT_JOIN, 2);
08080                 break;
08081             case JOIN_RIGHT:
08082                 appendContextKeyword(context, " RIGHT JOIN ",
08083                                      -PRETTYINDENT_JOIN,
08084                                      PRETTYINDENT_JOIN, 2);
08085                 break;
08086             default:
08087                 elog(ERROR, "unrecognized join type: %d",
08088                      (int) j->jointype);
08089         }
08090 
08091         if (need_paren_on_right)
08092             appendStringInfoChar(buf, '(');
08093         get_from_clause_item(j->rarg, query, context);
08094         if (need_paren_on_right)
08095             appendStringInfoChar(buf, ')');
08096 
08097         context->indentLevel -= PRETTYINDENT_JOIN_ON;
08098 
08099         if (j->usingClause)
08100         {
08101             ListCell   *lc;
08102             bool        first = true;
08103 
08104             appendStringInfo(buf, " USING (");
08105             /* Use the assigned names, not what's in usingClause */
08106             foreach(lc, colinfo->usingNames)
08107             {
08108                 char       *colname = (char *) lfirst(lc);
08109 
08110                 if (first)
08111                     first = false;
08112                 else
08113                     appendStringInfo(buf, ", ");
08114                 appendStringInfoString(buf, quote_identifier(colname));
08115             }
08116             appendStringInfoChar(buf, ')');
08117         }
08118         else if (j->quals)
08119         {
08120             appendStringInfo(buf, " ON ");
08121             if (!PRETTY_PAREN(context))
08122                 appendStringInfoChar(buf, '(');
08123             get_rule_expr(j->quals, context, false);
08124             if (!PRETTY_PAREN(context))
08125                 appendStringInfoChar(buf, ')');
08126         }
08127 
08128         if (!PRETTY_PAREN(context) || j->alias != NULL)
08129             appendStringInfoChar(buf, ')');
08130 
08131         /* Yes, it's correct to put alias after the right paren ... */
08132         if (j->alias != NULL)
08133         {
08134             appendStringInfo(buf, " %s",
08135                              quote_identifier(j->alias->aliasname));
08136             get_column_alias_list(colinfo, context);
08137         }
08138     }
08139     else
08140         elog(ERROR, "unrecognized node type: %d",
08141              (int) nodeTag(jtnode));
08142 }
08143 
08144 /*
08145  * get_column_alias_list - print column alias list for an RTE
08146  *
08147  * Caller must already have printed the relation's alias name.
08148  */
08149 static void
08150 get_column_alias_list(deparse_columns *colinfo, deparse_context *context)
08151 {
08152     StringInfo  buf = context->buf;
08153     int         i;
08154     bool        first = true;
08155 
08156     /* Don't print aliases if not needed */
08157     if (!colinfo->printaliases)
08158         return;
08159 
08160     for (i = 0; i < colinfo->num_new_cols; i++)
08161     {
08162         char       *colname = colinfo->new_colnames[i];
08163 
08164         if (first)
08165         {
08166             appendStringInfoChar(buf, '(');
08167             first = false;
08168         }
08169         else
08170             appendStringInfo(buf, ", ");
08171         appendStringInfoString(buf, quote_identifier(colname));
08172     }
08173     if (!first)
08174         appendStringInfoChar(buf, ')');
08175 }
08176 
08177 /*
08178  * get_from_clause_coldeflist - reproduce FROM clause coldeflist
08179  *
08180  * The coldeflist is appended immediately (no space) to buf.  Caller is
08181  * responsible for ensuring that an alias or AS is present before it.
08182  */
08183 static void
08184 get_from_clause_coldeflist(deparse_columns *colinfo,
08185                            List *types, List *typmods, List *collations,
08186                            deparse_context *context)
08187 {
08188     StringInfo  buf = context->buf;
08189     ListCell   *l1;
08190     ListCell   *l2;
08191     ListCell   *l3;
08192     int         i;
08193 
08194     appendStringInfoChar(buf, '(');
08195 
08196     i = 0;
08197     forthree(l1, types, l2, typmods, l3, collations)
08198     {
08199         char       *attname = colinfo->colnames[i];
08200         Oid         atttypid = lfirst_oid(l1);
08201         int32       atttypmod = lfirst_int(l2);
08202         Oid         attcollation = lfirst_oid(l3);
08203 
08204         Assert(attname);        /* shouldn't be any dropped columns here */
08205 
08206         if (i > 0)
08207             appendStringInfo(buf, ", ");
08208         appendStringInfo(buf, "%s %s",
08209                          quote_identifier(attname),
08210                          format_type_with_typemod(atttypid, atttypmod));
08211         if (OidIsValid(attcollation) &&
08212             attcollation != get_typcollation(atttypid))
08213             appendStringInfo(buf, " COLLATE %s",
08214                              generate_collation_name(attcollation));
08215         i++;
08216     }
08217 
08218     appendStringInfoChar(buf, ')');
08219 }
08220 
08221 /*
08222  * get_opclass_name         - fetch name of an index operator class
08223  *
08224  * The opclass name is appended (after a space) to buf.
08225  *
08226  * Output is suppressed if the opclass is the default for the given
08227  * actual_datatype.  (If you don't want this behavior, just pass
08228  * InvalidOid for actual_datatype.)
08229  */
08230 static void
08231 get_opclass_name(Oid opclass, Oid actual_datatype,
08232                  StringInfo buf)
08233 {
08234     HeapTuple   ht_opc;
08235     Form_pg_opclass opcrec;
08236     char       *opcname;
08237     char       *nspname;
08238 
08239     ht_opc = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
08240     if (!HeapTupleIsValid(ht_opc))
08241         elog(ERROR, "cache lookup failed for opclass %u", opclass);
08242     opcrec = (Form_pg_opclass) GETSTRUCT(ht_opc);
08243 
08244     if (!OidIsValid(actual_datatype) ||
08245         GetDefaultOpClass(actual_datatype, opcrec->opcmethod) != opclass)
08246     {
08247         /* Okay, we need the opclass name.  Do we need to qualify it? */
08248         opcname = NameStr(opcrec->opcname);
08249         if (OpclassIsVisible(opclass))
08250             appendStringInfo(buf, " %s", quote_identifier(opcname));
08251         else
08252         {
08253             nspname = get_namespace_name(opcrec->opcnamespace);
08254             appendStringInfo(buf, " %s.%s",
08255                              quote_identifier(nspname),
08256                              quote_identifier(opcname));
08257         }
08258     }
08259     ReleaseSysCache(ht_opc);
08260 }
08261 
08262 /*
08263  * processIndirection - take care of array and subfield assignment
08264  *
08265  * We strip any top-level FieldStore or assignment ArrayRef nodes that
08266  * appear in the input, and return the subexpression that's to be assigned.
08267  * If printit is true, we also print out the appropriate decoration for the
08268  * base column name (that the caller just printed).
08269  */
08270 static Node *
08271 processIndirection(Node *node, deparse_context *context, bool printit)
08272 {
08273     StringInfo  buf = context->buf;
08274 
08275     for (;;)
08276     {
08277         if (node == NULL)
08278             break;
08279         if (IsA(node, FieldStore))
08280         {
08281             FieldStore *fstore = (FieldStore *) node;
08282             Oid         typrelid;
08283             char       *fieldname;
08284 
08285             /* lookup tuple type */
08286             typrelid = get_typ_typrelid(fstore->resulttype);
08287             if (!OidIsValid(typrelid))
08288                 elog(ERROR, "argument type %s of FieldStore is not a tuple type",
08289                      format_type_be(fstore->resulttype));
08290 
08291             /*
08292              * Print the field name.  There should only be one target field in
08293              * stored rules.  There could be more than that in executable
08294              * target lists, but this function cannot be used for that case.
08295              */
08296             Assert(list_length(fstore->fieldnums) == 1);
08297             fieldname = get_relid_attribute_name(typrelid,
08298                                             linitial_int(fstore->fieldnums));
08299             if (printit)
08300                 appendStringInfo(buf, ".%s", quote_identifier(fieldname));
08301 
08302             /*
08303              * We ignore arg since it should be an uninteresting reference to
08304              * the target column or subcolumn.
08305              */
08306             node = (Node *) linitial(fstore->newvals);
08307         }
08308         else if (IsA(node, ArrayRef))
08309         {
08310             ArrayRef   *aref = (ArrayRef *) node;
08311 
08312             if (aref->refassgnexpr == NULL)
08313                 break;
08314             if (printit)
08315                 printSubscripts(aref, context);
08316 
08317             /*
08318              * We ignore refexpr since it should be an uninteresting reference
08319              * to the target column or subcolumn.
08320              */
08321             node = (Node *) aref->refassgnexpr;
08322         }
08323         else
08324             break;
08325     }
08326 
08327     return node;
08328 }
08329 
08330 static void
08331 printSubscripts(ArrayRef *aref, deparse_context *context)
08332 {
08333     StringInfo  buf = context->buf;
08334     ListCell   *lowlist_item;
08335     ListCell   *uplist_item;
08336 
08337     lowlist_item = list_head(aref->reflowerindexpr);    /* could be NULL */
08338     foreach(uplist_item, aref->refupperindexpr)
08339     {
08340         appendStringInfoChar(buf, '[');
08341         if (lowlist_item)
08342         {
08343             get_rule_expr((Node *) lfirst(lowlist_item), context, false);
08344             appendStringInfoChar(buf, ':');
08345             lowlist_item = lnext(lowlist_item);
08346         }
08347         get_rule_expr((Node *) lfirst(uplist_item), context, false);
08348         appendStringInfoChar(buf, ']');
08349     }
08350 }
08351 
08352 /*
08353  * quote_identifier         - Quote an identifier only if needed
08354  *
08355  * When quotes are needed, we palloc the required space; slightly
08356  * space-wasteful but well worth it for notational simplicity.
08357  */
08358 const char *
08359 quote_identifier(const char *ident)
08360 {
08361     /*
08362      * Can avoid quoting if ident starts with a lowercase letter or underscore
08363      * and contains only lowercase letters, digits, and underscores, *and* is
08364      * not any SQL keyword.  Otherwise, supply quotes.
08365      */
08366     int         nquotes = 0;
08367     bool        safe;
08368     const char *ptr;
08369     char       *result;
08370     char       *optr;
08371 
08372     /*
08373      * would like to use <ctype.h> macros here, but they might yield unwanted
08374      * locale-specific results...
08375      */
08376     safe = ((ident[0] >= 'a' && ident[0] <= 'z') || ident[0] == '_');
08377 
08378     for (ptr = ident; *ptr; ptr++)
08379     {
08380         char        ch = *ptr;
08381 
08382         if ((ch >= 'a' && ch <= 'z') ||
08383             (ch >= '0' && ch <= '9') ||
08384             (ch == '_'))
08385         {
08386             /* okay */
08387         }
08388         else
08389         {
08390             safe = false;
08391             if (ch == '"')
08392                 nquotes++;
08393         }
08394     }
08395 
08396     if (quote_all_identifiers)
08397         safe = false;
08398 
08399     if (safe)
08400     {
08401         /*
08402          * Check for keyword.  We quote keywords except for unreserved ones.
08403          * (In some cases we could avoid quoting a col_name or type_func_name
08404          * keyword, but it seems much harder than it's worth to tell that.)
08405          *
08406          * Note: ScanKeywordLookup() does case-insensitive comparison, but
08407          * that's fine, since we already know we have all-lower-case.
08408          */
08409         const ScanKeyword *keyword = ScanKeywordLookup(ident,
08410                                                        ScanKeywords,
08411                                                        NumScanKeywords);
08412 
08413         if (keyword != NULL && keyword->category != UNRESERVED_KEYWORD)
08414             safe = false;
08415     }
08416 
08417     if (safe)
08418         return ident;           /* no change needed */
08419 
08420     result = (char *) palloc(strlen(ident) + nquotes + 2 + 1);
08421 
08422     optr = result;
08423     *optr++ = '"';
08424     for (ptr = ident; *ptr; ptr++)
08425     {
08426         char        ch = *ptr;
08427 
08428         if (ch == '"')
08429             *optr++ = '"';
08430         *optr++ = ch;
08431     }
08432     *optr++ = '"';
08433     *optr = '\0';
08434 
08435     return result;
08436 }
08437 
08438 /*
08439  * quote_qualified_identifier   - Quote a possibly-qualified identifier
08440  *
08441  * Return a name of the form qualifier.ident, or just ident if qualifier
08442  * is NULL, quoting each component if necessary.  The result is palloc'd.
08443  */
08444 char *
08445 quote_qualified_identifier(const char *qualifier,
08446                            const char *ident)
08447 {
08448     StringInfoData buf;
08449 
08450     initStringInfo(&buf);
08451     if (qualifier)
08452         appendStringInfo(&buf, "%s.", quote_identifier(qualifier));
08453     appendStringInfoString(&buf, quote_identifier(ident));
08454     return buf.data;
08455 }
08456 
08457 /*
08458  * get_relation_name
08459  *      Get the unqualified name of a relation specified by OID
08460  *
08461  * This differs from the underlying get_rel_name() function in that it will
08462  * throw error instead of silently returning NULL if the OID is bad.
08463  */
08464 static char *
08465 get_relation_name(Oid relid)
08466 {
08467     char       *relname = get_rel_name(relid);
08468 
08469     if (!relname)
08470         elog(ERROR, "cache lookup failed for relation %u", relid);
08471     return relname;
08472 }
08473 
08474 /*
08475  * generate_relation_name
08476  *      Compute the name to display for a relation specified by OID
08477  *
08478  * The result includes all necessary quoting and schema-prefixing.
08479  *
08480  * If namespaces isn't NIL, it must be a list of deparse_namespace nodes.
08481  * We will forcibly qualify the relation name if it equals any CTE name
08482  * visible in the namespace list.
08483  */
08484 static char *
08485 generate_relation_name(Oid relid, List *namespaces)
08486 {
08487     HeapTuple   tp;
08488     Form_pg_class reltup;
08489     bool        need_qual;
08490     ListCell   *nslist;
08491     char       *relname;
08492     char       *nspname;
08493     char       *result;
08494 
08495     tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
08496     if (!HeapTupleIsValid(tp))
08497         elog(ERROR, "cache lookup failed for relation %u", relid);
08498     reltup = (Form_pg_class) GETSTRUCT(tp);
08499     relname = NameStr(reltup->relname);
08500 
08501     /* Check for conflicting CTE name */
08502     need_qual = false;
08503     foreach(nslist, namespaces)
08504     {
08505         deparse_namespace *dpns = (deparse_namespace *) lfirst(nslist);
08506         ListCell   *ctlist;
08507 
08508         foreach(ctlist, dpns->ctes)
08509         {
08510             CommonTableExpr *cte = (CommonTableExpr *) lfirst(ctlist);
08511 
08512             if (strcmp(cte->ctename, relname) == 0)
08513             {
08514                 need_qual = true;
08515                 break;
08516             }
08517         }
08518         if (need_qual)
08519             break;
08520     }
08521 
08522     /* Otherwise, qualify the name if not visible in search path */
08523     if (!need_qual)
08524         need_qual = !RelationIsVisible(relid);
08525 
08526     if (need_qual)
08527         nspname = get_namespace_name(reltup->relnamespace);
08528     else
08529         nspname = NULL;
08530 
08531     result = quote_qualified_identifier(nspname, relname);
08532 
08533     ReleaseSysCache(tp);
08534 
08535     return result;
08536 }
08537 
08538 /*
08539  * generate_function_name
08540  *      Compute the name to display for a function specified by OID,
08541  *      given that it is being called with the specified actual arg names and
08542  *      types.  (Those matter because of ambiguous-function resolution rules.)
08543  *
08544  * If we're dealing with a potentially variadic function (in practice, this
08545  * means a FuncExpr and not some other way of calling the function), then
08546  * was_variadic must specify whether VARIADIC appeared in the original call,
08547  * and *use_variadic_p will be set to indicate whether to print VARIADIC in
08548  * the output.  For non-FuncExpr cases, was_variadic should be FALSE and
08549  * use_variadic_p can be NULL.
08550  *
08551  * The result includes all necessary quoting and schema-prefixing.
08552  */
08553 static char *
08554 generate_function_name(Oid funcid, int nargs, List *argnames, Oid *argtypes,
08555                        bool was_variadic, bool *use_variadic_p)
08556 {
08557     char       *result;
08558     HeapTuple   proctup;
08559     Form_pg_proc procform;
08560     char       *proname;
08561     bool        use_variadic;
08562     char       *nspname;
08563     FuncDetailCode p_result;
08564     Oid         p_funcid;
08565     Oid         p_rettype;
08566     bool        p_retset;
08567     int         p_nvargs;
08568     Oid        *p_true_typeids;
08569 
08570     proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
08571     if (!HeapTupleIsValid(proctup))
08572         elog(ERROR, "cache lookup failed for function %u", funcid);
08573     procform = (Form_pg_proc) GETSTRUCT(proctup);
08574     proname = NameStr(procform->proname);
08575 
08576     /*
08577      * Determine whether VARIADIC should be printed.  We must do this first
08578      * since it affects the lookup rules in func_get_detail().
08579      *
08580      * Currently, we always print VARIADIC if the function is variadic and
08581      * takes a variadic type other than ANY.  (In principle, if VARIADIC
08582      * wasn't originally specified and the array actual argument is
08583      * deconstructable, we could print the array elements separately and not
08584      * print VARIADIC, thus more nearly reproducing the original input.  For
08585      * the moment that seems like too much complication for the benefit.)
08586      * However, if the function takes VARIADIC ANY, then the parser didn't
08587      * fold the arguments together into an array, so we must print VARIADIC if
08588      * and only if it was used originally.
08589      */
08590     if (use_variadic_p)
08591     {
08592         if (OidIsValid(procform->provariadic))
08593         {
08594             if (procform->provariadic != ANYOID)
08595                 use_variadic = true;
08596             else
08597                 use_variadic = was_variadic;
08598         }
08599         else
08600             use_variadic = false;
08601         *use_variadic_p = use_variadic;
08602     }
08603     else
08604     {
08605         Assert(!was_variadic);
08606         use_variadic = false;
08607     }
08608 
08609     /*
08610      * The idea here is to schema-qualify only if the parser would fail to
08611      * resolve the correct function given the unqualified func name with the
08612      * specified argtypes and VARIADIC flag.
08613      */
08614     p_result = func_get_detail(list_make1(makeString(proname)),
08615                                NIL, argnames, nargs, argtypes,
08616                                !use_variadic, true,
08617                                &p_funcid, &p_rettype,
08618                                &p_retset, &p_nvargs, &p_true_typeids, NULL);
08619     if ((p_result == FUNCDETAIL_NORMAL ||
08620          p_result == FUNCDETAIL_AGGREGATE ||
08621          p_result == FUNCDETAIL_WINDOWFUNC) &&
08622         p_funcid == funcid)
08623         nspname = NULL;
08624     else
08625         nspname = get_namespace_name(procform->pronamespace);
08626 
08627     result = quote_qualified_identifier(nspname, proname);
08628 
08629     ReleaseSysCache(proctup);
08630 
08631     return result;
08632 }
08633 
08634 /*
08635  * generate_operator_name
08636  *      Compute the name to display for an operator specified by OID,
08637  *      given that it is being called with the specified actual arg types.
08638  *      (Arg types matter because of ambiguous-operator resolution rules.
08639  *      Pass InvalidOid for unused arg of a unary operator.)
08640  *
08641  * The result includes all necessary quoting and schema-prefixing,
08642  * plus the OPERATOR() decoration needed to use a qualified operator name
08643  * in an expression.
08644  */
08645 static char *
08646 generate_operator_name(Oid operid, Oid arg1, Oid arg2)
08647 {
08648     StringInfoData buf;
08649     HeapTuple   opertup;
08650     Form_pg_operator operform;
08651     char       *oprname;
08652     char       *nspname;
08653     Operator    p_result;
08654 
08655     initStringInfo(&buf);
08656 
08657     opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operid));
08658     if (!HeapTupleIsValid(opertup))
08659         elog(ERROR, "cache lookup failed for operator %u", operid);
08660     operform = (Form_pg_operator) GETSTRUCT(opertup);
08661     oprname = NameStr(operform->oprname);
08662 
08663     /*
08664      * The idea here is to schema-qualify only if the parser would fail to
08665      * resolve the correct operator given the unqualified op name with the
08666      * specified argtypes.
08667      */
08668     switch (operform->oprkind)
08669     {
08670         case 'b':
08671             p_result = oper(NULL, list_make1(makeString(oprname)), arg1, arg2,
08672                             true, -1);
08673             break;
08674         case 'l':
08675             p_result = left_oper(NULL, list_make1(makeString(oprname)), arg2,
08676                                  true, -1);
08677             break;
08678         case 'r':
08679             p_result = right_oper(NULL, list_make1(makeString(oprname)), arg1,
08680                                   true, -1);
08681             break;
08682         default:
08683             elog(ERROR, "unrecognized oprkind: %d", operform->oprkind);
08684             p_result = NULL;    /* keep compiler quiet */
08685             break;
08686     }
08687 
08688     if (p_result != NULL && oprid(p_result) == operid)
08689         nspname = NULL;
08690     else
08691     {
08692         nspname = get_namespace_name(operform->oprnamespace);
08693         appendStringInfo(&buf, "OPERATOR(%s.", quote_identifier(nspname));
08694     }
08695 
08696     appendStringInfoString(&buf, oprname);
08697 
08698     if (nspname)
08699         appendStringInfoChar(&buf, ')');
08700 
08701     if (p_result != NULL)
08702         ReleaseSysCache(p_result);
08703 
08704     ReleaseSysCache(opertup);
08705 
08706     return buf.data;
08707 }
08708 
08709 /*
08710  * generate_collation_name
08711  *      Compute the name to display for a collation specified by OID
08712  *
08713  * The result includes all necessary quoting and schema-prefixing.
08714  */
08715 char *
08716 generate_collation_name(Oid collid)
08717 {
08718     HeapTuple   tp;
08719     Form_pg_collation colltup;
08720     char       *collname;
08721     char       *nspname;
08722     char       *result;
08723 
08724     tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(collid));
08725     if (!HeapTupleIsValid(tp))
08726         elog(ERROR, "cache lookup failed for collation %u", collid);
08727     colltup = (Form_pg_collation) GETSTRUCT(tp);
08728     collname = NameStr(colltup->collname);
08729 
08730     if (!CollationIsVisible(collid))
08731         nspname = get_namespace_name(colltup->collnamespace);
08732     else
08733         nspname = NULL;
08734 
08735     result = quote_qualified_identifier(nspname, collname);
08736 
08737     ReleaseSysCache(tp);
08738 
08739     return result;
08740 }
08741 
08742 /*
08743  * Given a C string, produce a TEXT datum.
08744  *
08745  * We assume that the input was palloc'd and may be freed.
08746  */
08747 static text *
08748 string_to_text(char *str)
08749 {
08750     text       *result;
08751 
08752     result = cstring_to_text(str);
08753     pfree(str);
08754     return result;
08755 }
08756 
08757 /*
08758  * Generate a C string representing a relation's reloptions, or NULL if none.
08759  */
08760 static char *
08761 flatten_reloptions(Oid relid)
08762 {
08763     char       *result = NULL;
08764     HeapTuple   tuple;
08765     Datum       reloptions;
08766     bool        isnull;
08767 
08768     tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
08769     if (!HeapTupleIsValid(tuple))
08770         elog(ERROR, "cache lookup failed for relation %u", relid);
08771 
08772     reloptions = SysCacheGetAttr(RELOID, tuple,
08773                                  Anum_pg_class_reloptions, &isnull);
08774     if (!isnull)
08775     {
08776         Datum       sep,
08777                     txt;
08778 
08779         /*
08780          * We want to use array_to_text(reloptions, ', ') --- but
08781          * DirectFunctionCall2(array_to_text) does not work, because
08782          * array_to_text() relies on flinfo to be valid.  So use
08783          * OidFunctionCall2.
08784          */
08785         sep = CStringGetTextDatum(", ");
08786         txt = OidFunctionCall2(F_ARRAY_TO_TEXT, reloptions, sep);
08787         result = TextDatumGetCString(txt);
08788     }
08789 
08790     ReleaseSysCache(tuple);
08791 
08792     return result;
08793 }