LCOV - differential code coverage report
Current view: top level - src/backend/utils/adt - ruleutils.c (source / functions) Coverage Total Hit UNC LBC UIC UBC GBC GIC GNC CBC EUB ECB DUB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 89.0 % 4825 4293 16 168 294 54 180 2401 207 1505 293 2539 5 81
Current Date: 2023-04-08 15:15:32 Functions: 98.7 % 154 152 2 141 9 2 2 149
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  Line data    Source code
       1                 : /*-------------------------------------------------------------------------
       2                 :  *
       3                 :  * ruleutils.c
       4                 :  *    Functions to convert stored expressions/querytrees back to
       5                 :  *    source text
       6                 :  *
       7                 :  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
       8                 :  * Portions Copyright (c) 1994, Regents of the University of California
       9                 :  *
      10                 :  *
      11                 :  * IDENTIFICATION
      12                 :  *    src/backend/utils/adt/ruleutils.c
      13                 :  *
      14                 :  *-------------------------------------------------------------------------
      15                 :  */
      16                 : #include "postgres.h"
      17                 : 
      18                 : #include <ctype.h>
      19                 : #include <unistd.h>
      20                 : #include <fcntl.h>
      21                 : 
      22                 : #include "access/amapi.h"
      23                 : #include "access/htup_details.h"
      24                 : #include "access/relation.h"
      25                 : #include "access/sysattr.h"
      26                 : #include "access/table.h"
      27                 : #include "catalog/pg_aggregate.h"
      28                 : #include "catalog/pg_am.h"
      29                 : #include "catalog/pg_authid.h"
      30                 : #include "catalog/pg_collation.h"
      31                 : #include "catalog/pg_constraint.h"
      32                 : #include "catalog/pg_depend.h"
      33                 : #include "catalog/pg_language.h"
      34                 : #include "catalog/pg_opclass.h"
      35                 : #include "catalog/pg_operator.h"
      36                 : #include "catalog/pg_partitioned_table.h"
      37                 : #include "catalog/pg_proc.h"
      38                 : #include "catalog/pg_statistic_ext.h"
      39                 : #include "catalog/pg_trigger.h"
      40                 : #include "catalog/pg_type.h"
      41                 : #include "commands/defrem.h"
      42                 : #include "commands/tablespace.h"
      43                 : #include "common/keywords.h"
      44                 : #include "executor/spi.h"
      45                 : #include "funcapi.h"
      46                 : #include "mb/pg_wchar.h"
      47                 : #include "miscadmin.h"
      48                 : #include "nodes/makefuncs.h"
      49                 : #include "nodes/nodeFuncs.h"
      50                 : #include "nodes/pathnodes.h"
      51                 : #include "optimizer/optimizer.h"
      52                 : #include "parser/parse_agg.h"
      53                 : #include "parser/parse_func.h"
      54                 : #include "parser/parse_node.h"
      55                 : #include "parser/parse_oper.h"
      56                 : #include "parser/parse_relation.h"
      57                 : #include "parser/parser.h"
      58                 : #include "parser/parsetree.h"
      59                 : #include "rewrite/rewriteHandler.h"
      60                 : #include "rewrite/rewriteManip.h"
      61                 : #include "rewrite/rewriteSupport.h"
      62                 : #include "utils/array.h"
      63                 : #include "utils/builtins.h"
      64                 : #include "utils/fmgroids.h"
      65                 : #include "utils/guc.h"
      66                 : #include "utils/hsearch.h"
      67                 : #include "utils/lsyscache.h"
      68                 : #include "utils/partcache.h"
      69                 : #include "utils/rel.h"
      70                 : #include "utils/ruleutils.h"
      71                 : #include "utils/snapmgr.h"
      72                 : #include "utils/syscache.h"
      73                 : #include "utils/typcache.h"
      74                 : #include "utils/varlena.h"
      75                 : #include "utils/xml.h"
      76                 : 
      77                 : /* ----------
      78                 :  * Pretty formatting constants
      79                 :  * ----------
      80                 :  */
      81                 : 
      82                 : /* Indent counts */
      83                 : #define PRETTYINDENT_STD        8
      84                 : #define PRETTYINDENT_JOIN       4
      85                 : #define PRETTYINDENT_VAR        4
      86                 : 
      87                 : #define PRETTYINDENT_LIMIT      40  /* wrap limit */
      88                 : 
      89                 : /* Pretty flags */
      90                 : #define PRETTYFLAG_PAREN        0x0001
      91                 : #define PRETTYFLAG_INDENT       0x0002
      92                 : #define PRETTYFLAG_SCHEMA       0x0004
      93                 : 
      94                 : /* Standard conversion of a "bool pretty" option to detailed flags */
      95                 : #define GET_PRETTY_FLAGS(pretty) \
      96                 :     ((pretty) ? (PRETTYFLAG_PAREN | PRETTYFLAG_INDENT | PRETTYFLAG_SCHEMA) \
      97                 :      : PRETTYFLAG_INDENT)
      98                 : 
      99                 : /* Default line length for pretty-print wrapping: 0 means wrap always */
     100                 : #define WRAP_COLUMN_DEFAULT     0
     101                 : 
     102                 : /* macros to test if pretty action needed */
     103                 : #define PRETTY_PAREN(context)   ((context)->prettyFlags & PRETTYFLAG_PAREN)
     104                 : #define PRETTY_INDENT(context)  ((context)->prettyFlags & PRETTYFLAG_INDENT)
     105                 : #define PRETTY_SCHEMA(context)  ((context)->prettyFlags & PRETTYFLAG_SCHEMA)
     106                 : 
     107                 : 
     108                 : /* ----------
     109                 :  * Local data types
     110                 :  * ----------
     111                 :  */
     112                 : 
     113                 : /* Context info needed for invoking a recursive querytree display routine */
     114                 : typedef struct
     115                 : {
     116                 :     StringInfo  buf;            /* output buffer to append to */
     117                 :     List       *namespaces;     /* List of deparse_namespace nodes */
     118                 :     List       *windowClause;   /* Current query level's WINDOW clause */
     119                 :     List       *windowTList;    /* targetlist for resolving WINDOW clause */
     120                 :     int         prettyFlags;    /* enabling of pretty-print functions */
     121                 :     int         wrapColumn;     /* max line length, or -1 for no limit */
     122                 :     int         indentLevel;    /* current indent level for pretty-print */
     123                 :     bool        varprefix;      /* true to print prefixes on Vars */
     124                 :     ParseExprKind special_exprkind; /* set only for exprkinds needing special
     125                 :                                      * handling */
     126                 :     Bitmapset  *appendparents;  /* if not null, map child Vars of these relids
     127                 :                                  * back to the parent rel */
     128                 : } deparse_context;
     129                 : 
     130                 : /*
     131                 :  * Each level of query context around a subtree needs a level of Var namespace.
     132                 :  * A Var having varlevelsup=N refers to the N'th item (counting from 0) in
     133                 :  * the current context's namespaces list.
     134                 :  *
     135                 :  * rtable is the list of actual RTEs from the Query or PlannedStmt.
     136                 :  * rtable_names holds the alias name to be used for each RTE (either a C
     137                 :  * string, or NULL for nameless RTEs such as unnamed joins).
     138                 :  * rtable_columns holds the column alias names to be used for each RTE.
     139                 :  *
     140                 :  * subplans is a list of Plan trees for SubPlans and CTEs (it's only used
     141                 :  * in the PlannedStmt case).
     142                 :  * ctes is a list of CommonTableExpr nodes (only used in the Query case).
     143                 :  * appendrels, if not null (it's only used in the PlannedStmt case), is an
     144                 :  * array of AppendRelInfo nodes, indexed by child relid.  We use that to map
     145                 :  * child-table Vars to their inheritance parents.
     146                 :  *
     147                 :  * In some cases we need to make names of merged JOIN USING columns unique
     148                 :  * across the whole query, not only per-RTE.  If so, unique_using is true
     149                 :  * and using_names is a list of C strings representing names already assigned
     150                 :  * to USING columns.
     151                 :  *
     152                 :  * When deparsing plan trees, there is always just a single item in the
     153                 :  * deparse_namespace list (since a plan tree never contains Vars with
     154                 :  * varlevelsup > 0).  We store the Plan node that is the immediate
     155                 :  * parent of the expression to be deparsed, as well as a list of that
     156                 :  * Plan's ancestors.  In addition, we store its outer and inner subplan nodes,
     157                 :  * as well as their targetlists, and the index tlist if the current plan node
     158                 :  * might contain INDEX_VAR Vars.  (These fields could be derived on-the-fly
     159                 :  * from the current Plan node, but it seems notationally clearer to set them
     160                 :  * up as separate fields.)
     161                 :  */
     162                 : typedef struct
     163                 : {
     164                 :     List       *rtable;         /* List of RangeTblEntry nodes */
     165                 :     List       *rtable_names;   /* Parallel list of names for RTEs */
     166                 :     List       *rtable_columns; /* Parallel list of deparse_columns structs */
     167                 :     List       *subplans;       /* List of Plan trees for SubPlans */
     168                 :     List       *ctes;           /* List of CommonTableExpr nodes */
     169                 :     AppendRelInfo **appendrels; /* Array of AppendRelInfo nodes, or NULL */
     170                 :     /* Workspace for column alias assignment: */
     171                 :     bool        unique_using;   /* Are we making USING names globally unique */
     172                 :     List       *using_names;    /* List of assigned names for USING columns */
     173                 :     /* Remaining fields are used only when deparsing a Plan tree: */
     174                 :     Plan       *plan;           /* immediate parent of current expression */
     175                 :     List       *ancestors;      /* ancestors of plan */
     176                 :     Plan       *outer_plan;     /* outer subnode, or NULL if none */
     177                 :     Plan       *inner_plan;     /* inner subnode, or NULL if none */
     178                 :     List       *outer_tlist;    /* referent for OUTER_VAR Vars */
     179                 :     List       *inner_tlist;    /* referent for INNER_VAR Vars */
     180                 :     List       *index_tlist;    /* referent for INDEX_VAR Vars */
     181                 :     /* Special namespace representing a function signature: */
     182                 :     char       *funcname;
     183                 :     int         numargs;
     184                 :     char      **argnames;
     185                 : } deparse_namespace;
     186                 : 
     187                 : /*
     188                 :  * Per-relation data about column alias names.
     189                 :  *
     190                 :  * Selecting aliases is unreasonably complicated because of the need to dump
     191                 :  * rules/views whose underlying tables may have had columns added, deleted, or
     192                 :  * renamed since the query was parsed.  We must nonetheless print the rule/view
     193                 :  * in a form that can be reloaded and will produce the same results as before.
     194                 :  *
     195                 :  * For each RTE used in the query, we must assign column aliases that are
     196                 :  * unique within that RTE.  SQL does not require this of the original query,
     197                 :  * but due to factors such as *-expansion we need to be able to uniquely
     198                 :  * reference every column in a decompiled query.  As long as we qualify all
     199                 :  * column references, per-RTE uniqueness is sufficient for that.
     200                 :  *
     201                 :  * However, we can't ensure per-column name uniqueness for unnamed join RTEs,
     202                 :  * since they just inherit column names from their input RTEs, and we can't
     203                 :  * rename the columns at the join level.  Most of the time this isn't an issue
     204                 :  * because we don't need to reference the join's output columns as such; we
     205                 :  * can reference the input columns instead.  That approach can fail for merged
     206                 :  * JOIN USING columns, however, so when we have one of those in an unnamed
     207                 :  * join, we have to make that column's alias globally unique across the whole
     208                 :  * query to ensure it can be referenced unambiguously.
     209                 :  *
     210                 :  * Another problem is that a JOIN USING clause requires the columns to be
     211                 :  * merged to have the same aliases in both input RTEs, and that no other
     212                 :  * columns in those RTEs or their children conflict with the USING names.
     213                 :  * To handle that, we do USING-column alias assignment in a recursive
     214                 :  * traversal of the query's jointree.  When descending through a JOIN with
     215                 :  * USING, we preassign the USING column names to the child columns, overriding
     216                 :  * other rules for column alias assignment.  We also mark each RTE with a list
     217                 :  * of all USING column names selected for joins containing that RTE, so that
     218                 :  * when we assign other columns' aliases later, we can avoid conflicts.
     219                 :  *
     220                 :  * Another problem is that if a JOIN's input tables have had columns added or
     221                 :  * deleted since the query was parsed, we must generate a column alias list
     222                 :  * for the join that matches the current set of input columns --- otherwise, a
     223                 :  * change in the number of columns in the left input would throw off matching
     224                 :  * of aliases to columns of the right input.  Thus, positions in the printable
     225                 :  * column alias list are not necessarily one-for-one with varattnos of the
     226                 :  * JOIN, so we need a separate new_colnames[] array for printing purposes.
     227                 :  */
     228                 : typedef struct
     229                 : {
     230                 :     /*
     231                 :      * colnames is an array containing column aliases to use for columns that
     232                 :      * existed when the query was parsed.  Dropped columns have NULL entries.
     233                 :      * This array can be directly indexed by varattno to get a Var's name.
     234                 :      *
     235                 :      * Non-NULL entries are guaranteed unique within the RTE, *except* when
     236                 :      * this is for an unnamed JOIN RTE.  In that case we merely copy up names
     237                 :      * from the two input RTEs.
     238                 :      *
     239                 :      * During the recursive descent in set_using_names(), forcible assignment
     240                 :      * of a child RTE's column name is represented by pre-setting that element
     241                 :      * of the child's colnames array.  So at that stage, NULL entries in this
     242                 :      * array just mean that no name has been preassigned, not necessarily that
     243                 :      * the column is dropped.
     244                 :      */
     245                 :     int         num_cols;       /* length of colnames[] array */
     246                 :     char      **colnames;       /* array of C strings and NULLs */
     247                 : 
     248                 :     /*
     249                 :      * new_colnames is an array containing column aliases to use for columns
     250                 :      * that would exist if the query was re-parsed against the current
     251                 :      * definitions of its base tables.  This is what to print as the column
     252                 :      * alias list for the RTE.  This array does not include dropped columns,
     253                 :      * but it will include columns added since original parsing.  Indexes in
     254                 :      * it therefore have little to do with current varattno values.  As above,
     255                 :      * entries are unique unless this is for an unnamed JOIN RTE.  (In such an
     256                 :      * RTE, we never actually print this array, but we must compute it anyway
     257                 :      * for possible use in computing column names of upper joins.) The
     258                 :      * parallel array is_new_col marks which of these columns are new since
     259                 :      * original parsing.  Entries with is_new_col false must match the
     260                 :      * non-NULL colnames entries one-for-one.
     261                 :      */
     262                 :     int         num_new_cols;   /* length of new_colnames[] array */
     263                 :     char      **new_colnames;   /* array of C strings */
     264                 :     bool       *is_new_col;     /* array of bool flags */
     265                 : 
     266                 :     /* This flag tells whether we should actually print a column alias list */
     267                 :     bool        printaliases;
     268                 : 
     269                 :     /* This list has all names used as USING names in joins above this RTE */
     270                 :     List       *parentUsing;    /* names assigned to parent merged columns */
     271                 : 
     272                 :     /*
     273                 :      * If this struct is for a JOIN RTE, we fill these fields during the
     274                 :      * set_using_names() pass to describe its relationship to its child RTEs.
     275                 :      *
     276                 :      * leftattnos and rightattnos are arrays with one entry per existing
     277                 :      * output column of the join (hence, indexable by join varattno).  For a
     278                 :      * simple reference to a column of the left child, leftattnos[i] is the
     279                 :      * child RTE's attno and rightattnos[i] is zero; and conversely for a
     280                 :      * column of the right child.  But for merged columns produced by JOIN
     281                 :      * USING/NATURAL JOIN, both leftattnos[i] and rightattnos[i] are nonzero.
     282                 :      * Note that a simple reference might be to a child RTE column that's been
     283                 :      * dropped; but that's OK since the column could not be used in the query.
     284                 :      *
     285                 :      * If it's a JOIN USING, usingNames holds the alias names selected for the
     286                 :      * merged columns (these might be different from the original USING list,
     287                 :      * if we had to modify names to achieve uniqueness).
     288                 :      */
     289                 :     int         leftrti;        /* rangetable index of left child */
     290                 :     int         rightrti;       /* rangetable index of right child */
     291                 :     int        *leftattnos;     /* left-child varattnos of join cols, or 0 */
     292                 :     int        *rightattnos;    /* right-child varattnos of join cols, or 0 */
     293                 :     List       *usingNames;     /* names assigned to merged columns */
     294                 : } deparse_columns;
     295                 : 
     296                 : /* This macro is analogous to rt_fetch(), but for deparse_columns structs */
     297                 : #define deparse_columns_fetch(rangetable_index, dpns) \
     298                 :     ((deparse_columns *) list_nth((dpns)->rtable_columns, (rangetable_index)-1))
     299                 : 
     300                 : /*
     301                 :  * Entry in set_rtable_names' hash table
     302                 :  */
     303                 : typedef struct
     304                 : {
     305                 :     char        name[NAMEDATALEN];  /* Hash key --- must be first */
     306                 :     int         counter;        /* Largest addition used so far for name */
     307                 : } NameHashEntry;
     308                 : 
     309                 : /* Callback signature for resolve_special_varno() */
     310                 : typedef void (*rsv_callback) (Node *node, deparse_context *context,
     311                 :                               void *callback_arg);
     312                 : 
     313                 : 
     314                 : /* ----------
     315                 :  * Global data
     316                 :  * ----------
     317                 :  */
     318                 : static SPIPlanPtr plan_getrulebyoid = NULL;
     319                 : static const char *query_getrulebyoid = "SELECT * FROM pg_catalog.pg_rewrite WHERE oid = $1";
     320                 : static SPIPlanPtr plan_getviewrule = NULL;
     321                 : static const char *query_getviewrule = "SELECT * FROM pg_catalog.pg_rewrite WHERE ev_class = $1 AND rulename = $2";
     322                 : 
     323                 : /* GUC parameters */
     324                 : bool        quote_all_identifiers = false;
     325                 : 
     326                 : 
     327                 : /* ----------
     328                 :  * Local functions
     329                 :  *
     330                 :  * Most of these functions used to use fixed-size buffers to build their
     331                 :  * results.  Now, they take an (already initialized) StringInfo object
     332                 :  * as a parameter, and append their text output to its contents.
     333                 :  * ----------
     334                 :  */
     335                 : static char *deparse_expression_pretty(Node *expr, List *dpcontext,
     336                 :                                        bool forceprefix, bool showimplicit,
     337                 :                                        int prettyFlags, int startIndent);
     338                 : static char *pg_get_viewdef_worker(Oid viewoid,
     339                 :                                    int prettyFlags, int wrapColumn);
     340                 : static char *pg_get_triggerdef_worker(Oid trigid, bool pretty);
     341                 : static int  decompile_column_index_array(Datum column_index_array, Oid relId,
     342                 :                                          StringInfo buf);
     343                 : static char *pg_get_ruledef_worker(Oid ruleoid, int prettyFlags);
     344                 : static char *pg_get_indexdef_worker(Oid indexrelid, int colno,
     345                 :                                     const Oid *excludeOps,
     346                 :                                     bool attrsOnly, bool keysOnly,
     347                 :                                     bool showTblSpc, bool inherits,
     348                 :                                     int prettyFlags, bool missing_ok);
     349                 : static char *pg_get_statisticsobj_worker(Oid statextid, bool columns_only,
     350                 :                                          bool missing_ok);
     351                 : static char *pg_get_partkeydef_worker(Oid relid, int prettyFlags,
     352                 :                                       bool attrsOnly, bool missing_ok);
     353                 : static char *pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
     354                 :                                          int prettyFlags, bool missing_ok);
     355                 : static text *pg_get_expr_worker(text *expr, Oid relid, const char *relname,
     356                 :                                 int prettyFlags);
     357                 : static int  print_function_arguments(StringInfo buf, HeapTuple proctup,
     358                 :                                      bool print_table_args, bool print_defaults);
     359                 : static void print_function_rettype(StringInfo buf, HeapTuple proctup);
     360                 : static void print_function_trftypes(StringInfo buf, HeapTuple proctup);
     361                 : static void print_function_sqlbody(StringInfo buf, HeapTuple proctup);
     362                 : static void set_rtable_names(deparse_namespace *dpns, List *parent_namespaces,
     363                 :                              Bitmapset *rels_used);
     364                 : static void set_deparse_for_query(deparse_namespace *dpns, Query *query,
     365                 :                                   List *parent_namespaces);
     366                 : static void set_simple_column_names(deparse_namespace *dpns);
     367                 : static bool has_dangerous_join_using(deparse_namespace *dpns, Node *jtnode);
     368                 : static void set_using_names(deparse_namespace *dpns, Node *jtnode,
     369                 :                             List *parentUsing);
     370                 : static void set_relation_column_names(deparse_namespace *dpns,
     371                 :                                       RangeTblEntry *rte,
     372                 :                                       deparse_columns *colinfo);
     373                 : static void set_join_column_names(deparse_namespace *dpns, RangeTblEntry *rte,
     374                 :                                   deparse_columns *colinfo);
     375                 : static bool colname_is_unique(const char *colname, deparse_namespace *dpns,
     376                 :                               deparse_columns *colinfo);
     377                 : static char *make_colname_unique(char *colname, deparse_namespace *dpns,
     378                 :                                  deparse_columns *colinfo);
     379                 : static void expand_colnames_array_to(deparse_columns *colinfo, int n);
     380                 : static void identify_join_columns(JoinExpr *j, RangeTblEntry *jrte,
     381                 :                                   deparse_columns *colinfo);
     382                 : static char *get_rtable_name(int rtindex, deparse_context *context);
     383                 : static void set_deparse_plan(deparse_namespace *dpns, Plan *plan);
     384                 : static Plan *find_recursive_union(deparse_namespace *dpns,
     385                 :                                   WorkTableScan *wtscan);
     386                 : static void push_child_plan(deparse_namespace *dpns, Plan *plan,
     387                 :                             deparse_namespace *save_dpns);
     388                 : static void pop_child_plan(deparse_namespace *dpns,
     389                 :                            deparse_namespace *save_dpns);
     390                 : static void push_ancestor_plan(deparse_namespace *dpns, ListCell *ancestor_cell,
     391                 :                                deparse_namespace *save_dpns);
     392                 : static void pop_ancestor_plan(deparse_namespace *dpns,
     393                 :                               deparse_namespace *save_dpns);
     394                 : static void make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
     395                 :                          int prettyFlags);
     396                 : static void make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
     397                 :                          int prettyFlags, int wrapColumn);
     398                 : static void get_query_def(Query *query, StringInfo buf, List *parentnamespace,
     399                 :                           TupleDesc resultDesc, bool colNamesVisible,
     400                 :                           int prettyFlags, int wrapColumn, int startIndent);
     401                 : static void get_values_def(List *values_lists, deparse_context *context);
     402                 : static void get_with_clause(Query *query, deparse_context *context);
     403                 : static void get_select_query_def(Query *query, deparse_context *context,
     404                 :                                  TupleDesc resultDesc, bool colNamesVisible);
     405                 : static void get_insert_query_def(Query *query, deparse_context *context,
     406                 :                                  bool colNamesVisible);
     407                 : static void get_update_query_def(Query *query, deparse_context *context,
     408                 :                                  bool colNamesVisible);
     409                 : static void get_update_query_targetlist_def(Query *query, List *targetList,
     410                 :                                             deparse_context *context,
     411                 :                                             RangeTblEntry *rte);
     412                 : static void get_delete_query_def(Query *query, deparse_context *context,
     413                 :                                  bool colNamesVisible);
     414                 : static void get_utility_query_def(Query *query, deparse_context *context);
     415                 : static void get_basic_select_query(Query *query, deparse_context *context,
     416                 :                                    TupleDesc resultDesc, bool colNamesVisible);
     417                 : static void get_target_list(List *targetList, deparse_context *context,
     418                 :                             TupleDesc resultDesc, bool colNamesVisible);
     419                 : static void get_setop_query(Node *setOp, Query *query,
     420                 :                             deparse_context *context,
     421                 :                             TupleDesc resultDesc, bool colNamesVisible);
     422                 : static Node *get_rule_sortgroupclause(Index ref, List *tlist,
     423                 :                                       bool force_colno,
     424                 :                                       deparse_context *context);
     425                 : static void get_rule_groupingset(GroupingSet *gset, List *targetlist,
     426                 :                                  bool omit_parens, deparse_context *context);
     427                 : static void get_rule_orderby(List *orderList, List *targetList,
     428                 :                              bool force_colno, deparse_context *context);
     429                 : static void get_rule_windowclause(Query *query, deparse_context *context);
     430                 : static void get_rule_windowspec(WindowClause *wc, List *targetList,
     431                 :                                 deparse_context *context);
     432                 : static char *get_variable(Var *var, int levelsup, bool istoplevel,
     433                 :                           deparse_context *context);
     434                 : static void get_special_variable(Node *node, deparse_context *context,
     435                 :                                  void *callback_arg);
     436                 : static void resolve_special_varno(Node *node, deparse_context *context,
     437                 :                                   rsv_callback callback, void *callback_arg);
     438                 : static Node *find_param_referent(Param *param, deparse_context *context,
     439                 :                                  deparse_namespace **dpns_p, ListCell **ancestor_cell_p);
     440                 : static void get_parameter(Param *param, deparse_context *context);
     441                 : static const char *get_simple_binary_op_name(OpExpr *expr);
     442                 : static bool isSimpleNode(Node *node, Node *parentNode, int prettyFlags);
     443                 : static void appendContextKeyword(deparse_context *context, const char *str,
     444                 :                                  int indentBefore, int indentAfter, int indentPlus);
     445                 : static void removeStringInfoSpaces(StringInfo str);
     446                 : static void get_rule_expr(Node *node, deparse_context *context,
     447                 :                           bool showimplicit);
     448                 : static void get_rule_expr_toplevel(Node *node, deparse_context *context,
     449                 :                                    bool showimplicit);
     450                 : static void get_rule_list_toplevel(List *lst, deparse_context *context,
     451                 :                                    bool showimplicit);
     452                 : static void get_rule_expr_funccall(Node *node, deparse_context *context,
     453                 :                                    bool showimplicit);
     454                 : static bool looks_like_function(Node *node);
     455                 : static void get_oper_expr(OpExpr *expr, deparse_context *context);
     456                 : static void get_func_expr(FuncExpr *expr, deparse_context *context,
     457                 :                           bool showimplicit);
     458                 : static void get_agg_expr(Aggref *aggref, deparse_context *context,
     459                 :                          Aggref *original_aggref);
     460                 : static void get_agg_expr_helper(Aggref *aggref, deparse_context *context,
     461                 :                                 Aggref *original_aggref, const char *funcname,
     462                 :                                 const char *options, bool is_json_objectagg);
     463                 : static void get_agg_combine_expr(Node *node, deparse_context *context,
     464                 :                                  void *callback_arg);
     465                 : static void get_windowfunc_expr(WindowFunc *wfunc, deparse_context *context);
     466                 : static void get_windowfunc_expr_helper(WindowFunc *wfunc, deparse_context *context,
     467                 :                                        const char *funcname, const char *options,
     468                 :                                        bool is_json_objectagg);
     469                 : static bool get_func_sql_syntax(FuncExpr *expr, deparse_context *context);
     470                 : static void get_coercion_expr(Node *arg, deparse_context *context,
     471                 :                               Oid resulttype, int32 resulttypmod,
     472                 :                               Node *parentNode);
     473                 : static void get_const_expr(Const *constval, deparse_context *context,
     474                 :                            int showtype);
     475                 : static void get_const_collation(Const *constval, deparse_context *context);
     476                 : static void get_json_format(JsonFormat *format, StringInfo buf);
     477                 : static void get_json_constructor(JsonConstructorExpr *ctor,
     478                 :                                  deparse_context *context, bool showimplicit);
     479                 : static void get_json_constructor_options(JsonConstructorExpr *ctor,
     480                 :                                          StringInfo buf);
     481                 : static void get_json_agg_constructor(JsonConstructorExpr *ctor,
     482                 :                                      deparse_context *context,
     483                 :                                      const char *funcname,
     484                 :                                      bool is_json_objectagg);
     485                 : static void simple_quote_literal(StringInfo buf, const char *val);
     486                 : static void get_sublink_expr(SubLink *sublink, deparse_context *context);
     487                 : static void get_tablefunc(TableFunc *tf, deparse_context *context,
     488                 :                           bool showimplicit);
     489                 : static void get_from_clause(Query *query, const char *prefix,
     490                 :                             deparse_context *context);
     491                 : static void get_from_clause_item(Node *jtnode, Query *query,
     492                 :                                  deparse_context *context);
     493                 : static void get_rte_alias(RangeTblEntry *rte, int varno, bool use_as,
     494                 :                           deparse_context *context);
     495                 : static void get_column_alias_list(deparse_columns *colinfo,
     496                 :                                   deparse_context *context);
     497                 : static void get_from_clause_coldeflist(RangeTblFunction *rtfunc,
     498                 :                                        deparse_columns *colinfo,
     499                 :                                        deparse_context *context);
     500                 : static void get_tablesample_def(TableSampleClause *tablesample,
     501                 :                                 deparse_context *context);
     502                 : static void get_opclass_name(Oid opclass, Oid actual_datatype,
     503                 :                              StringInfo buf);
     504                 : static Node *processIndirection(Node *node, deparse_context *context);
     505                 : static void printSubscripts(SubscriptingRef *sbsref, deparse_context *context);
     506                 : static char *get_relation_name(Oid relid);
     507                 : static char *generate_relation_name(Oid relid, List *namespaces);
     508                 : static char *generate_qualified_relation_name(Oid relid);
     509                 : static char *generate_function_name(Oid funcid, int nargs,
     510                 :                                     List *argnames, Oid *argtypes,
     511                 :                                     bool has_variadic, bool *use_variadic_p,
     512                 :                                     ParseExprKind special_exprkind);
     513                 : static char *generate_operator_name(Oid operid, Oid arg1, Oid arg2);
     514                 : static void add_cast_to(StringInfo buf, Oid typid);
     515                 : static char *generate_qualified_type_name(Oid typid);
     516                 : static text *string_to_text(char *str);
     517                 : static char *flatten_reloptions(Oid relid);
     518                 : static void get_reloptions(StringInfo buf, Datum reloptions);
     519                 : 
     520                 : #define only_marker(rte)  ((rte)->inh ? "" : "ONLY ")
     521                 : 
     522                 : 
     523                 : /* ----------
     524                 :  * pg_get_ruledef       - Do it all and return a text
     525                 :  *                that could be used as a statement
     526                 :  *                to recreate the rule
     527                 :  * ----------
     528                 :  */
     529                 : Datum
     530 GIC         219 : pg_get_ruledef(PG_FUNCTION_ARGS)
     531                 : {
     532             219 :     Oid         ruleoid = PG_GETARG_OID(0);
     533                 :     int         prettyFlags;
     534                 :     char       *res;
     535                 : 
     536             219 :     prettyFlags = PRETTYFLAG_INDENT;
     537                 : 
     538             219 :     res = pg_get_ruledef_worker(ruleoid, prettyFlags);
     539                 : 
     540             219 :     if (res == NULL)
     541               3 :         PG_RETURN_NULL();
     542                 : 
     543             216 :     PG_RETURN_TEXT_P(string_to_text(res));
     544                 : }
     545 ECB             : 
     546                 : 
     547                 : Datum
     548 GIC          48 : pg_get_ruledef_ext(PG_FUNCTION_ARGS)
     549                 : {
     550              48 :     Oid         ruleoid = PG_GETARG_OID(0);
     551 CBC          48 :     bool        pretty = PG_GETARG_BOOL(1);
     552                 :     int         prettyFlags;
     553 ECB             :     char       *res;
     554                 : 
     555 CBC          48 :     prettyFlags = GET_PRETTY_FLAGS(pretty);
     556 ECB             : 
     557 GIC          48 :     res = pg_get_ruledef_worker(ruleoid, prettyFlags);
     558 ECB             : 
     559 GIC          48 :     if (res == NULL)
     560 UIC           0 :         PG_RETURN_NULL();
     561                 : 
     562 GIC          48 :     PG_RETURN_TEXT_P(string_to_text(res));
     563 ECB             : }
     564                 : 
     565                 : 
     566                 : static char *
     567 GIC         267 : pg_get_ruledef_worker(Oid ruleoid, int prettyFlags)
     568                 : {
     569                 :     Datum       args[1];
     570 ECB             :     char        nulls[1];
     571                 :     int         spirc;
     572                 :     HeapTuple   ruletup;
     573                 :     TupleDesc   rulettc;
     574                 :     StringInfoData buf;
     575 EUB             : 
     576                 :     /*
     577 ECB             :      * Do this first so that string is alloc'd in outer context not SPI's.
     578                 :      */
     579 GIC         267 :     initStringInfo(&buf);
     580                 : 
     581                 :     /*
     582 ECB             :      * Connect to SPI manager
     583                 :      */
     584 GIC         267 :     if (SPI_connect() != SPI_OK_CONNECT)
     585 UIC           0 :         elog(ERROR, "SPI_connect failed");
     586                 : 
     587                 :     /*
     588                 :      * On the first call prepare the plan to lookup pg_rewrite. We read
     589                 :      * pg_rewrite over the SPI manager instead of using the syscache to be
     590                 :      * checked for read access on pg_rewrite.
     591                 :      */
     592 GIC         267 :     if (plan_getrulebyoid == NULL)
     593                 :     {
     594 ECB             :         Oid         argtypes[1];
     595                 :         SPIPlanPtr  plan;
     596                 : 
     597 GIC          17 :         argtypes[0] = OIDOID;
     598              17 :         plan = SPI_prepare(query_getrulebyoid, 1, argtypes);
     599 CBC          17 :         if (plan == NULL)
     600 UBC           0 :             elog(ERROR, "SPI_prepare failed for \"%s\"", query_getrulebyoid);
     601 GIC          17 :         SPI_keepplan(plan);
     602              17 :         plan_getrulebyoid = plan;
     603                 :     }
     604                 : 
     605                 :     /*
     606                 :      * Get the pg_rewrite tuple for this rule
     607 ECB             :      */
     608 GIC         267 :     args[0] = ObjectIdGetDatum(ruleoid);
     609             267 :     nulls[0] = ' ';
     610             267 :     spirc = SPI_execute_plan(plan_getrulebyoid, args, nulls, true, 0);
     611             267 :     if (spirc != SPI_OK_SELECT)
     612 LBC           0 :         elog(ERROR, "failed to get pg_rewrite tuple for rule %u", ruleoid);
     613 CBC         267 :     if (SPI_processed != 1)
     614 ECB             :     {
     615 EUB             :         /*
     616 ECB             :          * There is no tuple data available here, just keep the output buffer
     617                 :          * empty.
     618                 :          */
     619                 :     }
     620                 :     else
     621                 :     {
     622                 :         /*
     623                 :          * Get the rule's definition and put it into executor's memory
     624                 :          */
     625 CBC         264 :         ruletup = SPI_tuptable->vals[0];
     626             264 :         rulettc = SPI_tuptable->tupdesc;
     627 GBC         264 :         make_ruledef(&buf, ruletup, rulettc, prettyFlags);
     628 ECB             :     }
     629                 : 
     630                 :     /*
     631                 :      * Disconnect from SPI manager
     632                 :      */
     633 GIC         267 :     if (SPI_finish() != SPI_OK_FINISH)
     634 UIC           0 :         elog(ERROR, "SPI_finish failed");
     635                 : 
     636 GIC         267 :     if (buf.len == 0)
     637               3 :         return NULL;
     638                 : 
     639             264 :     return buf.data;
     640 ECB             : }
     641                 : 
     642                 : 
     643                 : /* ----------
     644                 :  * pg_get_viewdef       - Mainly the same thing, but we
     645                 :  *                only return the SELECT part of a view
     646                 :  * ----------
     647                 :  */
     648                 : Datum
     649 GBC         947 : pg_get_viewdef(PG_FUNCTION_ARGS)
     650                 : {
     651 ECB             :     /* By OID */
     652 CBC         947 :     Oid         viewoid = PG_GETARG_OID(0);
     653                 :     int         prettyFlags;
     654 ECB             :     char       *res;
     655                 : 
     656 GIC         947 :     prettyFlags = PRETTYFLAG_INDENT;
     657                 : 
     658             947 :     res = pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT);
     659                 : 
     660             947 :     if (res == NULL)
     661               3 :         PG_RETURN_NULL();
     662                 : 
     663             944 :     PG_RETURN_TEXT_P(string_to_text(res));
     664 ECB             : }
     665                 : 
     666                 : 
     667                 : Datum
     668 GIC         233 : pg_get_viewdef_ext(PG_FUNCTION_ARGS)
     669                 : {
     670                 :     /* By OID */
     671 CBC         233 :     Oid         viewoid = PG_GETARG_OID(0);
     672 GIC         233 :     bool        pretty = PG_GETARG_BOOL(1);
     673 ECB             :     int         prettyFlags;
     674                 :     char       *res;
     675                 : 
     676 CBC         233 :     prettyFlags = GET_PRETTY_FLAGS(pretty);
     677                 : 
     678             233 :     res = pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT);
     679                 : 
     680 GIC         233 :     if (res == NULL)
     681 UIC           0 :         PG_RETURN_NULL();
     682                 : 
     683 CBC         233 :     PG_RETURN_TEXT_P(string_to_text(res));
     684                 : }
     685                 : 
     686 ECB             : Datum
     687 CBC           3 : pg_get_viewdef_wrap(PG_FUNCTION_ARGS)
     688                 : {
     689                 :     /* By OID */
     690 GIC           3 :     Oid         viewoid = PG_GETARG_OID(0);
     691 CBC           3 :     int         wrap = PG_GETARG_INT32(1);
     692                 :     int         prettyFlags;
     693 ECB             :     char       *res;
     694                 : 
     695                 :     /* calling this implies we want pretty printing */
     696 GBC           3 :     prettyFlags = GET_PRETTY_FLAGS(true);
     697                 : 
     698 CBC           3 :     res = pg_get_viewdef_worker(viewoid, prettyFlags, wrap);
     699                 : 
     700 GIC           3 :     if (res == NULL)
     701 UIC           0 :         PG_RETURN_NULL();
     702 ECB             : 
     703 GIC           3 :     PG_RETURN_TEXT_P(string_to_text(res));
     704                 : }
     705 ECB             : 
     706                 : Datum
     707 GIC          36 : pg_get_viewdef_name(PG_FUNCTION_ARGS)
     708                 : {
     709                 :     /* By qualified name */
     710              36 :     text       *viewname = PG_GETARG_TEXT_PP(0);
     711 ECB             :     int         prettyFlags;
     712                 :     RangeVar   *viewrel;
     713                 :     Oid         viewoid;
     714                 :     char       *res;
     715                 : 
     716 GBC          36 :     prettyFlags = PRETTYFLAG_INDENT;
     717                 : 
     718 ECB             :     /* Look up view name.  Can't lock it - we might not have privileges. */
     719 GIC          36 :     viewrel = makeRangeVarFromNameList(textToQualifiedNameList(viewname));
     720              36 :     viewoid = RangeVarGetRelid(viewrel, NoLock, false);
     721                 : 
     722 CBC          36 :     res = pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT);
     723                 : 
     724 GIC          36 :     if (res == NULL)
     725 LBC           0 :         PG_RETURN_NULL();
     726                 : 
     727 GIC          36 :     PG_RETURN_TEXT_P(string_to_text(res));
     728                 : }
     729                 : 
     730                 : 
     731 ECB             : Datum
     732 GIC         192 : pg_get_viewdef_name_ext(PG_FUNCTION_ARGS)
     733                 : {
     734 ECB             :     /* By qualified name */
     735 CBC         192 :     text       *viewname = PG_GETARG_TEXT_PP(0);
     736 GIC         192 :     bool        pretty = PG_GETARG_BOOL(1);
     737 ECB             :     int         prettyFlags;
     738                 :     RangeVar   *viewrel;
     739                 :     Oid         viewoid;
     740 EUB             :     char       *res;
     741                 : 
     742 CBC         192 :     prettyFlags = GET_PRETTY_FLAGS(pretty);
     743                 : 
     744                 :     /* Look up view name.  Can't lock it - we might not have privileges. */
     745 GIC         192 :     viewrel = makeRangeVarFromNameList(textToQualifiedNameList(viewname));
     746             192 :     viewoid = RangeVarGetRelid(viewrel, NoLock, false);
     747 ECB             : 
     748 GIC         192 :     res = pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT);
     749                 : 
     750 CBC         192 :     if (res == NULL)
     751 LBC           0 :         PG_RETURN_NULL();
     752                 : 
     753 GIC         192 :     PG_RETURN_TEXT_P(string_to_text(res));
     754                 : }
     755                 : 
     756                 : /*
     757 ECB             :  * Common code for by-OID and by-name variants of pg_get_viewdef
     758                 :  */
     759                 : static char *
     760 CBC        1411 : pg_get_viewdef_worker(Oid viewoid, int prettyFlags, int wrapColumn)
     761 ECB             : {
     762                 :     Datum       args[2];
     763                 :     char        nulls[2];
     764                 :     int         spirc;
     765                 :     HeapTuple   ruletup;
     766 EUB             :     TupleDesc   rulettc;
     767                 :     StringInfoData buf;
     768 ECB             : 
     769                 :     /*
     770                 :      * Do this first so that string is alloc'd in outer context not SPI's.
     771                 :      */
     772 GIC        1411 :     initStringInfo(&buf);
     773                 : 
     774                 :     /*
     775 ECB             :      * Connect to SPI manager
     776                 :      */
     777 GIC        1411 :     if (SPI_connect() != SPI_OK_CONNECT)
     778 UIC           0 :         elog(ERROR, "SPI_connect failed");
     779                 : 
     780                 :     /*
     781                 :      * On the first call prepare the plan to lookup pg_rewrite. We read
     782                 :      * pg_rewrite over the SPI manager instead of using the syscache to be
     783                 :      * checked for read access on pg_rewrite.
     784                 :      */
     785 GIC        1411 :     if (plan_getviewrule == NULL)
     786                 :     {
     787 ECB             :         Oid         argtypes[2];
     788                 :         SPIPlanPtr  plan;
     789                 : 
     790 GIC         108 :         argtypes[0] = OIDOID;
     791             108 :         argtypes[1] = NAMEOID;
     792 CBC         108 :         plan = SPI_prepare(query_getviewrule, 2, argtypes);
     793 GBC         108 :         if (plan == NULL)
     794 UIC           0 :             elog(ERROR, "SPI_prepare failed for \"%s\"", query_getviewrule);
     795 GIC         108 :         SPI_keepplan(plan);
     796             108 :         plan_getviewrule = plan;
     797                 :     }
     798                 : 
     799                 :     /*
     800 ECB             :      * Get the pg_rewrite tuple for the view's SELECT rule
     801                 :      */
     802 GIC        1411 :     args[0] = ObjectIdGetDatum(viewoid);
     803            1411 :     args[1] = DirectFunctionCall1(namein, CStringGetDatum(ViewSelectRuleName));
     804            1411 :     nulls[0] = ' ';
     805 CBC        1411 :     nulls[1] = ' ';
     806            1411 :     spirc = SPI_execute_plan(plan_getviewrule, args, nulls, true, 0);
     807            1411 :     if (spirc != SPI_OK_SELECT)
     808 LBC           0 :         elog(ERROR, "failed to get pg_rewrite tuple for view %u", viewoid);
     809 GBC        1411 :     if (SPI_processed != 1)
     810 ECB             :     {
     811                 :         /*
     812                 :          * There is no tuple data available here, just keep the output buffer
     813                 :          * empty.
     814                 :          */
     815                 :     }
     816                 :     else
     817                 :     {
     818                 :         /*
     819                 :          * Get the rule's definition and put it into executor's memory
     820                 :          */
     821 CBC        1408 :         ruletup = SPI_tuptable->vals[0];
     822            1408 :         rulettc = SPI_tuptable->tupdesc;
     823 GBC        1408 :         make_viewdef(&buf, ruletup, rulettc, prettyFlags, wrapColumn);
     824 ECB             :     }
     825                 : 
     826                 :     /*
     827                 :      * Disconnect from SPI manager
     828                 :      */
     829 GIC        1411 :     if (SPI_finish() != SPI_OK_FINISH)
     830 UIC           0 :         elog(ERROR, "SPI_finish failed");
     831                 : 
     832 GIC        1411 :     if (buf.len == 0)
     833               3 :         return NULL;
     834                 : 
     835            1408 :     return buf.data;
     836 ECB             : }
     837                 : 
     838                 : /* ----------
     839                 :  * pg_get_triggerdef        - Get the definition of a trigger
     840                 :  * ----------
     841                 :  */
     842                 : Datum
     843 GIC         102 : pg_get_triggerdef(PG_FUNCTION_ARGS)
     844 ECB             : {
     845 GBC         102 :     Oid         trigid = PG_GETARG_OID(0);
     846                 :     char       *res;
     847 ECB             : 
     848 CBC         102 :     res = pg_get_triggerdef_worker(trigid, false);
     849                 : 
     850             102 :     if (res == NULL)
     851 GIC           3 :         PG_RETURN_NULL();
     852                 : 
     853              99 :     PG_RETURN_TEXT_P(string_to_text(res));
     854                 : }
     855                 : 
     856                 : Datum
     857             576 : pg_get_triggerdef_ext(PG_FUNCTION_ARGS)
     858 ECB             : {
     859 GIC         576 :     Oid         trigid = PG_GETARG_OID(0);
     860 CBC         576 :     bool        pretty = PG_GETARG_BOOL(1);
     861                 :     char       *res;
     862                 : 
     863             576 :     res = pg_get_triggerdef_worker(trigid, pretty);
     864                 : 
     865             576 :     if (res == NULL)
     866 LBC           0 :         PG_RETURN_NULL();
     867                 : 
     868 CBC         576 :     PG_RETURN_TEXT_P(string_to_text(res));
     869                 : }
     870                 : 
     871                 : static char *
     872             678 : pg_get_triggerdef_worker(Oid trigid, bool pretty)
     873                 : {
     874 ECB             :     HeapTuple   ht_trig;
     875                 :     Form_pg_trigger trigrec;
     876                 :     StringInfoData buf;
     877                 :     Relation    tgrel;
     878                 :     ScanKeyData skey[1];
     879                 :     SysScanDesc tgscan;
     880 CBC         678 :     int         findx = 0;
     881 EUB             :     char       *tgname;
     882                 :     char       *tgoldtable;
     883 ECB             :     char       *tgnewtable;
     884                 :     Datum       value;
     885                 :     bool        isnull;
     886                 : 
     887                 :     /*
     888                 :      * Fetch the pg_trigger tuple by the Oid of the trigger
     889                 :      */
     890 GIC         678 :     tgrel = table_open(TriggerRelationId, AccessShareLock);
     891                 : 
     892             678 :     ScanKeyInit(&skey[0],
     893                 :                 Anum_pg_trigger_oid,
     894                 :                 BTEqualStrategyNumber, F_OIDEQ,
     895 ECB             :                 ObjectIdGetDatum(trigid));
     896                 : 
     897 GIC         678 :     tgscan = systable_beginscan(tgrel, TriggerOidIndexId, true,
     898                 :                                 NULL, 1, skey);
     899                 : 
     900             678 :     ht_trig = systable_getnext(tgscan);
     901                 : 
     902             678 :     if (!HeapTupleIsValid(ht_trig))
     903                 :     {
     904               3 :         systable_endscan(tgscan);
     905 CBC           3 :         table_close(tgrel, AccessShareLock);
     906 GIC           3 :         return NULL;
     907 ECB             :     }
     908                 : 
     909 GIC         675 :     trigrec = (Form_pg_trigger) GETSTRUCT(ht_trig);
     910                 : 
     911                 :     /*
     912 ECB             :      * Start the trigger definition. Note that the trigger's name should never
     913                 :      * be schema-qualified, but the trigger rel's name may be.
     914                 :      */
     915 CBC         675 :     initStringInfo(&buf);
     916                 : 
     917             675 :     tgname = NameStr(trigrec->tgname);
     918 GIC        1350 :     appendStringInfo(&buf, "CREATE %sTRIGGER %s ",
     919 CBC         675 :                      OidIsValid(trigrec->tgconstraint) ? "CONSTRAINT " : "",
     920 ECB             :                      quote_identifier(tgname));
     921                 : 
     922 GIC         675 :     if (TRIGGER_FOR_BEFORE(trigrec->tgtype))
     923             259 :         appendStringInfoString(&buf, "BEFORE");
     924 CBC         416 :     else if (TRIGGER_FOR_AFTER(trigrec->tgtype))
     925 GIC         404 :         appendStringInfoString(&buf, "AFTER");
     926              12 :     else if (TRIGGER_FOR_INSTEAD(trigrec->tgtype))
     927              12 :         appendStringInfoString(&buf, "INSTEAD OF");
     928                 :     else
     929 UIC           0 :         elog(ERROR, "unexpected tgtype value: %d", trigrec->tgtype);
     930 ECB             : 
     931 GIC         675 :     if (TRIGGER_FOR_INSERT(trigrec->tgtype))
     932 ECB             :     {
     933 CBC         443 :         appendStringInfoString(&buf, " INSERT");
     934             443 :         findx++;
     935                 :     }
     936 GIC         675 :     if (TRIGGER_FOR_DELETE(trigrec->tgtype))
     937 ECB             :     {
     938 CBC         113 :         if (findx > 0)
     939              45 :             appendStringInfoString(&buf, " OR DELETE");
     940 ECB             :         else
     941 CBC          68 :             appendStringInfoString(&buf, " DELETE");
     942             113 :         findx++;
     943                 :     }
     944 GBC         675 :     if (TRIGGER_FOR_UPDATE(trigrec->tgtype))
     945                 :     {
     946 CBC         324 :         if (findx > 0)
     947 GIC         160 :             appendStringInfoString(&buf, " OR UPDATE");
     948 ECB             :         else
     949 CBC         164 :             appendStringInfoString(&buf, " UPDATE");
     950 GIC         324 :         findx++;
     951 ECB             :         /* tgattr is first var-width field, so OK to access directly */
     952 GIC         324 :         if (trigrec->tgattr.dim1 > 0)
     953 ECB             :         {
     954                 :             int         i;
     955                 : 
     956 CBC          38 :             appendStringInfoString(&buf, " OF ");
     957              84 :             for (i = 0; i < trigrec->tgattr.dim1; i++)
     958                 :             {
     959 ECB             :                 char       *attname;
     960                 : 
     961 CBC          46 :                 if (i > 0)
     962               8 :                     appendStringInfoString(&buf, ", ");
     963 GIC          46 :                 attname = get_attname(trigrec->tgrelid,
     964 CBC          46 :                                       trigrec->tgattr.values[i], false);
     965              46 :                 appendStringInfoString(&buf, quote_identifier(attname));
     966                 :             }
     967 ECB             :         }
     968                 :     }
     969 GIC         675 :     if (TRIGGER_FOR_TRUNCATE(trigrec->tgtype))
     970                 :     {
     971 LBC           0 :         if (findx > 0)
     972               0 :             appendStringInfoString(&buf, " OR TRUNCATE");
     973                 :         else
     974 UIC           0 :             appendStringInfoString(&buf, " TRUNCATE");
     975               0 :         findx++;
     976 ECB             :     }
     977                 : 
     978                 :     /*
     979                 :      * In non-pretty mode, always schema-qualify the target table name for
     980                 :      * safety.  In pretty mode, schema-qualify only if not visible.
     981                 :      */
     982 GIC        1350 :     appendStringInfo(&buf, " ON %s ",
     983                 :                      pretty ?
     984 CBC          69 :                      generate_relation_name(trigrec->tgrelid, NIL) :
     985 GIC         606 :                      generate_qualified_relation_name(trigrec->tgrelid));
     986 EUB             : 
     987 GBC         675 :     if (OidIsValid(trigrec->tgconstraint))
     988                 :     {
     989 UBC           0 :         if (OidIsValid(trigrec->tgconstrrelid))
     990               0 :             appendStringInfo(&buf, "FROM %s ",
     991                 :                              generate_relation_name(trigrec->tgconstrrelid, NIL));
     992 UIC           0 :         if (!trigrec->tgdeferrable)
     993               0 :             appendStringInfoString(&buf, "NOT ");
     994               0 :         appendStringInfoString(&buf, "DEFERRABLE INITIALLY ");
     995               0 :         if (trigrec->tginitdeferred)
     996               0 :             appendStringInfoString(&buf, "DEFERRED ");
     997 ECB             :         else
     998 UIC           0 :             appendStringInfoString(&buf, "IMMEDIATE ");
     999 ECB             :     }
    1000                 : 
    1001 GIC         675 :     value = fastgetattr(ht_trig, Anum_pg_trigger_tgoldtable,
    1002 ECB             :                         tgrel->rd_att, &isnull);
    1003 GIC         675 :     if (!isnull)
    1004 GBC          49 :         tgoldtable = NameStr(*DatumGetName(value));
    1005 EUB             :     else
    1006 GIC         626 :         tgoldtable = NULL;
    1007 GBC         675 :     value = fastgetattr(ht_trig, Anum_pg_trigger_tgnewtable,
    1008 EUB             :                         tgrel->rd_att, &isnull);
    1009 GBC         675 :     if (!isnull)
    1010              54 :         tgnewtable = NameStr(*DatumGetName(value));
    1011 EUB             :     else
    1012 GIC         621 :         tgnewtable = NULL;
    1013 GBC         675 :     if (tgoldtable != NULL || tgnewtable != NULL)
    1014                 :     {
    1015 GIC          76 :         appendStringInfoString(&buf, "REFERENCING ");
    1016 CBC          76 :         if (tgoldtable != NULL)
    1017 GIC          49 :             appendStringInfo(&buf, "OLD TABLE AS %s ",
    1018 ECB             :                              quote_identifier(tgoldtable));
    1019 CBC          76 :         if (tgnewtable != NULL)
    1020 GIC          54 :             appendStringInfo(&buf, "NEW TABLE AS %s ",
    1021 ECB             :                              quote_identifier(tgnewtable));
    1022                 :     }
    1023                 : 
    1024 CBC         675 :     if (TRIGGER_FOR_ROW(trigrec->tgtype))
    1025             520 :         appendStringInfoString(&buf, "FOR EACH ROW ");
    1026                 :     else
    1027             155 :         appendStringInfoString(&buf, "FOR EACH STATEMENT ");
    1028 ECB             : 
    1029                 :     /* If the trigger has a WHEN qualification, add that */
    1030 CBC         675 :     value = fastgetattr(ht_trig, Anum_pg_trigger_tgqual,
    1031 ECB             :                         tgrel->rd_att, &isnull);
    1032 CBC         675 :     if (!isnull)
    1033                 :     {
    1034 ECB             :         Node       *qual;
    1035                 :         char        relkind;
    1036                 :         deparse_context context;
    1037                 :         deparse_namespace dpns;
    1038                 :         RangeTblEntry *oldrte;
    1039                 :         RangeTblEntry *newrte;
    1040                 : 
    1041 GIC          72 :         appendStringInfoString(&buf, "WHEN (");
    1042 ECB             : 
    1043 GIC          72 :         qual = stringToNode(TextDatumGetCString(value));
    1044                 : 
    1045 CBC          72 :         relkind = get_rel_relkind(trigrec->tgrelid);
    1046                 : 
    1047 ECB             :         /* Build minimal OLD and NEW RTEs for the rel */
    1048 GIC          72 :         oldrte = makeNode(RangeTblEntry);
    1049              72 :         oldrte->rtekind = RTE_RELATION;
    1050              72 :         oldrte->relid = trigrec->tgrelid;
    1051              72 :         oldrte->relkind = relkind;
    1052              72 :         oldrte->rellockmode = AccessShareLock;
    1053              72 :         oldrte->alias = makeAlias("old", NIL);
    1054              72 :         oldrte->eref = oldrte->alias;
    1055              72 :         oldrte->lateral = false;
    1056 CBC          72 :         oldrte->inh = false;
    1057 GIC          72 :         oldrte->inFromCl = true;
    1058 ECB             : 
    1059 GIC          72 :         newrte = makeNode(RangeTblEntry);
    1060 CBC          72 :         newrte->rtekind = RTE_RELATION;
    1061 GIC          72 :         newrte->relid = trigrec->tgrelid;
    1062              72 :         newrte->relkind = relkind;
    1063 CBC          72 :         newrte->rellockmode = AccessShareLock;
    1064              72 :         newrte->alias = makeAlias("new", NIL);
    1065              72 :         newrte->eref = newrte->alias;
    1066              72 :         newrte->lateral = false;
    1067              72 :         newrte->inh = false;
    1068              72 :         newrte->inFromCl = true;
    1069 ECB             : 
    1070                 :         /* Build two-element rtable */
    1071 CBC          72 :         memset(&dpns, 0, sizeof(dpns));
    1072              72 :         dpns.rtable = list_make2(oldrte, newrte);
    1073 GIC          72 :         dpns.subplans = NIL;
    1074 CBC          72 :         dpns.ctes = NIL;
    1075              72 :         dpns.appendrels = NULL;
    1076              72 :         set_rtable_names(&dpns, NIL, NULL);
    1077              72 :         set_simple_column_names(&dpns);
    1078 ECB             : 
    1079                 :         /* Set up context with one-deep namespace stack */
    1080 CBC          72 :         context.buf = &buf;
    1081              72 :         context.namespaces = list_make1(&dpns);
    1082              72 :         context.windowClause = NIL;
    1083              72 :         context.windowTList = NIL;
    1084 GIC          72 :         context.varprefix = true;
    1085              72 :         context.prettyFlags = GET_PRETTY_FLAGS(pretty);
    1086 CBC          72 :         context.wrapColumn = WRAP_COLUMN_DEFAULT;
    1087              72 :         context.indentLevel = PRETTYINDENT_STD;
    1088              72 :         context.special_exprkind = EXPR_KIND_NONE;
    1089              72 :         context.appendparents = NULL;
    1090 ECB             : 
    1091 CBC          72 :         get_rule_expr(qual, &context, false);
    1092 ECB             : 
    1093 GIC          72 :         appendStringInfoString(&buf, ") ");
    1094                 :     }
    1095 ECB             : 
    1096 CBC         675 :     appendStringInfo(&buf, "EXECUTE FUNCTION %s(",
    1097 ECB             :                      generate_function_name(trigrec->tgfoid, 0,
    1098                 :                                             NIL, NULL,
    1099                 :                                             false, NULL, EXPR_KIND_NONE));
    1100                 : 
    1101 CBC         675 :     if (trigrec->tgnargs > 0)
    1102 ECB             :     {
    1103                 :         char       *p;
    1104                 :         int         i;
    1105                 : 
    1106 CBC         225 :         value = fastgetattr(ht_trig, Anum_pg_trigger_tgargs,
    1107                 :                             tgrel->rd_att, &isnull);
    1108             225 :         if (isnull)
    1109 UIC           0 :             elog(ERROR, "tgargs is null for trigger %u", trigid);
    1110 GIC         225 :         p = (char *) VARDATA_ANY(DatumGetByteaPP(value));
    1111 CBC         598 :         for (i = 0; i < trigrec->tgnargs; i++)
    1112                 :         {
    1113 GIC         373 :             if (i > 0)
    1114             148 :                 appendStringInfoString(&buf, ", ");
    1115             373 :             simple_quote_literal(&buf, p);
    1116 ECB             :             /* advance p to next string embedded in tgargs */
    1117 GIC        3378 :             while (*p)
    1118            3005 :                 p++;
    1119             373 :             p++;
    1120                 :         }
    1121 ECB             :     }
    1122                 : 
    1123                 :     /* We deliberately do not put semi-colon at end */
    1124 GBC         675 :     appendStringInfoChar(&buf, ')');
    1125 ECB             : 
    1126                 :     /* Clean up */
    1127 GIC         675 :     systable_endscan(tgscan);
    1128 ECB             : 
    1129 CBC         675 :     table_close(tgrel, AccessShareLock);
    1130 ECB             : 
    1131 GIC         675 :     return buf.data;
    1132 ECB             : }
    1133                 : 
    1134                 : /* ----------
    1135                 :  * pg_get_indexdef          - Get the definition of an index
    1136                 :  *
    1137                 :  * In the extended version, there is a colno argument as well as pretty bool.
    1138                 :  *  if colno == 0, we want a complete index definition.
    1139                 :  *  if colno > 0, we only want the Nth index key's variable or expression.
    1140                 :  *
    1141                 :  * Note that the SQL-function versions of this omit any info about the
    1142                 :  * index tablespace; this is intentional because pg_dump wants it that way.
    1143                 :  * However pg_get_indexdef_string() includes the index tablespace.
    1144                 :  * ----------
    1145                 :  */
    1146                 : Datum
    1147 GIC        2088 : pg_get_indexdef(PG_FUNCTION_ARGS)
    1148                 : {
    1149            2088 :     Oid         indexrelid = PG_GETARG_OID(0);
    1150                 :     int         prettyFlags;
    1151                 :     char       *res;
    1152                 : 
    1153            2088 :     prettyFlags = PRETTYFLAG_INDENT;
    1154                 : 
    1155            2088 :     res = pg_get_indexdef_worker(indexrelid, 0, NULL,
    1156                 :                                  false, false,
    1157                 :                                  false, false,
    1158                 :                                  prettyFlags, true);
    1159                 : 
    1160            2088 :     if (res == NULL)
    1161               3 :         PG_RETURN_NULL();
    1162 ECB             : 
    1163 GIC        2085 :     PG_RETURN_TEXT_P(string_to_text(res));
    1164 ECB             : }
    1165                 : 
    1166                 : Datum
    1167 GIC         850 : pg_get_indexdef_ext(PG_FUNCTION_ARGS)
    1168 ECB             : {
    1169 GIC         850 :     Oid         indexrelid = PG_GETARG_OID(0);
    1170 CBC         850 :     int32       colno = PG_GETARG_INT32(1);
    1171 GIC         850 :     bool        pretty = PG_GETARG_BOOL(2);
    1172                 :     int         prettyFlags;
    1173                 :     char       *res;
    1174                 : 
    1175 CBC         850 :     prettyFlags = GET_PRETTY_FLAGS(pretty);
    1176 ECB             : 
    1177 GIC         850 :     res = pg_get_indexdef_worker(indexrelid, colno, NULL,
    1178 ECB             :                                  colno != 0, false,
    1179                 :                                  false, false,
    1180                 :                                  prettyFlags, true);
    1181                 : 
    1182 CBC         850 :     if (res == NULL)
    1183 UIC           0 :         PG_RETURN_NULL();
    1184 ECB             : 
    1185 CBC         850 :     PG_RETURN_TEXT_P(string_to_text(res));
    1186 ECB             : }
    1187                 : 
    1188                 : /*
    1189                 :  * Internal version for use by ALTER TABLE.
    1190                 :  * Includes a tablespace clause in the result.
    1191                 :  * Returns a palloc'd C string; no pretty-printing.
    1192                 :  */
    1193                 : char *
    1194 GIC          97 : pg_get_indexdef_string(Oid indexrelid)
    1195                 : {
    1196              97 :     return pg_get_indexdef_worker(indexrelid, 0, NULL,
    1197 ECB             :                                   false, false,
    1198 EUB             :                                   true, true,
    1199                 :                                   0, false);
    1200 ECB             : }
    1201                 : 
    1202                 : /* Internal version that just reports the key-column definitions */
    1203                 : char *
    1204 GIC         550 : pg_get_indexdef_columns(Oid indexrelid, bool pretty)
    1205                 : {
    1206                 :     int         prettyFlags;
    1207                 : 
    1208             550 :     prettyFlags = GET_PRETTY_FLAGS(pretty);
    1209 ECB             : 
    1210 GIC         550 :     return pg_get_indexdef_worker(indexrelid, 0, NULL,
    1211 ECB             :                                   true, true,
    1212                 :                                   false, false,
    1213                 :                                   prettyFlags, false);
    1214                 : }
    1215                 : 
    1216                 : /*
    1217                 :  * Internal workhorse to decompile an index definition.
    1218                 :  *
    1219                 :  * This is now used for exclusion constraints as well: if excludeOps is not
    1220                 :  * NULL then it points to an array of exclusion operator OIDs.
    1221                 :  */
    1222                 : static char *
    1223 CBC        3637 : pg_get_indexdef_worker(Oid indexrelid, int colno,
    1224                 :                        const Oid *excludeOps,
    1225 ECB             :                        bool attrsOnly, bool keysOnly,
    1226                 :                        bool showTblSpc, bool inherits,
    1227                 :                        int prettyFlags, bool missing_ok)
    1228                 : {
    1229                 :     /* might want a separate isConstraint parameter later */
    1230 GIC        3637 :     bool        isConstraint = (excludeOps != NULL);
    1231                 :     HeapTuple   ht_idx;
    1232                 :     HeapTuple   ht_idxrel;
    1233                 :     HeapTuple   ht_am;
    1234                 :     Form_pg_index idxrec;
    1235                 :     Form_pg_class idxrelrec;
    1236                 :     Form_pg_am  amrec;
    1237                 :     IndexAmRoutine *amroutine;
    1238 ECB             :     List       *indexprs;
    1239                 :     ListCell   *indexpr_item;
    1240                 :     List       *context;
    1241                 :     Oid         indrelid;
    1242                 :     int         keyno;
    1243                 :     Datum       indcollDatum;
    1244                 :     Datum       indclassDatum;
    1245                 :     Datum       indoptionDatum;
    1246                 :     oidvector  *indcollation;
    1247                 :     oidvector  *indclass;
    1248                 :     int2vector *indoption;
    1249                 :     StringInfoData buf;
    1250                 :     char       *str;
    1251                 :     char       *sep;
    1252                 : 
    1253                 :     /*
    1254                 :      * Fetch the pg_index tuple by the Oid of the index
    1255                 :      */
    1256 GIC        3637 :     ht_idx = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexrelid));
    1257            3637 :     if (!HeapTupleIsValid(ht_idx))
    1258                 :     {
    1259               3 :         if (missing_ok)
    1260               3 :             return NULL;
    1261 UIC           0 :         elog(ERROR, "cache lookup failed for index %u", indexrelid);
    1262                 :     }
    1263 GIC        3634 :     idxrec = (Form_pg_index) GETSTRUCT(ht_idx);
    1264                 : 
    1265            3634 :     indrelid = idxrec->indrelid;
    1266            3634 :     Assert(indexrelid == idxrec->indexrelid);
    1267                 : 
    1268                 :     /* Must get indcollation, indclass, and indoption the hard way */
    1269 GNC        3634 :     indcollDatum = SysCacheGetAttrNotNull(INDEXRELID, ht_idx,
    1270                 :                                           Anum_pg_index_indcollation);
    1271 GIC        3634 :     indcollation = (oidvector *) DatumGetPointer(indcollDatum);
    1272 ECB             : 
    1273 GNC        3634 :     indclassDatum = SysCacheGetAttrNotNull(INDEXRELID, ht_idx,
    1274                 :                                            Anum_pg_index_indclass);
    1275 CBC        3634 :     indclass = (oidvector *) DatumGetPointer(indclassDatum);
    1276                 : 
    1277 GNC        3634 :     indoptionDatum = SysCacheGetAttrNotNull(INDEXRELID, ht_idx,
    1278                 :                                             Anum_pg_index_indoption);
    1279 GIC        3634 :     indoption = (int2vector *) DatumGetPointer(indoptionDatum);
    1280 ECB             : 
    1281                 :     /*
    1282                 :      * Fetch the pg_class tuple of the index relation
    1283                 :      */
    1284 CBC        3634 :     ht_idxrel = SearchSysCache1(RELOID, ObjectIdGetDatum(indexrelid));
    1285 GIC        3634 :     if (!HeapTupleIsValid(ht_idxrel))
    1286 LBC           0 :         elog(ERROR, "cache lookup failed for relation %u", indexrelid);
    1287 GIC        3634 :     idxrelrec = (Form_pg_class) GETSTRUCT(ht_idxrel);
    1288 ECB             : 
    1289                 :     /*
    1290                 :      * Fetch the pg_am tuple of the index' access method
    1291                 :      */
    1292 GIC        3634 :     ht_am = SearchSysCache1(AMOID, ObjectIdGetDatum(idxrelrec->relam));
    1293            3634 :     if (!HeapTupleIsValid(ht_am))
    1294 UIC           0 :         elog(ERROR, "cache lookup failed for access method %u",
    1295 ECB             :              idxrelrec->relam);
    1296 CBC        3634 :     amrec = (Form_pg_am) GETSTRUCT(ht_am);
    1297 EUB             : 
    1298 ECB             :     /* Fetch the index AM's API struct */
    1299 GIC        3634 :     amroutine = GetIndexAmRoutine(amrec->amhandler);
    1300                 : 
    1301                 :     /*
    1302                 :      * Get the index expressions, if any.  (NOTE: we do not use the relcache
    1303 ECB             :      * versions of the expressions and predicate, because we want to display
    1304                 :      * non-const-folded expressions.)
    1305 EUB             :      */
    1306 GIC        3634 :     if (!heap_attisnull(ht_idx, Anum_pg_index_indexprs, NULL))
    1307 ECB             :     {
    1308                 :         Datum       exprsDatum;
    1309                 :         char       *exprsString;
    1310                 : 
    1311 GNC         276 :         exprsDatum = SysCacheGetAttrNotNull(INDEXRELID, ht_idx,
    1312                 :                                             Anum_pg_index_indexprs);
    1313 GIC         276 :         exprsString = TextDatumGetCString(exprsDatum);
    1314             276 :         indexprs = (List *) stringToNode(exprsString);
    1315 CBC         276 :         pfree(exprsString);
    1316                 :     }
    1317                 :     else
    1318 GIC        3358 :         indexprs = NIL;
    1319                 : 
    1320 CBC        3634 :     indexpr_item = list_head(indexprs);
    1321                 : 
    1322            3634 :     context = deparse_context_for(get_relation_name(indrelid), indrelid);
    1323 ECB             : 
    1324                 :     /*
    1325                 :      * Start the index definition.  Note that the index's name should never be
    1326                 :      * schema-qualified, but the indexed rel's name may be.
    1327                 :      */
    1328 GIC        3634 :     initStringInfo(&buf);
    1329 ECB             : 
    1330 GIC        3634 :     if (!attrsOnly)
    1331 ECB             :     {
    1332 GIC        2859 :         if (!isConstraint)
    1333            5614 :             appendStringInfo(&buf, "CREATE %sINDEX %s ON %s%s USING %s (",
    1334            2807 :                              idxrec->indisunique ? "UNIQUE " : "",
    1335            2807 :                              quote_identifier(NameStr(idxrelrec->relname)),
    1336            2807 :                              idxrelrec->relkind == RELKIND_PARTITIONED_INDEX
    1337 CBC         318 :                              && !inherits ? "ONLY " : "",
    1338 GIC        2807 :                              (prettyFlags & PRETTYFLAG_SCHEMA) ?
    1339 CBC         625 :                              generate_relation_name(indrelid, NIL) :
    1340 GIC        2182 :                              generate_qualified_relation_name(indrelid),
    1341 CBC        2807 :                              quote_identifier(NameStr(amrec->amname)));
    1342 ECB             :         else                    /* currently, must be EXCLUDE constraint */
    1343 CBC          52 :             appendStringInfo(&buf, "EXCLUDE USING %s (",
    1344              52 :                              quote_identifier(NameStr(amrec->amname)));
    1345 ECB             :     }
    1346                 : 
    1347                 :     /*
    1348                 :      * Report the indexed attributes
    1349                 :      */
    1350 CBC        3634 :     sep = "";
    1351 GIC        8973 :     for (keyno = 0; keyno < idxrec->indnatts; keyno++)
    1352 ECB             :     {
    1353 CBC        5387 :         AttrNumber  attnum = idxrec->indkey.values[keyno];
    1354                 :         Oid         keycoltype;
    1355                 :         Oid         keycolcollation;
    1356                 : 
    1357                 :         /*
    1358                 :          * Ignore non-key attributes if told to.
    1359 ECB             :          */
    1360 CBC        5387 :         if (keysOnly && keyno >= idxrec->indnkeyatts)
    1361 GIC          48 :             break;
    1362 ECB             : 
    1363                 :         /* Otherwise, print INCLUDE to divide key and non-key attrs. */
    1364 GIC        5339 :         if (!colno && keyno == idxrec->indnkeyatts)
    1365                 :         {
    1366             124 :             appendStringInfoString(&buf, ") INCLUDE (");
    1367             124 :             sep = "";
    1368                 :         }
    1369 ECB             : 
    1370 CBC        5339 :         if (!colno)
    1371 GIC        5024 :             appendStringInfoString(&buf, sep);
    1372            5339 :         sep = ", ";
    1373 ECB             : 
    1374 GIC        5339 :         if (attnum != 0)
    1375 ECB             :         {
    1376                 :             /* Simple index column */
    1377                 :             char       *attname;
    1378                 :             int32       keycoltypmod;
    1379                 : 
    1380 CBC        4984 :             attname = get_attname(indrelid, attnum, false);
    1381            4984 :             if (!colno || colno == keyno + 1)
    1382 GIC        4900 :                 appendStringInfoString(&buf, quote_identifier(attname));
    1383 CBC        4984 :             get_atttypetypmodcoll(indrelid, attnum,
    1384                 :                                   &keycoltype, &keycoltypmod,
    1385                 :                                   &keycolcollation);
    1386                 :         }
    1387                 :         else
    1388                 :         {
    1389 ECB             :             /* expressional index */
    1390                 :             Node       *indexkey;
    1391                 : 
    1392 CBC         355 :             if (indexpr_item == NULL)
    1393 UIC           0 :                 elog(ERROR, "too few entries in indexprs list");
    1394 GIC         355 :             indexkey = (Node *) lfirst(indexpr_item);
    1395             355 :             indexpr_item = lnext(indexprs, indexpr_item);
    1396                 :             /* Deparse */
    1397             355 :             str = deparse_expression_pretty(indexkey, context, false, false,
    1398                 :                                             prettyFlags, 0);
    1399             355 :             if (!colno || colno == keyno + 1)
    1400                 :             {
    1401 ECB             :                 /* Need parens if it's not a bare function call */
    1402 GBC         349 :                 if (looks_like_function(indexkey))
    1403 CBC          26 :                     appendStringInfoString(&buf, str);
    1404 ECB             :                 else
    1405 GIC         323 :                     appendStringInfo(&buf, "(%s)", str);
    1406 ECB             :             }
    1407 GIC         355 :             keycoltype = exprType(indexkey);
    1408 CBC         355 :             keycolcollation = exprCollation(indexkey);
    1409                 :         }
    1410                 : 
    1411 ECB             :         /* Print additional decoration for (selected) key columns */
    1412 CBC        5339 :         if (!attrsOnly && keyno < idxrec->indnkeyatts &&
    1413 UIC           0 :             (!colno || colno == keyno + 1))
    1414 ECB             :         {
    1415 GIC        4169 :             int16       opt = indoption->values[keyno];
    1416 CBC        4169 :             Oid         indcoll = indcollation->values[keyno];
    1417            4169 :             Datum       attoptions = get_attoptions(indexrelid, keyno + 1);
    1418 GIC        4169 :             bool        has_options = attoptions != (Datum) 0;
    1419                 : 
    1420                 :             /* Add collation, if not default for column */
    1421 CBC        4169 :             if (OidIsValid(indcoll) && indcoll != keycolcollation)
    1422 GBC          54 :                 appendStringInfo(&buf, " COLLATE %s",
    1423                 :                                  generate_collation_name((indcoll)));
    1424 ECB             : 
    1425                 :             /* Add the operator class name, if not default */
    1426 CBC        4169 :             get_opclass_name(indclass->values[keyno],
    1427 ECB             :                              has_options ? InvalidOid : keycoltype, &buf);
    1428                 : 
    1429 GIC        4169 :             if (has_options)
    1430 ECB             :             {
    1431 CBC          15 :                 appendStringInfoString(&buf, " (");
    1432 GIC          15 :                 get_reloptions(&buf, attoptions);
    1433              15 :                 appendStringInfoChar(&buf, ')');
    1434                 :             }
    1435 ECB             : 
    1436                 :             /* Add options if relevant */
    1437 GIC        4169 :             if (amroutine->amcanorder)
    1438 ECB             :             {
    1439                 :                 /* if it supports sort ordering, report DESC and NULLS opts */
    1440 CBC        3520 :                 if (opt & INDOPTION_DESC)
    1441 ECB             :                 {
    1442 LBC           0 :                     appendStringInfoString(&buf, " DESC");
    1443                 :                     /* NULLS FIRST is the default in this case */
    1444 UIC           0 :                     if (!(opt & INDOPTION_NULLS_FIRST))
    1445               0 :                         appendStringInfoString(&buf, " NULLS LAST");
    1446 ECB             :                 }
    1447                 :                 else
    1448                 :                 {
    1449 CBC        3520 :                     if (opt & INDOPTION_NULLS_FIRST)
    1450 UIC           0 :                         appendStringInfoString(&buf, " NULLS FIRST");
    1451 EUB             :                 }
    1452                 :             }
    1453                 : 
    1454                 :             /* Add the exclusion operator if relevant */
    1455 GIC        4169 :             if (excludeOps != NULL)
    1456              62 :                 appendStringInfo(&buf, " WITH %s",
    1457              62 :                                  generate_operator_name(excludeOps[keyno],
    1458 ECB             :                                                         keycoltype,
    1459 EUB             :                                                         keycoltype));
    1460                 :         }
    1461                 :     }
    1462                 : 
    1463 GIC        3634 :     if (!attrsOnly)
    1464 ECB             :     {
    1465 CBC        2859 :         appendStringInfoChar(&buf, ')');
    1466 ECB             : 
    1467 GIC        2859 :         if (idxrec->indnullsnotdistinct)
    1468 GNC           6 :             appendStringInfoString(&buf, " NULLS NOT DISTINCT");
    1469                 : 
    1470                 :         /*
    1471                 :          * If it has options, append "WITH (options)"
    1472 ECB             :          */
    1473 GIC        2859 :         str = flatten_reloptions(indexrelid);
    1474 CBC        2859 :         if (str)
    1475                 :         {
    1476             105 :             appendStringInfo(&buf, " WITH (%s)", str);
    1477             105 :             pfree(str);
    1478                 :         }
    1479                 : 
    1480                 :         /*
    1481                 :          * Print tablespace, but only if requested
    1482 ECB             :          */
    1483 CBC        2859 :         if (showTblSpc)
    1484                 :         {
    1485 ECB             :             Oid         tblspc;
    1486                 : 
    1487 GIC          97 :             tblspc = get_rel_tablespace(indexrelid);
    1488              97 :             if (OidIsValid(tblspc))
    1489                 :             {
    1490              27 :                 if (isConstraint)
    1491 UIC           0 :                     appendStringInfoString(&buf, " USING INDEX");
    1492 CBC          27 :                 appendStringInfo(&buf, " TABLESPACE %s",
    1493 GIC          27 :                                  quote_identifier(get_tablespace_name(tblspc)));
    1494                 :             }
    1495                 :         }
    1496 ECB             : 
    1497                 :         /*
    1498                 :          * If it's a partial index, decompile and append the predicate
    1499                 :          */
    1500 GBC        2859 :         if (!heap_attisnull(ht_idx, Anum_pg_index_indpred, NULL))
    1501 ECB             :         {
    1502                 :             Node       *node;
    1503                 :             Datum       predDatum;
    1504                 :             char       *predString;
    1505                 : 
    1506                 :             /* Convert text string to node tree */
    1507 GNC         154 :             predDatum = SysCacheGetAttrNotNull(INDEXRELID, ht_idx,
    1508                 :                                                Anum_pg_index_indpred);
    1509 GIC         154 :             predString = TextDatumGetCString(predDatum);
    1510             154 :             node = (Node *) stringToNode(predString);
    1511             154 :             pfree(predString);
    1512                 : 
    1513                 :             /* Deparse */
    1514 CBC         154 :             str = deparse_expression_pretty(node, context, false, false,
    1515                 :                                             prettyFlags, 0);
    1516             154 :             if (isConstraint)
    1517              21 :                 appendStringInfo(&buf, " WHERE (%s)", str);
    1518 ECB             :             else
    1519 GIC         133 :                 appendStringInfo(&buf, " WHERE %s", str);
    1520                 :         }
    1521 ECB             :     }
    1522                 : 
    1523                 :     /* Clean up */
    1524 CBC        3634 :     ReleaseSysCache(ht_idx);
    1525 GIC        3634 :     ReleaseSysCache(ht_idxrel);
    1526 CBC        3634 :     ReleaseSysCache(ht_am);
    1527                 : 
    1528 GIC        3634 :     return buf.data;
    1529                 : }
    1530                 : 
    1531 ECB             : /* ----------
    1532                 :  * pg_get_querydef
    1533                 :  *
    1534                 :  * Public entry point to deparse one query parsetree.
    1535                 :  * The pretty flags are determined by GET_PRETTY_FLAGS(pretty).
    1536                 :  *
    1537                 :  * The result is a palloc'd C string.
    1538                 :  * ----------
    1539                 :  */
    1540                 : char *
    1541 UIC           0 : pg_get_querydef(Query *query, bool pretty)
    1542                 : {
    1543                 :     StringInfoData buf;
    1544                 :     int         prettyFlags;
    1545                 : 
    1546               0 :     prettyFlags = GET_PRETTY_FLAGS(pretty);
    1547                 : 
    1548 UBC           0 :     initStringInfo(&buf);
    1549                 : 
    1550 UIC           0 :     get_query_def(query, &buf, NIL, NULL, true,
    1551                 :                   prettyFlags, WRAP_COLUMN_DEFAULT, 0);
    1552                 : 
    1553 UBC           0 :     return buf.data;
    1554                 : }
    1555 EUB             : 
    1556                 : /*
    1557                 :  * pg_get_statisticsobjdef
    1558                 :  *      Get the definition of an extended statistics object
    1559                 :  */
    1560                 : Datum
    1561 GIC         134 : pg_get_statisticsobjdef(PG_FUNCTION_ARGS)
    1562                 : {
    1563             134 :     Oid         statextid = PG_GETARG_OID(0);
    1564                 :     char       *res;
    1565                 : 
    1566             134 :     res = pg_get_statisticsobj_worker(statextid, false, true);
    1567                 : 
    1568 CBC         134 :     if (res == NULL)
    1569 GIC           3 :         PG_RETURN_NULL();
    1570 ECB             : 
    1571 GIC         131 :     PG_RETURN_TEXT_P(string_to_text(res));
    1572                 : }
    1573 ECB             : 
    1574                 : /*
    1575                 :  * Internal version for use by ALTER TABLE.
    1576                 :  * Includes a tablespace clause in the result.
    1577                 :  * Returns a palloc'd C string; no pretty-printing.
    1578                 :  */
    1579                 : char *
    1580 GIC           7 : pg_get_statisticsobjdef_string(Oid statextid)
    1581                 : {
    1582               7 :     return pg_get_statisticsobj_worker(statextid, false, false);
    1583                 : }
    1584                 : 
    1585                 : /*
    1586                 :  * pg_get_statisticsobjdef_columns
    1587 ECB             :  *      Get columns and expressions for an extended statistics object
    1588                 :  */
    1589                 : Datum
    1590 GIC         198 : pg_get_statisticsobjdef_columns(PG_FUNCTION_ARGS)
    1591                 : {
    1592             198 :     Oid         statextid = PG_GETARG_OID(0);
    1593                 :     char       *res;
    1594                 : 
    1595             198 :     res = pg_get_statisticsobj_worker(statextid, true, true);
    1596                 : 
    1597 CBC         198 :     if (res == NULL)
    1598 UIC           0 :         PG_RETURN_NULL();
    1599 ECB             : 
    1600 GIC         198 :     PG_RETURN_TEXT_P(string_to_text(res));
    1601                 : }
    1602 ECB             : 
    1603                 : /*
    1604                 :  * Internal workhorse to decompile an extended statistics object.
    1605 EUB             :  */
    1606                 : static char *
    1607 CBC         339 : pg_get_statisticsobj_worker(Oid statextid, bool columns_only, bool missing_ok)
    1608                 : {
    1609                 :     Form_pg_statistic_ext statextrec;
    1610                 :     HeapTuple   statexttup;
    1611                 :     StringInfoData buf;
    1612                 :     int         colno;
    1613                 :     char       *nsp;
    1614 ECB             :     ArrayType  *arr;
    1615                 :     char       *enabled;
    1616                 :     Datum       datum;
    1617                 :     bool        ndistinct_enabled;
    1618                 :     bool        dependencies_enabled;
    1619                 :     bool        mcv_enabled;
    1620                 :     int         i;
    1621                 :     List       *context;
    1622                 :     ListCell   *lc;
    1623 GIC         339 :     List       *exprs = NIL;
    1624                 :     bool        has_exprs;
    1625                 :     int         ncolumns;
    1626                 : 
    1627             339 :     statexttup = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(statextid));
    1628                 : 
    1629 CBC         339 :     if (!HeapTupleIsValid(statexttup))
    1630                 :     {
    1631 GIC           3 :         if (missing_ok)
    1632               3 :             return NULL;
    1633 LBC           0 :         elog(ERROR, "cache lookup failed for statistics object %u", statextid);
    1634                 :     }
    1635 ECB             : 
    1636                 :     /* has the statistics expressions? */
    1637 CBC         336 :     has_exprs = !heap_attisnull(statexttup, Anum_pg_statistic_ext_stxexprs, NULL);
    1638 ECB             : 
    1639 GBC         336 :     statextrec = (Form_pg_statistic_ext) GETSTRUCT(statexttup);
    1640                 : 
    1641                 :     /*
    1642                 :      * Get the statistics expressions, if any.  (NOTE: we do not use the
    1643 ECB             :      * relcache versions of the expressions, because we want to display
    1644                 :      * non-const-folded expressions.)
    1645                 :      */
    1646 GIC         336 :     if (has_exprs)
    1647                 :     {
    1648                 :         Datum       exprsDatum;
    1649                 :         char       *exprsString;
    1650                 : 
    1651 GNC          71 :         exprsDatum = SysCacheGetAttrNotNull(STATEXTOID, statexttup,
    1652                 :                                             Anum_pg_statistic_ext_stxexprs);
    1653 GIC          71 :         exprsString = TextDatumGetCString(exprsDatum);
    1654              71 :         exprs = (List *) stringToNode(exprsString);
    1655 CBC          71 :         pfree(exprsString);
    1656                 :     }
    1657 ECB             :     else
    1658 CBC         265 :         exprs = NIL;
    1659 ECB             : 
    1660                 :     /* count the number of columns (attributes and expressions) */
    1661 GIC         336 :     ncolumns = statextrec->stxkeys.dim1 + list_length(exprs);
    1662 ECB             : 
    1663 GIC         336 :     initStringInfo(&buf);
    1664                 : 
    1665 CBC         336 :     if (!columns_only)
    1666                 :     {
    1667             138 :         nsp = get_namespace_name_or_temp(statextrec->stxnamespace);
    1668 GIC         138 :         appendStringInfo(&buf, "CREATE STATISTICS %s",
    1669 ECB             :                          quote_qualified_identifier(nsp,
    1670 GIC         138 :                                                     NameStr(statextrec->stxname)));
    1671 ECB             : 
    1672                 :         /*
    1673                 :          * Decode the stxkind column so that we know which stats types to
    1674                 :          * print.
    1675                 :          */
    1676 GNC         138 :         datum = SysCacheGetAttrNotNull(STATEXTOID, statexttup,
    1677                 :                                        Anum_pg_statistic_ext_stxkind);
    1678 GIC         138 :         arr = DatumGetArrayTypeP(datum);
    1679 CBC         138 :         if (ARR_NDIM(arr) != 1 ||
    1680 GIC         138 :             ARR_HASNULL(arr) ||
    1681 CBC         138 :             ARR_ELEMTYPE(arr) != CHAROID)
    1682 LBC           0 :             elog(ERROR, "stxkind is not a 1-D char array");
    1683 CBC         138 :         enabled = (char *) ARR_DATA_PTR(arr);
    1684 ECB             : 
    1685 GBC         138 :         ndistinct_enabled = false;
    1686 CBC         138 :         dependencies_enabled = false;
    1687 GIC         138 :         mcv_enabled = false;
    1688 ECB             : 
    1689 CBC         359 :         for (i = 0; i < ARR_DIMS(arr)[0]; i++)
    1690 ECB             :         {
    1691 GIC         221 :             if (enabled[i] == STATS_EXT_NDISTINCT)
    1692 CBC          75 :                 ndistinct_enabled = true;
    1693 GIC         146 :             else if (enabled[i] == STATS_EXT_DEPENDENCIES)
    1694 CBC          48 :                 dependencies_enabled = true;
    1695              98 :             else if (enabled[i] == STATS_EXT_MCV)
    1696              57 :                 mcv_enabled = true;
    1697 ECB             : 
    1698                 :             /* ignore STATS_EXT_EXPRESSIONS (it's built automatically) */
    1699                 :         }
    1700                 : 
    1701                 :         /*
    1702                 :          * If any option is disabled, then we'll need to append the types
    1703                 :          * clause to show which options are enabled.  We omit the types clause
    1704                 :          * on purpose when all options are enabled, so a pg_dump/pg_restore
    1705                 :          * will create all statistics types on a newer postgres version, if
    1706                 :          * the statistics had all options enabled on the original version.
    1707                 :          *
    1708                 :          * But if the statistics is defined on just a single column, it has to
    1709                 :          * be an expression statistics. In that case we don't need to specify
    1710                 :          * kinds.
    1711                 :          */
    1712 GIC         138 :         if ((!ndistinct_enabled || !dependencies_enabled || !mcv_enabled) &&
    1713                 :             (ncolumns > 1))
    1714                 :         {
    1715 CBC          63 :             bool        gotone = false;
    1716                 : 
    1717 GIC          63 :             appendStringInfoString(&buf, " (");
    1718 ECB             : 
    1719 GIC          63 :             if (ndistinct_enabled)
    1720 ECB             :             {
    1721 GIC          36 :                 appendStringInfoString(&buf, "ndistinct");
    1722 CBC          36 :                 gotone = true;
    1723                 :             }
    1724 ECB             : 
    1725 CBC          63 :             if (dependencies_enabled)
    1726                 :             {
    1727 GIC           9 :                 appendStringInfo(&buf, "%sdependencies", gotone ? ", " : "");
    1728 CBC           9 :                 gotone = true;
    1729                 :             }
    1730 ECB             : 
    1731 CBC          63 :             if (mcv_enabled)
    1732 GIC          18 :                 appendStringInfo(&buf, "%smcv", gotone ? ", " : "");
    1733                 : 
    1734 CBC          63 :             appendStringInfoChar(&buf, ')');
    1735 ECB             :         }
    1736                 : 
    1737 CBC         138 :         appendStringInfoString(&buf, " ON ");
    1738                 :     }
    1739                 : 
    1740 ECB             :     /* decode simple column references */
    1741 GIC         956 :     for (colno = 0; colno < statextrec->stxkeys.dim1; colno++)
    1742                 :     {
    1743             620 :         AttrNumber  attnum = statextrec->stxkeys.values[colno];
    1744 ECB             :         char       *attname;
    1745                 : 
    1746 CBC         620 :         if (colno > 0)
    1747 GIC         349 :             appendStringInfoString(&buf, ", ");
    1748                 : 
    1749 CBC         620 :         attname = get_attname(statextrec->stxrelid, attnum, false);
    1750 ECB             : 
    1751 GIC         620 :         appendStringInfoString(&buf, quote_identifier(attname));
    1752 ECB             :     }
    1753                 : 
    1754 CBC         336 :     context = deparse_context_for(get_relation_name(statextrec->stxrelid),
    1755                 :                                   statextrec->stxrelid);
    1756                 : 
    1757             450 :     foreach(lc, exprs)
    1758                 :     {
    1759 GIC         114 :         Node       *expr = (Node *) lfirst(lc);
    1760 ECB             :         char       *str;
    1761 GIC         114 :         int         prettyFlags = PRETTYFLAG_PAREN;
    1762 ECB             : 
    1763 GIC         114 :         str = deparse_expression_pretty(expr, context, false, false,
    1764 ECB             :                                         prettyFlags, 0);
    1765                 : 
    1766 CBC         114 :         if (colno > 0)
    1767 GIC          49 :             appendStringInfoString(&buf, ", ");
    1768                 : 
    1769 ECB             :         /* Need parens if it's not a bare function call */
    1770 CBC         114 :         if (looks_like_function(expr))
    1771 GIC          17 :             appendStringInfoString(&buf, str);
    1772                 :         else
    1773 CBC          97 :             appendStringInfo(&buf, "(%s)", str);
    1774 ECB             : 
    1775 GIC         114 :         colno++;
    1776 ECB             :     }
    1777                 : 
    1778 CBC         336 :     if (!columns_only)
    1779 GIC         138 :         appendStringInfo(&buf, " FROM %s",
    1780                 :                          generate_relation_name(statextrec->stxrelid, NIL));
    1781 ECB             : 
    1782 CBC         336 :     ReleaseSysCache(statexttup);
    1783                 : 
    1784 GIC         336 :     return buf.data;
    1785 ECB             : }
    1786                 : 
    1787                 : /*
    1788                 :  * Generate text array of expressions for statistics object.
    1789                 :  */
    1790                 : Datum
    1791 UIC           0 : pg_get_statisticsobjdef_expressions(PG_FUNCTION_ARGS)
    1792                 : {
    1793               0 :     Oid         statextid = PG_GETARG_OID(0);
    1794 EUB             :     Form_pg_statistic_ext statextrec;
    1795                 :     HeapTuple   statexttup;
    1796                 :     Datum       datum;
    1797                 :     List       *context;
    1798                 :     ListCell   *lc;
    1799 UIC           0 :     List       *exprs = NIL;
    1800                 :     bool        has_exprs;
    1801 EUB             :     char       *tmp;
    1802 UIC           0 :     ArrayBuildState *astate = NULL;
    1803                 : 
    1804 UBC           0 :     statexttup = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(statextid));
    1805                 : 
    1806               0 :     if (!HeapTupleIsValid(statexttup))
    1807 UIC           0 :         PG_RETURN_NULL();
    1808 EUB             : 
    1809                 :     /* Does the stats object have expressions? */
    1810 UIC           0 :     has_exprs = !heap_attisnull(statexttup, Anum_pg_statistic_ext_stxexprs, NULL);
    1811                 : 
    1812 EUB             :     /* no expressions? we're done */
    1813 UIC           0 :     if (!has_exprs)
    1814                 :     {
    1815 UBC           0 :         ReleaseSysCache(statexttup);
    1816 UIC           0 :         PG_RETURN_NULL();
    1817 EUB             :     }
    1818                 : 
    1819 UIC           0 :     statextrec = (Form_pg_statistic_ext) GETSTRUCT(statexttup);
    1820                 : 
    1821 EUB             :     /*
    1822                 :      * Get the statistics expressions, and deparse them into text values.
    1823                 :      */
    1824 UNC           0 :     datum = SysCacheGetAttrNotNull(STATEXTOID, statexttup,
    1825                 :                                    Anum_pg_statistic_ext_stxexprs);
    1826 UBC           0 :     tmp = TextDatumGetCString(datum);
    1827               0 :     exprs = (List *) stringToNode(tmp);
    1828               0 :     pfree(tmp);
    1829                 : 
    1830               0 :     context = deparse_context_for(get_relation_name(statextrec->stxrelid),
    1831                 :                                   statextrec->stxrelid);
    1832                 : 
    1833               0 :     foreach(lc, exprs)
    1834                 :     {
    1835               0 :         Node       *expr = (Node *) lfirst(lc);
    1836                 :         char       *str;
    1837               0 :         int         prettyFlags = PRETTYFLAG_INDENT;
    1838                 : 
    1839               0 :         str = deparse_expression_pretty(expr, context, false, false,
    1840                 :                                         prettyFlags, 0);
    1841                 : 
    1842               0 :         astate = accumArrayResult(astate,
    1843               0 :                                   PointerGetDatum(cstring_to_text(str)),
    1844                 :                                   false,
    1845                 :                                   TEXTOID,
    1846                 :                                   CurrentMemoryContext);
    1847                 :     }
    1848                 : 
    1849               0 :     ReleaseSysCache(statexttup);
    1850                 : 
    1851               0 :     PG_RETURN_DATUM(makeArrayResult(astate, CurrentMemoryContext));
    1852                 : }
    1853                 : 
    1854                 : /*
    1855                 :  * pg_get_partkeydef
    1856                 :  *
    1857                 :  * Returns the partition key specification, ie, the following:
    1858                 :  *
    1859                 :  * { RANGE | LIST | HASH } (column opt_collation opt_opclass [, ...])
    1860                 :  */
    1861                 : Datum
    1862 CBC         586 : pg_get_partkeydef(PG_FUNCTION_ARGS)
    1863                 : {
    1864             586 :     Oid         relid = PG_GETARG_OID(0);
    1865                 :     char       *res;
    1866                 : 
    1867             586 :     res = pg_get_partkeydef_worker(relid, PRETTYFLAG_INDENT, false, true);
    1868                 : 
    1869             586 :     if (res == NULL)
    1870               3 :         PG_RETURN_NULL();
    1871                 : 
    1872             583 :     PG_RETURN_TEXT_P(string_to_text(res));
    1873                 : }
    1874                 : 
    1875                 : /* Internal version that just reports the column definitions */
    1876                 : char *
    1877              68 : pg_get_partkeydef_columns(Oid relid, bool pretty)
    1878                 : {
    1879                 :     int         prettyFlags;
    1880                 : 
    1881              68 :     prettyFlags = GET_PRETTY_FLAGS(pretty);
    1882                 : 
    1883              68 :     return pg_get_partkeydef_worker(relid, prettyFlags, true, false);
    1884                 : }
    1885                 : 
    1886                 : /*
    1887                 :  * Internal workhorse to decompile a partition key definition.
    1888                 :  */
    1889                 : static char *
    1890             654 : pg_get_partkeydef_worker(Oid relid, int prettyFlags,
    1891                 :                          bool attrsOnly, bool missing_ok)
    1892                 : {
    1893                 :     Form_pg_partitioned_table form;
    1894                 :     HeapTuple   tuple;
    1895                 :     oidvector  *partclass;
    1896                 :     oidvector  *partcollation;
    1897                 :     List       *partexprs;
    1898                 :     ListCell   *partexpr_item;
    1899                 :     List       *context;
    1900                 :     Datum       datum;
    1901                 :     StringInfoData buf;
    1902                 :     int         keyno;
    1903                 :     char       *str;
    1904                 :     char       *sep;
    1905 ECB             : 
    1906 CBC         654 :     tuple = SearchSysCache1(PARTRELID, ObjectIdGetDatum(relid));
    1907 GIC         654 :     if (!HeapTupleIsValid(tuple))
    1908 ECB             :     {
    1909 CBC           3 :         if (missing_ok)
    1910 GBC           3 :             return NULL;
    1911 UIC           0 :         elog(ERROR, "cache lookup failed for partition key of %u", relid);
    1912                 :     }
    1913 ECB             : 
    1914 GIC         651 :     form = (Form_pg_partitioned_table) GETSTRUCT(tuple);
    1915 ECB             : 
    1916 GIC         651 :     Assert(form->partrelid == relid);
    1917                 : 
    1918 ECB             :     /* Must get partclass and partcollation the hard way */
    1919 GNC         651 :     datum = SysCacheGetAttrNotNull(PARTRELID, tuple,
    1920                 :                                    Anum_pg_partitioned_table_partclass);
    1921 CBC         651 :     partclass = (oidvector *) DatumGetPointer(datum);
    1922                 : 
    1923 GNC         651 :     datum = SysCacheGetAttrNotNull(PARTRELID, tuple,
    1924                 :                                    Anum_pg_partitioned_table_partcollation);
    1925 GIC         651 :     partcollation = (oidvector *) DatumGetPointer(datum);
    1926                 : 
    1927                 : 
    1928                 :     /*
    1929                 :      * Get the expressions, if any.  (NOTE: we do not use the relcache
    1930 ECB             :      * versions of the expressions, because we want to display
    1931                 :      * non-const-folded expressions.)
    1932                 :      */
    1933 GIC         651 :     if (!heap_attisnull(tuple, Anum_pg_partitioned_table_partexprs, NULL))
    1934                 :     {
    1935 ECB             :         Datum       exprsDatum;
    1936                 :         char       *exprsString;
    1937                 : 
    1938 GNC          73 :         exprsDatum = SysCacheGetAttrNotNull(PARTRELID, tuple,
    1939                 :                                             Anum_pg_partitioned_table_partexprs);
    1940 GIC          73 :         exprsString = TextDatumGetCString(exprsDatum);
    1941              73 :         partexprs = (List *) stringToNode(exprsString);
    1942 ECB             : 
    1943 GIC          73 :         if (!IsA(partexprs, List))
    1944 UIC           0 :             elog(ERROR, "unexpected node type found in partexprs: %d",
    1945 ECB             :                  (int) nodeTag(partexprs));
    1946                 : 
    1947 CBC          73 :         pfree(exprsString);
    1948 ECB             :     }
    1949                 :     else
    1950 CBC         578 :         partexprs = NIL;
    1951                 : 
    1952             651 :     partexpr_item = list_head(partexprs);
    1953 GIC         651 :     context = deparse_context_for(get_relation_name(relid), relid);
    1954 ECB             : 
    1955 CBC         651 :     initStringInfo(&buf);
    1956 ECB             : 
    1957 CBC         651 :     switch (form->partstrat)
    1958 ECB             :     {
    1959 CBC          27 :         case PARTITION_STRATEGY_HASH:
    1960              27 :             if (!attrsOnly)
    1961              27 :                 appendStringInfoString(&buf, "HASH");
    1962              27 :             break;
    1963             220 :         case PARTITION_STRATEGY_LIST:
    1964             220 :             if (!attrsOnly)
    1965             200 :                 appendStringInfoString(&buf, "LIST");
    1966 GBC         220 :             break;
    1967             404 :         case PARTITION_STRATEGY_RANGE:
    1968 GIC         404 :             if (!attrsOnly)
    1969             356 :                 appendStringInfoString(&buf, "RANGE");
    1970             404 :             break;
    1971 LBC           0 :         default:
    1972               0 :             elog(ERROR, "unexpected partition strategy: %d",
    1973 ECB             :                  (int) form->partstrat);
    1974                 :     }
    1975                 : 
    1976 CBC         651 :     if (!attrsOnly)
    1977 GIC         583 :         appendStringInfoString(&buf, " (");
    1978             651 :     sep = "";
    1979            1378 :     for (keyno = 0; keyno < form->partnatts; keyno++)
    1980                 :     {
    1981 CBC         727 :         AttrNumber  attnum = form->partattrs.values[keyno];
    1982 ECB             :         Oid         keycoltype;
    1983                 :         Oid         keycolcollation;
    1984                 :         Oid         partcoll;
    1985                 : 
    1986 GIC         727 :         appendStringInfoString(&buf, sep);
    1987             727 :         sep = ", ";
    1988             727 :         if (attnum != 0)
    1989 ECB             :         {
    1990                 :             /* Simple attribute reference */
    1991                 :             char       *attname;
    1992                 :             int32       keycoltypmod;
    1993                 : 
    1994 GIC         648 :             attname = get_attname(relid, attnum, false);
    1995             648 :             appendStringInfoString(&buf, quote_identifier(attname));
    1996             648 :             get_atttypetypmodcoll(relid, attnum,
    1997                 :                                   &keycoltype, &keycoltypmod,
    1998                 :                                   &keycolcollation);
    1999                 :         }
    2000 ECB             :         else
    2001 EUB             :         {
    2002 ECB             :             /* Expression */
    2003                 :             Node       *partkey;
    2004                 : 
    2005 GIC          79 :             if (partexpr_item == NULL)
    2006 LBC           0 :                 elog(ERROR, "too few entries in partexprs list");
    2007 GIC          79 :             partkey = (Node *) lfirst(partexpr_item);
    2008              79 :             partexpr_item = lnext(partexprs, partexpr_item);
    2009 ECB             : 
    2010                 :             /* Deparse */
    2011 GIC          79 :             str = deparse_expression_pretty(partkey, context, false, false,
    2012 ECB             :                                             prettyFlags, 0);
    2013                 :             /* Need parens if it's not a bare function call */
    2014 CBC          79 :             if (looks_like_function(partkey))
    2015              28 :                 appendStringInfoString(&buf, str);
    2016                 :             else
    2017 GIC          51 :                 appendStringInfo(&buf, "(%s)", str);
    2018                 : 
    2019 CBC          79 :             keycoltype = exprType(partkey);
    2020              79 :             keycolcollation = exprCollation(partkey);
    2021 ECB             :         }
    2022                 : 
    2023                 :         /* Add collation, if not default for column */
    2024 GIC         727 :         partcoll = partcollation->values[keyno];
    2025 CBC         727 :         if (!attrsOnly && OidIsValid(partcoll) && partcoll != keycolcollation)
    2026               3 :             appendStringInfo(&buf, " COLLATE %s",
    2027                 :                              generate_collation_name((partcoll)));
    2028                 : 
    2029 ECB             :         /* Add the operator class name, if not default */
    2030 CBC         727 :         if (!attrsOnly)
    2031 GIC         632 :             get_opclass_name(partclass->values[keyno], keycoltype, &buf);
    2032                 :     }
    2033 ECB             : 
    2034 GIC         651 :     if (!attrsOnly)
    2035 CBC         583 :         appendStringInfoChar(&buf, ')');
    2036                 : 
    2037                 :     /* Clean up */
    2038 GIC         651 :     ReleaseSysCache(tuple);
    2039                 : 
    2040             651 :     return buf.data;
    2041                 : }
    2042                 : 
    2043                 : /*
    2044 ECB             :  * pg_get_partition_constraintdef
    2045                 :  *
    2046                 :  * Returns partition constraint expression as a string for the input relation
    2047                 :  */
    2048                 : Datum
    2049 GIC          78 : pg_get_partition_constraintdef(PG_FUNCTION_ARGS)
    2050                 : {
    2051              78 :     Oid         relationId = PG_GETARG_OID(0);
    2052 ECB             :     Expr       *constr_expr;
    2053                 :     int         prettyFlags;
    2054                 :     List       *context;
    2055                 :     char       *consrc;
    2056                 : 
    2057 GIC          78 :     constr_expr = get_partition_qual_relid(relationId);
    2058                 : 
    2059                 :     /* Quick exit if no partition constraint */
    2060              78 :     if (constr_expr == NULL)
    2061 CBC           9 :         PG_RETURN_NULL();
    2062 ECB             : 
    2063                 :     /*
    2064                 :      * Deparse and return the constraint expression.
    2065                 :      */
    2066 CBC          69 :     prettyFlags = PRETTYFLAG_INDENT;
    2067 GIC          69 :     context = deparse_context_for(get_relation_name(relationId), relationId);
    2068              69 :     consrc = deparse_expression_pretty((Node *) constr_expr, context, false,
    2069                 :                                        false, prettyFlags, 0);
    2070                 : 
    2071              69 :     PG_RETURN_TEXT_P(string_to_text(consrc));
    2072                 : }
    2073                 : 
    2074                 : /*
    2075                 :  * pg_get_partconstrdef_string
    2076 ECB             :  *
    2077                 :  * Returns the partition constraint as a C-string for the input relation, with
    2078                 :  * the given alias.  No pretty-printing.
    2079                 :  */
    2080                 : char *
    2081 CBC          43 : pg_get_partconstrdef_string(Oid partitionId, char *aliasname)
    2082 ECB             : {
    2083                 :     Expr       *constr_expr;
    2084                 :     List       *context;
    2085                 : 
    2086 GIC          43 :     constr_expr = get_partition_qual_relid(partitionId);
    2087              43 :     context = deparse_context_for(aliasname, partitionId);
    2088                 : 
    2089              43 :     return deparse_expression((Node *) constr_expr, context, true, false);
    2090                 : }
    2091                 : 
    2092                 : /*
    2093                 :  * pg_get_constraintdef
    2094 ECB             :  *
    2095                 :  * Returns the definition for the constraint, ie, everything that needs to
    2096                 :  * appear after "ALTER TABLE ... ADD CONSTRAINT <constraintname>".
    2097                 :  */
    2098                 : Datum
    2099 GIC         843 : pg_get_constraintdef(PG_FUNCTION_ARGS)
    2100 ECB             : {
    2101 GIC         843 :     Oid         constraintId = PG_GETARG_OID(0);
    2102 ECB             :     int         prettyFlags;
    2103                 :     char       *res;
    2104                 : 
    2105 CBC         843 :     prettyFlags = PRETTYFLAG_INDENT;
    2106                 : 
    2107             843 :     res = pg_get_constraintdef_worker(constraintId, false, prettyFlags, true);
    2108                 : 
    2109 GIC         843 :     if (res == NULL)
    2110               3 :         PG_RETURN_NULL();
    2111 ECB             : 
    2112 GIC         840 :     PG_RETURN_TEXT_P(string_to_text(res));
    2113 ECB             : }
    2114                 : 
    2115                 : Datum
    2116 GIC        1521 : pg_get_constraintdef_ext(PG_FUNCTION_ARGS)
    2117                 : {
    2118 CBC        1521 :     Oid         constraintId = PG_GETARG_OID(0);
    2119 GIC        1521 :     bool        pretty = PG_GETARG_BOOL(1);
    2120 ECB             :     int         prettyFlags;
    2121                 :     char       *res;
    2122                 : 
    2123 GBC        1521 :     prettyFlags = GET_PRETTY_FLAGS(pretty);
    2124                 : 
    2125 CBC        1521 :     res = pg_get_constraintdef_worker(constraintId, false, prettyFlags, true);
    2126                 : 
    2127 GIC        1521 :     if (res == NULL)
    2128 UIC           0 :         PG_RETURN_NULL();
    2129                 : 
    2130 GIC        1521 :     PG_RETURN_TEXT_P(string_to_text(res));
    2131                 : }
    2132 ECB             : 
    2133                 : /*
    2134                 :  * Internal version that returns a full ALTER TABLE ... ADD CONSTRAINT command
    2135                 :  */
    2136                 : char *
    2137 GIC         202 : pg_get_constraintdef_command(Oid constraintId)
    2138                 : {
    2139             202 :     return pg_get_constraintdef_worker(constraintId, true, 0, false);
    2140                 : }
    2141 ECB             : 
    2142                 : /*
    2143                 :  * As of 9.4, we now use an MVCC snapshot for this.
    2144                 :  */
    2145                 : static char *
    2146 GIC        2566 : pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
    2147                 :                             int prettyFlags, bool missing_ok)
    2148                 : {
    2149 ECB             :     HeapTuple   tup;
    2150                 :     Form_pg_constraint conForm;
    2151                 :     StringInfoData buf;
    2152                 :     SysScanDesc scandesc;
    2153                 :     ScanKeyData scankey[1];
    2154 GIC        2566 :     Snapshot    snapshot = RegisterSnapshot(GetTransactionSnapshot());
    2155            2566 :     Relation    relation = table_open(ConstraintRelationId, AccessShareLock);
    2156                 : 
    2157 CBC        2566 :     ScanKeyInit(&scankey[0],
    2158                 :                 Anum_pg_constraint_oid,
    2159                 :                 BTEqualStrategyNumber, F_OIDEQ,
    2160                 :                 ObjectIdGetDatum(constraintId));
    2161                 : 
    2162 GIC        2566 :     scandesc = systable_beginscan(relation,
    2163                 :                                   ConstraintOidIndexId,
    2164                 :                                   true,
    2165                 :                                   snapshot,
    2166                 :                                   1,
    2167                 :                                   scankey);
    2168 ECB             : 
    2169                 :     /*
    2170                 :      * We later use the tuple with SysCacheGetAttr() as if we had obtained it
    2171                 :      * via SearchSysCache, which works fine.
    2172                 :      */
    2173 GIC        2566 :     tup = systable_getnext(scandesc);
    2174 ECB             : 
    2175 GIC        2566 :     UnregisterSnapshot(snapshot);
    2176 ECB             : 
    2177 CBC        2566 :     if (!HeapTupleIsValid(tup))
    2178 ECB             :     {
    2179 GIC           3 :         if (missing_ok)
    2180 EUB             :         {
    2181 GIC           3 :             systable_endscan(scandesc);
    2182               3 :             table_close(relation, AccessShareLock);
    2183 CBC           3 :             return NULL;
    2184                 :         }
    2185 LBC           0 :         elog(ERROR, "could not find tuple for constraint %u", constraintId);
    2186                 :     }
    2187 ECB             : 
    2188 GIC        2563 :     conForm = (Form_pg_constraint) GETSTRUCT(tup);
    2189 ECB             : 
    2190 GIC        2563 :     initStringInfo(&buf);
    2191                 : 
    2192            2563 :     if (fullCommand)
    2193                 :     {
    2194             202 :         if (OidIsValid(conForm->conrelid))
    2195                 :         {
    2196                 :             /*
    2197                 :              * Currently, callers want ALTER TABLE (without ONLY) for CHECK
    2198 ECB             :              * constraints, and other types of constraints don't inherit
    2199                 :              * anyway so it doesn't matter whether we say ONLY or not. Someday
    2200                 :              * we might need to let callers specify whether to put ONLY in the
    2201                 :              * command.
    2202                 :              */
    2203 GIC         195 :             appendStringInfo(&buf, "ALTER TABLE %s ADD CONSTRAINT %s ",
    2204                 :                              generate_qualified_relation_name(conForm->conrelid),
    2205 CBC         195 :                              quote_identifier(NameStr(conForm->conname)));
    2206 ECB             :         }
    2207                 :         else
    2208                 :         {
    2209                 :             /* Must be a domain constraint */
    2210 GIC           7 :             Assert(OidIsValid(conForm->contypid));
    2211               7 :             appendStringInfo(&buf, "ALTER DOMAIN %s ADD CONSTRAINT %s ",
    2212 ECB             :                              generate_qualified_type_name(conForm->contypid),
    2213 GIC           7 :                              quote_identifier(NameStr(conForm->conname)));
    2214 ECB             :         }
    2215                 :     }
    2216                 : 
    2217 GIC        2563 :     switch (conForm->contype)
    2218                 :     {
    2219             314 :         case CONSTRAINT_FOREIGN:
    2220                 :             {
    2221 ECB             :                 Datum       val;
    2222                 :                 bool        isnull;
    2223                 :                 const char *string;
    2224                 : 
    2225                 :                 /* Start off the constraint definition */
    2226 GIC         314 :                 appendStringInfoString(&buf, "FOREIGN KEY (");
    2227 ECB             : 
    2228                 :                 /* Fetch and build referencing-column list */
    2229 GNC         314 :                 val = SysCacheGetAttrNotNull(CONSTROID, tup,
    2230                 :                                              Anum_pg_constraint_conkey);
    2231                 : 
    2232 CBC         314 :                 decompile_column_index_array(val, conForm->conrelid, &buf);
    2233                 : 
    2234                 :                 /* add foreign relation name */
    2235             314 :                 appendStringInfo(&buf, ") REFERENCES %s(",
    2236                 :                                  generate_relation_name(conForm->confrelid,
    2237 ECB             :                                                         NIL));
    2238                 : 
    2239                 :                 /* Fetch and build referenced-column list */
    2240 GNC         314 :                 val = SysCacheGetAttrNotNull(CONSTROID, tup,
    2241                 :                                              Anum_pg_constraint_confkey);
    2242 EUB             : 
    2243 GBC         314 :                 decompile_column_index_array(val, conForm->confrelid, &buf);
    2244 EUB             : 
    2245 CBC         314 :                 appendStringInfoChar(&buf, ')');
    2246 ECB             : 
    2247                 :                 /* Add match type */
    2248 GBC         314 :                 switch (conForm->confmatchtype)
    2249 EUB             :                 {
    2250 GIC          17 :                     case FKCONSTR_MATCH_FULL:
    2251              17 :                         string = " MATCH FULL";
    2252              17 :                         break;
    2253 UIC           0 :                     case FKCONSTR_MATCH_PARTIAL:
    2254 LBC           0 :                         string = " MATCH PARTIAL";
    2255 UIC           0 :                         break;
    2256 GIC         297 :                     case FKCONSTR_MATCH_SIMPLE:
    2257 CBC         297 :                         string = "";
    2258 GIC         297 :                         break;
    2259 LBC           0 :                     default:
    2260               0 :                         elog(ERROR, "unrecognized confmatchtype: %d",
    2261 ECB             :                              conForm->confmatchtype);
    2262 EUB             :                         string = "";  /* keep compiler quiet */
    2263                 :                         break;
    2264                 :                 }
    2265 CBC         314 :                 appendStringInfoString(&buf, string);
    2266 ECB             : 
    2267                 :                 /* Add ON UPDATE and ON DELETE clauses, if needed */
    2268 CBC         314 :                 switch (conForm->confupdtype)
    2269 ECB             :                 {
    2270 CBC         252 :                     case FKCONSTR_ACTION_NOACTION:
    2271 GBC         252 :                         string = NULL;  /* suppress default */
    2272             252 :                         break;
    2273 UBC           0 :                     case FKCONSTR_ACTION_RESTRICT:
    2274               0 :                         string = "RESTRICT";
    2275               0 :                         break;
    2276 GIC          48 :                     case FKCONSTR_ACTION_CASCADE:
    2277              48 :                         string = "CASCADE";
    2278              48 :                         break;
    2279              14 :                     case FKCONSTR_ACTION_SETNULL:
    2280 CBC          14 :                         string = "SET NULL";
    2281              14 :                         break;
    2282 UIC           0 :                     case FKCONSTR_ACTION_SETDEFAULT:
    2283 LBC           0 :                         string = "SET DEFAULT";
    2284 UIC           0 :                         break;
    2285 LBC           0 :                     default:
    2286               0 :                         elog(ERROR, "unrecognized confupdtype: %d",
    2287 ECB             :                              conForm->confupdtype);
    2288 EUB             :                         string = NULL;  /* keep compiler quiet */
    2289                 :                         break;
    2290                 :                 }
    2291 CBC         314 :                 if (string)
    2292              62 :                     appendStringInfo(&buf, " ON UPDATE %s", string);
    2293 ECB             : 
    2294 CBC         314 :                 switch (conForm->confdeltype)
    2295 ECB             :                 {
    2296 CBC         254 :                     case FKCONSTR_ACTION_NOACTION:
    2297             254 :                         string = NULL;  /* suppress default */
    2298             254 :                         break;
    2299 LBC           0 :                     case FKCONSTR_ACTION_RESTRICT:
    2300 UBC           0 :                         string = "RESTRICT";
    2301               0 :                         break;
    2302 GIC          48 :                     case FKCONSTR_ACTION_CASCADE:
    2303              48 :                         string = "CASCADE";
    2304              48 :                         break;
    2305               9 :                     case FKCONSTR_ACTION_SETNULL:
    2306 CBC           9 :                         string = "SET NULL";
    2307               9 :                         break;
    2308 GIC           3 :                     case FKCONSTR_ACTION_SETDEFAULT:
    2309               3 :                         string = "SET DEFAULT";
    2310               3 :                         break;
    2311 UIC           0 :                     default:
    2312               0 :                         elog(ERROR, "unrecognized confdeltype: %d",
    2313 ECB             :                              conForm->confdeltype);
    2314                 :                         string = NULL;  /* keep compiler quiet */
    2315                 :                         break;
    2316                 :                 }
    2317 CBC         314 :                 if (string)
    2318              60 :                     appendStringInfo(&buf, " ON DELETE %s", string);
    2319 ECB             : 
    2320                 :                 /*
    2321                 :                  * Add columns specified to SET NULL or SET DEFAULT if
    2322                 :                  * provided.
    2323                 :                  */
    2324 CBC         314 :                 val = SysCacheGetAttr(CONSTROID, tup,
    2325                 :                                       Anum_pg_constraint_confdelsetcols, &isnull);
    2326 GIC         314 :                 if (!isnull)
    2327                 :                 {
    2328 GNC           6 :                     appendStringInfoString(&buf, " (");
    2329 GIC           6 :                     decompile_column_index_array(val, conForm->conrelid, &buf);
    2330 GNC           6 :                     appendStringInfoChar(&buf, ')');
    2331                 :                 }
    2332                 : 
    2333 CBC         314 :                 break;
    2334 ECB             :             }
    2335 GIC        1199 :         case CONSTRAINT_PRIMARY:
    2336 ECB             :         case CONSTRAINT_UNIQUE:
    2337                 :             {
    2338                 :                 Datum       val;
    2339                 :                 Oid         indexId;
    2340                 :                 int         keyatts;
    2341 EUB             :                 HeapTuple   indtup;
    2342 ECB             : 
    2343                 :                 /* Start off the constraint definition */
    2344 GBC        1199 :                 if (conForm->contype == CONSTRAINT_PRIMARY)
    2345 GIC        1047 :                     appendStringInfoString(&buf, "PRIMARY KEY ");
    2346 ECB             :                 else
    2347 GIC         152 :                     appendStringInfoString(&buf, "UNIQUE ");
    2348                 : 
    2349 CBC        1199 :                 indexId = conForm->conindid;
    2350                 : 
    2351 GIC        1199 :                 indtup = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexId));
    2352 CBC        1199 :                 if (!HeapTupleIsValid(indtup))
    2353 UIC           0 :                     elog(ERROR, "cache lookup failed for index %u", indexId);
    2354 CBC        1199 :                 if (conForm->contype == CONSTRAINT_UNIQUE &&
    2355 GIC         152 :                     ((Form_pg_index) GETSTRUCT(indtup))->indnullsnotdistinct)
    2356 UIC           0 :                     appendStringInfoString(&buf, "NULLS NOT DISTINCT ");
    2357 ECB             : 
    2358 GNC        1199 :                 appendStringInfoChar(&buf, '(');
    2359 ECB             : 
    2360                 :                 /* Fetch and build target column list */
    2361 GNC        1199 :                 val = SysCacheGetAttrNotNull(CONSTROID, tup,
    2362                 :                                              Anum_pg_constraint_conkey);
    2363 ECB             : 
    2364 GIC        1199 :                 keyatts = decompile_column_index_array(val, conForm->conrelid, &buf);
    2365 ECB             : 
    2366 GIC        1199 :                 appendStringInfoChar(&buf, ')');
    2367                 : 
    2368 ECB             :                 /* Build including column list (from pg_index.indkeys) */
    2369 GNC        1199 :                 val = SysCacheGetAttrNotNull(INDEXRELID, indtup,
    2370                 :                                              Anum_pg_index_indnatts);
    2371 GIC        1199 :                 if (DatumGetInt32(val) > keyatts)
    2372                 :                 {
    2373 ECB             :                     Datum       cols;
    2374                 :                     Datum      *keys;
    2375                 :                     int         nKeys;
    2376                 :                     int         j;
    2377                 : 
    2378 GIC          41 :                     appendStringInfoString(&buf, " INCLUDE (");
    2379                 : 
    2380 GNC          41 :                     cols = SysCacheGetAttrNotNull(INDEXRELID, indtup,
    2381                 :                                                   Anum_pg_index_indkey);
    2382                 : 
    2383              41 :                     deconstruct_array_builtin(DatumGetArrayTypeP(cols), INT2OID,
    2384                 :                                               &keys, NULL, &nKeys);
    2385                 : 
    2386 GIC         123 :                     for (j = keyatts; j < nKeys; j++)
    2387 ECB             :                     {
    2388                 :                         char       *colName;
    2389 EUB             : 
    2390 GBC          82 :                         colName = get_attname(conForm->conrelid,
    2391 GIC          82 :                                               DatumGetInt16(keys[j]), false);
    2392              82 :                         if (j > keyatts)
    2393              41 :                             appendStringInfoString(&buf, ", ");
    2394              82 :                         appendStringInfoString(&buf, quote_identifier(colName));
    2395                 :                     }
    2396                 : 
    2397              41 :                     appendStringInfoChar(&buf, ')');
    2398                 :                 }
    2399 CBC        1199 :                 ReleaseSysCache(indtup);
    2400 ECB             : 
    2401                 :                 /* XXX why do we only print these bits if fullCommand? */
    2402 CBC        1199 :                 if (fullCommand && OidIsValid(indexId))
    2403                 :                 {
    2404 GIC          90 :                     char       *options = flatten_reloptions(indexId);
    2405 ECB             :                     Oid         tblspc;
    2406                 : 
    2407 CBC          90 :                     if (options)
    2408                 :                     {
    2409 UIC           0 :                         appendStringInfo(&buf, " WITH (%s)", options);
    2410               0 :                         pfree(options);
    2411                 :                     }
    2412                 : 
    2413                 :                     /*
    2414                 :                      * Print the tablespace, unless it's the database default.
    2415                 :                      * This is to help ALTER TABLE usage of this facility,
    2416 ECB             :                      * which needs this behavior to recreate exact catalog
    2417                 :                      * state.
    2418                 :                      */
    2419 CBC          90 :                     tblspc = get_rel_tablespace(indexId);
    2420              90 :                     if (OidIsValid(tblspc))
    2421 GIC          12 :                         appendStringInfo(&buf, " USING INDEX TABLESPACE %s",
    2422              12 :                                          quote_identifier(get_tablespace_name(tblspc)));
    2423 ECB             :                 }
    2424                 : 
    2425 GIC        1199 :                 break;
    2426 ECB             :             }
    2427 GIC         971 :         case CONSTRAINT_CHECK:
    2428                 :             {
    2429                 :                 Datum       val;
    2430                 :                 char       *conbin;
    2431 ECB             :                 char       *consrc;
    2432                 :                 Node       *expr;
    2433                 :                 List       *context;
    2434                 : 
    2435                 :                 /* Fetch constraint expression in parsetree form */
    2436 GNC         971 :                 val = SysCacheGetAttrNotNull(CONSTROID, tup,
    2437                 :                                              Anum_pg_constraint_conbin);
    2438                 : 
    2439 GIC         971 :                 conbin = TextDatumGetCString(val);
    2440             971 :                 expr = stringToNode(conbin);
    2441                 : 
    2442                 :                 /* Set up deparsing context for Var nodes in constraint */
    2443             971 :                 if (conForm->conrelid != InvalidOid)
    2444                 :                 {
    2445                 :                     /* relation constraint */
    2446 CBC         880 :                     context = deparse_context_for(get_relation_name(conForm->conrelid),
    2447                 :                                                   conForm->conrelid);
    2448 ECB             :                 }
    2449                 :                 else
    2450                 :                 {
    2451                 :                     /* domain constraint --- can't have Vars */
    2452 GIC          91 :                     context = NIL;
    2453                 :                 }
    2454                 : 
    2455 CBC         971 :                 consrc = deparse_expression_pretty(expr, context, false, false,
    2456                 :                                                    prettyFlags, 0);
    2457 ECB             : 
    2458                 :                 /*
    2459                 :                  * Now emit the constraint definition, adding NO INHERIT if
    2460                 :                  * necessary.
    2461 EUB             :                  *
    2462 ECB             :                  * There are cases where the constraint expression will be
    2463                 :                  * fully parenthesized and we don't need the outer parens ...
    2464                 :                  * but there are other cases where we do need 'em.  Be
    2465 EUB             :                  * conservative for now.
    2466                 :                  *
    2467                 :                  * Note that simply checking for leading '(' and trailing ')'
    2468                 :                  * would NOT be good enough, consider "(x > 0) AND (y > 0)".
    2469                 :                  */
    2470 GIC         971 :                 appendStringInfo(&buf, "CHECK (%s)%s",
    2471                 :                                  consrc,
    2472             971 :                                  conForm->connoinherit ? " NO INHERIT" : "");
    2473 GBC         971 :                 break;
    2474 EUB             :             }
    2475 GNC          27 :         case CONSTRAINT_NOTNULL:
    2476                 :             {
    2477                 :                 AttrNumber  attnum;
    2478                 : 
    2479              27 :                 attnum = extractNotNullColumn(tup);
    2480                 : 
    2481              27 :                 appendStringInfo(&buf, "NOT NULL %s",
    2482              27 :                                  quote_identifier(get_attname(conForm->conrelid,
    2483                 :                                                               attnum, false)));
    2484              27 :                 if (((Form_pg_constraint) GETSTRUCT(tup))->connoinherit)
    2485 UNC           0 :                     appendStringInfoString(&buf, " NO INHERIT");
    2486 GNC          27 :                 break;
    2487                 :             }
    2488                 : 
    2489 LBC           0 :         case CONSTRAINT_TRIGGER:
    2490                 : 
    2491 ECB             :             /*
    2492                 :              * There isn't an ALTER TABLE syntax for creating a user-defined
    2493                 :              * constraint trigger, but it seems better to print something than
    2494                 :              * throw an error; if we throw error then this function couldn't
    2495                 :              * safely be applied to all rows of pg_constraint.
    2496                 :              */
    2497 UIC           0 :             appendStringInfoString(&buf, "TRIGGER");
    2498               0 :             break;
    2499 CBC          52 :         case CONSTRAINT_EXCLUSION:
    2500                 :             {
    2501 GIC          52 :                 Oid         indexOid = conForm->conindid;
    2502 ECB             :                 Datum       val;
    2503                 :                 Datum      *elems;
    2504                 :                 int         nElems;
    2505                 :                 int         i;
    2506                 :                 Oid        *operators;
    2507                 : 
    2508                 :                 /* Extract operator OIDs from the pg_constraint tuple */
    2509 GNC          52 :                 val = SysCacheGetAttrNotNull(CONSTROID, tup,
    2510                 :                                              Anum_pg_constraint_conexclop);
    2511                 : 
    2512              52 :                 deconstruct_array_builtin(DatumGetArrayTypeP(val), OIDOID,
    2513                 :                                           &elems, NULL, &nElems);
    2514                 : 
    2515 CBC          52 :                 operators = (Oid *) palloc(nElems * sizeof(Oid));
    2516 GIC         114 :                 for (i = 0; i < nElems; i++)
    2517 GBC          62 :                     operators[i] = DatumGetObjectId(elems[i]);
    2518 EUB             : 
    2519                 :                 /* pg_get_indexdef_worker does the rest */
    2520                 :                 /* suppress tablespace because pg_dump wants it that way */
    2521 GIC          52 :                 appendStringInfoString(&buf,
    2522 CBC          52 :                                        pg_get_indexdef_worker(indexOid,
    2523 ECB             :                                                               0,
    2524                 :                                                               operators,
    2525 EUB             :                                                               false,
    2526 ECB             :                                                               false,
    2527                 :                                                               false,
    2528                 :                                                               false,
    2529                 :                                                               prettyFlags,
    2530                 :                                                               false));
    2531 CBC          52 :                 break;
    2532                 :             }
    2533 LBC           0 :         default:
    2534 UIC           0 :             elog(ERROR, "invalid constraint type \"%c\"", conForm->contype);
    2535                 :             break;
    2536                 :     }
    2537                 : 
    2538 GIC        2563 :     if (conForm->condeferrable)
    2539              20 :         appendStringInfoString(&buf, " DEFERRABLE");
    2540            2563 :     if (conForm->condeferred)
    2541 UIC           0 :         appendStringInfoString(&buf, " INITIALLY DEFERRED");
    2542 GIC        2563 :     if (!conForm->convalidated)
    2543 CBC          47 :         appendStringInfoString(&buf, " NOT VALID");
    2544                 : 
    2545                 :     /* Cleanup */
    2546 GIC        2563 :     systable_endscan(scandesc);
    2547            2563 :     table_close(relation, AccessShareLock);
    2548                 : 
    2549            2563 :     return buf.data;
    2550                 : }
    2551 ECB             : 
    2552                 : 
    2553                 : /*
    2554                 :  * Convert an int16[] Datum into a comma-separated list of column names
    2555                 :  * for the indicated relation; append the list to buf.  Returns the number
    2556                 :  * of keys.
    2557                 :  */
    2558                 : static int
    2559 GIC        1833 : decompile_column_index_array(Datum column_index_array, Oid relId,
    2560 ECB             :                              StringInfo buf)
    2561                 : {
    2562                 :     Datum      *keys;
    2563                 :     int         nKeys;
    2564                 :     int         j;
    2565                 : 
    2566                 :     /* Extract data from array of int16 */
    2567 GNC        1833 :     deconstruct_array_builtin(DatumGetArrayTypeP(column_index_array), INT2OID,
    2568                 :                               &keys, NULL, &nKeys);
    2569                 : 
    2570 GIC        4229 :     for (j = 0; j < nKeys; j++)
    2571                 :     {
    2572                 :         char       *colName;
    2573                 : 
    2574            2396 :         colName = get_attname(relId, DatumGetInt16(keys[j]), false);
    2575                 : 
    2576            2396 :         if (j == 0)
    2577            1833 :             appendStringInfoString(buf, quote_identifier(colName));
    2578                 :         else
    2579             563 :             appendStringInfo(buf, ", %s", quote_identifier(colName));
    2580                 :     }
    2581                 : 
    2582            1833 :     return nKeys;
    2583                 : }
    2584                 : 
    2585                 : 
    2586                 : /* ----------
    2587                 :  * pg_get_expr          - Decompile an expression tree
    2588                 :  *
    2589 ECB             :  * Input: an expression tree in nodeToString form, and a relation OID
    2590                 :  *
    2591                 :  * Output: reverse-listed expression
    2592                 :  *
    2593                 :  * Currently, the expression can only refer to a single relation, namely
    2594                 :  * the one specified by the second parameter.  This is sufficient for
    2595                 :  * partial indexes, column default expressions, etc.  We also support
    2596                 :  * Var-free expressions, for which the OID can be InvalidOid.
    2597                 :  *
    2598                 :  * We expect this function to work, or throw a reasonably clean error,
    2599                 :  * for any node tree that can appear in a catalog pg_node_tree column.
    2600                 :  * Query trees, such as those appearing in pg_rewrite.ev_action, are
    2601                 :  * not supported.  Nor are expressions in more than one relation, which
    2602                 :  * can appear in places like pg_rewrite.ev_qual.
    2603                 :  * ----------
    2604                 :  */
    2605                 : Datum
    2606 GIC        3353 : pg_get_expr(PG_FUNCTION_ARGS)
    2607                 : {
    2608            3353 :     text       *expr = PG_GETARG_TEXT_PP(0);
    2609 CBC        3353 :     Oid         relid = PG_GETARG_OID(1);
    2610 EUB             :     int         prettyFlags;
    2611                 :     char       *relname;
    2612                 : 
    2613 GBC        3353 :     prettyFlags = PRETTYFLAG_INDENT;
    2614                 : 
    2615 CBC        3353 :     if (OidIsValid(relid))
    2616                 :     {
    2617                 :         /* Get the name for the relation */
    2618 GIC        3353 :         relname = get_rel_name(relid);
    2619 ECB             : 
    2620                 :         /*
    2621                 :          * If the OID isn't actually valid, don't throw an error, just return
    2622                 :          * NULL.  This is a bit questionable, but it's what we've done
    2623                 :          * historically, and it can help avoid unwanted failures when
    2624                 :          * examining catalog entries for just-deleted relations.
    2625                 :          */
    2626 GIC        3353 :         if (relname == NULL)
    2627 LBC           0 :             PG_RETURN_NULL();
    2628                 :     }
    2629 ECB             :     else
    2630 UIC           0 :         relname = NULL;
    2631                 : 
    2632 CBC        3353 :     PG_RETURN_TEXT_P(pg_get_expr_worker(expr, relid, relname, prettyFlags));
    2633                 : }
    2634 ECB             : 
    2635 EUB             : Datum
    2636 GIC         203 : pg_get_expr_ext(PG_FUNCTION_ARGS)
    2637                 : {
    2638 GBC         203 :     text       *expr = PG_GETARG_TEXT_PP(0);
    2639 GIC         203 :     Oid         relid = PG_GETARG_OID(1);
    2640 CBC         203 :     bool        pretty = PG_GETARG_BOOL(2);
    2641                 :     int         prettyFlags;
    2642                 :     char       *relname;
    2643                 : 
    2644             203 :     prettyFlags = GET_PRETTY_FLAGS(pretty);
    2645                 : 
    2646 GIC         203 :     if (OidIsValid(relid))
    2647                 :     {
    2648                 :         /* Get the name for the relation */
    2649             203 :         relname = get_rel_name(relid);
    2650                 :         /* See notes above */
    2651             203 :         if (relname == NULL)
    2652 UIC           0 :             PG_RETURN_NULL();
    2653                 :     }
    2654 ECB             :     else
    2655 UIC           0 :         relname = NULL;
    2656                 : 
    2657 CBC         203 :     PG_RETURN_TEXT_P(pg_get_expr_worker(expr, relid, relname, prettyFlags));
    2658                 : }
    2659 ECB             : 
    2660                 : static text *
    2661 GIC        3556 : pg_get_expr_worker(text *expr, Oid relid, const char *relname, int prettyFlags)
    2662                 : {
    2663                 :     Node       *node;
    2664                 :     Node       *tst;
    2665                 :     Relids      relids;
    2666                 :     List       *context;
    2667 ECB             :     char       *exprstr;
    2668                 :     char       *str;
    2669 EUB             : 
    2670 ECB             :     /* Convert input pg_node_tree (really TEXT) object to C string */
    2671 GBC        3556 :     exprstr = text_to_cstring(expr);
    2672                 : 
    2673                 :     /* Convert expression to node tree */
    2674 GIC        3556 :     node = (Node *) stringToNode(exprstr);
    2675                 : 
    2676            3556 :     pfree(exprstr);
    2677                 : 
    2678                 :     /*
    2679 ECB             :      * Throw error if the input is a querytree rather than an expression tree.
    2680                 :      * While we could support queries here, there seems no very good reason
    2681                 :      * to.  In most such catalog columns, we'll see a List of Query nodes, or
    2682                 :      * even nested Lists, so drill down to a non-List node before checking.
    2683 EUB             :      */
    2684 GIC        3556 :     tst = node;
    2685            3556 :     while (tst && IsA(tst, List))
    2686 UIC           0 :         tst = linitial((List *) tst);
    2687 GIC        3556 :     if (tst && IsA(tst, Query))
    2688 UIC           0 :         ereport(ERROR,
    2689 EUB             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    2690                 :                  errmsg("input is a query, not an expression")));
    2691                 : 
    2692                 :     /*
    2693                 :      * Throw error if the expression contains Vars we won't be able to
    2694                 :      * deparse.
    2695                 :      */
    2696 CBC        3556 :     relids = pull_varnos(NULL, node);
    2697            3556 :     if (OidIsValid(relid))
    2698                 :     {
    2699 GBC        3556 :         if (!bms_is_subset(relids, bms_make_singleton(1)))
    2700 UIC           0 :             ereport(ERROR,
    2701                 :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    2702 ECB             :                      errmsg("expression contains variables of more than one relation")));
    2703                 :     }
    2704                 :     else
    2705                 :     {
    2706 UIC           0 :         if (!bms_is_empty(relids))
    2707               0 :             ereport(ERROR,
    2708                 :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    2709                 :                      errmsg("expression contains variables")));
    2710                 :     }
    2711                 : 
    2712                 :     /* Prepare deparse context if needed */
    2713 GIC        3556 :     if (OidIsValid(relid))
    2714            3556 :         context = deparse_context_for(relname, relid);
    2715 ECB             :     else
    2716 UIC           0 :         context = NIL;
    2717 ECB             : 
    2718                 :     /* Deparse */
    2719 GIC        3556 :     str = deparse_expression_pretty(node, context, false, false,
    2720                 :                                     prettyFlags, 0);
    2721                 : 
    2722            3556 :     return string_to_text(str);
    2723                 : }
    2724                 : 
    2725 ECB             : 
    2726                 : /* ----------
    2727                 :  * pg_get_userbyid      - Get a user name by roleid and
    2728                 :  *                fallback to 'unknown (OID=n)'
    2729                 :  * ----------
    2730                 :  */
    2731                 : Datum
    2732 CBC         774 : pg_get_userbyid(PG_FUNCTION_ARGS)
    2733                 : {
    2734             774 :     Oid         roleid = PG_GETARG_OID(0);
    2735 ECB             :     Name        result;
    2736                 :     HeapTuple   roletup;
    2737                 :     Form_pg_authid role_rec;
    2738                 : 
    2739 EUB             :     /*
    2740                 :      * Allocate space for the result
    2741 ECB             :      */
    2742 GIC         774 :     result = (Name) palloc(NAMEDATALEN);
    2743             774 :     memset(NameStr(*result), 0, NAMEDATALEN);
    2744                 : 
    2745                 :     /*
    2746                 :      * Get the pg_authid entry and print the result
    2747                 :      */
    2748             774 :     roletup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
    2749             774 :     if (HeapTupleIsValid(roletup))
    2750                 :     {
    2751             774 :         role_rec = (Form_pg_authid) GETSTRUCT(roletup);
    2752             774 :         *result = role_rec->rolname;
    2753 CBC         774 :         ReleaseSysCache(roletup);
    2754                 :     }
    2755 ECB             :     else
    2756 LBC           0 :         sprintf(NameStr(*result), "unknown (OID=%u)", roleid);
    2757                 : 
    2758 GIC         774 :     PG_RETURN_NAME(result);
    2759                 : }
    2760                 : 
    2761 ECB             : 
    2762                 : /*
    2763                 :  * pg_get_serial_sequence
    2764                 :  *      Get the name of the sequence used by an identity or serial column,
    2765                 :  *      formatted suitably for passing to setval, nextval or currval.
    2766                 :  *      First parameter is not treated as double-quoted, second parameter
    2767                 :  *      is --- see documentation for reason.
    2768                 :  */
    2769                 : Datum
    2770 GIC           6 : pg_get_serial_sequence(PG_FUNCTION_ARGS)
    2771                 : {
    2772 CBC           6 :     text       *tablename = PG_GETARG_TEXT_PP(0);
    2773 GIC           6 :     text       *columnname = PG_GETARG_TEXT_PP(1);
    2774 ECB             :     RangeVar   *tablerv;
    2775                 :     Oid         tableOid;
    2776 EUB             :     char       *column;
    2777                 :     AttrNumber  attnum;
    2778 GIC           6 :     Oid         sequenceId = InvalidOid;
    2779                 :     Relation    depRel;
    2780                 :     ScanKeyData key[3];
    2781                 :     SysScanDesc scan;
    2782 ECB             :     HeapTuple   tup;
    2783                 : 
    2784                 :     /* Look up table name.  Can't lock it - we might not have privileges. */
    2785 GIC           6 :     tablerv = makeRangeVarFromNameList(textToQualifiedNameList(tablename));
    2786               6 :     tableOid = RangeVarGetRelid(tablerv, NoLock, false);
    2787                 : 
    2788 ECB             :     /* Get the number of the column */
    2789 GIC           6 :     column = text_to_cstring(columnname);
    2790                 : 
    2791               6 :     attnum = get_attnum(tableOid, column);
    2792 CBC           6 :     if (attnum == InvalidAttrNumber)
    2793 UIC           0 :         ereport(ERROR,
    2794                 :                 (errcode(ERRCODE_UNDEFINED_COLUMN),
    2795                 :                  errmsg("column \"%s\" of relation \"%s\" does not exist",
    2796                 :                         column, tablerv->relname)));
    2797 ECB             : 
    2798                 :     /* Search the dependency table for the dependent sequence */
    2799 GIC           6 :     depRel = table_open(DependRelationId, AccessShareLock);
    2800 ECB             : 
    2801 GIC           6 :     ScanKeyInit(&key[0],
    2802 ECB             :                 Anum_pg_depend_refclassid,
    2803                 :                 BTEqualStrategyNumber, F_OIDEQ,
    2804                 :                 ObjectIdGetDatum(RelationRelationId));
    2805 GIC           6 :     ScanKeyInit(&key[1],
    2806                 :                 Anum_pg_depend_refobjid,
    2807                 :                 BTEqualStrategyNumber, F_OIDEQ,
    2808                 :                 ObjectIdGetDatum(tableOid));
    2809 CBC           6 :     ScanKeyInit(&key[2],
    2810 ECB             :                 Anum_pg_depend_refobjsubid,
    2811                 :                 BTEqualStrategyNumber, F_INT4EQ,
    2812                 :                 Int32GetDatum(attnum));
    2813                 : 
    2814 GIC           6 :     scan = systable_beginscan(depRel, DependReferenceIndexId, true,
    2815 ECB             :                               NULL, 3, key);
    2816                 : 
    2817 GIC          15 :     while (HeapTupleIsValid(tup = systable_getnext(scan)))
    2818                 :     {
    2819              15 :         Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
    2820 ECB             : 
    2821                 :         /*
    2822                 :          * Look for an auto dependency (serial column) or internal dependency
    2823                 :          * (identity column) of a sequence on a column.  (We need the relkind
    2824                 :          * test because indexes can also have auto dependencies on columns.)
    2825                 :          */
    2826 GIC          15 :         if (deprec->classid == RelationRelationId &&
    2827 CBC           6 :             deprec->objsubid == 0 &&
    2828 GIC           6 :             (deprec->deptype == DEPENDENCY_AUTO ||
    2829 CBC           9 :              deprec->deptype == DEPENDENCY_INTERNAL) &&
    2830 GIC           6 :             get_rel_relkind(deprec->objid) == RELKIND_SEQUENCE)
    2831                 :         {
    2832 GBC           6 :             sequenceId = deprec->objid;
    2833 GIC           6 :             break;
    2834                 :         }
    2835                 :     }
    2836                 : 
    2837               6 :     systable_endscan(scan);
    2838               6 :     table_close(depRel, AccessShareLock);
    2839                 : 
    2840               6 :     if (OidIsValid(sequenceId))
    2841                 :     {
    2842                 :         char       *result;
    2843                 : 
    2844               6 :         result = generate_qualified_relation_name(sequenceId);
    2845                 : 
    2846               6 :         PG_RETURN_TEXT_P(string_to_text(result));
    2847 ECB             :     }
    2848                 : 
    2849 LBC           0 :     PG_RETURN_NULL();
    2850                 : }
    2851                 : 
    2852                 : 
    2853                 : /*
    2854                 :  * pg_get_functiondef
    2855                 :  *      Returns the complete "CREATE OR REPLACE FUNCTION ..." statement for
    2856                 :  *      the specified function.
    2857                 :  *
    2858                 :  * Note: if you change the output format of this function, be careful not
    2859                 :  * to break psql's rules (in \ef and \sf) for identifying the start of the
    2860                 :  * function body.  To wit: the function body starts on a line that begins with
    2861                 :  * "AS ", "BEGIN ", or "RETURN ", and no preceding line will look like that.
    2862                 :  */
    2863 ECB             : Datum
    2864 GIC          73 : pg_get_functiondef(PG_FUNCTION_ARGS)
    2865                 : {
    2866 CBC          73 :     Oid         funcid = PG_GETARG_OID(0);
    2867 ECB             :     StringInfoData buf;
    2868                 :     StringInfoData dq;
    2869                 :     HeapTuple   proctup;
    2870                 :     Form_pg_proc proc;
    2871                 :     bool        isfunction;
    2872                 :     Datum       tmp;
    2873                 :     bool        isnull;
    2874 EUB             :     const char *prosrc;
    2875                 :     const char *name;
    2876                 :     const char *nsp;
    2877                 :     float4      procost;
    2878 ECB             :     int         oldlen;
    2879                 : 
    2880 GIC          73 :     initStringInfo(&buf);
    2881                 : 
    2882                 :     /* Look up the function */
    2883              73 :     proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
    2884 CBC          73 :     if (!HeapTupleIsValid(proctup))
    2885               3 :         PG_RETURN_NULL();
    2886                 : 
    2887 GIC          70 :     proc = (Form_pg_proc) GETSTRUCT(proctup);
    2888 CBC          70 :     name = NameStr(proc->proname);
    2889 ECB             : 
    2890 CBC          70 :     if (proc->prokind == PROKIND_AGGREGATE)
    2891 UIC           0 :         ereport(ERROR,
    2892 ECB             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    2893                 :                  errmsg("\"%s\" is an aggregate function", name)));
    2894                 : 
    2895 GIC          70 :     isfunction = (proc->prokind != PROKIND_PROCEDURE);
    2896                 : 
    2897 ECB             :     /*
    2898                 :      * We always qualify the function name, to ensure the right function gets
    2899                 :      * replaced.
    2900                 :      */
    2901 GIC          70 :     nsp = get_namespace_name_or_temp(proc->pronamespace);
    2902              70 :     appendStringInfo(&buf, "CREATE OR REPLACE %s %s(",
    2903 ECB             :                      isfunction ? "FUNCTION" : "PROCEDURE",
    2904                 :                      quote_qualified_identifier(nsp, name));
    2905 CBC          70 :     (void) print_function_arguments(&buf, proctup, false, true);
    2906 GBC          70 :     appendStringInfoString(&buf, ")\n");
    2907 CBC          70 :     if (isfunction)
    2908                 :     {
    2909              61 :         appendStringInfoString(&buf, " RETURNS ");
    2910              61 :         print_function_rettype(&buf, proctup);
    2911              61 :         appendStringInfoChar(&buf, '\n');
    2912 ECB             :     }
    2913                 : 
    2914 CBC          70 :     print_function_trftypes(&buf, proctup);
    2915 ECB             : 
    2916 CBC          70 :     appendStringInfo(&buf, " LANGUAGE %s\n",
    2917 GIC          70 :                      quote_identifier(get_language_name(proc->prolang, false)));
    2918                 : 
    2919 ECB             :     /* Emit some miscellaneous options on one line */
    2920 GIC          70 :     oldlen = buf.len;
    2921 ECB             : 
    2922 CBC          70 :     if (proc->prokind == PROKIND_WINDOW)
    2923 LBC           0 :         appendStringInfoString(&buf, " WINDOW");
    2924 GBC          70 :     switch (proc->provolatile)
    2925 EUB             :     {
    2926 GBC          12 :         case PROVOLATILE_IMMUTABLE:
    2927 CBC          12 :             appendStringInfoString(&buf, " IMMUTABLE");
    2928              12 :             break;
    2929 GIC           9 :         case PROVOLATILE_STABLE:
    2930               9 :             appendStringInfoString(&buf, " STABLE");
    2931 CBC           9 :             break;
    2932              49 :         case PROVOLATILE_VOLATILE:
    2933              49 :             break;
    2934 ECB             :     }
    2935                 : 
    2936 GBC          70 :     switch (proc->proparallel)
    2937                 :     {
    2938 GIC          19 :         case PROPARALLEL_SAFE:
    2939 CBC          19 :             appendStringInfoString(&buf, " PARALLEL SAFE");
    2940              19 :             break;
    2941 LBC           0 :         case PROPARALLEL_RESTRICTED:
    2942 UIC           0 :             appendStringInfoString(&buf, " PARALLEL RESTRICTED");
    2943 LBC           0 :             break;
    2944 CBC          51 :         case PROPARALLEL_UNSAFE:
    2945              51 :             break;
    2946                 :     }
    2947 ECB             : 
    2948 GBC          70 :     if (proc->proisstrict)
    2949 GIC          24 :         appendStringInfoString(&buf, " STRICT");
    2950 CBC          70 :     if (proc->prosecdef)
    2951 GIC           3 :         appendStringInfoString(&buf, " SECURITY DEFINER");
    2952              70 :     if (proc->proleakproof)
    2953 UIC           0 :         appendStringInfoString(&buf, " LEAKPROOF");
    2954                 : 
    2955                 :     /* This code for the default cost and rows should match functioncmds.c */
    2956 GIC          70 :     if (proc->prolang == INTERNALlanguageId ||
    2957              70 :         proc->prolang == ClanguageId)
    2958 GBC           4 :         procost = 1;
    2959 EUB             :     else
    2960 GIC          66 :         procost = 100;
    2961              70 :     if (proc->procost != procost)
    2962               3 :         appendStringInfo(&buf, " COST %g", proc->procost);
    2963                 : 
    2964              70 :     if (proc->prorows > 0 && proc->prorows != 1000)
    2965 LBC           0 :         appendStringInfo(&buf, " ROWS %g", proc->prorows);
    2966 ECB             : 
    2967 GIC          70 :     if (proc->prosupport)
    2968                 :     {
    2969 ECB             :         Oid         argtypes[1];
    2970                 : 
    2971                 :         /*
    2972                 :          * We should qualify the support function's name if it wouldn't be
    2973                 :          * resolved by lookup in the current search path.
    2974                 :          */
    2975 LBC           0 :         argtypes[0] = INTERNALOID;
    2976               0 :         appendStringInfo(&buf, " SUPPORT %s",
    2977 ECB             :                          generate_function_name(proc->prosupport, 1,
    2978                 :                                                 NIL, argtypes,
    2979                 :                                                 false, NULL, EXPR_KIND_NONE));
    2980                 :     }
    2981                 : 
    2982 GIC          70 :     if (oldlen != buf.len)
    2983 CBC          31 :         appendStringInfoChar(&buf, '\n');
    2984                 : 
    2985                 :     /* Emit any proconfig options, one per line */
    2986 GIC          70 :     tmp = SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_proconfig, &isnull);
    2987              70 :     if (!isnull)
    2988                 :     {
    2989 CBC           3 :         ArrayType  *a = DatumGetArrayTypeP(tmp);
    2990                 :         int         i;
    2991 ECB             : 
    2992 GIC           3 :         Assert(ARR_ELEMTYPE(a) == TEXTOID);
    2993               3 :         Assert(ARR_NDIM(a) == 1);
    2994 CBC           3 :         Assert(ARR_LBOUND(a)[0] == 1);
    2995 ECB             : 
    2996 GBC          18 :         for (i = 1; i <= ARR_DIMS(a)[0]; i++)
    2997 ECB             :         {
    2998                 :             Datum       d;
    2999                 : 
    3000 GIC          15 :             d = array_ref(a, 1, &i,
    3001                 :                           -1 /* varlenarray */ ,
    3002                 :                           -1 /* TEXT's typlen */ ,
    3003                 :                           false /* TEXT's typbyval */ ,
    3004                 :                           TYPALIGN_INT /* TEXT's typalign */ ,
    3005                 :                           &isnull);
    3006              15 :             if (!isnull)
    3007                 :             {
    3008              15 :                 char       *configitem = TextDatumGetCString(d);
    3009                 :                 char       *pos;
    3010                 : 
    3011              15 :                 pos = strchr(configitem, '=');
    3012              15 :                 if (pos == NULL)
    3013 UIC           0 :                     continue;
    3014 GIC          15 :                 *pos++ = '\0';
    3015                 : 
    3016              15 :                 appendStringInfo(&buf, " SET %s TO ",
    3017                 :                                  quote_identifier(configitem));
    3018 ECB             : 
    3019                 :                 /*
    3020                 :                  * Variables that are marked GUC_LIST_QUOTE were already fully
    3021                 :                  * quoted by flatten_set_variable_args() before they were put
    3022                 :                  * into the proconfig array.  However, because the quoting
    3023                 :                  * rules used there aren't exactly like SQL's, we have to
    3024                 :                  * break the list value apart and then quote the elements as
    3025                 :                  * string literals.  (The elements may be double-quoted as-is,
    3026                 :                  * but we can't just feed them to the SQL parser; it would do
    3027 EUB             :                  * the wrong thing with elements that are zero-length or
    3028                 :                  * longer than NAMEDATALEN.)
    3029 ECB             :                  *
    3030                 :                  * Variables that are not so marked should just be emitted as
    3031                 :                  * simple string literals.  If the variable is not known to
    3032                 :                  * guc.c, we'll do that; this makes it unsafe to use
    3033                 :                  * GUC_LIST_QUOTE for extension variables.
    3034                 :                  */
    3035 CBC          15 :                 if (GetConfigOptionFlags(configitem, true) & GUC_LIST_QUOTE)
    3036                 :                 {
    3037                 :                     List       *namelist;
    3038                 :                     ListCell   *lc;
    3039 ECB             : 
    3040                 :                     /* Parse string into list of identifiers */
    3041 GIC           6 :                     if (!SplitGUCList(pos, ',', &namelist))
    3042                 :                     {
    3043                 :                         /* this shouldn't fail really */
    3044 UIC           0 :                         elog(ERROR, "invalid list syntax in proconfig item");
    3045                 :                     }
    3046 CBC          21 :                     foreach(lc, namelist)
    3047 ECB             :                     {
    3048 GIC          15 :                         char       *curname = (char *) lfirst(lc);
    3049 ECB             : 
    3050 GIC          15 :                         simple_quote_literal(&buf, curname);
    3051              15 :                         if (lnext(namelist, lc))
    3052               9 :                             appendStringInfoString(&buf, ", ");
    3053 ECB             :                     }
    3054                 :                 }
    3055                 :                 else
    3056 CBC           9 :                     simple_quote_literal(&buf, pos);
    3057 GIC          15 :                 appendStringInfoChar(&buf, '\n');
    3058 ECB             :             }
    3059                 :         }
    3060                 :     }
    3061                 : 
    3062                 :     /* And finally the function definition ... */
    3063 CBC          70 :     (void) SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_prosqlbody, &isnull);
    3064 GIC          70 :     if (proc->prolang == SQLlanguageId && !isnull)
    3065                 :     {
    3066              39 :         print_function_sqlbody(&buf, proctup);
    3067                 :     }
    3068                 :     else
    3069                 :     {
    3070              31 :         appendStringInfoString(&buf, "AS ");
    3071                 : 
    3072              31 :         tmp = SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_probin, &isnull);
    3073 CBC          31 :         if (!isnull)
    3074 ECB             :         {
    3075 CBC           4 :             simple_quote_literal(&buf, TextDatumGetCString(tmp));
    3076               4 :             appendStringInfoString(&buf, ", "); /* assume prosrc isn't null */
    3077 EUB             :         }
    3078 ECB             : 
    3079 GNC          31 :         tmp = SysCacheGetAttrNotNull(PROCOID, proctup, Anum_pg_proc_prosrc);
    3080 CBC          31 :         prosrc = TextDatumGetCString(tmp);
    3081                 : 
    3082                 :         /*
    3083 ECB             :          * We always use dollar quoting.  Figure out a suitable delimiter.
    3084                 :          *
    3085                 :          * Since the user is likely to be editing the function body string, we
    3086                 :          * shouldn't use a short delimiter that he might easily create a
    3087                 :          * conflict with.  Hence prefer "$function$"/"$procedure$", but extend
    3088                 :          * if needed.
    3089                 :          */
    3090 GIC          31 :         initStringInfo(&dq);
    3091              31 :         appendStringInfoChar(&dq, '$');
    3092              31 :         appendStringInfoString(&dq, (isfunction ? "function" : "procedure"));
    3093              31 :         while (strstr(prosrc, dq.data) != NULL)
    3094 UIC           0 :             appendStringInfoChar(&dq, 'x');
    3095 GIC          31 :         appendStringInfoChar(&dq, '$');
    3096                 : 
    3097 CBC          31 :         appendBinaryStringInfo(&buf, dq.data, dq.len);
    3098 GIC          31 :         appendStringInfoString(&buf, prosrc);
    3099 CBC          31 :         appendBinaryStringInfo(&buf, dq.data, dq.len);
    3100                 :     }
    3101                 : 
    3102 GIC          70 :     appendStringInfoChar(&buf, '\n');
    3103 ECB             : 
    3104 CBC          70 :     ReleaseSysCache(proctup);
    3105 ECB             : 
    3106 GIC          70 :     PG_RETURN_TEXT_P(string_to_text(buf.data));
    3107 ECB             : }
    3108                 : 
    3109                 : /*
    3110                 :  * pg_get_function_arguments
    3111                 :  *      Get a nicely-formatted list of arguments for a function.
    3112                 :  *      This is everything that would go between the parentheses in
    3113                 :  *      CREATE FUNCTION.
    3114                 :  */
    3115                 : Datum
    3116 GIC        2234 : pg_get_function_arguments(PG_FUNCTION_ARGS)
    3117                 : {
    3118            2234 :     Oid         funcid = PG_GETARG_OID(0);
    3119                 :     StringInfoData buf;
    3120                 :     HeapTuple   proctup;
    3121                 : 
    3122            2234 :     proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
    3123 CBC        2234 :     if (!HeapTupleIsValid(proctup))
    3124 GIC           3 :         PG_RETURN_NULL();
    3125 ECB             : 
    3126 GIC        2231 :     initStringInfo(&buf);
    3127                 : 
    3128            2231 :     (void) print_function_arguments(&buf, proctup, false, true);
    3129 ECB             : 
    3130 CBC        2231 :     ReleaseSysCache(proctup);
    3131 ECB             : 
    3132 GIC        2231 :     PG_RETURN_TEXT_P(string_to_text(buf.data));
    3133 ECB             : }
    3134                 : 
    3135                 : /*
    3136                 :  * pg_get_function_identity_arguments
    3137                 :  *      Get a formatted list of arguments for a function.
    3138                 :  *      This is everything that would go between the parentheses in
    3139                 :  *      ALTER FUNCTION, etc.  In particular, don't print defaults.
    3140                 :  */
    3141                 : Datum
    3142 GIC        1977 : pg_get_function_identity_arguments(PG_FUNCTION_ARGS)
    3143                 : {
    3144            1977 :     Oid         funcid = PG_GETARG_OID(0);
    3145                 :     StringInfoData buf;
    3146                 :     HeapTuple   proctup;
    3147                 : 
    3148 CBC        1977 :     proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
    3149 GIC        1977 :     if (!HeapTupleIsValid(proctup))
    3150 CBC           3 :         PG_RETURN_NULL();
    3151                 : 
    3152 GIC        1974 :     initStringInfo(&buf);
    3153                 : 
    3154 CBC        1974 :     (void) print_function_arguments(&buf, proctup, false, false);
    3155 ECB             : 
    3156 CBC        1974 :     ReleaseSysCache(proctup);
    3157                 : 
    3158            1974 :     PG_RETURN_TEXT_P(string_to_text(buf.data));
    3159                 : }
    3160 ECB             : 
    3161                 : /*
    3162                 :  * pg_get_function_result
    3163                 :  *      Get a nicely-formatted version of the result type of a function.
    3164                 :  *      This is what would appear after RETURNS in CREATE FUNCTION.
    3165                 :  */
    3166                 : Datum
    3167 GIC        1939 : pg_get_function_result(PG_FUNCTION_ARGS)
    3168 ECB             : {
    3169 GIC        1939 :     Oid         funcid = PG_GETARG_OID(0);
    3170 ECB             :     StringInfoData buf;
    3171                 :     HeapTuple   proctup;
    3172                 : 
    3173 GIC        1939 :     proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
    3174            1939 :     if (!HeapTupleIsValid(proctup))
    3175               3 :         PG_RETURN_NULL();
    3176                 : 
    3177            1936 :     if (((Form_pg_proc) GETSTRUCT(proctup))->prokind == PROKIND_PROCEDURE)
    3178 ECB             :     {
    3179 GIC         105 :         ReleaseSysCache(proctup);
    3180 CBC         105 :         PG_RETURN_NULL();
    3181 ECB             :     }
    3182                 : 
    3183 GIC        1831 :     initStringInfo(&buf);
    3184 ECB             : 
    3185 GIC        1831 :     print_function_rettype(&buf, proctup);
    3186 ECB             : 
    3187 GIC        1831 :     ReleaseSysCache(proctup);
    3188                 : 
    3189 CBC        1831 :     PG_RETURN_TEXT_P(string_to_text(buf.data));
    3190 ECB             : }
    3191                 : 
    3192                 : /*
    3193                 :  * Guts of pg_get_function_result: append the function's return type
    3194                 :  * to the specified buffer.
    3195                 :  */
    3196                 : static void
    3197 CBC        1892 : print_function_rettype(StringInfo buf, HeapTuple proctup)
    3198                 : {
    3199 GIC        1892 :     Form_pg_proc proc = (Form_pg_proc) GETSTRUCT(proctup);
    3200 CBC        1892 :     int         ntabargs = 0;
    3201 ECB             :     StringInfoData rbuf;
    3202                 : 
    3203 GIC        1892 :     initStringInfo(&rbuf);
    3204                 : 
    3205 CBC        1892 :     if (proc->proretset)
    3206 ECB             :     {
    3207                 :         /* It might be a table function; try to print the arguments */
    3208 GIC         173 :         appendStringInfoString(&rbuf, "TABLE(");
    3209             173 :         ntabargs = print_function_arguments(&rbuf, proctup, true, false);
    3210             173 :         if (ntabargs > 0)
    3211              35 :             appendStringInfoChar(&rbuf, ')');
    3212                 :         else
    3213             138 :             resetStringInfo(&rbuf);
    3214                 :     }
    3215                 : 
    3216 CBC        1892 :     if (ntabargs == 0)
    3217                 :     {
    3218                 :         /* Not a table function, so do the normal thing */
    3219            1857 :         if (proc->proretset)
    3220 GIC         138 :             appendStringInfoString(&rbuf, "SETOF ");
    3221            1857 :         appendStringInfoString(&rbuf, format_type_be(proc->prorettype));
    3222                 :     }
    3223                 : 
    3224 CBC        1892 :     appendBinaryStringInfo(buf, rbuf.data, rbuf.len);
    3225 GIC        1892 : }
    3226                 : 
    3227                 : /*
    3228 ECB             :  * Common code for pg_get_function_arguments and pg_get_function_result:
    3229                 :  * append the desired subset of arguments to buf.  We print only TABLE
    3230                 :  * arguments when print_table_args is true, and all the others when it's false.
    3231                 :  * We print argument defaults only if print_defaults is true.
    3232                 :  * Function return value is the number of arguments printed.
    3233                 :  */
    3234                 : static int
    3235 CBC        4448 : print_function_arguments(StringInfo buf, HeapTuple proctup,
    3236 ECB             :                          bool print_table_args, bool print_defaults)
    3237                 : {
    3238 GIC        4448 :     Form_pg_proc proc = (Form_pg_proc) GETSTRUCT(proctup);
    3239                 :     int         numargs;
    3240                 :     Oid        *argtypes;
    3241 ECB             :     char      **argnames;
    3242                 :     char       *argmodes;
    3243 GIC        4448 :     int         insertorderbyat = -1;
    3244 ECB             :     int         argsprinted;
    3245                 :     int         inputargno;
    3246                 :     int         nlackdefaults;
    3247 GIC        4448 :     List       *argdefaults = NIL;
    3248 CBC        4448 :     ListCell   *nextargdefault = NULL;
    3249 ECB             :     int         i;
    3250                 : 
    3251 CBC        4448 :     numargs = get_func_arg_info(proctup,
    3252                 :                                 &argtypes, &argnames, &argmodes);
    3253 ECB             : 
    3254 GIC        4448 :     nlackdefaults = numargs;
    3255            4448 :     if (print_defaults && proc->pronargdefaults > 0)
    3256                 :     {
    3257                 :         Datum       proargdefaults;
    3258 ECB             :         bool        isnull;
    3259                 : 
    3260 GIC          18 :         proargdefaults = SysCacheGetAttr(PROCOID, proctup,
    3261                 :                                          Anum_pg_proc_proargdefaults,
    3262                 :                                          &isnull);
    3263 CBC          18 :         if (!isnull)
    3264 ECB             :         {
    3265 EUB             :             char       *str;
    3266                 : 
    3267 CBC          18 :             str = TextDatumGetCString(proargdefaults);
    3268              18 :             argdefaults = castNode(List, stringToNode(str));
    3269              18 :             pfree(str);
    3270              18 :             nextargdefault = list_head(argdefaults);
    3271                 :             /* nlackdefaults counts only *input* arguments lacking defaults */
    3272 GIC          18 :             nlackdefaults = proc->pronargs - list_length(argdefaults);
    3273 ECB             :         }
    3274                 :     }
    3275                 : 
    3276                 :     /* Check for special treatment of ordered-set aggregates */
    3277 CBC        4448 :     if (proc->prokind == PROKIND_AGGREGATE)
    3278 ECB             :     {
    3279                 :         HeapTuple   aggtup;
    3280                 :         Form_pg_aggregate agg;
    3281                 : 
    3282 GIC         591 :         aggtup = SearchSysCache1(AGGFNOID, proc->oid);
    3283 CBC         591 :         if (!HeapTupleIsValid(aggtup))
    3284 UIC           0 :             elog(ERROR, "cache lookup failed for aggregate %u",
    3285 ECB             :                  proc->oid);
    3286 GIC         591 :         agg = (Form_pg_aggregate) GETSTRUCT(aggtup);
    3287             591 :         if (AGGKIND_IS_ORDERED_SET(agg->aggkind))
    3288              26 :             insertorderbyat = agg->aggnumdirectargs;
    3289             591 :         ReleaseSysCache(aggtup);
    3290                 :     }
    3291 ECB             : 
    3292 CBC        4448 :     argsprinted = 0;
    3293 GIC        4448 :     inputargno = 0;
    3294 CBC        9039 :     for (i = 0; i < numargs; i++)
    3295 ECB             :     {
    3296 CBC        4591 :         Oid         argtype = argtypes[i];
    3297            4591 :         char       *argname = argnames ? argnames[i] : NULL;
    3298            4591 :         char        argmode = argmodes ? argmodes[i] : PROARGMODE_IN;
    3299 ECB             :         const char *modename;
    3300                 :         bool        isinput;
    3301                 : 
    3302 CBC        4591 :         switch (argmode)
    3303 ECB             :         {
    3304 CBC        3860 :             case PROARGMODE_IN:
    3305 ECB             : 
    3306                 :                 /*
    3307                 :                  * For procedures, explicitly mark all argument modes, so as
    3308                 :                  * to avoid ambiguity with the SQL syntax for DROP PROCEDURE.
    3309                 :                  */
    3310 CBC        3860 :                 if (proc->prokind == PROKIND_PROCEDURE)
    3311             263 :                     modename = "IN ";
    3312 ECB             :                 else
    3313 GBC        3597 :                     modename = "";
    3314            3860 :                 isinput = true;
    3315 GIC        3860 :                 break;
    3316              20 :             case PROARGMODE_INOUT:
    3317              20 :                 modename = "INOUT ";
    3318              20 :                 isinput = true;
    3319 CBC          20 :                 break;
    3320             472 :             case PROARGMODE_OUT:
    3321 GIC         472 :                 modename = "OUT ";
    3322 CBC         472 :                 isinput = false;
    3323             472 :                 break;
    3324 GIC          89 :             case PROARGMODE_VARIADIC:
    3325 CBC          89 :                 modename = "VARIADIC ";
    3326 GIC          89 :                 isinput = true;
    3327 CBC          89 :                 break;
    3328             150 :             case PROARGMODE_TABLE:
    3329             150 :                 modename = "";
    3330 GIC         150 :                 isinput = false;
    3331 CBC         150 :                 break;
    3332 LBC           0 :             default:
    3333 UIC           0 :                 elog(ERROR, "invalid parameter mode '%c'", argmode);
    3334 ECB             :                 modename = NULL;    /* keep compiler quiet */
    3335                 :                 isinput = false;
    3336                 :                 break;
    3337                 :         }
    3338 CBC        4591 :         if (isinput)
    3339 GIC        3969 :             inputargno++;       /* this is a 1-based counter */
    3340                 : 
    3341            4591 :         if (print_table_args != (argmode == PROARGMODE_TABLE))
    3342 CBC         364 :             continue;
    3343 ECB             : 
    3344 CBC        4227 :         if (argsprinted == insertorderbyat)
    3345                 :         {
    3346              26 :             if (argsprinted)
    3347 GIC          26 :                 appendStringInfoChar(buf, ' ');
    3348              26 :             appendStringInfoString(buf, "ORDER BY ");
    3349 ECB             :         }
    3350 GIC        4201 :         else if (argsprinted)
    3351            1314 :             appendStringInfoString(buf, ", ");
    3352 ECB             : 
    3353 GIC        4227 :         appendStringInfoString(buf, modename);
    3354 CBC        4227 :         if (argname && argname[0])
    3355 GIC        1446 :             appendStringInfo(buf, "%s ", quote_identifier(argname));
    3356 CBC        4227 :         appendStringInfoString(buf, format_type_be(argtype));
    3357 GIC        4227 :         if (print_defaults && isinput && inputargno > nlackdefaults)
    3358                 :         {
    3359                 :             Node       *expr;
    3360 ECB             : 
    3361 GIC          25 :             Assert(nextargdefault != NULL);
    3362              25 :             expr = (Node *) lfirst(nextargdefault);
    3363              25 :             nextargdefault = lnext(argdefaults, nextargdefault);
    3364 ECB             : 
    3365 GIC          25 :             appendStringInfo(buf, " DEFAULT %s",
    3366                 :                              deparse_expression(expr, NIL, false, false));
    3367 ECB             :         }
    3368 CBC        4227 :         argsprinted++;
    3369 ECB             : 
    3370                 :         /* nasty hack: print the last arg twice for variadic ordered-set agg */
    3371 GIC        4227 :         if (argsprinted == insertorderbyat && i == numargs - 1)
    3372                 :         {
    3373              13 :             i--;
    3374                 :             /* aggs shouldn't have defaults anyway, but just to be sure ... */
    3375              13 :             print_defaults = false;
    3376 ECB             :         }
    3377                 :     }
    3378                 : 
    3379 GIC        4448 :     return argsprinted;
    3380                 : }
    3381 ECB             : 
    3382                 : static bool
    3383 GIC          48 : is_input_argument(int nth, const char *argmodes)
    3384                 : {
    3385                 :     return (!argmodes
    3386 CBC          21 :             || argmodes[nth] == PROARGMODE_IN
    3387               9 :             || argmodes[nth] == PROARGMODE_INOUT
    3388 GIC          69 :             || argmodes[nth] == PROARGMODE_VARIADIC);
    3389 ECB             : }
    3390                 : 
    3391                 : /*
    3392                 :  * Append used transformed types to specified buffer
    3393                 :  */
    3394                 : static void
    3395 CBC          70 : print_function_trftypes(StringInfo buf, HeapTuple proctup)
    3396                 : {
    3397                 :     Oid        *trftypes;
    3398                 :     int         ntypes;
    3399                 : 
    3400 GIC          70 :     ntypes = get_func_trftypes(proctup, &trftypes);
    3401              70 :     if (ntypes > 0)
    3402                 :     {
    3403                 :         int         i;
    3404 ECB             : 
    3405 GIC           3 :         appendStringInfoString(buf, " TRANSFORM ");
    3406 CBC           8 :         for (i = 0; i < ntypes; i++)
    3407 ECB             :         {
    3408 GIC           5 :             if (i != 0)
    3409               2 :                 appendStringInfoString(buf, ", ");
    3410               5 :             appendStringInfo(buf, "FOR TYPE %s", format_type_be(trftypes[i]));
    3411                 :         }
    3412               3 :         appendStringInfoChar(buf, '\n');
    3413                 :     }
    3414              70 : }
    3415                 : 
    3416                 : /*
    3417                 :  * Get textual representation of a function argument's default value.  The
    3418                 :  * second argument of this function is the argument number among all arguments
    3419                 :  * (i.e. proallargtypes, *not* proargtypes), starting with 1, because that's
    3420                 :  * how information_schema.sql uses it.
    3421                 :  */
    3422                 : Datum
    3423 CBC          27 : pg_get_function_arg_default(PG_FUNCTION_ARGS)
    3424 ECB             : {
    3425 CBC          27 :     Oid         funcid = PG_GETARG_OID(0);
    3426 GIC          27 :     int32       nth_arg = PG_GETARG_INT32(1);
    3427 ECB             :     HeapTuple   proctup;
    3428                 :     Form_pg_proc proc;
    3429                 :     int         numargs;
    3430                 :     Oid        *argtypes;
    3431                 :     char      **argnames;
    3432                 :     char       *argmodes;
    3433                 :     int         i;
    3434                 :     List       *argdefaults;
    3435                 :     Node       *node;
    3436                 :     char       *str;
    3437                 :     int         nth_inputarg;
    3438                 :     Datum       proargdefaults;
    3439                 :     bool        isnull;
    3440                 :     int         nth_default;
    3441                 : 
    3442 CBC          27 :     proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
    3443 GIC          27 :     if (!HeapTupleIsValid(proctup))
    3444 GBC           6 :         PG_RETURN_NULL();
    3445 EUB             : 
    3446 GIC          21 :     numargs = get_func_arg_info(proctup, &argtypes, &argnames, &argmodes);
    3447              21 :     if (nth_arg < 1 || nth_arg > numargs || !is_input_argument(nth_arg - 1, argmodes))
    3448 ECB             :     {
    3449 CBC           6 :         ReleaseSysCache(proctup);
    3450               6 :         PG_RETURN_NULL();
    3451                 :     }
    3452 ECB             : 
    3453 GIC          15 :     nth_inputarg = 0;
    3454              42 :     for (i = 0; i < nth_arg; i++)
    3455              27 :         if (is_input_argument(i, argmodes))
    3456              24 :             nth_inputarg++;
    3457                 : 
    3458 CBC          15 :     proargdefaults = SysCacheGetAttr(PROCOID, proctup,
    3459                 :                                      Anum_pg_proc_proargdefaults,
    3460 ECB             :                                      &isnull);
    3461 GIC          15 :     if (isnull)
    3462 ECB             :     {
    3463 LBC           0 :         ReleaseSysCache(proctup);
    3464 UIC           0 :         PG_RETURN_NULL();
    3465 ECB             :     }
    3466                 : 
    3467 GIC          15 :     str = TextDatumGetCString(proargdefaults);
    3468 CBC          15 :     argdefaults = castNode(List, stringToNode(str));
    3469 GIC          15 :     pfree(str);
    3470 ECB             : 
    3471 GIC          15 :     proc = (Form_pg_proc) GETSTRUCT(proctup);
    3472                 : 
    3473                 :     /*
    3474 ECB             :      * Calculate index into proargdefaults: proargdefaults corresponds to the
    3475                 :      * last N input arguments, where N = pronargdefaults.
    3476                 :      */
    3477 GIC          15 :     nth_default = nth_inputarg - 1 - (proc->pronargs - proc->pronargdefaults);
    3478                 : 
    3479              15 :     if (nth_default < 0 || nth_default >= list_length(argdefaults))
    3480 ECB             :     {
    3481 GIC           3 :         ReleaseSysCache(proctup);
    3482               3 :         PG_RETURN_NULL();
    3483                 :     }
    3484 CBC          12 :     node = list_nth(argdefaults, nth_default);
    3485              12 :     str = deparse_expression(node, NIL, false, false);
    3486                 : 
    3487              12 :     ReleaseSysCache(proctup);
    3488 ECB             : 
    3489 GIC          12 :     PG_RETURN_TEXT_P(string_to_text(str));
    3490 ECB             : }
    3491                 : 
    3492                 : static void
    3493 CBC          54 : print_function_sqlbody(StringInfo buf, HeapTuple proctup)
    3494                 : {
    3495                 :     int         numargs;
    3496                 :     Oid        *argtypes;
    3497                 :     char      **argnames;
    3498 ECB             :     char       *argmodes;
    3499 GIC          54 :     deparse_namespace dpns = {0};
    3500 ECB             :     Datum       tmp;
    3501                 :     Node       *n;
    3502                 : 
    3503 CBC          54 :     dpns.funcname = pstrdup(NameStr(((Form_pg_proc) GETSTRUCT(proctup))->proname));
    3504 GIC          54 :     numargs = get_func_arg_info(proctup,
    3505                 :                                 &argtypes, &argnames, &argmodes);
    3506 CBC          54 :     dpns.numargs = numargs;
    3507              54 :     dpns.argnames = argnames;
    3508                 : 
    3509 GNC          54 :     tmp = SysCacheGetAttrNotNull(PROCOID, proctup, Anum_pg_proc_prosqlbody);
    3510 GIC          54 :     n = stringToNode(TextDatumGetCString(tmp));
    3511                 : 
    3512 CBC          54 :     if (IsA(n, List))
    3513                 :     {
    3514                 :         List       *stmts;
    3515                 :         ListCell   *lc;
    3516 ECB             : 
    3517 GIC          32 :         stmts = linitial(castNode(List, n));
    3518                 : 
    3519 CBC          32 :         appendStringInfoString(buf, "BEGIN ATOMIC\n");
    3520 ECB             : 
    3521 GIC          59 :         foreach(lc, stmts)
    3522                 :         {
    3523 CBC          27 :             Query      *query = lfirst_node(Query, lc);
    3524                 : 
    3525                 :             /* It seems advisable to get at least AccessShareLock on rels */
    3526              27 :             AcquireRewriteLocks(query, false, false);
    3527 GIC          27 :             get_query_def(query, buf, list_make1(&dpns), NULL, false,
    3528 ECB             :                           PRETTYFLAG_INDENT, WRAP_COLUMN_DEFAULT, 1);
    3529 GIC          27 :             appendStringInfoChar(buf, ';');
    3530              27 :             appendStringInfoChar(buf, '\n');
    3531                 :         }
    3532                 : 
    3533 CBC          32 :         appendStringInfoString(buf, "END");
    3534                 :     }
    3535                 :     else
    3536 ECB             :     {
    3537 CBC          22 :         Query      *query = castNode(Query, n);
    3538 EUB             : 
    3539                 :         /* It seems advisable to get at least AccessShareLock on rels */
    3540 CBC          22 :         AcquireRewriteLocks(query, false, false);
    3541              22 :         get_query_def(query, buf, list_make1(&dpns), NULL, false,
    3542                 :                       0, WRAP_COLUMN_DEFAULT, 0);
    3543 ECB             :     }
    3544 CBC          54 : }
    3545                 : 
    3546                 : Datum
    3547            1686 : pg_get_function_sqlbody(PG_FUNCTION_ARGS)
    3548                 : {
    3549            1686 :     Oid         funcid = PG_GETARG_OID(0);
    3550                 :     StringInfoData buf;
    3551 ECB             :     HeapTuple   proctup;
    3552                 :     bool        isnull;
    3553                 : 
    3554 GIC        1686 :     initStringInfo(&buf);
    3555                 : 
    3556                 :     /* Look up the function */
    3557            1686 :     proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
    3558            1686 :     if (!HeapTupleIsValid(proctup))
    3559 UIC           0 :         PG_RETURN_NULL();
    3560                 : 
    3561 CBC        1686 :     (void) SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_prosqlbody, &isnull);
    3562 GIC        1686 :     if (isnull)
    3563                 :     {
    3564 CBC        1671 :         ReleaseSysCache(proctup);
    3565 GIC        1671 :         PG_RETURN_NULL();
    3566                 :     }
    3567                 : 
    3568              15 :     print_function_sqlbody(&buf, proctup);
    3569                 : 
    3570              15 :     ReleaseSysCache(proctup);
    3571                 : 
    3572 GNC          15 :     PG_RETURN_TEXT_P(cstring_to_text_with_len(buf.data, buf.len));
    3573                 : }
    3574                 : 
    3575                 : 
    3576                 : /*
    3577                 :  * deparse_expression           - General utility for deparsing expressions
    3578                 :  *
    3579                 :  * calls deparse_expression_pretty with all prettyPrinting disabled
    3580                 :  */
    3581                 : char *
    3582 GIC       28781 : deparse_expression(Node *expr, List *dpcontext,
    3583                 :                    bool forceprefix, bool showimplicit)
    3584                 : {
    3585           28781 :     return deparse_expression_pretty(expr, dpcontext, forceprefix,
    3586                 :                                      showimplicit, 0, 0);
    3587                 : }
    3588 ECB             : 
    3589                 : /* ----------
    3590                 :  * deparse_expression_pretty    - General utility for deparsing expressions
    3591                 :  *
    3592                 :  * expr is the node tree to be deparsed.  It must be a transformed expression
    3593                 :  * tree (ie, not the raw output of gram.y).
    3594                 :  *
    3595                 :  * dpcontext is a list of deparse_namespace nodes representing the context
    3596                 :  * for interpreting Vars in the node tree.  It can be NIL if no Vars are
    3597                 :  * expected.
    3598                 :  *
    3599                 :  * forceprefix is true to force all Vars to be prefixed with their table names.
    3600                 :  *
    3601                 :  * showimplicit is true to force all implicit casts to be shown explicitly.
    3602                 :  *
    3603                 :  * Tries to pretty up the output according to prettyFlags and startIndent.
    3604                 :  *
    3605                 :  * The result is a palloc'd string.
    3606                 :  * ----------
    3607                 :  */
    3608                 : static char *
    3609 CBC       34079 : deparse_expression_pretty(Node *expr, List *dpcontext,
    3610                 :                           bool forceprefix, bool showimplicit,
    3611                 :                           int prettyFlags, int startIndent)
    3612                 : {
    3613                 :     StringInfoData buf;
    3614                 :     deparse_context context;
    3615                 : 
    3616 GIC       34079 :     initStringInfo(&buf);
    3617           34079 :     context.buf = &buf;
    3618           34079 :     context.namespaces = dpcontext;
    3619           34079 :     context.windowClause = NIL;
    3620           34079 :     context.windowTList = NIL;
    3621 CBC       34079 :     context.varprefix = forceprefix;
    3622 GIC       34079 :     context.prettyFlags = prettyFlags;
    3623           34079 :     context.wrapColumn = WRAP_COLUMN_DEFAULT;
    3624           34079 :     context.indentLevel = startIndent;
    3625           34079 :     context.special_exprkind = EXPR_KIND_NONE;
    3626 CBC       34079 :     context.appendparents = NULL;
    3627                 : 
    3628 GIC       34079 :     get_rule_expr(expr, &context, showimplicit);
    3629 ECB             : 
    3630 CBC       34079 :     return buf.data;
    3631 ECB             : }
    3632                 : 
    3633                 : /* ----------
    3634                 :  * deparse_context_for          - Build deparse context for a single relation
    3635                 :  *
    3636                 :  * Given the reference name (alias) and OID of a relation, build deparsing
    3637                 :  * context for an expression referencing only that relation (as varno 1,
    3638                 :  * varlevelsup 0).  This is sufficient for many uses of deparse_expression.
    3639                 :  * ----------
    3640                 :  */
    3641                 : List *
    3642 CBC        9629 : deparse_context_for(const char *aliasname, Oid relid)
    3643 ECB             : {
    3644                 :     deparse_namespace *dpns;
    3645                 :     RangeTblEntry *rte;
    3646                 : 
    3647 GIC        9629 :     dpns = (deparse_namespace *) palloc0(sizeof(deparse_namespace));
    3648                 : 
    3649 ECB             :     /* Build a minimal RTE for the rel */
    3650 GIC        9629 :     rte = makeNode(RangeTblEntry);
    3651            9629 :     rte->rtekind = RTE_RELATION;
    3652            9629 :     rte->relid = relid;
    3653            9629 :     rte->relkind = RELKIND_RELATION; /* no need for exactness here */
    3654            9629 :     rte->rellockmode = AccessShareLock;
    3655            9629 :     rte->alias = makeAlias(aliasname, NIL);
    3656            9629 :     rte->eref = rte->alias;
    3657            9629 :     rte->lateral = false;
    3658            9629 :     rte->inh = false;
    3659            9629 :     rte->inFromCl = true;
    3660                 : 
    3661                 :     /* Build one-element rtable */
    3662            9629 :     dpns->rtable = list_make1(rte);
    3663            9629 :     dpns->subplans = NIL;
    3664            9629 :     dpns->ctes = NIL;
    3665            9629 :     dpns->appendrels = NULL;
    3666 CBC        9629 :     set_rtable_names(dpns, NIL, NULL);
    3667 GIC        9629 :     set_simple_column_names(dpns);
    3668                 : 
    3669                 :     /* Return a one-deep namespace stack */
    3670 CBC        9629 :     return list_make1(dpns);
    3671                 : }
    3672                 : 
    3673 ECB             : /*
    3674                 :  * deparse_context_for_plan_tree - Build deparse context for a Plan tree
    3675                 :  *
    3676                 :  * When deparsing an expression in a Plan tree, we use the plan's rangetable
    3677                 :  * to resolve names of simple Vars.  The initialization of column names for
    3678                 :  * this is rather expensive if the rangetable is large, and it'll be the same
    3679                 :  * for every expression in the Plan tree; so we do it just once and re-use
    3680                 :  * the result of this function for each expression.  (Note that the result
    3681                 :  * is not usable until set_deparse_context_plan() is applied to it.)
    3682                 :  *
    3683                 :  * In addition to the PlannedStmt, pass the per-RTE alias names
    3684                 :  * assigned by a previous call to select_rtable_names_for_explain.
    3685                 :  */
    3686                 : List *
    3687 CBC        9874 : deparse_context_for_plan_tree(PlannedStmt *pstmt, List *rtable_names)
    3688 ECB             : {
    3689                 :     deparse_namespace *dpns;
    3690                 : 
    3691 CBC        9874 :     dpns = (deparse_namespace *) palloc0(sizeof(deparse_namespace));
    3692 ECB             : 
    3693                 :     /* Initialize fields that stay the same across the whole plan tree */
    3694 GIC        9874 :     dpns->rtable = pstmt->rtable;
    3695            9874 :     dpns->rtable_names = rtable_names;
    3696 CBC        9874 :     dpns->subplans = pstmt->subplans;
    3697 GIC        9874 :     dpns->ctes = NIL;
    3698            9874 :     if (pstmt->appendRelations)
    3699                 :     {
    3700                 :         /* Set up the array, indexed by child relid */
    3701            1637 :         int         ntables = list_length(dpns->rtable);
    3702                 :         ListCell   *lc;
    3703 ECB             : 
    3704 GIC        1637 :         dpns->appendrels = (AppendRelInfo **)
    3705            1637 :             palloc0((ntables + 1) * sizeof(AppendRelInfo *));
    3706 CBC        9266 :         foreach(lc, pstmt->appendRelations)
    3707                 :         {
    3708 GIC        7629 :             AppendRelInfo *appinfo = lfirst_node(AppendRelInfo, lc);
    3709            7629 :             Index       crelid = appinfo->child_relid;
    3710                 : 
    3711            7629 :             Assert(crelid > 0 && crelid <= ntables);
    3712            7629 :             Assert(dpns->appendrels[crelid] == NULL);
    3713            7629 :             dpns->appendrels[crelid] = appinfo;
    3714                 :         }
    3715                 :     }
    3716                 :     else
    3717            8237 :         dpns->appendrels = NULL; /* don't need it */
    3718                 : 
    3719                 :     /*
    3720                 :      * Set up column name aliases.  We will get rather bogus results for join
    3721                 :      * RTEs, but that doesn't matter because plan trees don't contain any join
    3722                 :      * alias Vars.
    3723                 :      */
    3724            9874 :     set_simple_column_names(dpns);
    3725                 : 
    3726                 :     /* Return a one-deep namespace stack */
    3727            9874 :     return list_make1(dpns);
    3728                 : }
    3729                 : 
    3730                 : /*
    3731                 :  * set_deparse_context_plan - Specify Plan node containing expression
    3732                 :  *
    3733                 :  * When deparsing an expression in a Plan tree, we might have to resolve
    3734                 :  * OUTER_VAR, INNER_VAR, or INDEX_VAR references.  To do this, the caller must
    3735 ECB             :  * provide the parent Plan node.  Then OUTER_VAR and INNER_VAR references
    3736                 :  * can be resolved by drilling down into the left and right child plans.
    3737                 :  * Similarly, INDEX_VAR references can be resolved by reference to the
    3738                 :  * indextlist given in a parent IndexOnlyScan node, or to the scan tlist in
    3739                 :  * ForeignScan and CustomScan nodes.  (Note that we don't currently support
    3740                 :  * deparsing of indexquals in regular IndexScan or BitmapIndexScan nodes;
    3741                 :  * for those, we can only deparse the indexqualorig fields, which won't
    3742                 :  * contain INDEX_VAR Vars.)
    3743                 :  *
    3744                 :  * The ancestors list is a list of the Plan's parent Plan and SubPlan nodes,
    3745                 :  * the most-closely-nested first.  This is needed to resolve PARAM_EXEC
    3746                 :  * Params.  Note we assume that all the Plan nodes share the same rtable.
    3747                 :  *
    3748                 :  * Once this function has been called, deparse_expression() can be called on
    3749                 :  * subsidiary expression(s) of the specified Plan node.  To deparse
    3750                 :  * expressions of a different Plan node in the same Plan tree, re-call this
    3751                 :  * function to identify the new parent Plan node.
    3752                 :  *
    3753                 :  * The result is the same List passed in; this is a notational convenience.
    3754                 :  */
    3755                 : List *
    3756 GIC       21439 : set_deparse_context_plan(List *dpcontext, Plan *plan, List *ancestors)
    3757                 : {
    3758 ECB             :     deparse_namespace *dpns;
    3759                 : 
    3760                 :     /* Should always have one-entry namespace list for Plan deparsing */
    3761 GIC       21439 :     Assert(list_length(dpcontext) == 1);
    3762 CBC       21439 :     dpns = (deparse_namespace *) linitial(dpcontext);
    3763 ECB             : 
    3764                 :     /* Set our attention on the specific plan node passed in */
    3765 CBC       21439 :     dpns->ancestors = ancestors;
    3766           21439 :     set_deparse_plan(dpns, plan);
    3767 ECB             : 
    3768 GIC       21439 :     return dpcontext;
    3769                 : }
    3770 ECB             : 
    3771                 : /*
    3772                 :  * select_rtable_names_for_explain  - Select RTE aliases for EXPLAIN
    3773                 :  *
    3774                 :  * Determine the relation aliases we'll use during an EXPLAIN operation.
    3775                 :  * This is just a frontend to set_rtable_names.  We have to expose the aliases
    3776                 :  * to EXPLAIN because EXPLAIN needs to know the right alias names to print.
    3777                 :  */
    3778                 : List *
    3779 GIC        9874 : select_rtable_names_for_explain(List *rtable, Bitmapset *rels_used)
    3780                 : {
    3781                 :     deparse_namespace dpns;
    3782                 : 
    3783            9874 :     memset(&dpns, 0, sizeof(dpns));
    3784            9874 :     dpns.rtable = rtable;
    3785            9874 :     dpns.subplans = NIL;
    3786            9874 :     dpns.ctes = NIL;
    3787 CBC        9874 :     dpns.appendrels = NULL;
    3788 GIC        9874 :     set_rtable_names(&dpns, NIL, rels_used);
    3789                 :     /* We needn't bother computing column aliases yet */
    3790                 : 
    3791            9874 :     return dpns.rtable_names;
    3792                 : }
    3793                 : 
    3794                 : /*
    3795                 :  * set_rtable_names: select RTE aliases to be used in printing a query
    3796                 :  *
    3797 ECB             :  * We fill in dpns->rtable_names with a list of names that is one-for-one with
    3798                 :  * the already-filled dpns->rtable list.  Each RTE name is unique among those
    3799                 :  * in the new namespace plus any ancestor namespaces listed in
    3800                 :  * parent_namespaces.
    3801                 :  *
    3802                 :  * If rels_used isn't NULL, only RTE indexes listed in it are given aliases.
    3803                 :  *
    3804                 :  * Note that this function is only concerned with relation names, not column
    3805                 :  * names.
    3806                 :  */
    3807                 : static void
    3808 CBC       21939 : set_rtable_names(deparse_namespace *dpns, List *parent_namespaces,
    3809 ECB             :                  Bitmapset *rels_used)
    3810                 : {
    3811                 :     HASHCTL     hash_ctl;
    3812                 :     HTAB       *names_hash;
    3813                 :     NameHashEntry *hentry;
    3814                 :     bool        found;
    3815                 :     int         rtindex;
    3816                 :     ListCell   *lc;
    3817                 : 
    3818 GIC       21939 :     dpns->rtable_names = NIL;
    3819                 :     /* nothing more to do if empty rtable */
    3820 CBC       21939 :     if (dpns->rtable == NIL)
    3821 GIC         232 :         return;
    3822 ECB             : 
    3823                 :     /*
    3824                 :      * We use a hash table to hold known names, so that this process is O(N)
    3825                 :      * not O(N^2) for N names.
    3826                 :      */
    3827 GIC       21707 :     hash_ctl.keysize = NAMEDATALEN;
    3828           21707 :     hash_ctl.entrysize = sizeof(NameHashEntry);
    3829           21707 :     hash_ctl.hcxt = CurrentMemoryContext;
    3830           21707 :     names_hash = hash_create("set_rtable_names names",
    3831 CBC       21707 :                              list_length(dpns->rtable),
    3832                 :                              &hash_ctl,
    3833                 :                              HASH_ELEM | HASH_STRINGS | HASH_CONTEXT);
    3834                 : 
    3835                 :     /* Preload the hash table with names appearing in parent_namespaces */
    3836           22365 :     foreach(lc, parent_namespaces)
    3837 ECB             :     {
    3838 GIC         658 :         deparse_namespace *olddpns = (deparse_namespace *) lfirst(lc);
    3839 ECB             :         ListCell   *lc2;
    3840                 : 
    3841 GIC        2189 :         foreach(lc2, olddpns->rtable_names)
    3842                 :         {
    3843 CBC        1531 :             char       *oldname = (char *) lfirst(lc2);
    3844                 : 
    3845            1531 :             if (oldname == NULL)
    3846 GIC         114 :                 continue;
    3847            1417 :             hentry = (NameHashEntry *) hash_search(names_hash,
    3848 ECB             :                                                    oldname,
    3849                 :                                                    HASH_ENTER,
    3850                 :                                                    &found);
    3851                 :             /* we do not complain about duplicate names in parent namespaces */
    3852 GIC        1417 :             hentry->counter = 0;
    3853 ECB             :         }
    3854                 :     }
    3855                 : 
    3856                 :     /* Now we can scan the rtable */
    3857 GIC       21707 :     rtindex = 1;
    3858 CBC       60652 :     foreach(lc, dpns->rtable)
    3859                 :     {
    3860           38945 :         RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
    3861                 :         char       *refname;
    3862                 : 
    3863 ECB             :         /* Just in case this takes an unreasonable amount of time ... */
    3864 GIC       38945 :         CHECK_FOR_INTERRUPTS();
    3865                 : 
    3866           38945 :         if (rels_used && !bms_is_member(rtindex, rels_used))
    3867                 :         {
    3868 ECB             :             /* Ignore unreferenced RTE */
    3869 GIC        5831 :             refname = NULL;
    3870                 :         }
    3871           33114 :         else if (rte->alias)
    3872                 :         {
    3873                 :             /* If RTE has a user-defined alias, prefer that */
    3874           21727 :             refname = rte->alias->aliasname;
    3875                 :         }
    3876           11387 :         else if (rte->rtekind == RTE_RELATION)
    3877 ECB             :         {
    3878                 :             /* Use the current actual name of the relation */
    3879 CBC        9798 :             refname = get_rel_name(rte->relid);
    3880                 :         }
    3881 GIC        1589 :         else if (rte->rtekind == RTE_JOIN)
    3882                 :         {
    3883 ECB             :             /* Unnamed join has no refname */
    3884 GIC         630 :             refname = NULL;
    3885                 :         }
    3886 ECB             :         else
    3887                 :         {
    3888                 :             /* Otherwise use whatever the parser assigned */
    3889 GIC         959 :             refname = rte->eref->aliasname;
    3890                 :         }
    3891                 : 
    3892 ECB             :         /*
    3893                 :          * If the selected name isn't unique, append digits to make it so, and
    3894                 :          * make a new hash entry for it once we've got a unique name.  For a
    3895                 :          * very long input name, we might have to truncate to stay within
    3896                 :          * NAMEDATALEN.
    3897                 :          */
    3898 CBC       38945 :         if (refname)
    3899                 :         {
    3900           32484 :             hentry = (NameHashEntry *) hash_search(names_hash,
    3901                 :                                                    refname,
    3902                 :                                                    HASH_ENTER,
    3903 ECB             :                                                    &found);
    3904 GIC       32484 :             if (found)
    3905                 :             {
    3906                 :                 /* Name already in use, must choose a new one */
    3907 CBC        6241 :                 int         refnamelen = strlen(refname);
    3908            6241 :                 char       *modname = (char *) palloc(refnamelen + 16);
    3909 ECB             :                 NameHashEntry *hentry2;
    3910                 : 
    3911                 :                 do
    3912                 :                 {
    3913 GIC        6244 :                     hentry->counter++;
    3914 ECB             :                     for (;;)
    3915                 :                     {
    3916 GIC        6250 :                         memcpy(modname, refname, refnamelen);
    3917            6250 :                         sprintf(modname + refnamelen, "_%d", hentry->counter);
    3918 CBC        6250 :                         if (strlen(modname) < NAMEDATALEN)
    3919            6244 :                             break;
    3920                 :                         /* drop chars from refname to keep all the digits */
    3921 GIC           6 :                         refnamelen = pg_mbcliplen(refname, refnamelen,
    3922 ECB             :                                                   refnamelen - 1);
    3923                 :                     }
    3924 GIC        6244 :                     hentry2 = (NameHashEntry *) hash_search(names_hash,
    3925                 :                                                             modname,
    3926                 :                                                             HASH_ENTER,
    3927                 :                                                             &found);
    3928            6244 :                 } while (found);
    3929            6241 :                 hentry2->counter = 0;    /* init new hash entry */
    3930            6241 :                 refname = modname;
    3931                 :             }
    3932 ECB             :             else
    3933                 :             {
    3934                 :                 /* Name not previously used, need only initialize hentry */
    3935 GIC       26243 :                 hentry->counter = 0;
    3936                 :             }
    3937                 :         }
    3938                 : 
    3939 CBC       38945 :         dpns->rtable_names = lappend(dpns->rtable_names, refname);
    3940           38945 :         rtindex++;
    3941 ECB             :     }
    3942                 : 
    3943 CBC       21707 :     hash_destroy(names_hash);
    3944                 : }
    3945                 : 
    3946 ECB             : /*
    3947                 :  * set_deparse_for_query: set up deparse_namespace for deparsing a Query tree
    3948                 :  *
    3949                 :  * For convenience, this is defined to initialize the deparse_namespace struct
    3950                 :  * from scratch.
    3951                 :  */
    3952                 : static void
    3953 GIC        2364 : set_deparse_for_query(deparse_namespace *dpns, Query *query,
    3954                 :                       List *parent_namespaces)
    3955 ECB             : {
    3956                 :     ListCell   *lc;
    3957                 :     ListCell   *lc2;
    3958                 : 
    3959                 :     /* Initialize *dpns and fill rtable/ctes links */
    3960 GIC        2364 :     memset(dpns, 0, sizeof(deparse_namespace));
    3961            2364 :     dpns->rtable = query->rtable;
    3962            2364 :     dpns->subplans = NIL;
    3963            2364 :     dpns->ctes = query->cteList;
    3964            2364 :     dpns->appendrels = NULL;
    3965 ECB             : 
    3966                 :     /* Assign a unique relation alias to each RTE */
    3967 GIC        2364 :     set_rtable_names(dpns, parent_namespaces, NULL);
    3968                 : 
    3969                 :     /* Initialize dpns->rtable_columns to contain zeroed structs */
    3970            2364 :     dpns->rtable_columns = NIL;
    3971            6395 :     while (list_length(dpns->rtable_columns) < list_length(dpns->rtable))
    3972            4031 :         dpns->rtable_columns = lappend(dpns->rtable_columns,
    3973                 :                                        palloc0(sizeof(deparse_columns)));
    3974                 : 
    3975                 :     /* If it's a utility query, it won't have a jointree */
    3976 CBC        2364 :     if (query->jointree)
    3977                 :     {
    3978 ECB             :         /* Detect whether global uniqueness of USING names is needed */
    3979 CBC        2356 :         dpns->unique_using =
    3980 GIC        2356 :             has_dangerous_join_using(dpns, (Node *) query->jointree);
    3981 ECB             : 
    3982                 :         /*
    3983                 :          * Select names for columns merged by USING, via a recursive pass over
    3984                 :          * the query jointree.
    3985                 :          */
    3986 CBC        2356 :         set_using_names(dpns, (Node *) query->jointree, NIL);
    3987                 :     }
    3988                 : 
    3989                 :     /*
    3990                 :      * Now assign remaining column aliases for each RTE.  We do this in a
    3991                 :      * linear scan of the rtable, so as to process RTEs whether or not they
    3992                 :      * are in the jointree (we mustn't miss NEW.*, INSERT target relations,
    3993                 :      * etc).  JOIN RTEs must be processed after their children, but this is
    3994                 :      * okay because they appear later in the rtable list than their children
    3995                 :      * (cf Asserts in identify_join_columns()).
    3996                 :      */
    3997            6395 :     forboth(lc, dpns->rtable, lc2, dpns->rtable_columns)
    3998                 :     {
    3999 GIC        4031 :         RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
    4000            4031 :         deparse_columns *colinfo = (deparse_columns *) lfirst(lc2);
    4001                 : 
    4002            4031 :         if (rte->rtekind == RTE_JOIN)
    4003 CBC         500 :             set_join_column_names(dpns, rte, colinfo);
    4004 ECB             :         else
    4005 CBC        3531 :             set_relation_column_names(dpns, rte, colinfo);
    4006                 :     }
    4007 GIC        2364 : }
    4008                 : 
    4009 ECB             : /*
    4010                 :  * set_simple_column_names: fill in column aliases for non-query situations
    4011                 :  *
    4012                 :  * This handles EXPLAIN and cases where we only have relation RTEs.  Without
    4013                 :  * a join tree, we can't do anything smart about join RTEs, but we don't
    4014                 :  * need to (note that EXPLAIN should never see join alias Vars anyway).
    4015                 :  * If we do hit a join RTE we'll just process it like a non-table base RTE.
    4016                 :  */
    4017                 : static void
    4018 GIC       19575 : set_simple_column_names(deparse_namespace *dpns)
    4019                 : {
    4020                 :     ListCell   *lc;
    4021                 :     ListCell   *lc2;
    4022                 : 
    4023                 :     /* Initialize dpns->rtable_columns to contain zeroed structs */
    4024           19575 :     dpns->rtable_columns = NIL;
    4025           54489 :     while (list_length(dpns->rtable_columns) < list_length(dpns->rtable))
    4026           34914 :         dpns->rtable_columns = lappend(dpns->rtable_columns,
    4027                 :                                        palloc0(sizeof(deparse_columns)));
    4028                 : 
    4029                 :     /* Assign unique column aliases within each RTE */
    4030           54489 :     forboth(lc, dpns->rtable, lc2, dpns->rtable_columns)
    4031                 :     {
    4032           34914 :         RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
    4033           34914 :         deparse_columns *colinfo = (deparse_columns *) lfirst(lc2);
    4034                 : 
    4035           34914 :         set_relation_column_names(dpns, rte, colinfo);
    4036                 :     }
    4037           19575 : }
    4038 ECB             : 
    4039                 : /*
    4040                 :  * has_dangerous_join_using: search jointree for unnamed JOIN USING
    4041                 :  *
    4042                 :  * Merged columns of a JOIN USING may act differently from either of the input
    4043                 :  * columns, either because they are merged with COALESCE (in a FULL JOIN) or
    4044                 :  * because an implicit coercion of the underlying input column is required.
    4045                 :  * In such a case the column must be referenced as a column of the JOIN not as
    4046                 :  * a column of either input.  And this is problematic if the join is unnamed
    4047                 :  * (alias-less): we cannot qualify the column's name with an RTE name, since
    4048                 :  * there is none.  (Forcibly assigning an alias to the join is not a solution,
    4049                 :  * since that will prevent legal references to tables below the join.)
    4050                 :  * To ensure that every column in the query is unambiguously referenceable,
    4051                 :  * we must assign such merged columns names that are globally unique across
    4052                 :  * the whole query, aliasing other columns out of the way as necessary.
    4053                 :  *
    4054                 :  * Because the ensuing re-aliasing is fairly damaging to the readability of
    4055                 :  * the query, we don't do this unless we have to.  So, we must pre-scan
    4056                 :  * the join tree to see if we have to, before starting set_using_names().
    4057                 :  */
    4058                 : static bool
    4059 GIC        5335 : has_dangerous_join_using(deparse_namespace *dpns, Node *jtnode)
    4060 ECB             : {
    4061 GIC        5335 :     if (IsA(jtnode, RangeTblRef))
    4062                 :     {
    4063                 :         /* nothing to do here */
    4064                 :     }
    4065            2823 :     else if (IsA(jtnode, FromExpr))
    4066                 :     {
    4067 CBC        2356 :         FromExpr   *f = (FromExpr *) jtnode;
    4068                 :         ListCell   *lc;
    4069                 : 
    4070            4437 :         foreach(lc, f->fromlist)
    4071                 :         {
    4072            2117 :             if (has_dangerous_join_using(dpns, (Node *) lfirst(lc)))
    4073 GIC          36 :                 return true;
    4074 ECB             :         }
    4075                 :     }
    4076 GIC         467 :     else if (IsA(jtnode, JoinExpr))
    4077                 :     {
    4078             467 :         JoinExpr   *j = (JoinExpr *) jtnode;
    4079                 : 
    4080 ECB             :         /* Is it an unnamed JOIN with USING? */
    4081 GBC         467 :         if (j->alias == NULL && j->usingClause)
    4082 ECB             :         {
    4083 EUB             :             /*
    4084                 :              * Yes, so check each join alias var to see if any of them are not
    4085                 :              * simple references to underlying columns.  If so, we have a
    4086                 :              * dangerous situation and must pick unique aliases.
    4087                 :              */
    4088 CBC         143 :             RangeTblEntry *jrte = rt_fetch(j->rtindex, dpns->rtable);
    4089                 : 
    4090                 :             /* We need only examine the merged columns */
    4091 GIC         298 :             for (int i = 0; i < jrte->joinmergedcols; i++)
    4092                 :             {
    4093             191 :                 Node       *aliasvar = list_nth(jrte->joinaliasvars, i);
    4094                 : 
    4095             191 :                 if (!IsA(aliasvar, Var))
    4096              36 :                     return true;
    4097                 :             }
    4098                 :         }
    4099                 : 
    4100                 :         /* Nope, but inspect children */
    4101             431 :         if (has_dangerous_join_using(dpns, j->larg))
    4102 UIC           0 :             return true;
    4103 GIC         431 :         if (has_dangerous_join_using(dpns, j->rarg))
    4104 LBC           0 :             return true;
    4105                 :     }
    4106 ECB             :     else
    4107 UIC           0 :         elog(ERROR, "unrecognized node type: %d",
    4108                 :              (int) nodeTag(jtnode));
    4109 GIC        5263 :     return false;
    4110 ECB             : }
    4111                 : 
    4112                 : /*
    4113                 :  * set_using_names: select column aliases to be used for merged USING columns
    4114                 :  *
    4115                 :  * We do this during a recursive descent of the query jointree.
    4116                 :  * dpns->unique_using must already be set to determine the global strategy.
    4117                 :  *
    4118                 :  * Column alias info is saved in the dpns->rtable_columns list, which is
    4119                 :  * assumed to be filled with pre-zeroed deparse_columns structs.
    4120                 :  *
    4121                 :  * parentUsing is a list of all USING aliases assigned in parent joins of
    4122                 :  * the current jointree node.  (The passed-in list must not be modified.)
    4123                 :  */
    4124                 : static void
    4125 GIC        5494 : set_using_names(deparse_namespace *dpns, Node *jtnode, List *parentUsing)
    4126                 : {
    4127            5494 :     if (IsA(jtnode, RangeTblRef))
    4128                 :     {
    4129                 :         /* nothing to do now */
    4130                 :     }
    4131 CBC        2856 :     else if (IsA(jtnode, FromExpr))
    4132 ECB             :     {
    4133 CBC        2356 :         FromExpr   *f = (FromExpr *) jtnode;
    4134                 :         ListCell   *lc;
    4135                 : 
    4136            4494 :         foreach(lc, f->fromlist)
    4137            2138 :             set_using_names(dpns, (Node *) lfirst(lc), parentUsing);
    4138                 :     }
    4139 GIC         500 :     else if (IsA(jtnode, JoinExpr))
    4140                 :     {
    4141             500 :         JoinExpr   *j = (JoinExpr *) jtnode;
    4142             500 :         RangeTblEntry *rte = rt_fetch(j->rtindex, dpns->rtable);
    4143             500 :         deparse_columns *colinfo = deparse_columns_fetch(j->rtindex, dpns);
    4144 ECB             :         int        *leftattnos;
    4145                 :         int        *rightattnos;
    4146                 :         deparse_columns *leftcolinfo;
    4147                 :         deparse_columns *rightcolinfo;
    4148                 :         int         i;
    4149                 :         ListCell   *lc;
    4150                 : 
    4151                 :         /* Get info about the shape of the join */
    4152 GIC         500 :         identify_join_columns(j, rte, colinfo);
    4153             500 :         leftattnos = colinfo->leftattnos;
    4154 CBC         500 :         rightattnos = colinfo->rightattnos;
    4155                 : 
    4156 ECB             :         /* Look up the not-yet-filled-in child deparse_columns structs */
    4157 CBC         500 :         leftcolinfo = deparse_columns_fetch(colinfo->leftrti, dpns);
    4158 GIC         500 :         rightcolinfo = deparse_columns_fetch(colinfo->rightrti, dpns);
    4159                 : 
    4160                 :         /*
    4161 ECB             :          * If this join is unnamed, then we cannot substitute new aliases at
    4162                 :          * this level, so any name requirements pushed down to here must be
    4163                 :          * pushed down again to the children.
    4164                 :          */
    4165 GIC         500 :         if (rte->alias == NULL)
    4166                 :         {
    4167             515 :             for (i = 0; i < colinfo->num_cols; i++)
    4168                 :             {
    4169              69 :                 char       *colname = colinfo->colnames[i];
    4170                 : 
    4171              69 :                 if (colname == NULL)
    4172              12 :                     continue;
    4173                 : 
    4174                 :                 /* Push down to left column, unless it's a system column */
    4175              57 :                 if (leftattnos[i] > 0)
    4176                 :                 {
    4177              51 :                     expand_colnames_array_to(leftcolinfo, leftattnos[i]);
    4178              51 :                     leftcolinfo->colnames[leftattnos[i] - 1] = colname;
    4179                 :                 }
    4180                 : 
    4181                 :                 /* Same on the righthand side */
    4182              57 :                 if (rightattnos[i] > 0)
    4183                 :                 {
    4184              57 :                     expand_colnames_array_to(rightcolinfo, rightattnos[i]);
    4185              57 :                     rightcolinfo->colnames[rightattnos[i] - 1] = colname;
    4186                 :                 }
    4187                 :             }
    4188                 :         }
    4189                 : 
    4190                 :         /*
    4191                 :          * If there's a USING clause, select the USING column names and push
    4192                 :          * those names down to the children.  We have two strategies:
    4193                 :          *
    4194 ECB             :          * If dpns->unique_using is true, we force all USING names to be
    4195                 :          * unique across the whole query level.  In principle we'd only need
    4196                 :          * the names of dangerous USING columns to be globally unique, but to
    4197                 :          * safely assign all USING names in a single pass, we have to enforce
    4198                 :          * the same uniqueness rule for all of them.  However, if a USING
    4199                 :          * column's name has been pushed down from the parent, we should use
    4200                 :          * it as-is rather than making a uniqueness adjustment.  This is
    4201                 :          * necessary when we're at an unnamed join, and it creates no risk of
    4202                 :          * ambiguity.  Also, if there's a user-written output alias for a
    4203                 :          * merged column, we prefer to use that rather than the input name;
    4204                 :          * this simplifies the logic and seems likely to lead to less aliasing
    4205                 :          * overall.
    4206                 :          *
    4207                 :          * If dpns->unique_using is false, we only need USING names to be
    4208                 :          * unique within their own join RTE.  We still need to honor
    4209                 :          * pushed-down names, though.
    4210                 :          *
    4211                 :          * Though significantly different in results, these two strategies are
    4212                 :          * implemented by the same code, with only the difference of whether
    4213                 :          * to put assigned names into dpns->using_names.
    4214                 :          */
    4215 CBC         500 :         if (j->usingClause)
    4216 EUB             :         {
    4217                 :             /* Copy the input parentUsing list so we don't modify it */
    4218 CBC         212 :             parentUsing = list_copy(parentUsing);
    4219 ECB             : 
    4220                 :             /* USING names must correspond to the first join output columns */
    4221 GIC         212 :             expand_colnames_array_to(colinfo, list_length(j->usingClause));
    4222             212 :             i = 0;
    4223 CBC         502 :             foreach(lc, j->usingClause)
    4224                 :             {
    4225 GIC         290 :                 char       *colname = strVal(lfirst(lc));
    4226                 : 
    4227 ECB             :                 /* Assert it's a merged column */
    4228 CBC         290 :                 Assert(leftattnos[i] != 0 && rightattnos[i] != 0);
    4229                 : 
    4230                 :                 /* Adopt passed-down name if any, else select unique name */
    4231             290 :                 if (colinfo->colnames[i] != NULL)
    4232 GIC          51 :                     colname = colinfo->colnames[i];
    4233 ECB             :                 else
    4234                 :                 {
    4235                 :                     /* Prefer user-written output alias if any */
    4236 GIC         239 :                     if (rte->alias && i < list_length(rte->alias->colnames))
    4237 UIC           0 :                         colname = strVal(list_nth(rte->alias->colnames, i));
    4238 ECB             :                     /* Make it appropriately unique */
    4239 GIC         239 :                     colname = make_colname_unique(colname, dpns, colinfo);
    4240 CBC         239 :                     if (dpns->unique_using)
    4241              63 :                         dpns->using_names = lappend(dpns->using_names,
    4242                 :                                                     colname);
    4243                 :                     /* Save it as output column name, too */
    4244             239 :                     colinfo->colnames[i] = colname;
    4245                 :                 }
    4246                 : 
    4247                 :                 /* Remember selected names for use later */
    4248 GIC         290 :                 colinfo->usingNames = lappend(colinfo->usingNames, colname);
    4249 CBC         290 :                 parentUsing = lappend(parentUsing, colname);
    4250 ECB             : 
    4251                 :                 /* Push down to left column, unless it's a system column */
    4252 GIC         290 :                 if (leftattnos[i] > 0)
    4253 ECB             :                 {
    4254 CBC         290 :                     expand_colnames_array_to(leftcolinfo, leftattnos[i]);
    4255 GIC         290 :                     leftcolinfo->colnames[leftattnos[i] - 1] = colname;
    4256                 :                 }
    4257 EUB             : 
    4258                 :                 /* Same on the righthand side */
    4259 CBC         290 :                 if (rightattnos[i] > 0)
    4260                 :                 {
    4261 GIC         290 :                     expand_colnames_array_to(rightcolinfo, rightattnos[i]);
    4262             290 :                     rightcolinfo->colnames[rightattnos[i] - 1] = colname;
    4263                 :                 }
    4264                 : 
    4265             290 :                 i++;
    4266                 :             }
    4267                 :         }
    4268                 : 
    4269 ECB             :         /* Mark child deparse_columns structs with correct parentUsing info */
    4270 GIC         500 :         leftcolinfo->parentUsing = parentUsing;
    4271             500 :         rightcolinfo->parentUsing = parentUsing;
    4272                 : 
    4273                 :         /* Now recursively assign USING column names in children */
    4274             500 :         set_using_names(dpns, j->larg, parentUsing);
    4275             500 :         set_using_names(dpns, j->rarg, parentUsing);
    4276                 :     }
    4277                 :     else
    4278 UIC           0 :         elog(ERROR, "unrecognized node type: %d",
    4279                 :              (int) nodeTag(jtnode));
    4280 GIC        5494 : }
    4281                 : 
    4282                 : /*
    4283                 :  * set_relation_column_names: select column aliases for a non-join RTE
    4284 ECB             :  *
    4285                 :  * Column alias info is saved in *colinfo, which is assumed to be pre-zeroed.
    4286                 :  * If any colnames entries are already filled in, those override local
    4287                 :  * choices.
    4288                 :  */
    4289                 : static void
    4290 CBC       38445 : set_relation_column_names(deparse_namespace *dpns, RangeTblEntry *rte,
    4291 ECB             :                           deparse_columns *colinfo)
    4292                 : {
    4293                 :     int         ncolumns;
    4294                 :     char      **real_colnames;
    4295                 :     bool        changed_any;
    4296                 :     int         noldcolumns;
    4297                 :     int         i;
    4298                 :     int         j;
    4299                 : 
    4300                 :     /*
    4301                 :      * Construct an array of the current "real" column names of the RTE.
    4302                 :      * real_colnames[] will be indexed by physical column number, with NULL
    4303                 :      * entries for dropped columns.
    4304                 :      */
    4305 CBC       38445 :     if (rte->rtekind == RTE_RELATION)
    4306                 :     {
    4307                 :         /* Relation --- look to the system catalogs for up-to-date info */
    4308                 :         Relation    rel;
    4309                 :         TupleDesc   tupdesc;
    4310                 : 
    4311 GIC       32179 :         rel = relation_open(rte->relid, AccessShareLock);
    4312           32179 :         tupdesc = RelationGetDescr(rel);
    4313                 : 
    4314           32179 :         ncolumns = tupdesc->natts;
    4315           32179 :         real_colnames = (char **) palloc(ncolumns * sizeof(char *));
    4316                 : 
    4317          207091 :         for (i = 0; i < ncolumns; i++)
    4318                 :         {
    4319          174912 :             Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
    4320                 : 
    4321          174912 :             if (attr->attisdropped)
    4322            1498 :                 real_colnames[i] = NULL;
    4323                 :             else
    4324          173414 :                 real_colnames[i] = pstrdup(NameStr(attr->attname));
    4325                 :         }
    4326           32179 :         relation_close(rel, AccessShareLock);
    4327                 :     }
    4328 ECB             :     else
    4329                 :     {
    4330                 :         /* Otherwise get the column names from eref or expandRTE() */
    4331                 :         List       *colnames;
    4332                 :         ListCell   *lc;
    4333                 : 
    4334                 :         /*
    4335                 :          * Functions returning composites have the annoying property that some
    4336                 :          * of the composite type's columns might have been dropped since the
    4337                 :          * query was parsed.  If possible, use expandRTE() to handle that
    4338                 :          * case, since it has the tedious logic needed to find out about
    4339                 :          * dropped columns.  However, if we're explaining a plan, then we
    4340                 :          * don't have rte->functions because the planner thinks that won't be
    4341                 :          * needed later, and that breaks expandRTE().  So in that case we have
    4342                 :          * to rely on rte->eref, which may lead us to report a dropped
    4343                 :          * column's old name; that seems close enough for EXPLAIN's purposes.
    4344                 :          *
    4345                 :          * For non-RELATION, non-FUNCTION RTEs, we can just look at rte->eref,
    4346                 :          * which should be sufficiently up-to-date: no other RTE types can
    4347                 :          * have columns get dropped from under them after parsing.
    4348                 :          */
    4349 CBC        6266 :         if (rte->rtekind == RTE_FUNCTION && rte->functions != NIL)
    4350 ECB             :         {
    4351                 :             /* Since we're not creating Vars, rtindex etc. don't matter */
    4352 CBC         267 :             expandRTE(rte, 1, 0, -1, true /* include dropped */ ,
    4353                 :                       &colnames, NULL);
    4354                 :         }
    4355                 :         else
    4356 GIC        5999 :             colnames = rte->eref->colnames;
    4357                 : 
    4358            6266 :         ncolumns = list_length(colnames);
    4359            6266 :         real_colnames = (char **) palloc(ncolumns * sizeof(char *));
    4360                 : 
    4361            6266 :         i = 0;
    4362           33471 :         foreach(lc, colnames)
    4363                 :         {
    4364 ECB             :             /*
    4365                 :              * If the column name we find here is an empty string, then it's a
    4366                 :              * dropped column, so change to NULL.
    4367                 :              */
    4368 GIC       27205 :             char       *cname = strVal(lfirst(lc));
    4369                 : 
    4370           27205 :             if (cname[0] == '\0')
    4371              27 :                 cname = NULL;
    4372           27205 :             real_colnames[i] = cname;
    4373           27205 :             i++;
    4374 ECB             :         }
    4375                 :     }
    4376                 : 
    4377                 :     /*
    4378                 :      * Ensure colinfo->colnames has a slot for each column.  (It could be long
    4379                 :      * enough already, if we pushed down a name for the last column.)  Note:
    4380                 :      * it's possible that there are now more columns than there were when the
    4381                 :      * query was parsed, ie colnames could be longer than rte->eref->colnames.
    4382                 :      * We must assign unique aliases to the new columns too, else there could
    4383                 :      * be unresolved conflicts when the view/rule is reloaded.
    4384                 :      */
    4385 CBC       38445 :     expand_colnames_array_to(colinfo, ncolumns);
    4386           38445 :     Assert(colinfo->num_cols == ncolumns);
    4387 ECB             : 
    4388                 :     /*
    4389                 :      * Make sufficiently large new_colnames and is_new_col arrays, too.
    4390                 :      *
    4391                 :      * Note: because we leave colinfo->num_new_cols zero until after the loop,
    4392                 :      * colname_is_unique will not consult that array, which is fine because it
    4393                 :      * would only be duplicate effort.
    4394                 :      */
    4395 CBC       38445 :     colinfo->new_colnames = (char **) palloc(ncolumns * sizeof(char *));
    4396           38445 :     colinfo->is_new_col = (bool *) palloc(ncolumns * sizeof(bool));
    4397                 : 
    4398                 :     /*
    4399                 :      * Scan the columns, select a unique alias for each one, and store it in
    4400 ECB             :      * colinfo->colnames and colinfo->new_colnames.  The former array has NULL
    4401                 :      * entries for dropped columns, the latter omits them.  Also mark
    4402                 :      * new_colnames entries as to whether they are new since parse time; this
    4403                 :      * is the case for entries beyond the length of rte->eref->colnames.
    4404                 :      */
    4405 GIC       38445 :     noldcolumns = list_length(rte->eref->colnames);
    4406 CBC       38445 :     changed_any = false;
    4407 GIC       38445 :     j = 0;
    4408          240562 :     for (i = 0; i < ncolumns; i++)
    4409 ECB             :     {
    4410 GIC      202117 :         char       *real_colname = real_colnames[i];
    4411 CBC      202117 :         char       *colname = colinfo->colnames[i];
    4412                 : 
    4413                 :         /* Skip dropped columns */
    4414 GIC      202117 :         if (real_colname == NULL)
    4415 ECB             :         {
    4416 GIC        1525 :             Assert(colname == NULL);    /* colnames[i] is already NULL */
    4417 CBC        1525 :             continue;
    4418 ECB             :         }
    4419                 : 
    4420                 :         /* If alias already assigned, that's what to use */
    4421 CBC      200592 :         if (colname == NULL)
    4422 ECB             :         {
    4423                 :             /* If user wrote an alias, prefer that over real column name */
    4424 GIC      200063 :             if (rte->alias && i < list_length(rte->alias->colnames))
    4425           19190 :                 colname = strVal(list_nth(rte->alias->colnames, i));
    4426                 :             else
    4427          180873 :                 colname = real_colname;
    4428                 : 
    4429                 :             /* Unique-ify and insert into colinfo */
    4430          200063 :             colname = make_colname_unique(colname, dpns, colinfo);
    4431 ECB             : 
    4432 GIC      200063 :             colinfo->colnames[i] = colname;
    4433                 :         }
    4434                 : 
    4435                 :         /* Put names of non-dropped columns in new_colnames[] too */
    4436          200592 :         colinfo->new_colnames[j] = colname;
    4437                 :         /* And mark them as new or not */
    4438          200592 :         colinfo->is_new_col[j] = (i >= noldcolumns);
    4439          200592 :         j++;
    4440                 : 
    4441                 :         /* Remember if any assigned aliases differ from "real" name */
    4442          200592 :         if (!changed_any && strcmp(colname, real_colname) != 0)
    4443 CBC        1641 :             changed_any = true;
    4444 ECB             :     }
    4445                 : 
    4446                 :     /*
    4447                 :      * Set correct length for new_colnames[] array.  (Note: if columns have
    4448                 :      * been added, colinfo->num_cols includes them, which is not really quite
    4449                 :      * right but is harmless, since any new columns must be at the end where
    4450                 :      * they won't affect varattnos of pre-existing columns.)
    4451                 :      */
    4452 CBC       38445 :     colinfo->num_new_cols = j;
    4453 ECB             : 
    4454                 :     /*
    4455                 :      * For a relation RTE, we need only print the alias column names if any
    4456                 :      * are different from the underlying "real" names.  For a function RTE,
    4457                 :      * always emit a complete column alias list; this is to protect against
    4458                 :      * possible instability of the default column names (eg, from altering
    4459                 :      * parameter names).  For tablefunc RTEs, we never print aliases, because
    4460                 :      * the column names are part of the clause itself.  For other RTE types,
    4461                 :      * print if we changed anything OR if there were user-written column
    4462                 :      * aliases (since the latter would be part of the underlying "reality").
    4463                 :      */
    4464 GIC       38445 :     if (rte->rtekind == RTE_RELATION)
    4465 CBC       32179 :         colinfo->printaliases = changed_any;
    4466 GIC        6266 :     else if (rte->rtekind == RTE_FUNCTION)
    4467             453 :         colinfo->printaliases = true;
    4468            5813 :     else if (rte->rtekind == RTE_TABLEFUNC)
    4469              28 :         colinfo->printaliases = false;
    4470            5785 :     else if (rte->alias && rte->alias->colnames != NIL)
    4471             336 :         colinfo->printaliases = true;
    4472                 :     else
    4473 CBC        5449 :         colinfo->printaliases = changed_any;
    4474           38445 : }
    4475                 : 
    4476                 : /*
    4477                 :  * set_join_column_names: select column aliases for a join RTE
    4478                 :  *
    4479                 :  * Column alias info is saved in *colinfo, which is assumed to be pre-zeroed.
    4480                 :  * If any colnames entries are already filled in, those override local
    4481 ECB             :  * choices.  Also, names for USING columns were already chosen by
    4482                 :  * set_using_names().  We further expect that column alias selection has been
    4483                 :  * completed for both input RTEs.
    4484                 :  */
    4485                 : static void
    4486 GIC         500 : set_join_column_names(deparse_namespace *dpns, RangeTblEntry *rte,
    4487                 :                       deparse_columns *colinfo)
    4488                 : {
    4489                 :     deparse_columns *leftcolinfo;
    4490                 :     deparse_columns *rightcolinfo;
    4491 ECB             :     bool        changed_any;
    4492                 :     int         noldcolumns;
    4493                 :     int         nnewcolumns;
    4494 GIC         500 :     Bitmapset  *leftmerged = NULL;
    4495             500 :     Bitmapset  *rightmerged = NULL;
    4496                 :     int         i;
    4497                 :     int         j;
    4498                 :     int         ic;
    4499                 :     int         jc;
    4500                 : 
    4501 ECB             :     /* Look up the previously-filled-in child deparse_columns structs */
    4502 CBC         500 :     leftcolinfo = deparse_columns_fetch(colinfo->leftrti, dpns);
    4503 GIC         500 :     rightcolinfo = deparse_columns_fetch(colinfo->rightrti, dpns);
    4504 ECB             : 
    4505                 :     /*
    4506                 :      * Ensure colinfo->colnames has a slot for each column.  (It could be long
    4507                 :      * enough already, if we pushed down a name for the last column.)  Note:
    4508                 :      * it's possible that one or both inputs now have more columns than there
    4509                 :      * were when the query was parsed, but we'll deal with that below.  We
    4510                 :      * only need entries in colnames for pre-existing columns.
    4511                 :      */
    4512 CBC         500 :     noldcolumns = list_length(rte->eref->colnames);
    4513             500 :     expand_colnames_array_to(colinfo, noldcolumns);
    4514             500 :     Assert(colinfo->num_cols == noldcolumns);
    4515                 : 
    4516                 :     /*
    4517                 :      * Scan the join output columns, select an alias for each one, and store
    4518 EUB             :      * it in colinfo->colnames.  If there are USING columns, set_using_names()
    4519                 :      * already selected their names, so we can start the loop at the first
    4520                 :      * non-merged column.
    4521                 :      */
    4522 CBC         500 :     changed_any = false;
    4523 GIC       12818 :     for (i = list_length(colinfo->usingNames); i < noldcolumns; i++)
    4524 ECB             :     {
    4525 CBC       12318 :         char       *colname = colinfo->colnames[i];
    4526                 :         char       *real_colname;
    4527                 : 
    4528                 :         /* Join column must refer to at least one input column */
    4529           12318 :         Assert(colinfo->leftattnos[i] != 0 || colinfo->rightattnos[i] != 0);
    4530                 : 
    4531 ECB             :         /* Get the child column name */
    4532 CBC       12318 :         if (colinfo->leftattnos[i] > 0)
    4533 GIC        8558 :             real_colname = leftcolinfo->colnames[colinfo->leftattnos[i] - 1];
    4534            3760 :         else if (colinfo->rightattnos[i] > 0)
    4535            3760 :             real_colname = rightcolinfo->colnames[colinfo->rightattnos[i] - 1];
    4536 ECB             :         else
    4537                 :         {
    4538                 :             /* We're joining system columns --- use eref name */
    4539 LBC           0 :             real_colname = strVal(list_nth(rte->eref->colnames, i));
    4540 ECB             :         }
    4541                 : 
    4542                 :         /* If child col has been dropped, no need to assign a join colname */
    4543 GIC       12318 :         if (real_colname == NULL)
    4544                 :         {
    4545 CBC           3 :             colinfo->colnames[i] = NULL;
    4546 GIC           3 :             continue;
    4547 ECB             :         }
    4548                 : 
    4549                 :         /* In an unnamed join, just report child column names as-is */
    4550 GIC       12315 :         if (rte->alias == NULL)
    4551 ECB             :         {
    4552 CBC       12126 :             colinfo->colnames[i] = real_colname;
    4553 GIC       12126 :             continue;
    4554                 :         }
    4555                 : 
    4556                 :         /* If alias already assigned, that's what to use */
    4557             189 :         if (colname == NULL)
    4558                 :         {
    4559                 :             /* If user wrote an alias, prefer that over real column name */
    4560             189 :             if (rte->alias && i < list_length(rte->alias->colnames))
    4561              48 :                 colname = strVal(list_nth(rte->alias->colnames, i));
    4562 ECB             :             else
    4563 CBC         141 :                 colname = real_colname;
    4564 ECB             : 
    4565                 :             /* Unique-ify and insert into colinfo */
    4566 CBC         189 :             colname = make_colname_unique(colname, dpns, colinfo);
    4567                 : 
    4568 GIC         189 :             colinfo->colnames[i] = colname;
    4569                 :         }
    4570                 : 
    4571                 :         /* Remember if any assigned aliases differ from "real" name */
    4572             189 :         if (!changed_any && strcmp(colname, real_colname) != 0)
    4573              12 :             changed_any = true;
    4574                 :     }
    4575                 : 
    4576                 :     /*
    4577                 :      * Calculate number of columns the join would have if it were re-parsed
    4578                 :      * now, and create storage for the new_colnames and is_new_col arrays.
    4579                 :      *
    4580                 :      * Note: colname_is_unique will be consulting new_colnames[] during the
    4581                 :      * loops below, so its not-yet-filled entries must be zeroes.
    4582                 :      */
    4583            1000 :     nnewcolumns = leftcolinfo->num_new_cols + rightcolinfo->num_new_cols -
    4584             500 :         list_length(colinfo->usingNames);
    4585 CBC         500 :     colinfo->num_new_cols = nnewcolumns;
    4586             500 :     colinfo->new_colnames = (char **) palloc0(nnewcolumns * sizeof(char *));
    4587             500 :     colinfo->is_new_col = (bool *) palloc0(nnewcolumns * sizeof(bool));
    4588 ECB             : 
    4589                 :     /*
    4590                 :      * Generating the new_colnames array is a bit tricky since any new columns
    4591                 :      * added since parse time must be inserted in the right places.  This code
    4592                 :      * must match the parser, which will order a join's columns as merged
    4593                 :      * columns first (in USING-clause order), then non-merged columns from the
    4594                 :      * left input (in attnum order), then non-merged columns from the right
    4595                 :      * input (ditto).  If one of the inputs is itself a join, its columns will
    4596                 :      * be ordered according to the same rule, which means newly-added columns
    4597                 :      * might not be at the end.  We can figure out what's what by consulting
    4598                 :      * the leftattnos and rightattnos arrays plus the input is_new_col arrays.
    4599                 :      *
    4600                 :      * In these loops, i indexes leftattnos/rightattnos (so it's join varattno
    4601                 :      * less one), j indexes new_colnames/is_new_col, and ic/jc have similar
    4602                 :      * meanings for the current child RTE.
    4603                 :      */
    4604                 : 
    4605                 :     /* Handle merged columns; they are first and can't be new */
    4606 GIC         500 :     i = j = 0;
    4607 CBC         500 :     while (i < noldcolumns &&
    4608 GIC         790 :            colinfo->leftattnos[i] != 0 &&
    4609 CBC         790 :            colinfo->rightattnos[i] != 0)
    4610                 :     {
    4611                 :         /* column name is already determined and known unique */
    4612             290 :         colinfo->new_colnames[j] = colinfo->colnames[i];
    4613             290 :         colinfo->is_new_col[j] = false;
    4614 ECB             : 
    4615                 :         /* build bitmapsets of child attnums of merged columns */
    4616 CBC         290 :         if (colinfo->leftattnos[i] > 0)
    4617 GIC         290 :             leftmerged = bms_add_member(leftmerged, colinfo->leftattnos[i]);
    4618 CBC         290 :         if (colinfo->rightattnos[i] > 0)
    4619             290 :             rightmerged = bms_add_member(rightmerged, colinfo->rightattnos[i]);
    4620                 : 
    4621             290 :         i++, j++;
    4622 ECB             :     }
    4623                 : 
    4624                 :     /* Handle non-merged left-child columns */
    4625 CBC         500 :     ic = 0;
    4626 GIC        9591 :     for (jc = 0; jc < leftcolinfo->num_new_cols; jc++)
    4627 ECB             :     {
    4628 CBC        9091 :         char       *child_colname = leftcolinfo->new_colnames[jc];
    4629                 : 
    4630 GIC        9091 :         if (!leftcolinfo->is_new_col[jc])
    4631                 :         {
    4632                 :             /* Advance ic to next non-dropped old column of left child */
    4633            8887 :             while (ic < leftcolinfo->num_cols &&
    4634            8887 :                    leftcolinfo->colnames[ic] == NULL)
    4635              42 :                 ic++;
    4636 CBC        8845 :             Assert(ic < leftcolinfo->num_cols);
    4637 GIC        8845 :             ic++;
    4638 ECB             :             /* If it is a merged column, we already processed it */
    4639 CBC        8845 :             if (bms_is_member(ic, leftmerged))
    4640             290 :                 continue;
    4641 ECB             :             /* Else, advance i to the corresponding existing join column */
    4642 CBC        8558 :             while (i < colinfo->num_cols &&
    4643 GIC        8558 :                    colinfo->colnames[i] == NULL)
    4644               3 :                 i++;
    4645 CBC        8555 :             Assert(i < colinfo->num_cols);
    4646 GIC        8555 :             Assert(ic == colinfo->leftattnos[i]);
    4647                 :             /* Use the already-assigned name of this column */
    4648 CBC        8555 :             colinfo->new_colnames[j] = colinfo->colnames[i];
    4649            8555 :             i++;
    4650                 :         }
    4651                 :         else
    4652                 :         {
    4653 ECB             :             /*
    4654                 :              * Unique-ify the new child column name and assign, unless we're
    4655                 :              * in an unnamed join, in which case just copy
    4656                 :              */
    4657 GIC         246 :             if (rte->alias != NULL)
    4658 ECB             :             {
    4659 GIC         132 :                 colinfo->new_colnames[j] =
    4660              66 :                     make_colname_unique(child_colname, dpns, colinfo);
    4661 CBC          66 :                 if (!changed_any &&
    4662              54 :                     strcmp(colinfo->new_colnames[j], child_colname) != 0)
    4663 GBC           6 :                     changed_any = true;
    4664 ECB             :             }
    4665                 :             else
    4666 GIC         180 :                 colinfo->new_colnames[j] = child_colname;
    4667 ECB             :         }
    4668                 : 
    4669 GIC        8801 :         colinfo->is_new_col[j] = leftcolinfo->is_new_col[jc];
    4670 CBC        8801 :         j++;
    4671 ECB             :     }
    4672 EUB             : 
    4673 ECB             :     /* Handle non-merged right-child columns in exactly the same way */
    4674 CBC         500 :     ic = 0;
    4675 GIC        4634 :     for (jc = 0; jc < rightcolinfo->num_new_cols; jc++)
    4676 ECB             :     {
    4677 CBC        4134 :         char       *child_colname = rightcolinfo->new_colnames[jc];
    4678                 : 
    4679 GIC        4134 :         if (!rightcolinfo->is_new_col[jc])
    4680                 :         {
    4681                 :             /* Advance ic to next non-dropped old column of right child */
    4682            4050 :             while (ic < rightcolinfo->num_cols &&
    4683            4050 :                    rightcolinfo->colnames[ic] == NULL)
    4684 UIC           0 :                 ic++;
    4685 CBC        4050 :             Assert(ic < rightcolinfo->num_cols);
    4686 GIC        4050 :             ic++;
    4687 ECB             :             /* If it is a merged column, we already processed it */
    4688 CBC        4050 :             if (bms_is_member(ic, rightmerged))
    4689             290 :                 continue;
    4690 ECB             :             /* Else, advance i to the corresponding existing join column */
    4691 CBC        3760 :             while (i < colinfo->num_cols &&
    4692 GIC        3760 :                    colinfo->colnames[i] == NULL)
    4693 UIC           0 :                 i++;
    4694 CBC        3760 :             Assert(i < colinfo->num_cols);
    4695 GIC        3760 :             Assert(ic == colinfo->rightattnos[i]);
    4696                 :             /* Use the already-assigned name of this column */
    4697 CBC        3760 :             colinfo->new_colnames[j] = colinfo->colnames[i];
    4698            3760 :             i++;
    4699                 :         }
    4700                 :         else
    4701                 :         {
    4702                 :             /*
    4703 ECB             :              * Unique-ify the new child column name and assign, unless we're
    4704 EUB             :              * in an unnamed join, in which case just copy
    4705 ECB             :              */
    4706 CBC          84 :             if (rte->alias != NULL)
    4707                 :             {
    4708 GIC          24 :                 colinfo->new_colnames[j] =
    4709              12 :                     make_colname_unique(child_colname, dpns, colinfo);
    4710              12 :                 if (!changed_any &&
    4711              12 :                     strcmp(colinfo->new_colnames[j], child_colname) != 0)
    4712               6 :                     changed_any = true;
    4713 ECB             :             }
    4714                 :             else
    4715 GIC          72 :                 colinfo->new_colnames[j] = child_colname;
    4716 ECB             :         }
    4717                 : 
    4718 GIC        3844 :         colinfo->is_new_col[j] = rightcolinfo->is_new_col[jc];
    4719            3844 :         j++;
    4720                 :     }
    4721                 : 
    4722                 :     /* Assert we processed the right number of columns */
    4723                 : #ifdef USE_ASSERT_CHECKING
    4724             500 :     while (i < colinfo->num_cols && colinfo->colnames[i] == NULL)
    4725 LBC           0 :         i++;
    4726 GIC         500 :     Assert(i == colinfo->num_cols);
    4727             500 :     Assert(j == nnewcolumns);
    4728                 : #endif
    4729                 : 
    4730                 :     /*
    4731                 :      * For a named join, print column aliases if we changed any from the child
    4732 ECB             :      * names.  Unnamed joins cannot print aliases.
    4733                 :      */
    4734 CBC         500 :     if (rte->alias != NULL)
    4735 GIC          54 :         colinfo->printaliases = changed_any;
    4736 ECB             :     else
    4737 CBC         446 :         colinfo->printaliases = false;
    4738 GIC         500 : }
    4739                 : 
    4740                 : /*
    4741                 :  * colname_is_unique: is colname distinct from already-chosen column names?
    4742                 :  *
    4743                 :  * dpns is query-wide info, colinfo is for the column's RTE
    4744 ECB             :  */
    4745                 : static bool
    4746 CBC      209077 : colname_is_unique(const char *colname, deparse_namespace *dpns,
    4747                 :                   deparse_columns *colinfo)
    4748 ECB             : {
    4749                 :     int         i;
    4750                 :     ListCell   *lc;
    4751                 : 
    4752                 :     /* Check against already-assigned column aliases within RTE */
    4753 CBC     3170987 :     for (i = 0; i < colinfo->num_cols; i++)
    4754                 :     {
    4755         2970382 :         char       *oldname = colinfo->colnames[i];
    4756                 : 
    4757         2970382 :         if (oldname && strcmp(oldname, colname) == 0)
    4758            8472 :             return false;
    4759                 :     }
    4760                 : 
    4761                 :     /*
    4762 ECB             :      * If we're building a new_colnames array, check that too (this will be
    4763                 :      * partially but not completely redundant with the previous checks)
    4764                 :      */
    4765 GIC      201241 :     for (i = 0; i < colinfo->num_new_cols; i++)
    4766 ECB             :     {
    4767 CBC         648 :         char       *oldname = colinfo->new_colnames[i];
    4768                 : 
    4769 GIC         648 :         if (oldname && strcmp(oldname, colname) == 0)
    4770 CBC          12 :             return false;
    4771                 :     }
    4772                 : 
    4773                 :     /* Also check against USING-column names that must be globally unique */
    4774 GIC      201013 :     foreach(lc, dpns->using_names)
    4775                 :     {
    4776             441 :         char       *oldname = (char *) lfirst(lc);
    4777                 : 
    4778             441 :         if (strcmp(oldname, colname) == 0)
    4779 CBC          21 :             return false;
    4780                 :     }
    4781                 : 
    4782                 :     /* Also check against names already assigned for parent-join USING cols */
    4783 GIC      201868 :     foreach(lc, colinfo->parentUsing)
    4784                 :     {
    4785            1299 :         char       *oldname = (char *) lfirst(lc);
    4786                 : 
    4787 CBC        1299 :         if (strcmp(oldname, colname) == 0)
    4788 GIC           3 :             return false;
    4789 ECB             :     }
    4790                 : 
    4791 CBC      200569 :     return true;
    4792                 : }
    4793                 : 
    4794                 : /*
    4795 ECB             :  * make_colname_unique: modify colname if necessary to make it unique
    4796                 :  *
    4797                 :  * dpns is query-wide info, colinfo is for the column's RTE
    4798                 :  */
    4799                 : static char *
    4800 CBC      200569 : make_colname_unique(char *colname, deparse_namespace *dpns,
    4801 ECB             :                     deparse_columns *colinfo)
    4802                 : {
    4803 EUB             :     /*
    4804                 :      * If the selected name isn't unique, append digits to make it so.  For a
    4805                 :      * very long input name, we might have to truncate to stay within
    4806 ECB             :      * NAMEDATALEN.
    4807                 :      */
    4808 GIC      200569 :     if (!colname_is_unique(colname, dpns, colinfo))
    4809 ECB             :     {
    4810 GIC        7412 :         int         colnamelen = strlen(colname);
    4811            7412 :         char       *modname = (char *) palloc(colnamelen + 16);
    4812            7412 :         int         i = 0;
    4813                 : 
    4814                 :         do
    4815                 :         {
    4816            8508 :             i++;
    4817                 :             for (;;)
    4818 ECB             :             {
    4819 GIC        8508 :                 memcpy(modname, colname, colnamelen);
    4820 CBC        8508 :                 sprintf(modname + colnamelen, "_%d", i);
    4821 GIC        8508 :                 if (strlen(modname) < NAMEDATALEN)
    4822 CBC        8508 :                     break;
    4823 ECB             :                 /* drop chars from colname to keep all the digits */
    4824 UIC           0 :                 colnamelen = pg_mbcliplen(colname, colnamelen,
    4825 ECB             :                                           colnamelen - 1);
    4826                 :             }
    4827 GIC        8508 :         } while (!colname_is_unique(modname, dpns, colinfo));
    4828 CBC        7412 :         colname = modname;
    4829                 :     }
    4830 GIC      200569 :     return colname;
    4831                 : }
    4832                 : 
    4833                 : /*
    4834                 :  * expand_colnames_array_to: make colinfo->colnames at least n items long
    4835                 :  *
    4836                 :  * Any added array entries are initialized to zero.
    4837 ECB             :  */
    4838                 : static void
    4839 GIC       39845 : expand_colnames_array_to(deparse_columns *colinfo, int n)
    4840                 : {
    4841           39845 :     if (n > colinfo->num_cols)
    4842                 :     {
    4843           38860 :         if (colinfo->colnames == NULL)
    4844 GNC       38152 :             colinfo->colnames = palloc0_array(char *, n);
    4845                 :         else
    4846             708 :             colinfo->colnames = repalloc0_array(colinfo->colnames, char *, colinfo->num_cols, n);
    4847 GIC       38860 :         colinfo->num_cols = n;
    4848 ECB             :     }
    4849 CBC       39845 : }
    4850 EUB             : 
    4851                 : /*
    4852                 :  * identify_join_columns: figure out where columns of a join come from
    4853                 :  *
    4854                 :  * Fills the join-specific fields of the colinfo struct, except for
    4855                 :  * usingNames which is filled later.
    4856                 :  */
    4857 ECB             : static void
    4858 CBC         500 : identify_join_columns(JoinExpr *j, RangeTblEntry *jrte,
    4859                 :                       deparse_columns *colinfo)
    4860                 : {
    4861 ECB             :     int         numjoincols;
    4862                 :     int         jcolno;
    4863                 :     int         rcolno;
    4864                 :     ListCell   *lc;
    4865                 : 
    4866                 :     /* Extract left/right child RT indexes */
    4867 GIC         500 :     if (IsA(j->larg, RangeTblRef))
    4868             335 :         colinfo->leftrti = ((RangeTblRef *) j->larg)->rtindex;
    4869             165 :     else if (IsA(j->larg, JoinExpr))
    4870             165 :         colinfo->leftrti = ((JoinExpr *) j->larg)->rtindex;
    4871                 :     else
    4872 UIC           0 :         elog(ERROR, "unrecognized node type in jointree: %d",
    4873 ECB             :              (int) nodeTag(j->larg));
    4874 CBC         500 :     if (IsA(j->rarg, RangeTblRef))
    4875 GIC         500 :         colinfo->rightrti = ((RangeTblRef *) j->rarg)->rtindex;
    4876 LBC           0 :     else if (IsA(j->rarg, JoinExpr))
    4877 UIC           0 :         colinfo->rightrti = ((JoinExpr *) j->rarg)->rtindex;
    4878 ECB             :     else
    4879 UIC           0 :         elog(ERROR, "unrecognized node type in jointree: %d",
    4880 ECB             :              (int) nodeTag(j->rarg));
    4881                 : 
    4882                 :     /* Assert children will be processed earlier than join in second pass */
    4883 CBC         500 :     Assert(colinfo->leftrti < j->rtindex);
    4884 GIC         500 :     Assert(colinfo->rightrti < j->rtindex);
    4885 ECB             : 
    4886                 :     /* Initialize result arrays with zeroes */
    4887 GIC         500 :     numjoincols = list_length(jrte->joinaliasvars);
    4888 CBC         500 :     Assert(numjoincols == list_length(jrte->eref->colnames));
    4889             500 :     colinfo->leftattnos = (int *) palloc0(numjoincols * sizeof(int));
    4890 GIC         500 :     colinfo->rightattnos = (int *) palloc0(numjoincols * sizeof(int));
    4891 ECB             : 
    4892                 :     /*
    4893                 :      * Deconstruct RTE's joinleftcols/joinrightcols into desired format.
    4894                 :      * Recall that the column(s) merged due to USING are the first column(s)
    4895                 :      * of the join output.  We need not do anything special while scanning
    4896                 :      * joinleftcols, but while scanning joinrightcols we must distinguish
    4897                 :      * merged from unmerged columns.
    4898                 :      */
    4899 GIC         500 :     jcolno = 0;
    4900 CBC        9348 :     foreach(lc, jrte->joinleftcols)
    4901                 :     {
    4902            8848 :         int         leftattno = lfirst_int(lc);
    4903                 : 
    4904            8848 :         colinfo->leftattnos[jcolno++] = leftattno;
    4905 ECB             :     }
    4906 GIC         500 :     rcolno = 0;
    4907            4550 :     foreach(lc, jrte->joinrightcols)
    4908                 :     {
    4909            4050 :         int         rightattno = lfirst_int(lc);
    4910                 : 
    4911            4050 :         if (rcolno < jrte->joinmergedcols)    /* merged column? */
    4912             290 :             colinfo->rightattnos[rcolno] = rightattno;
    4913                 :         else
    4914            3760 :             colinfo->rightattnos[jcolno++] = rightattno;
    4915            4050 :         rcolno++;
    4916                 :     }
    4917             500 :     Assert(jcolno == numjoincols);
    4918             500 : }
    4919 ECB             : 
    4920                 : /*
    4921                 :  * get_rtable_name: convenience function to get a previously assigned RTE alias
    4922                 :  *
    4923                 :  * The RTE must belong to the topmost namespace level in "context".
    4924                 :  */
    4925                 : static char *
    4926 GIC        2564 : get_rtable_name(int rtindex, deparse_context *context)
    4927                 : {
    4928            2564 :     deparse_namespace *dpns = (deparse_namespace *) linitial(context->namespaces);
    4929 ECB             : 
    4930 CBC        2564 :     Assert(rtindex > 0 && rtindex <= list_length(dpns->rtable_names));
    4931            2564 :     return (char *) list_nth(dpns->rtable_names, rtindex - 1);
    4932 ECB             : }
    4933                 : 
    4934                 : /*
    4935                 :  * set_deparse_plan: set up deparse_namespace to parse subexpressions
    4936                 :  * of a given Plan node
    4937                 :  *
    4938                 :  * This sets the plan, outer_plan, inner_plan, outer_tlist, inner_tlist,
    4939                 :  * and index_tlist fields.  Caller must already have adjusted the ancestors
    4940                 :  * list if necessary.  Note that the rtable, subplans, and ctes fields do
    4941                 :  * not need to change when shifting attention to different plan nodes in a
    4942                 :  * single plan tree.
    4943                 :  */
    4944                 : static void
    4945 GIC       49052 : set_deparse_plan(deparse_namespace *dpns, Plan *plan)
    4946                 : {
    4947           49052 :     dpns->plan = plan;
    4948                 : 
    4949                 :     /*
    4950                 :      * We special-case Append and MergeAppend to pretend that the first child
    4951                 :      * plan is the OUTER referent; we have to interpret OUTER Vars in their
    4952                 :      * tlists according to one of the children, and the first one is the most
    4953                 :      * natural choice.
    4954                 :      */
    4955 CBC       49052 :     if (IsA(plan, Append))
    4956            1924 :         dpns->outer_plan = linitial(((Append *) plan)->appendplans);
    4957           47128 :     else if (IsA(plan, MergeAppend))
    4958             213 :         dpns->outer_plan = linitial(((MergeAppend *) plan)->mergeplans);
    4959 ECB             :     else
    4960 CBC       46915 :         dpns->outer_plan = outerPlan(plan);
    4961 ECB             : 
    4962 GIC       49052 :     if (dpns->outer_plan)
    4963 CBC       21939 :         dpns->outer_tlist = dpns->outer_plan->targetlist;
    4964 ECB             :     else
    4965 GIC       27113 :         dpns->outer_tlist = NIL;
    4966 ECB             : 
    4967                 :     /*
    4968                 :      * For a SubqueryScan, pretend the subplan is INNER referent.  (We don't
    4969                 :      * use OUTER because that could someday conflict with the normal meaning.)
    4970                 :      * Likewise, for a CteScan, pretend the subquery's plan is INNER referent.
    4971                 :      * For a WorkTableScan, locate the parent RecursiveUnion plan node and use
    4972                 :      * that as INNER referent.
    4973                 :      *
    4974                 :      * For MERGE, make the inner tlist point to the merge source tlist, which
    4975                 :      * is same as the targetlist that the ModifyTable's source plan provides.
    4976                 :      * For ON CONFLICT .. UPDATE we just need the inner tlist to point to the
    4977                 :      * excluded expression's tlist. (Similar to the SubqueryScan we don't want
    4978                 :      * to reuse OUTER, it's used for RETURNING in some modify table cases,
    4979                 :      * although not INSERT .. CONFLICT).
    4980                 :      */
    4981 CBC       49052 :     if (IsA(plan, SubqueryScan))
    4982             238 :         dpns->inner_plan = ((SubqueryScan *) plan)->subplan;
    4983           48814 :     else if (IsA(plan, CteScan))
    4984             240 :         dpns->inner_plan = list_nth(dpns->subplans,
    4985             240 :                                     ((CteScan *) plan)->ctePlanId - 1);
    4986 GBC       48574 :     else if (IsA(plan, WorkTableScan))
    4987 GIC          87 :         dpns->inner_plan = find_recursive_union(dpns,
    4988 ECB             :                                                 (WorkTableScan *) plan);
    4989 CBC       48487 :     else if (IsA(plan, ModifyTable))
    4990 GIC         107 :         dpns->inner_plan = plan;
    4991                 :     else
    4992           48380 :         dpns->inner_plan = innerPlan(plan);
    4993                 : 
    4994           49052 :     if (IsA(plan, ModifyTable))
    4995                 :     {
    4996             107 :         if (((ModifyTable *) plan)->operation == CMD_MERGE)
    4997 CBC           3 :             dpns->inner_tlist = dpns->outer_tlist;
    4998                 :         else
    4999 GIC         104 :             dpns->inner_tlist = ((ModifyTable *) plan)->exclRelTlist;
    5000                 :     }
    5001 CBC       48945 :     else if (dpns->inner_plan)
    5002 GIC        7593 :         dpns->inner_tlist = dpns->inner_plan->targetlist;
    5003 ECB             :     else
    5004 GIC       41352 :         dpns->inner_tlist = NIL;
    5005 ECB             : 
    5006                 :     /* Set up referent for INDEX_VAR Vars, if needed */
    5007 CBC       49052 :     if (IsA(plan, IndexOnlyScan))
    5008 GIC        1229 :         dpns->index_tlist = ((IndexOnlyScan *) plan)->indextlist;
    5009 GBC       47823 :     else if (IsA(plan, ForeignScan))
    5010 GIC        1360 :         dpns->index_tlist = ((ForeignScan *) plan)->fdw_scan_tlist;
    5011           46463 :     else if (IsA(plan, CustomScan))
    5012 UIC           0 :         dpns->index_tlist = ((CustomScan *) plan)->custom_scan_tlist;
    5013                 :     else
    5014 GIC       46463 :         dpns->index_tlist = NIL;
    5015           49052 : }
    5016                 : 
    5017                 : /*
    5018                 :  * Locate the ancestor plan node that is the RecursiveUnion generating
    5019                 :  * the WorkTableScan's work table.  We can match on wtParam, since that
    5020                 :  * should be unique within the plan tree.
    5021                 :  */
    5022                 : static Plan *
    5023              87 : find_recursive_union(deparse_namespace *dpns, WorkTableScan *wtscan)
    5024                 : {
    5025                 :     ListCell   *lc;
    5026                 : 
    5027 CBC         219 :     foreach(lc, dpns->ancestors)
    5028                 :     {
    5029 GIC         219 :         Plan       *ancestor = (Plan *) lfirst(lc);
    5030                 : 
    5031 CBC         219 :         if (IsA(ancestor, RecursiveUnion) &&
    5032 GIC          87 :             ((RecursiveUnion *) ancestor)->wtParam == wtscan->wtParam)
    5033              87 :             return ancestor;
    5034 ECB             :     }
    5035 UIC           0 :     elog(ERROR, "could not find RecursiveUnion for WorkTableScan with wtParam %d",
    5036                 :          wtscan->wtParam);
    5037 ECB             :     return NULL;
    5038                 : }
    5039                 : 
    5040                 : /*
    5041                 :  * push_child_plan: temporarily transfer deparsing attention to a child plan
    5042                 :  *
    5043                 :  * When expanding an OUTER_VAR or INNER_VAR reference, we must adjust the
    5044                 :  * deparse context in case the referenced expression itself uses
    5045                 :  * OUTER_VAR/INNER_VAR.  We modify the top stack entry in-place to avoid
    5046                 :  * affecting levelsup issues (although in a Plan tree there really shouldn't
    5047                 :  * be any).
    5048                 :  *
    5049                 :  * Caller must provide a local deparse_namespace variable to save the
    5050                 :  * previous state for pop_child_plan.
    5051                 :  */
    5052                 : static void
    5053 GIC       26217 : push_child_plan(deparse_namespace *dpns, Plan *plan,
    5054                 :                 deparse_namespace *save_dpns)
    5055 ECB             : {
    5056                 :     /* Save state for restoration later */
    5057 GIC       26217 :     *save_dpns = *dpns;
    5058                 : 
    5059                 :     /* Link current plan node into ancestors list */
    5060           26217 :     dpns->ancestors = lcons(dpns->plan, dpns->ancestors);
    5061                 : 
    5062                 :     /* Set attention on selected child */
    5063           26217 :     set_deparse_plan(dpns, plan);
    5064           26217 : }
    5065                 : 
    5066                 : /*
    5067                 :  * pop_child_plan: undo the effects of push_child_plan
    5068                 :  */
    5069                 : static void
    5070           26217 : pop_child_plan(deparse_namespace *dpns, deparse_namespace *save_dpns)
    5071                 : {
    5072                 :     List       *ancestors;
    5073                 : 
    5074 ECB             :     /* Get rid of ancestors list cell added by push_child_plan */
    5075 GIC       26217 :     ancestors = list_delete_first(dpns->ancestors);
    5076                 : 
    5077 ECB             :     /* Restore fields changed by push_child_plan */
    5078 GIC       26217 :     *dpns = *save_dpns;
    5079                 : 
    5080 ECB             :     /* Make sure dpns->ancestors is right (may be unnecessary) */
    5081 GIC       26217 :     dpns->ancestors = ancestors;
    5082           26217 : }
    5083 ECB             : 
    5084                 : /*
    5085                 :  * push_ancestor_plan: temporarily transfer deparsing attention to an
    5086                 :  * ancestor plan
    5087                 :  *
    5088                 :  * When expanding a Param reference, we must adjust the deparse context
    5089                 :  * to match the plan node that contains the expression being printed;
    5090                 :  * otherwise we'd fail if that expression itself contains a Param or
    5091                 :  * OUTER_VAR/INNER_VAR/INDEX_VAR variable.
    5092                 :  *
    5093                 :  * The target ancestor is conveniently identified by the ListCell holding it
    5094                 :  * in dpns->ancestors.
    5095                 :  *
    5096                 :  * Caller must provide a local deparse_namespace variable to save the
    5097                 :  * previous state for pop_ancestor_plan.
    5098                 :  */
    5099                 : static void
    5100 GIC        1396 : push_ancestor_plan(deparse_namespace *dpns, ListCell *ancestor_cell,
    5101 ECB             :                    deparse_namespace *save_dpns)
    5102                 : {
    5103 GIC        1396 :     Plan       *plan = (Plan *) lfirst(ancestor_cell);
    5104                 : 
    5105                 :     /* Save state for restoration later */
    5106            1396 :     *save_dpns = *dpns;
    5107                 : 
    5108                 :     /* Build a new ancestor list with just this node's ancestors */
    5109            1396 :     dpns->ancestors =
    5110            1396 :         list_copy_tail(dpns->ancestors,
    5111 CBC        1396 :                        list_cell_number(dpns->ancestors, ancestor_cell) + 1);
    5112                 : 
    5113                 :     /* Set attention on selected ancestor */
    5114 GIC        1396 :     set_deparse_plan(dpns, plan);
    5115            1396 : }
    5116                 : 
    5117                 : /*
    5118                 :  * pop_ancestor_plan: undo the effects of push_ancestor_plan
    5119                 :  */
    5120                 : static void
    5121            1396 : pop_ancestor_plan(deparse_namespace *dpns, deparse_namespace *save_dpns)
    5122 ECB             : {
    5123                 :     /* Free the ancestor list made in push_ancestor_plan */
    5124 GIC        1396 :     list_free(dpns->ancestors);
    5125                 : 
    5126                 :     /* Restore fields changed by push_ancestor_plan */
    5127            1396 :     *dpns = *save_dpns;
    5128            1396 : }
    5129                 : 
    5130 ECB             : 
    5131                 : /* ----------
    5132                 :  * make_ruledef         - reconstruct the CREATE RULE command
    5133                 :  *                for a given pg_rewrite tuple
    5134                 :  * ----------
    5135                 :  */
    5136                 : static void
    5137 CBC         264 : make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
    5138 ECB             :              int prettyFlags)
    5139                 : {
    5140                 :     char       *rulename;
    5141                 :     char        ev_type;
    5142                 :     Oid         ev_class;
    5143                 :     bool        is_instead;
    5144                 :     char       *ev_qual;
    5145                 :     char       *ev_action;
    5146                 :     List       *actions;
    5147                 :     Relation    ev_relation;
    5148 CBC         264 :     TupleDesc   viewResultDesc = NULL;
    5149                 :     int         fno;
    5150 ECB             :     Datum       dat;
    5151                 :     bool        isnull;
    5152                 : 
    5153                 :     /*
    5154                 :      * Get the attribute values from the rules tuple
    5155                 :      */
    5156 CBC         264 :     fno = SPI_fnumber(rulettc, "rulename");
    5157             264 :     dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
    5158             264 :     Assert(!isnull);
    5159 GBC         264 :     rulename = NameStr(*(DatumGetName(dat)));
    5160                 : 
    5161 CBC         264 :     fno = SPI_fnumber(rulettc, "ev_type");
    5162 GIC         264 :     dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
    5163             264 :     Assert(!isnull);
    5164             264 :     ev_type = DatumGetChar(dat);
    5165                 : 
    5166 CBC         264 :     fno = SPI_fnumber(rulettc, "ev_class");
    5167 GIC         264 :     dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
    5168             264 :     Assert(!isnull);
    5169 CBC         264 :     ev_class = DatumGetObjectId(dat);
    5170 ECB             : 
    5171 GIC         264 :     fno = SPI_fnumber(rulettc, "is_instead");
    5172 GBC         264 :     dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
    5173 GIC         264 :     Assert(!isnull);
    5174             264 :     is_instead = DatumGetBool(dat);
    5175 ECB             : 
    5176 GIC         264 :     fno = SPI_fnumber(rulettc, "ev_qual");
    5177 CBC         264 :     ev_qual = SPI_getvalue(ruletup, rulettc, fno);
    5178             264 :     Assert(ev_qual != NULL);
    5179 ECB             : 
    5180 CBC         264 :     fno = SPI_fnumber(rulettc, "ev_action");
    5181 GIC         264 :     ev_action = SPI_getvalue(ruletup, rulettc, fno);
    5182 CBC         264 :     Assert(ev_action != NULL);
    5183             264 :     actions = (List *) stringToNode(ev_action);
    5184             264 :     if (actions == NIL)
    5185 UIC           0 :         elog(ERROR, "invalid empty ev_action list");
    5186 ECB             : 
    5187 CBC         264 :     ev_relation = table_open(ev_class, AccessShareLock);
    5188 ECB             : 
    5189                 :     /*
    5190                 :      * Build the rules definition text
    5191                 :      */
    5192 CBC         264 :     appendStringInfo(buf, "CREATE RULE %s AS",
    5193                 :                      quote_identifier(rulename));
    5194 EUB             : 
    5195 GBC         264 :     if (prettyFlags & PRETTYFLAG_INDENT)
    5196 GIC         264 :         appendStringInfoString(buf, "\n    ON ");
    5197                 :     else
    5198 UIC           0 :         appendStringInfoString(buf, " ON ");
    5199                 : 
    5200                 :     /* The event the rule is fired for */
    5201 GIC         264 :     switch (ev_type)
    5202                 :     {
    5203 CBC           3 :         case '1':
    5204               3 :             appendStringInfoString(buf, "SELECT");
    5205               3 :             viewResultDesc = RelationGetDescr(ev_relation);
    5206               3 :             break;
    5207                 : 
    5208 GIC          71 :         case '2':
    5209 CBC          71 :             appendStringInfoString(buf, "UPDATE");
    5210 GIC          71 :             break;
    5211                 : 
    5212             138 :         case '3':
    5213             138 :             appendStringInfoString(buf, "INSERT");
    5214             138 :             break;
    5215                 : 
    5216 CBC          52 :         case '4':
    5217              52 :             appendStringInfoString(buf, "DELETE");
    5218              52 :             break;
    5219                 : 
    5220 LBC           0 :         default:
    5221 UIC           0 :             ereport(ERROR,
    5222                 :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    5223                 :                      errmsg("rule \"%s\" has unsupported event type %d",
    5224                 :                             rulename, ev_type)));
    5225                 :             break;
    5226                 :     }
    5227 ECB             : 
    5228                 :     /* The relation the rule is fired on */
    5229 GIC         264 :     appendStringInfo(buf, " TO %s",
    5230             264 :                      (prettyFlags & PRETTYFLAG_SCHEMA) ?
    5231              48 :                      generate_relation_name(ev_class, NIL) :
    5232             216 :                      generate_qualified_relation_name(ev_class));
    5233                 : 
    5234 ECB             :     /* If the rule has an event qualification, add it */
    5235 GIC         264 :     if (strcmp(ev_qual, "<>") != 0)
    5236                 :     {
    5237 ECB             :         Node       *qual;
    5238                 :         Query      *query;
    5239                 :         deparse_context context;
    5240                 :         deparse_namespace dpns;
    5241                 : 
    5242 CBC          58 :         if (prettyFlags & PRETTYFLAG_INDENT)
    5243              58 :             appendStringInfoString(buf, "\n  ");
    5244              58 :         appendStringInfoString(buf, " WHERE ");
    5245 ECB             : 
    5246 CBC          58 :         qual = stringToNode(ev_qual);
    5247 ECB             : 
    5248                 :         /*
    5249                 :          * We need to make a context for recognizing any Vars in the qual
    5250                 :          * (which can only be references to OLD and NEW).  Use the rtable of
    5251                 :          * the first query in the action list for this purpose.
    5252                 :          */
    5253 GIC          58 :         query = (Query *) linitial(actions);
    5254                 : 
    5255 ECB             :         /*
    5256                 :          * If the action is INSERT...SELECT, OLD/NEW have been pushed down
    5257                 :          * into the SELECT, and that's what we need to look at. (Ugly kluge
    5258                 :          * ... try to fix this when we redesign querytrees.)
    5259                 :          */
    5260 GIC          58 :         query = getInsertSelectQuery(query, NULL);
    5261                 : 
    5262 ECB             :         /* Must acquire locks right away; see notes in get_query_def() */
    5263 GIC          58 :         AcquireRewriteLocks(query, false, false);
    5264                 : 
    5265              58 :         context.buf = buf;
    5266              58 :         context.namespaces = list_make1(&dpns);
    5267 CBC          58 :         context.windowClause = NIL;
    5268              58 :         context.windowTList = NIL;
    5269 GIC          58 :         context.varprefix = (list_length(query->rtable) != 1);
    5270 CBC          58 :         context.prettyFlags = prettyFlags;
    5271              58 :         context.wrapColumn = WRAP_COLUMN_DEFAULT;
    5272 GIC          58 :         context.indentLevel = PRETTYINDENT_STD;
    5273 CBC          58 :         context.special_exprkind = EXPR_KIND_NONE;
    5274              58 :         context.appendparents = NULL;
    5275                 : 
    5276 GBC          58 :         set_deparse_for_query(&dpns, query, NIL);
    5277                 : 
    5278 CBC          58 :         get_rule_expr(qual, &context, false);
    5279                 :     }
    5280                 : 
    5281 GIC         264 :     appendStringInfoString(buf, " DO ");
    5282                 : 
    5283                 :     /* The INSTEAD keyword (if so) */
    5284 CBC         264 :     if (is_instead)
    5285             162 :         appendStringInfoString(buf, "INSTEAD ");
    5286                 : 
    5287 ECB             :     /* Finally the rules actions */
    5288 GIC         264 :     if (list_length(actions) > 1)
    5289                 :     {
    5290 ECB             :         ListCell   *action;
    5291                 :         Query      *query;
    5292                 : 
    5293 GIC          10 :         appendStringInfoChar(buf, '(');
    5294              30 :         foreach(action, actions)
    5295                 :         {
    5296              20 :             query = (Query *) lfirst(action);
    5297              20 :             get_query_def(query, buf, NIL, viewResultDesc, true,
    5298                 :                           prettyFlags, WRAP_COLUMN_DEFAULT, 0);
    5299              20 :             if (prettyFlags)
    5300 CBC          20 :                 appendStringInfoString(buf, ";\n");
    5301                 :             else
    5302 UIC           0 :                 appendStringInfoString(buf, "; ");
    5303                 :         }
    5304 GIC          10 :         appendStringInfoString(buf, ");");
    5305                 :     }
    5306                 :     else
    5307                 :     {
    5308                 :         Query      *query;
    5309                 : 
    5310             254 :         query = (Query *) linitial(actions);
    5311             254 :         get_query_def(query, buf, NIL, viewResultDesc, true,
    5312                 :                       prettyFlags, WRAP_COLUMN_DEFAULT, 0);
    5313             254 :         appendStringInfoChar(buf, ';');
    5314                 :     }
    5315                 : 
    5316             264 :     table_close(ev_relation, AccessShareLock);
    5317             264 : }
    5318 ECB             : 
    5319                 : 
    5320                 : /* ----------
    5321                 :  * make_viewdef         - reconstruct the SELECT part of a
    5322                 :  *                view rewrite rule
    5323                 :  * ----------
    5324                 :  */
    5325                 : static void
    5326 CBC        1408 : make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
    5327                 :              int prettyFlags, int wrapColumn)
    5328 ECB             : {
    5329                 :     Query      *query;
    5330                 :     char        ev_type;
    5331                 :     Oid         ev_class;
    5332                 :     bool        is_instead;
    5333                 :     char       *ev_qual;
    5334                 :     char       *ev_action;
    5335                 :     List       *actions;
    5336                 :     Relation    ev_relation;
    5337                 :     int         fno;
    5338                 :     Datum       dat;
    5339                 :     bool        isnull;
    5340                 : 
    5341                 :     /*
    5342                 :      * Get the attribute values from the rules tuple
    5343                 :      */
    5344 GIC        1408 :     fno = SPI_fnumber(rulettc, "ev_type");
    5345 GBC        1408 :     dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
    5346 GIC        1408 :     Assert(!isnull);
    5347            1408 :     ev_type = DatumGetChar(dat);
    5348 ECB             : 
    5349 GIC        1408 :     fno = SPI_fnumber(rulettc, "ev_class");
    5350 CBC        1408 :     dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
    5351            1408 :     Assert(!isnull);
    5352 GIC        1408 :     ev_class = DatumGetObjectId(dat);
    5353                 : 
    5354 GBC        1408 :     fno = SPI_fnumber(rulettc, "is_instead");
    5355 GIC        1408 :     dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
    5356            1408 :     Assert(!isnull);
    5357 CBC        1408 :     is_instead = DatumGetBool(dat);
    5358                 : 
    5359            1408 :     fno = SPI_fnumber(rulettc, "ev_qual");
    5360 GIC        1408 :     ev_qual = SPI_getvalue(ruletup, rulettc, fno);
    5361 CBC        1408 :     Assert(ev_qual != NULL);
    5362                 : 
    5363            1408 :     fno = SPI_fnumber(rulettc, "ev_action");
    5364 GIC        1408 :     ev_action = SPI_getvalue(ruletup, rulettc, fno);
    5365            1408 :     Assert(ev_action != NULL);
    5366            1408 :     actions = (List *) stringToNode(ev_action);
    5367                 : 
    5368            1408 :     if (list_length(actions) != 1)
    5369                 :     {
    5370                 :         /* keep output buffer empty and leave */
    5371 UIC           0 :         return;
    5372                 :     }
    5373                 : 
    5374 GIC        1408 :     query = (Query *) linitial(actions);
    5375                 : 
    5376            1408 :     if (ev_type != '1' || !is_instead ||
    5377            1408 :         strcmp(ev_qual, "<>") != 0 || query->commandType != CMD_SELECT)
    5378                 :     {
    5379                 :         /* keep output buffer empty and leave */
    5380 UIC           0 :         return;
    5381                 :     }
    5382                 : 
    5383 GIC        1408 :     ev_relation = table_open(ev_class, AccessShareLock);
    5384                 : 
    5385 CBC        1408 :     get_query_def(query, buf, NIL, RelationGetDescr(ev_relation), true,
    5386                 :                   prettyFlags, wrapColumn, 0);
    5387 GIC        1408 :     appendStringInfoChar(buf, ';');
    5388                 : 
    5389            1408 :     table_close(ev_relation, AccessShareLock);
    5390                 : }
    5391                 : 
    5392                 : 
    5393 ECB             : /* ----------
    5394                 :  * get_query_def            - Parse back one query parsetree
    5395                 :  *
    5396                 :  * query: parsetree to be displayed
    5397                 :  * buf: output text is appended to buf
    5398                 :  * parentnamespace: list (initially empty) of outer-level deparse_namespace's
    5399                 :  * resultDesc: if not NULL, the output tuple descriptor for the view
    5400                 :  *      represented by a SELECT query.  We use the column names from it
    5401                 :  *      to label SELECT output columns, in preference to names in the query
    5402                 :  * colNamesVisible: true if the surrounding context cares about the output
    5403                 :  *      column names at all (as, for example, an EXISTS() context does not);
    5404                 :  *      when false, we can suppress dummy column labels such as "?column?"
    5405                 :  * prettyFlags: bitmask of PRETTYFLAG_XXX options
    5406                 :  * wrapColumn: maximum line length, or -1 to disable wrapping
    5407                 :  * startIndent: initial indentation amount
    5408                 :  * ----------
    5409                 :  */
    5410                 : static void
    5411 CBC        2294 : get_query_def(Query *query, StringInfo buf, List *parentnamespace,
    5412 ECB             :               TupleDesc resultDesc, bool colNamesVisible,
    5413                 :               int prettyFlags, int wrapColumn, int startIndent)
    5414                 : {
    5415                 :     deparse_context context;
    5416                 :     deparse_namespace dpns;
    5417                 : 
    5418                 :     /* Guard against excessively long or deeply-nested queries */
    5419 CBC        2294 :     CHECK_FOR_INTERRUPTS();
    5420 GIC        2294 :     check_stack_depth();
    5421 ECB             : 
    5422                 :     /*
    5423                 :      * Before we begin to examine the query, acquire locks on referenced
    5424                 :      * relations, and fix up deleted columns in JOIN RTEs.  This ensures
    5425                 :      * consistent results.  Note we assume it's OK to scribble on the passed
    5426                 :      * querytree!
    5427                 :      *
    5428                 :      * We are only deparsing the query (we are not about to execute it), so we
    5429                 :      * only need AccessShareLock on the relations it mentions.
    5430                 :      */
    5431 CBC        2294 :     AcquireRewriteLocks(query, false, false);
    5432 ECB             : 
    5433 CBC        2294 :     context.buf = buf;
    5434 GIC        2294 :     context.namespaces = lcons(&dpns, list_copy(parentnamespace));
    5435 CBC        2294 :     context.windowClause = NIL;
    5436            2294 :     context.windowTList = NIL;
    5437            3976 :     context.varprefix = (parentnamespace != NIL ||
    5438 GIC        1682 :                          list_length(query->rtable) != 1);
    5439 CBC        2294 :     context.prettyFlags = prettyFlags;
    5440            2294 :     context.wrapColumn = wrapColumn;
    5441            2294 :     context.indentLevel = startIndent;
    5442 GIC        2294 :     context.special_exprkind = EXPR_KIND_NONE;
    5443 CBC        2294 :     context.appendparents = NULL;
    5444 ECB             : 
    5445 CBC        2294 :     set_deparse_for_query(&dpns, query, parentnamespace);
    5446                 : 
    5447 GBC        2294 :     switch (query->commandType)
    5448 EUB             :     {
    5449 GIC        2004 :         case CMD_SELECT:
    5450            2004 :             get_select_query_def(query, &context, resultDesc, colNamesVisible);
    5451            2004 :             break;
    5452 ECB             : 
    5453 GIC          65 :         case CMD_UPDATE:
    5454              65 :             get_update_query_def(query, &context, colNamesVisible);
    5455              65 :             break;
    5456                 : 
    5457             161 :         case CMD_INSERT:
    5458             161 :             get_insert_query_def(query, &context, colNamesVisible);
    5459 CBC         161 :             break;
    5460                 : 
    5461              38 :         case CMD_DELETE:
    5462              38 :             get_delete_query_def(query, &context, colNamesVisible);
    5463 GIC          38 :             break;
    5464                 : 
    5465 CBC          18 :         case CMD_NOTHING:
    5466 GIC          18 :             appendStringInfoString(buf, "NOTHING");
    5467 CBC          18 :             break;
    5468                 : 
    5469               8 :         case CMD_UTILITY:
    5470               8 :             get_utility_query_def(query, &context);
    5471 GIC           8 :             break;
    5472                 : 
    5473 LBC           0 :         default:
    5474               0 :             elog(ERROR, "unrecognized query command type: %d",
    5475                 :                  query->commandType);
    5476 ECB             :             break;
    5477                 :     }
    5478 CBC        2294 : }
    5479 ECB             : 
    5480                 : /* ----------
    5481                 :  * get_values_def           - Parse back a VALUES list
    5482                 :  * ----------
    5483                 :  */
    5484                 : static void
    5485 GIC         130 : get_values_def(List *values_lists, deparse_context *context)
    5486 ECB             : {
    5487 GIC         130 :     StringInfo  buf = context->buf;
    5488             130 :     bool        first_list = true;
    5489                 :     ListCell   *vtl;
    5490                 : 
    5491 CBC         130 :     appendStringInfoString(buf, "VALUES ");
    5492                 : 
    5493             374 :     foreach(vtl, values_lists)
    5494                 :     {
    5495             244 :         List       *sublist = (List *) lfirst(vtl);
    5496 GIC         244 :         bool        first_col = true;
    5497                 :         ListCell   *lc;
    5498                 : 
    5499             244 :         if (first_list)
    5500             130 :             first_list = false;
    5501                 :         else
    5502 CBC         114 :             appendStringInfoString(buf, ", ");
    5503                 : 
    5504             244 :         appendStringInfoChar(buf, '(');
    5505 GIC         955 :         foreach(lc, sublist)
    5506                 :         {
    5507             711 :             Node       *col = (Node *) lfirst(lc);
    5508 ECB             : 
    5509 CBC         711 :             if (first_col)
    5510 GIC         244 :                 first_col = false;
    5511 ECB             :             else
    5512 GIC         467 :                 appendStringInfoChar(buf, ',');
    5513 ECB             : 
    5514                 :             /*
    5515                 :              * Print the value.  Whole-row Vars need special treatment.
    5516                 :              */
    5517 CBC         711 :             get_rule_expr_toplevel(col, context, false);
    5518 ECB             :         }
    5519 GIC         244 :         appendStringInfoChar(buf, ')');
    5520 ECB             :     }
    5521 CBC         130 : }
    5522                 : 
    5523 ECB             : /* ----------
    5524                 :  * get_with_clause          - Parse back a WITH clause
    5525                 :  * ----------
    5526                 :  */
    5527                 : static void
    5528 GIC        2268 : get_with_clause(Query *query, deparse_context *context)
    5529 ECB             : {
    5530 GIC        2268 :     StringInfo  buf = context->buf;
    5531                 :     const char *sep;
    5532 ECB             :     ListCell   *l;
    5533                 : 
    5534 GIC        2268 :     if (query->cteList == NIL)
    5535 CBC        2226 :         return;
    5536 ECB             : 
    5537 GIC          42 :     if (PRETTY_INDENT(context))
    5538 ECB             :     {
    5539 CBC          42 :         context->indentLevel += PRETTYINDENT_STD;
    5540              42 :         appendStringInfoChar(buf, ' ');
    5541                 :     }
    5542 ECB             : 
    5543 GIC          42 :     if (query->hasRecursive)
    5544 CBC          28 :         sep = "WITH RECURSIVE ";
    5545 ECB             :     else
    5546 GIC          14 :         sep = "WITH ";
    5547 CBC         100 :     foreach(l, query->cteList)
    5548 ECB             :     {
    5549 CBC          58 :         CommonTableExpr *cte = (CommonTableExpr *) lfirst(l);
    5550 ECB             : 
    5551 CBC          58 :         appendStringInfoString(buf, sep);
    5552 GBC          58 :         appendStringInfoString(buf, quote_identifier(cte->ctename));
    5553              58 :         if (cte->aliascolnames)
    5554 EUB             :         {
    5555 GIC          22 :             bool        first = true;
    5556 ECB             :             ListCell   *col;
    5557                 : 
    5558 CBC          22 :             appendStringInfoChar(buf, '(');
    5559              62 :             foreach(col, cte->aliascolnames)
    5560                 :             {
    5561 GIC          40 :                 if (first)
    5562              22 :                     first = false;
    5563 ECB             :                 else
    5564 CBC          18 :                     appendStringInfoString(buf, ", ");
    5565              40 :                 appendStringInfoString(buf,
    5566 GIC          40 :                                        quote_identifier(strVal(lfirst(col))));
    5567 ECB             :             }
    5568 GIC          22 :             appendStringInfoChar(buf, ')');
    5569 ECB             :         }
    5570 GIC          58 :         appendStringInfoString(buf, " AS ");
    5571              58 :         switch (cte->ctematerialized)
    5572 ECB             :         {
    5573 CBC          52 :             case CTEMaterializeDefault:
    5574 GIC          52 :                 break;
    5575 CBC           6 :             case CTEMaterializeAlways:
    5576 GIC           6 :                 appendStringInfoString(buf, "MATERIALIZED ");
    5577 CBC           6 :                 break;
    5578 LBC           0 :             case CTEMaterializeNever:
    5579 UIC           0 :                 appendStringInfoString(buf, "NOT MATERIALIZED ");
    5580 LBC           0 :                 break;
    5581 ECB             :         }
    5582 CBC          58 :         appendStringInfoChar(buf, '(');
    5583 GIC          58 :         if (PRETTY_INDENT(context))
    5584              58 :             appendContextKeyword(context, "", 0, 0, 0);
    5585 CBC          58 :         get_query_def((Query *) cte->ctequery, buf, context->namespaces, NULL,
    5586                 :                       true,
    5587                 :                       context->prettyFlags, context->wrapColumn,
    5588 ECB             :                       context->indentLevel);
    5589 GIC          58 :         if (PRETTY_INDENT(context))
    5590 CBC          58 :             appendContextKeyword(context, "", 0, 0, 0);
    5591 GIC          58 :         appendStringInfoChar(buf, ')');
    5592                 : 
    5593 CBC          58 :         if (cte->search_clause)
    5594                 :         {
    5595               3 :             bool        first = true;
    5596                 :             ListCell   *lc;
    5597 ECB             : 
    5598 CBC           3 :             appendStringInfo(buf, " SEARCH %s FIRST BY ",
    5599 GIC           3 :                              cte->search_clause->search_breadth_first ? "BREADTH" : "DEPTH");
    5600 ECB             : 
    5601 CBC           9 :             foreach(lc, cte->search_clause->search_col_list)
    5602 ECB             :             {
    5603 GIC           6 :                 if (first)
    5604               3 :                     first = false;
    5605 ECB             :                 else
    5606 GIC           3 :                     appendStringInfoString(buf, ", ");
    5607               6 :                 appendStringInfoString(buf,
    5608 CBC           6 :                                        quote_identifier(strVal(lfirst(lc))));
    5609 ECB             :             }
    5610                 : 
    5611 CBC           3 :             appendStringInfo(buf, " SET %s", quote_identifier(cte->search_clause->search_seq_column));
    5612 ECB             :         }
    5613                 : 
    5614 CBC          58 :         if (cte->cycle_clause)
    5615 ECB             :         {
    5616 CBC           6 :             bool        first = true;
    5617 ECB             :             ListCell   *lc;
    5618                 : 
    5619 GIC           6 :             appendStringInfoString(buf, " CYCLE ");
    5620                 : 
    5621 CBC          18 :             foreach(lc, cte->cycle_clause->cycle_col_list)
    5622                 :             {
    5623 GIC          12 :                 if (first)
    5624 CBC           6 :                     first = false;
    5625                 :                 else
    5626 GIC           6 :                     appendStringInfoString(buf, ", ");
    5627 CBC          12 :                 appendStringInfoString(buf,
    5628 GIC          12 :                                        quote_identifier(strVal(lfirst(lc))));
    5629 ECB             :             }
    5630                 : 
    5631 GIC           6 :             appendStringInfo(buf, " SET %s", quote_identifier(cte->cycle_clause->cycle_mark_column));
    5632                 : 
    5633 EUB             :             {
    5634 GIC           6 :                 Const      *cmv = castNode(Const, cte->cycle_clause->cycle_mark_value);
    5635               6 :                 Const      *cmd = castNode(Const, cte->cycle_clause->cycle_mark_default);
    5636                 : 
    5637               9 :                 if (!(cmv->consttype == BOOLOID && !cmv->constisnull && DatumGetBool(cmv->constvalue) == true &&
    5638               3 :                       cmd->consttype == BOOLOID && !cmd->constisnull && DatumGetBool(cmd->constvalue) == false))
    5639                 :                 {
    5640               3 :                     appendStringInfoString(buf, " TO ");
    5641 CBC           3 :                     get_rule_expr(cte->cycle_clause->cycle_mark_value, context, false);
    5642 GIC           3 :                     appendStringInfoString(buf, " DEFAULT ");
    5643               3 :                     get_rule_expr(cte->cycle_clause->cycle_mark_default, context, false);
    5644 ECB             :                 }
    5645                 :             }
    5646                 : 
    5647 GIC           6 :             appendStringInfo(buf, " USING %s", quote_identifier(cte->cycle_clause->cycle_path_column));
    5648                 :         }
    5649                 : 
    5650              58 :         sep = ", ";
    5651 ECB             :     }
    5652                 : 
    5653 GIC          42 :     if (PRETTY_INDENT(context))
    5654 ECB             :     {
    5655 CBC          42 :         context->indentLevel -= PRETTYINDENT_STD;
    5656              42 :         appendContextKeyword(context, "", 0, 0, 0);
    5657 ECB             :     }
    5658                 :     else
    5659 UIC           0 :         appendStringInfoChar(buf, ' ');
    5660                 : }
    5661                 : 
    5662                 : /* ----------
    5663                 :  * get_select_query_def         - Parse back a SELECT parsetree
    5664 ECB             :  * ----------
    5665                 :  */
    5666                 : static void
    5667 GIC        2004 : get_select_query_def(Query *query, deparse_context *context,
    5668                 :                      TupleDesc resultDesc, bool colNamesVisible)
    5669 ECB             : {
    5670 GIC        2004 :     StringInfo  buf = context->buf;
    5671                 :     List       *save_windowclause;
    5672                 :     List       *save_windowtlist;
    5673 ECB             :     bool        force_colno;
    5674                 :     ListCell   *l;
    5675                 : 
    5676                 :     /* Insert the WITH clause if given */
    5677 GIC        2004 :     get_with_clause(query, context);
    5678 ECB             : 
    5679                 :     /* Set up context for possible window functions */
    5680 CBC        2004 :     save_windowclause = context->windowClause;
    5681 GIC        2004 :     context->windowClause = query->windowClause;
    5682 CBC        2004 :     save_windowtlist = context->windowTList;
    5683 GIC        2004 :     context->windowTList = query->targetList;
    5684                 : 
    5685                 :     /*
    5686                 :      * If the Query node has a setOperations tree, then it's the top level of
    5687                 :      * a UNION/INTERSECT/EXCEPT query; only the WITH, ORDER BY and LIMIT
    5688                 :      * fields are interesting in the top query itself.
    5689                 :      */
    5690 CBC        2004 :     if (query->setOperations)
    5691                 :     {
    5692              70 :         get_setop_query(query->setOperations, query, context, resultDesc,
    5693                 :                         colNamesVisible);
    5694 ECB             :         /* ORDER BY clauses must be simple in this case */
    5695 GIC          70 :         force_colno = true;
    5696 ECB             :     }
    5697                 :     else
    5698                 :     {
    5699 GIC        1934 :         get_basic_select_query(query, context, resultDesc, colNamesVisible);
    5700 CBC        1934 :         force_colno = false;
    5701                 :     }
    5702 ECB             : 
    5703                 :     /* Add the ORDER BY clause if given */
    5704 GIC        2004 :     if (query->sortClause != NIL)
    5705                 :     {
    5706              64 :         appendContextKeyword(context, " ORDER BY ",
    5707 ECB             :                              -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
    5708 GIC          64 :         get_rule_orderby(query->sortClause, query->targetList,
    5709 ECB             :                          force_colno, context);
    5710                 :     }
    5711                 : 
    5712                 :     /*
    5713                 :      * Add the LIMIT/OFFSET clauses if given. If non-default options, use the
    5714                 :      * standard spelling of LIMIT.
    5715                 :      */
    5716 GIC        2004 :     if (query->limitOffset != NULL)
    5717                 :     {
    5718 CBC          16 :         appendContextKeyword(context, " OFFSET ",
    5719                 :                              -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
    5720              16 :         get_rule_expr(query->limitOffset, context, false);
    5721                 :     }
    5722            2004 :     if (query->limitCount != NULL)
    5723                 :     {
    5724 GIC          35 :         if (query->limitOption == LIMIT_OPTION_WITH_TIES)
    5725 ECB             :         {
    5726 GBC          16 :             appendContextKeyword(context, " FETCH FIRST ",
    5727                 :                                  -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
    5728 CBC          16 :             get_rule_expr(query->limitCount, context, false);
    5729 GIC          16 :             appendStringInfoString(buf, " ROWS WITH TIES");
    5730 EUB             :         }
    5731                 :         else
    5732                 :         {
    5733 GIC          19 :             appendContextKeyword(context, " LIMIT ",
    5734                 :                                  -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
    5735 GBC          19 :             if (IsA(query->limitCount, Const) &&
    5736               8 :                 ((Const *) query->limitCount)->constisnull)
    5737 GIC           8 :                 appendStringInfoString(buf, "ALL");
    5738 EUB             :             else
    5739 GBC          11 :                 get_rule_expr(query->limitCount, context, false);
    5740 EUB             :         }
    5741                 :     }
    5742                 : 
    5743                 :     /* Add FOR [KEY] UPDATE/SHARE clauses if present */
    5744 GBC        2004 :     if (query->hasForUpdate)
    5745                 :     {
    5746               6 :         foreach(l, query->rowMarks)
    5747 ECB             :         {
    5748 CBC           3 :             RowMarkClause *rc = (RowMarkClause *) lfirst(l);
    5749                 : 
    5750 ECB             :             /* don't print implicit clauses */
    5751 GIC           3 :             if (rc->pushedDown)
    5752 UIC           0 :                 continue;
    5753 ECB             : 
    5754 CBC           3 :             switch (rc->strength)
    5755                 :             {
    5756 LBC           0 :                 case LCS_NONE:
    5757 EUB             :                     /* we intentionally throw an error for LCS_NONE */
    5758 LBC           0 :                     elog(ERROR, "unrecognized LockClauseStrength %d",
    5759 EUB             :                          (int) rc->strength);
    5760                 :                     break;
    5761 UIC           0 :                 case LCS_FORKEYSHARE:
    5762               0 :                     appendContextKeyword(context, " FOR KEY SHARE",
    5763 ECB             :                                          -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
    5764 LBC           0 :                     break;
    5765               0 :                 case LCS_FORSHARE:
    5766 UIC           0 :                     appendContextKeyword(context, " FOR SHARE",
    5767                 :                                          -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
    5768               0 :                     break;
    5769               0 :                 case LCS_FORNOKEYUPDATE:
    5770               0 :                     appendContextKeyword(context, " FOR NO KEY UPDATE",
    5771                 :                                          -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
    5772               0 :                     break;
    5773 CBC           3 :                 case LCS_FORUPDATE:
    5774 GIC           3 :                     appendContextKeyword(context, " FOR UPDATE",
    5775 ECB             :                                          -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
    5776 GIC           3 :                     break;
    5777                 :             }
    5778                 : 
    5779               3 :             appendStringInfo(buf, " OF %s",
    5780               3 :                              quote_identifier(get_rtable_name(rc->rti,
    5781                 :                                                               context)));
    5782               3 :             if (rc->waitPolicy == LockWaitError)
    5783 LBC           0 :                 appendStringInfoString(buf, " NOWAIT");
    5784 GIC           3 :             else if (rc->waitPolicy == LockWaitSkip)
    5785 LBC           0 :                 appendStringInfoString(buf, " SKIP LOCKED");
    5786                 :         }
    5787 ECB             :     }
    5788                 : 
    5789 CBC        2004 :     context->windowClause = save_windowclause;
    5790            2004 :     context->windowTList = save_windowtlist;
    5791            2004 : }
    5792                 : 
    5793 ECB             : /*
    5794                 :  * Detect whether query looks like SELECT ... FROM VALUES(),
    5795                 :  * with no need to rename the output columns of the VALUES RTE.
    5796                 :  * If so, return the VALUES RTE.  Otherwise return NULL.
    5797                 :  */
    5798                 : static RangeTblEntry *
    5799 GIC        1934 : get_simple_values_rte(Query *query, TupleDesc resultDesc)
    5800                 : {
    5801            1934 :     RangeTblEntry *result = NULL;
    5802                 :     ListCell   *lc;
    5803                 : 
    5804                 :     /*
    5805                 :      * We want to detect a match even if the Query also contains OLD or NEW
    5806                 :      * rule RTEs.  So the idea is to scan the rtable and see if there is only
    5807                 :      * one inFromCl RTE that is a VALUES RTE.
    5808 ECB             :      */
    5809 GIC        2105 :     foreach(lc, query->rtable)
    5810                 :     {
    5811            1756 :         RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
    5812                 : 
    5813 CBC        1756 :         if (rte->rtekind == RTE_VALUES && rte->inFromCl)
    5814 EUB             :         {
    5815 CBC         111 :             if (result)
    5816            1585 :                 return NULL;    /* multiple VALUES (probably not possible) */
    5817 GIC         111 :             result = rte;
    5818 ECB             :         }
    5819 CBC        1645 :         else if (rte->rtekind == RTE_RELATION && !rte->inFromCl)
    5820 GIC          60 :             continue;           /* ignore rule entries */
    5821                 :         else
    5822 CBC        1585 :             return NULL;        /* something else -> not simple VALUES */
    5823 ECB             :     }
    5824                 : 
    5825                 :     /*
    5826                 :      * We don't need to check the targetlist in any great detail, because
    5827                 :      * parser/analyze.c will never generate a "bare" VALUES RTE --- they only
    5828                 :      * appear inside auto-generated sub-queries with very restricted
    5829                 :      * structure.  However, DefineView might have modified the tlist by
    5830                 :      * injecting new column aliases, or we might have some other column
    5831                 :      * aliases forced by a resultDesc.  We can only simplify if the RTE's
    5832                 :      * column names match the names that get_target_list() would select.
    5833                 :      */
    5834 CBC         349 :     if (result)
    5835                 :     {
    5836                 :         ListCell   *lcn;
    5837                 :         int         colno;
    5838 ECB             : 
    5839 GIC         111 :         if (list_length(query->targetList) != list_length(result->eref->colnames))
    5840 UIC           0 :             return NULL;        /* this probably cannot happen */
    5841 GIC         111 :         colno = 0;
    5842 CBC         415 :         forboth(lc, query->targetList, lcn, result->eref->colnames)
    5843                 :         {
    5844 GIC         310 :             TargetEntry *tle = (TargetEntry *) lfirst(lc);
    5845 CBC         310 :             char       *cname = strVal(lfirst(lcn));
    5846                 :             char       *colname;
    5847                 : 
    5848 GIC         310 :             if (tle->resjunk)
    5849               6 :                 return NULL;    /* this probably cannot happen */
    5850 ECB             : 
    5851                 :             /* compute name that get_target_list would use for column */
    5852 CBC         310 :             colno++;
    5853             310 :             if (resultDesc && colno <= resultDesc->natts)
    5854 GIC          15 :                 colname = NameStr(TupleDescAttr(resultDesc, colno - 1)->attname);
    5855                 :             else
    5856             295 :                 colname = tle->resname;
    5857                 : 
    5858                 :             /* does it match the VALUES RTE? */
    5859             310 :             if (colname == NULL || strcmp(colname, cname) != 0)
    5860               6 :                 return NULL;    /* column name has been changed */
    5861 ECB             :         }
    5862                 :     }
    5863                 : 
    5864 CBC         343 :     return result;
    5865 ECB             : }
    5866                 : 
    5867                 : static void
    5868 GIC        1934 : get_basic_select_query(Query *query, deparse_context *context,
    5869                 :                        TupleDesc resultDesc, bool colNamesVisible)
    5870                 : {
    5871 CBC        1934 :     StringInfo  buf = context->buf;
    5872 ECB             :     RangeTblEntry *values_rte;
    5873                 :     char       *sep;
    5874                 :     ListCell   *l;
    5875                 : 
    5876 GIC        1934 :     if (PRETTY_INDENT(context))
    5877 ECB             :     {
    5878 GIC        1912 :         context->indentLevel += PRETTYINDENT_STD;
    5879 GBC        1912 :         appendStringInfoChar(buf, ' ');
    5880                 :     }
    5881 EUB             : 
    5882                 :     /*
    5883                 :      * If the query looks like SELECT * FROM (VALUES ...), then print just the
    5884                 :      * VALUES part.  This reverses what transformValuesClause() did at parse
    5885                 :      * time.
    5886                 :      */
    5887 GBC        1934 :     values_rte = get_simple_values_rte(query, resultDesc);
    5888            1934 :     if (values_rte)
    5889                 :     {
    5890             105 :         get_values_def(values_rte->values_lists, context);
    5891 GIC         105 :         return;
    5892 EUB             :     }
    5893                 : 
    5894                 :     /*
    5895                 :      * Build up the query string - first we say SELECT
    5896                 :      */
    5897 GIC        1829 :     if (query->isReturn)
    5898              25 :         appendStringInfoString(buf, "RETURN");
    5899 ECB             :     else
    5900 GIC        1804 :         appendStringInfoString(buf, "SELECT");
    5901                 : 
    5902 ECB             :     /* Add the DISTINCT clause if given */
    5903 GIC        1829 :     if (query->distinctClause != NIL)
    5904                 :     {
    5905 LBC           0 :         if (query->hasDistinctOn)
    5906                 :         {
    5907               0 :             appendStringInfoString(buf, " DISTINCT ON (");
    5908 UIC           0 :             sep = "";
    5909 LBC           0 :             foreach(l, query->distinctClause)
    5910                 :             {
    5911 UIC           0 :                 SortGroupClause *srt = (SortGroupClause *) lfirst(l);
    5912                 : 
    5913 LBC           0 :                 appendStringInfoString(buf, sep);
    5914 UIC           0 :                 get_rule_sortgroupclause(srt->tleSortGroupRef, query->targetList,
    5915                 :                                          false, context);
    5916               0 :                 sep = ", ";
    5917 ECB             :             }
    5918 UIC           0 :             appendStringInfoChar(buf, ')');
    5919 ECB             :         }
    5920 EUB             :         else
    5921 UIC           0 :             appendStringInfoString(buf, " DISTINCT");
    5922 ECB             :     }
    5923                 : 
    5924                 :     /* Then we tell what to select (the targetlist) */
    5925 CBC        1829 :     get_target_list(query->targetList, context, resultDesc, colNamesVisible);
    5926                 : 
    5927 ECB             :     /* Add the FROM clause if needed */
    5928 CBC        1829 :     get_from_clause(query, " FROM ", context);
    5929                 : 
    5930 ECB             :     /* Add the WHERE clause if given */
    5931 GIC        1829 :     if (query->jointree->quals != NULL)
    5932 ECB             :     {
    5933 CBC         534 :         appendContextKeyword(context, " WHERE ",
    5934                 :                              -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
    5935             534 :         get_rule_expr(query->jointree->quals, context, false);
    5936                 :     }
    5937                 : 
    5938                 :     /* Add the GROUP BY clause if given */
    5939 GIC        1829 :     if (query->groupClause != NULL || query->groupingSets != NULL)
    5940 ECB             :     {
    5941                 :         ParseExprKind save_exprkind;
    5942                 : 
    5943 CBC          37 :         appendContextKeyword(context, " GROUP BY ",
    5944                 :                              -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
    5945              37 :         if (query->groupDistinct)
    5946 LBC           0 :             appendStringInfoString(buf, "DISTINCT ");
    5947 ECB             : 
    5948 GIC          37 :         save_exprkind = context->special_exprkind;
    5949              37 :         context->special_exprkind = EXPR_KIND_GROUP_BY;
    5950                 : 
    5951 CBC          37 :         if (query->groupingSets == NIL)
    5952                 :         {
    5953 GIC          34 :             sep = "";
    5954              85 :             foreach(l, query->groupClause)
    5955 ECB             :             {
    5956 GIC          51 :                 SortGroupClause *grp = (SortGroupClause *) lfirst(l);
    5957 ECB             : 
    5958 GIC          51 :                 appendStringInfoString(buf, sep);
    5959 CBC          51 :                 get_rule_sortgroupclause(grp->tleSortGroupRef, query->targetList,
    5960                 :                                          false, context);
    5961 GIC          51 :                 sep = ", ";
    5962                 :             }
    5963 ECB             :         }
    5964                 :         else
    5965                 :         {
    5966 GIC           3 :             sep = "";
    5967               6 :             foreach(l, query->groupingSets)
    5968                 :             {
    5969               3 :                 GroupingSet *grp = lfirst(l);
    5970                 : 
    5971               3 :                 appendStringInfoString(buf, sep);
    5972               3 :                 get_rule_groupingset(grp, query->targetList, true, context);
    5973               3 :                 sep = ", ";
    5974                 :             }
    5975                 :         }
    5976 ECB             : 
    5977 GIC          37 :         context->special_exprkind = save_exprkind;
    5978                 :     }
    5979 ECB             : 
    5980                 :     /* Add the HAVING clause if given */
    5981 CBC        1829 :     if (query->havingQual != NULL)
    5982                 :     {
    5983 GIC           5 :         appendContextKeyword(context, " HAVING ",
    5984                 :                              -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
    5985               5 :         get_rule_expr(query->havingQual, context, false);
    5986                 :     }
    5987 ECB             : 
    5988                 :     /* Add the WINDOW clause if needed */
    5989 CBC        1829 :     if (query->windowClause != NIL)
    5990              21 :         get_rule_windowclause(query, context);
    5991 ECB             : }
    5992                 : 
    5993                 : /* ----------
    5994                 :  * get_target_list          - Parse back a SELECT target list
    5995                 :  *
    5996                 :  * This is also used for RETURNING lists in INSERT/UPDATE/DELETE.
    5997                 :  *
    5998                 :  * resultDesc and colNamesVisible are as for get_query_def()
    5999                 :  * ----------
    6000                 :  */
    6001                 : static void
    6002 CBC        1887 : get_target_list(List *targetList, deparse_context *context,
    6003                 :                 TupleDesc resultDesc, bool colNamesVisible)
    6004                 : {
    6005 GIC        1887 :     StringInfo  buf = context->buf;
    6006                 :     StringInfoData targetbuf;
    6007            1887 :     bool        last_was_multiline = false;
    6008 ECB             :     char       *sep;
    6009                 :     int         colno;
    6010                 :     ListCell   *l;
    6011                 : 
    6012                 :     /* we use targetbuf to hold each TLE's text temporarily */
    6013 GIC        1887 :     initStringInfo(&targetbuf);
    6014                 : 
    6015            1887 :     sep = " ";
    6016            1887 :     colno = 0;
    6017            8180 :     foreach(l, targetList)
    6018                 :     {
    6019            6293 :         TargetEntry *tle = (TargetEntry *) lfirst(l);
    6020                 :         char       *colname;
    6021 ECB             :         char       *attname;
    6022                 : 
    6023 CBC        6293 :         if (tle->resjunk)
    6024 GIC          20 :             continue;           /* ignore junk entries */
    6025                 : 
    6026            6273 :         appendStringInfoString(buf, sep);
    6027 CBC        6273 :         sep = ", ";
    6028 GIC        6273 :         colno++;
    6029                 : 
    6030                 :         /*
    6031                 :          * Put the new field text into targetbuf so we can decide after we've
    6032                 :          * got it whether or not it needs to go on a new line.
    6033                 :          */
    6034 CBC        6273 :         resetStringInfo(&targetbuf);
    6035 GIC        6273 :         context->buf = &targetbuf;
    6036                 : 
    6037                 :         /*
    6038                 :          * We special-case Var nodes rather than using get_rule_expr. This is
    6039                 :          * needed because get_rule_expr will display a whole-row Var as
    6040                 :          * "foo.*", which is the preferred notation in most contexts, but at
    6041                 :          * the top level of a SELECT list it's not right (the parser will
    6042                 :          * expand that notation into multiple columns, yielding behavior
    6043 ECB             :          * different from a whole-row Var).  We need to call get_variable
    6044                 :          * directly so that we can tell it to do the right thing, and so that
    6045                 :          * we can get the attribute name which is the default AS label.
    6046                 :          */
    6047 GIC        6273 :         if (tle->expr && (IsA(tle->expr, Var)))
    6048                 :         {
    6049 CBC        4813 :             attname = get_variable((Var *) tle->expr, 0, true, context);
    6050                 :         }
    6051 ECB             :         else
    6052                 :         {
    6053 GIC        1460 :             get_rule_expr((Node *) tle->expr, context, true);
    6054                 : 
    6055                 :             /*
    6056 ECB             :              * When colNamesVisible is true, we should always show the
    6057                 :              * assigned column name explicitly.  Otherwise, show it only if
    6058                 :              * it's not FigureColname's fallback.
    6059                 :              */
    6060 GIC        1460 :             attname = colNamesVisible ? NULL : "?column?";
    6061                 :         }
    6062                 : 
    6063                 :         /*
    6064 ECB             :          * Figure out what the result column should be called.  In the context
    6065                 :          * of a view, use the view's tuple descriptor (so as to pick up the
    6066                 :          * effects of any column RENAME that's been done on the view).
    6067                 :          * Otherwise, just use what we can find in the TLE.
    6068                 :          */
    6069 GIC        6273 :         if (resultDesc && colno <= resultDesc->natts)
    6070 CBC        5681 :             colname = NameStr(TupleDescAttr(resultDesc, colno - 1)->attname);
    6071                 :         else
    6072 GIC         592 :             colname = tle->resname;
    6073 ECB             : 
    6074                 :         /* Show AS unless the column's name is correct as-is */
    6075 GIC        6273 :         if (colname)            /* resname could be NULL */
    6076                 :         {
    6077            6248 :             if (attname == NULL || strcmp(attname, colname) != 0)
    6078            1941 :                 appendStringInfo(&targetbuf, " AS %s", quote_identifier(colname));
    6079                 :         }
    6080 ECB             : 
    6081                 :         /* Restore context's output buffer */
    6082 CBC        6273 :         context->buf = buf;
    6083                 : 
    6084 ECB             :         /* Consider line-wrapping if enabled */
    6085 GIC        6273 :         if (PRETTY_INDENT(context) && context->wrapColumn >= 0)
    6086                 :         {
    6087                 :             int         leading_nl_pos;
    6088                 : 
    6089                 :             /* Does the new field start with a new line? */
    6090            6251 :             if (targetbuf.len > 0 && targetbuf.data[0] == '\n')
    6091 CBC         111 :                 leading_nl_pos = 0;
    6092 ECB             :             else
    6093 GIC        6140 :                 leading_nl_pos = -1;
    6094 ECB             : 
    6095                 :             /* If so, we shouldn't add anything */
    6096 GIC        6251 :             if (leading_nl_pos >= 0)
    6097                 :             {
    6098                 :                 /* instead, remove any trailing spaces currently in buf */
    6099 CBC         111 :                 removeStringInfoSpaces(buf);
    6100 ECB             :             }
    6101                 :             else
    6102                 :             {
    6103                 :                 char       *trailing_nl;
    6104                 : 
    6105                 :                 /* Locate the start of the current line in the output buffer */
    6106 GIC        6140 :                 trailing_nl = strrchr(buf->data, '\n');
    6107            6140 :                 if (trailing_nl == NULL)
    6108 CBC        2229 :                     trailing_nl = buf->data;
    6109 ECB             :                 else
    6110 GIC        3911 :                     trailing_nl++;
    6111                 : 
    6112 ECB             :                 /*
    6113                 :                  * Add a newline, plus some indentation, if the new field is
    6114                 :                  * not the first and either the new field would cause an
    6115                 :                  * overflow or the last field used more than one line.
    6116                 :                  */
    6117 GIC        6140 :                 if (colno > 1 &&
    6118            4283 :                     ((strlen(trailing_nl) + targetbuf.len > context->wrapColumn) ||
    6119 ECB             :                      last_was_multiline))
    6120 CBC        4283 :                     appendContextKeyword(context, "", -PRETTYINDENT_STD,
    6121                 :                                          PRETTYINDENT_STD, PRETTYINDENT_VAR);
    6122 ECB             :             }
    6123                 : 
    6124                 :             /* Remember this field's multiline status for next iteration */
    6125 CBC        6251 :             last_was_multiline =
    6126            6251 :                 (strchr(targetbuf.data + leading_nl_pos + 1, '\n') != NULL);
    6127                 :         }
    6128 ECB             : 
    6129                 :         /* Add the new field */
    6130 GIC        6273 :         appendBinaryStringInfo(buf, targetbuf.data, targetbuf.len);
    6131 ECB             :     }
    6132                 : 
    6133                 :     /* clean up */
    6134 CBC        1887 :     pfree(targetbuf.data);
    6135            1887 : }
    6136 ECB             : 
    6137 EUB             : static void
    6138 CBC         276 : get_setop_query(Node *setOp, Query *query, deparse_context *context,
    6139                 :                 TupleDesc resultDesc, bool colNamesVisible)
    6140                 : {
    6141 GIC         276 :     StringInfo  buf = context->buf;
    6142 ECB             :     bool        need_paren;
    6143 EUB             : 
    6144                 :     /* Guard against excessively long or deeply-nested queries */
    6145 CBC         276 :     CHECK_FOR_INTERRUPTS();
    6146 GIC         276 :     check_stack_depth();
    6147 ECB             : 
    6148 GIC         276 :     if (IsA(setOp, RangeTblRef))
    6149                 :     {
    6150             173 :         RangeTblRef *rtr = (RangeTblRef *) setOp;
    6151             173 :         RangeTblEntry *rte = rt_fetch(rtr->rtindex, query->rtable);
    6152             173 :         Query      *subquery = rte->subquery;
    6153                 : 
    6154             173 :         Assert(subquery != NULL);
    6155             173 :         Assert(subquery->setOperations == NULL);
    6156                 :         /* Need parens if WITH, ORDER BY, FOR UPDATE, or LIMIT; see gram.y */
    6157             519 :         need_paren = (subquery->cteList ||
    6158             173 :                       subquery->sortClause ||
    6159             173 :                       subquery->rowMarks ||
    6160             519 :                       subquery->limitOffset ||
    6161 CBC         173 :                       subquery->limitCount);
    6162 GIC         173 :         if (need_paren)
    6163 LBC           0 :             appendStringInfoChar(buf, '(');
    6164 GIC         173 :         get_query_def(subquery, buf, context->namespaces, resultDesc,
    6165 ECB             :                       colNamesVisible,
    6166                 :                       context->prettyFlags, context->wrapColumn,
    6167                 :                       context->indentLevel);
    6168 GBC         173 :         if (need_paren)
    6169 UIC           0 :             appendStringInfoChar(buf, ')');
    6170                 :     }
    6171 CBC         103 :     else if (IsA(setOp, SetOperationStmt))
    6172                 :     {
    6173             103 :         SetOperationStmt *op = (SetOperationStmt *) setOp;
    6174                 :         int         subindent;
    6175 EUB             : 
    6176                 :         /*
    6177                 :          * We force parens when nesting two SetOperationStmts, except when the
    6178                 :          * lefthand input is another setop of the same kind.  Syntactically,
    6179                 :          * we could omit parens in rather more cases, but it seems best to use
    6180 ECB             :          * parens to flag cases where the setop operator changes.  If we use
    6181                 :          * parens, we also increase the indentation level for the child query.
    6182                 :          *
    6183                 :          * There are some cases in which parens are needed around a leaf query
    6184                 :          * too, but those are more easily handled at the next level down (see
    6185 EUB             :          * code above).
    6186 ECB             :          */
    6187 CBC         103 :         if (IsA(op->larg, SetOperationStmt))
    6188                 :         {
    6189 GBC          33 :             SetOperationStmt *lop = (SetOperationStmt *) op->larg;
    6190                 : 
    6191 CBC          33 :             if (op->op == lop->op && op->all == lop->all)
    6192 GIC          33 :                 need_paren = false;
    6193 ECB             :             else
    6194 LBC           0 :                 need_paren = true;
    6195 ECB             :         }
    6196 EUB             :         else
    6197 GBC          70 :             need_paren = false;
    6198 EUB             : 
    6199 GBC         103 :         if (need_paren)
    6200 EUB             :         {
    6201 UBC           0 :             appendStringInfoChar(buf, '(');
    6202               0 :             subindent = PRETTYINDENT_STD;
    6203               0 :             appendContextKeyword(context, "", subindent, 0, 0);
    6204                 :         }
    6205                 :         else
    6206 CBC         103 :             subindent = 0;
    6207 ECB             : 
    6208 GIC         103 :         get_setop_query(op->larg, query, context, resultDesc, colNamesVisible);
    6209                 : 
    6210 CBC         103 :         if (need_paren)
    6211 UIC           0 :             appendContextKeyword(context, ") ", -subindent, 0, 0);
    6212 GIC         103 :         else if (PRETTY_INDENT(context))
    6213             103 :             appendContextKeyword(context, "", -subindent, 0, 0);
    6214                 :         else
    6215 UIC           0 :             appendStringInfoChar(buf, ' ');
    6216                 : 
    6217 CBC         103 :         switch (op->op)
    6218                 :         {
    6219 GBC         103 :             case SETOP_UNION:
    6220             103 :                 appendStringInfoString(buf, "UNION ");
    6221 GIC         103 :                 break;
    6222 UIC           0 :             case SETOP_INTERSECT:
    6223 LBC           0 :                 appendStringInfoString(buf, "INTERSECT ");
    6224               0 :                 break;
    6225 UIC           0 :             case SETOP_EXCEPT:
    6226 LBC           0 :                 appendStringInfoString(buf, "EXCEPT ");
    6227 UIC           0 :                 break;
    6228 LBC           0 :             default:
    6229               0 :                 elog(ERROR, "unrecognized set op: %d",
    6230 ECB             :                      (int) op->op);
    6231 EUB             :         }
    6232 GIC         103 :         if (op->all)
    6233              97 :             appendStringInfoString(buf, "ALL ");
    6234                 : 
    6235 EUB             :         /* Always parenthesize if RHS is another setop */
    6236 GIC         103 :         need_paren = IsA(op->rarg, SetOperationStmt);
    6237                 : 
    6238 ECB             :         /*
    6239                 :          * The indentation code here is deliberately a bit different from that
    6240                 :          * for the lefthand input, because we want the line breaks in
    6241                 :          * different places.
    6242                 :          */
    6243 GIC         103 :         if (need_paren)
    6244                 :         {
    6245 UIC           0 :             appendStringInfoChar(buf, '(');
    6246 LBC           0 :             subindent = PRETTYINDENT_STD;
    6247                 :         }
    6248                 :         else
    6249 CBC         103 :             subindent = 0;
    6250 GIC         103 :         appendContextKeyword(context, "", subindent, 0, 0);
    6251                 : 
    6252             103 :         get_setop_query(op->rarg, query, context, resultDesc, false);
    6253 ECB             : 
    6254 CBC         103 :         if (PRETTY_INDENT(context))
    6255 GIC         103 :             context->indentLevel -= subindent;
    6256             103 :         if (need_paren)
    6257 UIC           0 :             appendContextKeyword(context, ")", 0, 0, 0);
    6258                 :     }
    6259                 :     else
    6260                 :     {
    6261               0 :         elog(ERROR, "unrecognized node type: %d",
    6262                 :              (int) nodeTag(setOp));
    6263                 :     }
    6264 GIC         276 : }
    6265 ECB             : 
    6266                 : /*
    6267 EUB             :  * Display a sort/group clause.
    6268                 :  *
    6269                 :  * Also returns the expression tree, so caller need not find it again.
    6270 ECB             :  */
    6271 EUB             : static Node *
    6272 CBC         216 : get_rule_sortgroupclause(Index ref, List *tlist, bool force_colno,
    6273 ECB             :                          deparse_context *context)
    6274                 : {
    6275 GIC         216 :     StringInfo  buf = context->buf;
    6276                 :     TargetEntry *tle;
    6277                 :     Node       *expr;
    6278                 : 
    6279             216 :     tle = get_sortgroupref_tle(ref, tlist);
    6280             216 :     expr = (Node *) tle->expr;
    6281                 : 
    6282                 :     /*
    6283 ECB             :      * Use column-number form if requested by caller.  Otherwise, if
    6284                 :      * expression is a constant, force it to be dumped with an explicit cast
    6285                 :      * as decoration --- this is because a simple integer constant is
    6286                 :      * ambiguous (and will be misinterpreted by findTargetlistEntry()) if we
    6287                 :      * dump it without any decoration.  If it's anything more complex than a
    6288                 :      * simple Var, then force extra parens around it, to ensure it can't be
    6289                 :      * misinterpreted as a cube() or rollup() construct.
    6290                 :      */
    6291 CBC         216 :     if (force_colno)
    6292 ECB             :     {
    6293 LBC           0 :         Assert(!tle->resjunk);
    6294 UIC           0 :         appendStringInfo(buf, "%d", tle->resno);
    6295                 :     }
    6296 CBC         216 :     else if (expr && IsA(expr, Const))
    6297 UIC           0 :         get_const_expr((Const *) expr, context, 1);
    6298 GIC         216 :     else if (!expr || IsA(expr, Var))
    6299             199 :         get_rule_expr(expr, context, true);
    6300                 :     else
    6301                 :     {
    6302                 :         /*
    6303 ECB             :          * We must force parens for function-like expressions even if
    6304                 :          * PRETTY_PAREN is off, since those are the ones in danger of
    6305                 :          * misparsing. For other expressions we need to force them only if
    6306                 :          * PRETTY_PAREN is on, since otherwise the expression will output them
    6307                 :          * itself. (We can't skip the parens.)
    6308                 :          */
    6309 CBC          34 :         bool        need_paren = (PRETTY_PAREN(context)
    6310 GIC          17 :                                   || IsA(expr, FuncExpr)
    6311 CBC          15 :                                   || IsA(expr, Aggref)
    6312 GNC          15 :                                   || IsA(expr, WindowFunc)
    6313              34 :                                   || IsA(expr, JsonConstructorExpr));
    6314 EUB             : 
    6315 GBC          17 :         if (need_paren)
    6316               2 :             appendStringInfoChar(context->buf, '(');
    6317 GIC          17 :         get_rule_expr(expr, context, true);
    6318 CBC          17 :         if (need_paren)
    6319 GIC           2 :             appendStringInfoChar(context->buf, ')');
    6320 ECB             :     }
    6321                 : 
    6322 GIC         216 :     return expr;
    6323 ECB             : }
    6324                 : 
    6325                 : /*
    6326                 :  * Display a GroupingSet
    6327                 :  */
    6328                 : static void
    6329 GIC           9 : get_rule_groupingset(GroupingSet *gset, List *targetlist,
    6330 ECB             :                      bool omit_parens, deparse_context *context)
    6331                 : {
    6332                 :     ListCell   *l;
    6333 CBC           9 :     StringInfo  buf = context->buf;
    6334               9 :     bool        omit_child_parens = true;
    6335 GIC           9 :     char       *sep = "";
    6336 ECB             : 
    6337 GIC           9 :     switch (gset->kind)
    6338 ECB             :     {
    6339 LBC           0 :         case GROUPING_SET_EMPTY:
    6340               0 :             appendStringInfoString(buf, "()");
    6341 UBC           0 :             return;
    6342 EUB             : 
    6343 GBC           6 :         case GROUPING_SET_SIMPLE:
    6344 EUB             :             {
    6345 GBC           6 :                 if (!omit_parens || list_length(gset->content) != 1)
    6346               6 :                     appendStringInfoChar(buf, '(');
    6347 EUB             : 
    6348 GIC          21 :                 foreach(l, gset->content)
    6349                 :                 {
    6350 CBC          15 :                     Index       ref = lfirst_int(l);
    6351                 : 
    6352              15 :                     appendStringInfoString(buf, sep);
    6353              15 :                     get_rule_sortgroupclause(ref, targetlist,
    6354 ECB             :                                              false, context);
    6355 GIC          15 :                     sep = ", ";
    6356                 :                 }
    6357 ECB             : 
    6358 GIC           6 :                 if (!omit_parens || list_length(gset->content) != 1)
    6359               6 :                     appendStringInfoChar(buf, ')');
    6360                 :             }
    6361               6 :             return;
    6362                 : 
    6363               3 :         case GROUPING_SET_ROLLUP:
    6364 CBC           3 :             appendStringInfoString(buf, "ROLLUP(");
    6365 GIC           3 :             break;
    6366 UIC           0 :         case GROUPING_SET_CUBE:
    6367 LBC           0 :             appendStringInfoString(buf, "CUBE(");
    6368 UIC           0 :             break;
    6369               0 :         case GROUPING_SET_SETS:
    6370               0 :             appendStringInfoString(buf, "GROUPING SETS (");
    6371 LBC           0 :             omit_child_parens = false;
    6372               0 :             break;
    6373                 :     }
    6374 ECB             : 
    6375 GIC           9 :     foreach(l, gset->content)
    6376                 :     {
    6377               6 :         appendStringInfoString(buf, sep);
    6378               6 :         get_rule_groupingset(lfirst(l), targetlist, omit_child_parens, context);
    6379 CBC           6 :         sep = ", ";
    6380 ECB             :     }
    6381                 : 
    6382 CBC           3 :     appendStringInfoChar(buf, ')');
    6383                 : }
    6384 ECB             : 
    6385                 : /*
    6386                 :  * Display an ORDER BY list.
    6387                 :  */
    6388                 : static void
    6389 CBC         134 : get_rule_orderby(List *orderList, List *targetList,
    6390 EUB             :                  bool force_colno, deparse_context *context)
    6391                 : {
    6392 CBC         134 :     StringInfo  buf = context->buf;
    6393                 :     const char *sep;
    6394 ECB             :     ListCell   *l;
    6395                 : 
    6396 CBC         134 :     sep = "";
    6397             284 :     foreach(l, orderList)
    6398                 :     {
    6399 GIC         150 :         SortGroupClause *srt = (SortGroupClause *) lfirst(l);
    6400                 :         Node       *sortexpr;
    6401 ECB             :         Oid         sortcoltype;
    6402                 :         TypeCacheEntry *typentry;
    6403                 : 
    6404 GIC         150 :         appendStringInfoString(buf, sep);
    6405             150 :         sortexpr = get_rule_sortgroupclause(srt->tleSortGroupRef, targetList,
    6406 ECB             :                                             force_colno, context);
    6407 GBC         150 :         sortcoltype = exprType(sortexpr);
    6408                 :         /* See whether operator is default < or > for datatype */
    6409 CBC         150 :         typentry = lookup_type_cache(sortcoltype,
    6410                 :                                      TYPECACHE_LT_OPR | TYPECACHE_GT_OPR);
    6411             150 :         if (srt->sortop == typentry->lt_opr)
    6412                 :         {
    6413 ECB             :             /* ASC is default, so emit nothing for it */
    6414 GIC         136 :             if (srt->nulls_first)
    6415 UIC           0 :                 appendStringInfoString(buf, " NULLS FIRST");
    6416                 :         }
    6417 GIC          14 :         else if (srt->sortop == typentry->gt_opr)
    6418                 :         {
    6419               5 :             appendStringInfoString(buf, " DESC");
    6420                 :             /* DESC defaults to NULLS FIRST */
    6421               5 :             if (!srt->nulls_first)
    6422 CBC           1 :                 appendStringInfoString(buf, " NULLS LAST");
    6423                 :         }
    6424 ECB             :         else
    6425                 :         {
    6426 GIC           9 :             appendStringInfo(buf, " USING %s",
    6427                 :                              generate_operator_name(srt->sortop,
    6428 ECB             :                                                     sortcoltype,
    6429                 :                                                     sortcoltype));
    6430                 :             /* be specific to eliminate ambiguity */
    6431 CBC           9 :             if (srt->nulls_first)
    6432 UIC           0 :                 appendStringInfoString(buf, " NULLS FIRST");
    6433 ECB             :             else
    6434 CBC           9 :                 appendStringInfoString(buf, " NULLS LAST");
    6435                 :         }
    6436 GBC         150 :         sep = ", ";
    6437 EUB             :     }
    6438 GIC         134 : }
    6439                 : 
    6440 EUB             : /*
    6441                 :  * Display a WINDOW clause.
    6442                 :  *
    6443                 :  * Note that the windowClause list might contain only anonymous window
    6444                 :  * specifications, in which case we should print nothing here.
    6445                 :  */
    6446                 : static void
    6447 GIC          21 : get_rule_windowclause(Query *query, deparse_context *context)
    6448 ECB             : {
    6449 GIC          21 :     StringInfo  buf = context->buf;
    6450                 :     const char *sep;
    6451                 :     ListCell   *l;
    6452                 : 
    6453              21 :     sep = NULL;
    6454 CBC          42 :     foreach(l, query->windowClause)
    6455                 :     {
    6456 GIC          21 :         WindowClause *wc = (WindowClause *) lfirst(l);
    6457 ECB             : 
    6458 CBC          21 :         if (wc->name == NULL)
    6459 GIC          21 :             continue;           /* ignore anonymous windows */
    6460                 : 
    6461 UIC           0 :         if (sep == NULL)
    6462 LBC           0 :             appendContextKeyword(context, " WINDOW ",
    6463 ECB             :                                  -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
    6464                 :         else
    6465 UBC           0 :             appendStringInfoString(buf, sep);
    6466 EUB             : 
    6467 UIC           0 :         appendStringInfo(buf, "%s AS ", quote_identifier(wc->name));
    6468                 : 
    6469 LBC           0 :         get_rule_windowspec(wc, query->targetList, context);
    6470                 : 
    6471 UBC           0 :         sep = ", ";
    6472 EUB             :     }
    6473 GBC          21 : }
    6474 EUB             : 
    6475                 : /*
    6476                 :  * Display a window definition
    6477                 :  */
    6478                 : static void
    6479 GBC          21 : get_rule_windowspec(WindowClause *wc, List *targetList,
    6480 EUB             :                     deparse_context *context)
    6481                 : {
    6482 GBC          21 :     StringInfo  buf = context->buf;
    6483 GIC          21 :     bool        needspace = false;
    6484 EUB             :     const char *sep;
    6485                 :     ListCell   *l;
    6486                 : 
    6487 CBC          21 :     appendStringInfoChar(buf, '(');
    6488 GIC          21 :     if (wc->refname)
    6489 ECB             :     {
    6490 UBC           0 :         appendStringInfoString(buf, quote_identifier(wc->refname));
    6491 LBC           0 :         needspace = true;
    6492 ECB             :     }
    6493                 :     /* partition clauses are always inherited, so only print if no refname */
    6494 GIC          21 :     if (wc->partitionClause && !wc->refname)
    6495                 :     {
    6496 LBC           0 :         if (needspace)
    6497 UIC           0 :             appendStringInfoChar(buf, ' ');
    6498 LBC           0 :         appendStringInfoString(buf, "PARTITION BY ");
    6499               0 :         sep = "";
    6500               0 :         foreach(l, wc->partitionClause)
    6501 ECB             :         {
    6502 LBC           0 :             SortGroupClause *grp = (SortGroupClause *) lfirst(l);
    6503 ECB             : 
    6504 LBC           0 :             appendStringInfoString(buf, sep);
    6505               0 :             get_rule_sortgroupclause(grp->tleSortGroupRef, targetList,
    6506                 :                                      false, context);
    6507 UBC           0 :             sep = ", ";
    6508 ECB             :         }
    6509 LBC           0 :         needspace = true;
    6510 ECB             :     }
    6511 EUB             :     /* print ordering clause only if not inherited */
    6512 CBC          21 :     if (wc->orderClause && !wc->copiedOrder)
    6513 EUB             :     {
    6514 CBC          21 :         if (needspace)
    6515 UIC           0 :             appendStringInfoChar(buf, ' ');
    6516 CBC          21 :         appendStringInfoString(buf, "ORDER BY ");
    6517              21 :         get_rule_orderby(wc->orderClause, targetList, false, context);
    6518              21 :         needspace = true;
    6519 EUB             :     }
    6520                 :     /* framing clause is never inherited, so print unless it's default */
    6521 GIC          21 :     if (wc->frameOptions & FRAMEOPTION_NONDEFAULT)
    6522 EUB             :     {
    6523 GIC          21 :         if (needspace)
    6524              21 :             appendStringInfoChar(buf, ' ');
    6525 GBC          21 :         if (wc->frameOptions & FRAMEOPTION_RANGE)
    6526 CBC           3 :             appendStringInfoString(buf, "RANGE ");
    6527 GIC          18 :         else if (wc->frameOptions & FRAMEOPTION_ROWS)
    6528 CBC          15 :             appendStringInfoString(buf, "ROWS ");
    6529               3 :         else if (wc->frameOptions & FRAMEOPTION_GROUPS)
    6530 GBC           3 :             appendStringInfoString(buf, "GROUPS ");
    6531 ECB             :         else
    6532 UBC           0 :             Assert(false);
    6533 CBC          21 :         if (wc->frameOptions & FRAMEOPTION_BETWEEN)
    6534 GIC          21 :             appendStringInfoString(buf, "BETWEEN ");
    6535 CBC          21 :         if (wc->frameOptions & FRAMEOPTION_START_UNBOUNDED_PRECEDING)
    6536 LBC           0 :             appendStringInfoString(buf, "UNBOUNDED PRECEDING ");
    6537 GBC          21 :         else if (wc->frameOptions & FRAMEOPTION_START_CURRENT_ROW)
    6538 LBC           0 :             appendStringInfoString(buf, "CURRENT ROW ");
    6539 CBC          21 :         else if (wc->frameOptions & FRAMEOPTION_START_OFFSET)
    6540                 :         {
    6541 GBC          21 :             get_rule_expr(wc->startOffset, context, false);
    6542 GIC          21 :             if (wc->frameOptions & FRAMEOPTION_START_OFFSET_PRECEDING)
    6543              21 :                 appendStringInfoString(buf, " PRECEDING ");
    6544 UBC           0 :             else if (wc->frameOptions & FRAMEOPTION_START_OFFSET_FOLLOWING)
    6545 UIC           0 :                 appendStringInfoString(buf, " FOLLOWING ");
    6546 ECB             :             else
    6547 LBC           0 :                 Assert(false);
    6548 ECB             :         }
    6549                 :         else
    6550 LBC           0 :             Assert(false);
    6551 CBC          21 :         if (wc->frameOptions & FRAMEOPTION_BETWEEN)
    6552                 :         {
    6553              21 :             appendStringInfoString(buf, "AND ");
    6554 GIC          21 :             if (wc->frameOptions & FRAMEOPTION_END_UNBOUNDED_FOLLOWING)
    6555 LBC           0 :                 appendStringInfoString(buf, "UNBOUNDED FOLLOWING ");
    6556 CBC          21 :             else if (wc->frameOptions & FRAMEOPTION_END_CURRENT_ROW)
    6557 UIC           0 :                 appendStringInfoString(buf, "CURRENT ROW ");
    6558 GIC          21 :             else if (wc->frameOptions & FRAMEOPTION_END_OFFSET)
    6559                 :             {
    6560              21 :                 get_rule_expr(wc->endOffset, context, false);
    6561              21 :                 if (wc->frameOptions & FRAMEOPTION_END_OFFSET_PRECEDING)
    6562 UIC           0 :                     appendStringInfoString(buf, " PRECEDING ");
    6563 CBC          21 :                 else if (wc->frameOptions & FRAMEOPTION_END_OFFSET_FOLLOWING)
    6564 GIC          21 :                     appendStringInfoString(buf, " FOLLOWING ");
    6565                 :                 else
    6566 LBC           0 :                     Assert(false);
    6567 ECB             :             }
    6568                 :             else
    6569 UIC           0 :                 Assert(false);
    6570                 :         }
    6571 GIC          21 :         if (wc->frameOptions & FRAMEOPTION_EXCLUDE_CURRENT_ROW)
    6572               3 :             appendStringInfoString(buf, "EXCLUDE CURRENT ROW ");
    6573              18 :         else if (wc->frameOptions & FRAMEOPTION_EXCLUDE_GROUP)
    6574               3 :             appendStringInfoString(buf, "EXCLUDE GROUP ");
    6575 CBC          15 :         else if (wc->frameOptions & FRAMEOPTION_EXCLUDE_TIES)
    6576 GIC           3 :             appendStringInfoString(buf, "EXCLUDE TIES ");
    6577                 :         /* we will now have a trailing space; remove it */
    6578              21 :         buf->len--;
    6579                 :     }
    6580              21 :     appendStringInfoChar(buf, ')');
    6581 CBC          21 : }
    6582                 : 
    6583 ECB             : /* ----------
    6584                 :  * get_insert_query_def         - Parse back an INSERT parsetree
    6585                 :  * ----------
    6586                 :  */
    6587                 : static void
    6588 GBC         161 : get_insert_query_def(Query *query, deparse_context *context,
    6589 ECB             :                      bool colNamesVisible)
    6590                 : {
    6591 GIC         161 :     StringInfo  buf = context->buf;
    6592 CBC         161 :     RangeTblEntry *select_rte = NULL;
    6593 GIC         161 :     RangeTblEntry *values_rte = NULL;
    6594 ECB             :     RangeTblEntry *rte;
    6595 EUB             :     char       *sep;
    6596 ECB             :     ListCell   *l;
    6597                 :     List       *strippedexprs;
    6598                 : 
    6599                 :     /* Insert the WITH clause if given */
    6600 GBC         161 :     get_with_clause(query, context);
    6601                 : 
    6602                 :     /*
    6603                 :      * If it's an INSERT ... SELECT or multi-row VALUES, there will be a
    6604                 :      * single RTE for the SELECT or VALUES.  Plain VALUES has neither.
    6605 ECB             :      */
    6606 CBC         625 :     foreach(l, query->rtable)
    6607                 :     {
    6608             464 :         rte = (RangeTblEntry *) lfirst(l);
    6609                 : 
    6610             464 :         if (rte->rtekind == RTE_SUBQUERY)
    6611 ECB             :         {
    6612 GIC          22 :             if (select_rte)
    6613 LBC           0 :                 elog(ERROR, "too many subquery RTEs in INSERT");
    6614 GIC          22 :             select_rte = rte;
    6615                 :         }
    6616                 : 
    6617 CBC         464 :         if (rte->rtekind == RTE_VALUES)
    6618                 :         {
    6619 GIC          19 :             if (values_rte)
    6620 LBC           0 :                 elog(ERROR, "too many values RTEs in INSERT");
    6621 GIC          19 :             values_rte = rte;
    6622                 :         }
    6623                 :     }
    6624             161 :     if (select_rte && values_rte)
    6625 UIC           0 :         elog(ERROR, "both subquery and values RTEs in INSERT");
    6626 ECB             : 
    6627                 :     /*
    6628                 :      * Start the query with INSERT INTO relname
    6629                 :      */
    6630 CBC         161 :     rte = rt_fetch(query->resultRelation, query->rtable);
    6631 GIC         161 :     Assert(rte->rtekind == RTE_RELATION);
    6632 ECB             : 
    6633 GIC         161 :     if (PRETTY_INDENT(context))
    6634 ECB             :     {
    6635 GBC         161 :         context->indentLevel += PRETTYINDENT_STD;
    6636 GIC         161 :         appendStringInfoChar(buf, ' ');
    6637 ECB             :     }
    6638 CBC         161 :     appendStringInfo(buf, "INSERT INTO %s",
    6639                 :                      generate_relation_name(rte->relid, NIL));
    6640                 : 
    6641                 :     /* Print the relation alias, if needed; INSERT requires explicit AS */
    6642 GIC         161 :     get_rte_alias(rte, query->resultRelation, true, context);
    6643                 : 
    6644 ECB             :     /* always want a space here */
    6645 CBC         161 :     appendStringInfoChar(buf, ' ');
    6646 ECB             : 
    6647                 :     /*
    6648                 :      * Add the insert-column-names list.  Any indirection decoration needed on
    6649                 :      * the column names can be inferred from the top targetlist.
    6650                 :      */
    6651 GIC         161 :     strippedexprs = NIL;
    6652             161 :     sep = "";
    6653             161 :     if (query->targetList)
    6654             161 :         appendStringInfoChar(buf, '(');
    6655             594 :     foreach(l, query->targetList)
    6656                 :     {
    6657 CBC         433 :         TargetEntry *tle = (TargetEntry *) lfirst(l);
    6658 ECB             : 
    6659 GIC         433 :         if (tle->resjunk)
    6660 UIC           0 :             continue;           /* ignore junk entries */
    6661 ECB             : 
    6662 CBC         433 :         appendStringInfoString(buf, sep);
    6663 GIC         433 :         sep = ", ";
    6664 ECB             : 
    6665                 :         /*
    6666 EUB             :          * Put out name of target column; look in the catalogs, not at
    6667                 :          * tle->resname, since resname will fail to track RENAME.
    6668                 :          */
    6669 GBC         433 :         appendStringInfoString(buf,
    6670 GIC         433 :                                quote_identifier(get_attname(rte->relid,
    6671             433 :                                                             tle->resno,
    6672 ECB             :                                                             false)));
    6673                 : 
    6674                 :         /*
    6675                 :          * Print any indirection needed (subfields or subscripts), and strip
    6676                 :          * off the top-level nodes representing the indirection assignments.
    6677                 :          * Add the stripped expressions to strippedexprs.  (If it's a
    6678                 :          * single-VALUES statement, the stripped expressions are the VALUES to
    6679                 :          * print below.  Otherwise they're just Vars and not really
    6680                 :          * interesting.)
    6681                 :          */
    6682 GIC         433 :         strippedexprs = lappend(strippedexprs,
    6683 CBC         433 :                                 processIndirection((Node *) tle->expr,
    6684                 :                                                    context));
    6685 ECB             :     }
    6686 GIC         161 :     if (query->targetList)
    6687             161 :         appendStringInfoString(buf, ") ");
    6688 ECB             : 
    6689 GIC         161 :     if (query->override)
    6690 ECB             :     {
    6691 LBC           0 :         if (query->override == OVERRIDING_SYSTEM_VALUE)
    6692 UIC           0 :             appendStringInfoString(buf, "OVERRIDING SYSTEM VALUE ");
    6693               0 :         else if (query->override == OVERRIDING_USER_VALUE)
    6694               0 :             appendStringInfoString(buf, "OVERRIDING USER VALUE ");
    6695                 :     }
    6696 EUB             : 
    6697 GIC         161 :     if (select_rte)
    6698                 :     {
    6699                 :         /* Add the SELECT */
    6700 CBC          22 :         get_query_def(select_rte->subquery, buf, context->namespaces, NULL,
    6701                 :                       false,
    6702 ECB             :                       context->prettyFlags, context->wrapColumn,
    6703                 :                       context->indentLevel);
    6704                 :     }
    6705 GIC         139 :     else if (values_rte)
    6706 ECB             :     {
    6707                 :         /* Add the multi-VALUES expression lists */
    6708 GIC          19 :         get_values_def(values_rte->values_lists, context);
    6709 ECB             :     }
    6710 CBC         120 :     else if (strippedexprs)
    6711 ECB             :     {
    6712                 :         /* Add the single-VALUES expression list */
    6713 GIC         120 :         appendContextKeyword(context, "VALUES (",
    6714 ECB             :                              -PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
    6715 GIC         120 :         get_rule_list_toplevel(strippedexprs, context, false);
    6716             120 :         appendStringInfoChar(buf, ')');
    6717                 :     }
    6718                 :     else
    6719                 :     {
    6720                 :         /* No expressions, so it must be DEFAULT VALUES */
    6721 UIC           0 :         appendStringInfoString(buf, "DEFAULT VALUES");
    6722                 :     }
    6723 ECB             : 
    6724                 :     /* Add ON CONFLICT if present */
    6725 GIC         161 :     if (query->onConflict)
    6726 ECB             :     {
    6727 GIC          15 :         OnConflictExpr *confl = query->onConflict;
    6728 ECB             : 
    6729 GIC          15 :         appendStringInfoString(buf, " ON CONFLICT");
    6730 ECB             : 
    6731 GIC          15 :         if (confl->arbiterElems)
    6732                 :         {
    6733 ECB             :             /* Add the single-VALUES expression list */
    6734 GIC          12 :             appendStringInfoChar(buf, '(');
    6735 GBC          12 :             get_rule_expr((Node *) confl->arbiterElems, context, false);
    6736 GIC          12 :             appendStringInfoChar(buf, ')');
    6737 EUB             : 
    6738                 :             /* Add a WHERE clause (for partial indexes) if given */
    6739 GIC          12 :             if (confl->arbiterWhere != NULL)
    6740 EUB             :             {
    6741                 :                 bool        save_varprefix;
    6742                 : 
    6743                 :                 /*
    6744 ECB             :                  * Force non-prefixing of Vars, since parser assumes that they
    6745                 :                  * belong to target relation.  WHERE clause does not use
    6746                 :                  * InferenceElem, so this is separately required.
    6747                 :                  */
    6748 GIC           6 :                 save_varprefix = context->varprefix;
    6749               6 :                 context->varprefix = false;
    6750 ECB             : 
    6751 GIC           6 :                 appendContextKeyword(context, " WHERE ",
    6752 ECB             :                                      -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
    6753 GIC           6 :                 get_rule_expr(confl->arbiterWhere, context, false);
    6754                 : 
    6755               6 :                 context->varprefix = save_varprefix;
    6756 ECB             :             }
    6757                 :         }
    6758 CBC           3 :         else if (OidIsValid(confl->constraint))
    6759                 :         {
    6760 LBC           0 :             char       *constraint = get_constraint_name(confl->constraint);
    6761                 : 
    6762 UIC           0 :             if (!constraint)
    6763               0 :                 elog(ERROR, "cache lookup failed for constraint %u",
    6764                 :                      confl->constraint);
    6765               0 :             appendStringInfo(buf, " ON CONSTRAINT %s",
    6766 ECB             :                              quote_identifier(constraint));
    6767                 :         }
    6768                 : 
    6769 GIC          15 :         if (confl->action == ONCONFLICT_NOTHING)
    6770 ECB             :         {
    6771 GIC           9 :             appendStringInfoString(buf, " DO NOTHING");
    6772 ECB             :         }
    6773                 :         else
    6774                 :         {
    6775 GIC           6 :             appendStringInfoString(buf, " DO UPDATE SET ");
    6776                 :             /* Deparse targetlist */
    6777               6 :             get_update_query_targetlist_def(query, confl->onConflictSet,
    6778                 :                                             context, rte);
    6779                 : 
    6780 ECB             :             /* Add a WHERE clause if given */
    6781 GIC           6 :             if (confl->onConflictWhere != NULL)
    6782                 :             {
    6783 CBC           6 :                 appendContextKeyword(context, " WHERE ",
    6784                 :                                      -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
    6785 GIC           6 :                 get_rule_expr(confl->onConflictWhere, context, false);
    6786                 :             }
    6787 ECB             :         }
    6788                 :     }
    6789                 : 
    6790                 :     /* Add RETURNING if present */
    6791 GIC         161 :     if (query->returningList)
    6792 ECB             :     {
    6793 CBC          39 :         appendContextKeyword(context, " RETURNING",
    6794 ECB             :                              -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
    6795 GIC          39 :         get_target_list(query->returningList, context, NULL, colNamesVisible);
    6796 ECB             :     }
    6797 CBC         161 : }
    6798                 : 
    6799 ECB             : 
    6800                 : /* ----------
    6801                 :  * get_update_query_def         - Parse back an UPDATE parsetree
    6802                 :  * ----------
    6803                 :  */
    6804                 : static void
    6805 GIC          65 : get_update_query_def(Query *query, deparse_context *context,
    6806 ECB             :                      bool colNamesVisible)
    6807                 : {
    6808 GIC          65 :     StringInfo  buf = context->buf;
    6809 ECB             :     RangeTblEntry *rte;
    6810                 : 
    6811                 :     /* Insert the WITH clause if given */
    6812 CBC          65 :     get_with_clause(query, context);
    6813                 : 
    6814                 :     /*
    6815 ECB             :      * Start the query with UPDATE relname SET
    6816                 :      */
    6817 CBC          65 :     rte = rt_fetch(query->resultRelation, query->rtable);
    6818 GIC          65 :     Assert(rte->rtekind == RTE_RELATION);
    6819 CBC          65 :     if (PRETTY_INDENT(context))
    6820                 :     {
    6821 GIC          65 :         appendStringInfoChar(buf, ' ');
    6822              65 :         context->indentLevel += PRETTYINDENT_STD;
    6823 ECB             :     }
    6824 GIC         130 :     appendStringInfo(buf, "UPDATE %s%s",
    6825 CBC          65 :                      only_marker(rte),
    6826                 :                      generate_relation_name(rte->relid, NIL));
    6827 ECB             : 
    6828                 :     /* Print the relation alias, if needed */
    6829 CBC          65 :     get_rte_alias(rte, query->resultRelation, false, context);
    6830                 : 
    6831 GIC          65 :     appendStringInfoString(buf, " SET ");
    6832                 : 
    6833                 :     /* Deparse targetlist */
    6834              65 :     get_update_query_targetlist_def(query, query->targetList, context, rte);
    6835                 : 
    6836                 :     /* Add the FROM clause if needed */
    6837 CBC          65 :     get_from_clause(query, " FROM ", context);
    6838                 : 
    6839                 :     /* Add a WHERE clause if given */
    6840              65 :     if (query->jointree->quals != NULL)
    6841                 :     {
    6842 GIC          57 :         appendContextKeyword(context, " WHERE ",
    6843                 :                              -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
    6844              57 :         get_rule_expr(query->jointree->quals, context, false);
    6845                 :     }
    6846                 : 
    6847                 :     /* Add RETURNING if present */
    6848              65 :     if (query->returningList)
    6849                 :     {
    6850              11 :         appendContextKeyword(context, " RETURNING",
    6851                 :                              -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
    6852              11 :         get_target_list(query->returningList, context, NULL, colNamesVisible);
    6853 ECB             :     }
    6854 CBC          65 : }
    6855                 : 
    6856 ECB             : 
    6857                 : /* ----------
    6858                 :  * get_update_query_targetlist_def          - Parse back an UPDATE targetlist
    6859                 :  * ----------
    6860                 :  */
    6861                 : static void
    6862 CBC          71 : get_update_query_targetlist_def(Query *query, List *targetList,
    6863                 :                                 deparse_context *context, RangeTblEntry *rte)
    6864 ECB             : {
    6865 GIC          71 :     StringInfo  buf = context->buf;
    6866 ECB             :     ListCell   *l;
    6867                 :     ListCell   *next_ma_cell;
    6868                 :     int         remaining_ma_columns;
    6869                 :     const char *sep;
    6870                 :     SubLink    *cur_ma_sublink;
    6871                 :     List       *ma_sublinks;
    6872                 : 
    6873                 :     /*
    6874                 :      * Prepare to deal with MULTIEXPR assignments: collect the source SubLinks
    6875                 :      * into a list.  We expect them to appear, in ID order, in resjunk tlist
    6876                 :      * entries.
    6877                 :      */
    6878 CBC          71 :     ma_sublinks = NIL;
    6879 GIC          71 :     if (query->hasSubLinks)      /* else there can't be any */
    6880 ECB             :     {
    6881 GIC          15 :         foreach(l, targetList)
    6882                 :         {
    6883 CBC          12 :             TargetEntry *tle = (TargetEntry *) lfirst(l);
    6884 ECB             : 
    6885 GIC          12 :             if (tle->resjunk && IsA(tle->expr, SubLink))
    6886                 :             {
    6887 CBC           3 :                 SubLink    *sl = (SubLink *) tle->expr;
    6888 ECB             : 
    6889 GIC           3 :                 if (sl->subLinkType == MULTIEXPR_SUBLINK)
    6890                 :                 {
    6891               3 :                     ma_sublinks = lappend(ma_sublinks, sl);
    6892               3 :                     Assert(sl->subLinkId == list_length(ma_sublinks));
    6893                 :                 }
    6894 ECB             :             }
    6895                 :         }
    6896                 :     }
    6897 GIC          71 :     next_ma_cell = list_head(ma_sublinks);
    6898              71 :     cur_ma_sublink = NULL;
    6899              71 :     remaining_ma_columns = 0;
    6900                 : 
    6901                 :     /* Add the comma separated list of 'attname = value' */
    6902              71 :     sep = "";
    6903             193 :     foreach(l, targetList)
    6904                 :     {
    6905 CBC         122 :         TargetEntry *tle = (TargetEntry *) lfirst(l);
    6906 ECB             :         Node       *expr;
    6907                 : 
    6908 CBC         122 :         if (tle->resjunk)
    6909 GIC           3 :             continue;           /* ignore junk entries */
    6910 EUB             : 
    6911                 :         /* Emit separator (OK whether we're in multiassignment or not) */
    6912 GBC         119 :         appendStringInfoString(buf, sep);
    6913 GIC         119 :         sep = ", ";
    6914 ECB             : 
    6915                 :         /*
    6916                 :          * Check to see if we're starting a multiassignment group: if so,
    6917                 :          * output a left paren.
    6918                 :          */
    6919 GBC         119 :         if (next_ma_cell != NULL && cur_ma_sublink == NULL)
    6920                 :         {
    6921 ECB             :             /*
    6922                 :              * We must dig down into the expr to see if it's a PARAM_MULTIEXPR
    6923                 :              * Param.  That could be buried under FieldStores and
    6924                 :              * SubscriptingRefs and CoerceToDomains (cf processIndirection()),
    6925 EUB             :              * and underneath those there could be an implicit type coercion.
    6926                 :              * Because we would ignore implicit type coercions anyway, we
    6927                 :              * don't need to be as careful as processIndirection() is about
    6928                 :              * descending past implicit CoerceToDomains.
    6929                 :              */
    6930 GIC           3 :             expr = (Node *) tle->expr;
    6931               6 :             while (expr)
    6932 ECB             :             {
    6933 GIC           6 :                 if (IsA(expr, FieldStore))
    6934 ECB             :                 {
    6935 UIC           0 :                     FieldStore *fstore = (FieldStore *) expr;
    6936 ECB             : 
    6937 LBC           0 :                     expr = (Node *) linitial(fstore->newvals);
    6938                 :                 }
    6939 CBC           6 :                 else if (IsA(expr, SubscriptingRef))
    6940 ECB             :                 {
    6941 CBC           3 :                     SubscriptingRef *sbsref = (SubscriptingRef *) expr;
    6942 ECB             : 
    6943 GIC           3 :                     if (sbsref->refassgnexpr == NULL)
    6944 LBC           0 :                         break;
    6945                 : 
    6946 GIC           3 :                     expr = (Node *) sbsref->refassgnexpr;
    6947                 :                 }
    6948               3 :                 else if (IsA(expr, CoerceToDomain))
    6949                 :                 {
    6950 UIC           0 :                     CoerceToDomain *cdomain = (CoerceToDomain *) expr;
    6951                 : 
    6952 LBC           0 :                     if (cdomain->coercionformat != COERCE_IMPLICIT_CAST)
    6953               0 :                         break;
    6954               0 :                     expr = (Node *) cdomain->arg;
    6955                 :                 }
    6956                 :                 else
    6957 GIC           3 :                     break;
    6958                 :             }
    6959               3 :             expr = strip_implicit_coercions(expr);
    6960                 : 
    6961 CBC           3 :             if (expr && IsA(expr, Param) &&
    6962 GIC           3 :                 ((Param *) expr)->paramkind == PARAM_MULTIEXPR)
    6963                 :             {
    6964               3 :                 cur_ma_sublink = (SubLink *) lfirst(next_ma_cell);
    6965               3 :                 next_ma_cell = lnext(ma_sublinks, next_ma_cell);
    6966               3 :                 remaining_ma_columns = count_nonjunk_tlist_entries(((Query *) cur_ma_sublink->subselect)->targetList);
    6967               3 :                 Assert(((Param *) expr)->paramid ==
    6968 ECB             :                        ((cur_ma_sublink->subLinkId << 16) | 1));
    6969 GIC           3 :                 appendStringInfoChar(buf, '(');
    6970 ECB             :             }
    6971                 :         }
    6972                 : 
    6973                 :         /*
    6974                 :          * Put out name of target column; look in the catalogs, not at
    6975                 :          * tle->resname, since resname will fail to track RENAME.
    6976                 :          */
    6977 CBC         119 :         appendStringInfoString(buf,
    6978 GIC         119 :                                quote_identifier(get_attname(rte->relid,
    6979 CBC         119 :                                                             tle->resno,
    6980                 :                                                             false)));
    6981 ECB             : 
    6982                 :         /*
    6983                 :          * Print any indirection needed (subfields or subscripts), and strip
    6984                 :          * off the top-level nodes representing the indirection assignments.
    6985                 :          */
    6986 GIC         119 :         expr = processIndirection((Node *) tle->expr, context);
    6987                 : 
    6988                 :         /*
    6989 ECB             :          * If we're in a multiassignment, skip printing anything more, unless
    6990                 :          * this is the last column; in which case, what we print should be the
    6991                 :          * sublink, not the Param.
    6992                 :          */
    6993 GIC         119 :         if (cur_ma_sublink != NULL)
    6994                 :         {
    6995               9 :             if (--remaining_ma_columns > 0)
    6996 CBC           6 :                 continue;       /* not the last column of multiassignment */
    6997 GIC           3 :             appendStringInfoChar(buf, ')');
    6998               3 :             expr = (Node *) cur_ma_sublink;
    6999               3 :             cur_ma_sublink = NULL;
    7000                 :         }
    7001 ECB             : 
    7002 CBC         113 :         appendStringInfoString(buf, " = ");
    7003 ECB             : 
    7004 GIC         113 :         get_rule_expr(expr, context, false);
    7005 ECB             :     }
    7006 CBC          71 : }
    7007                 : 
    7008 ECB             : 
    7009                 : /* ----------
    7010                 :  * get_delete_query_def         - Parse back a DELETE parsetree
    7011                 :  * ----------
    7012                 :  */
    7013                 : static void
    7014 GIC          38 : get_delete_query_def(Query *query, deparse_context *context,
    7015                 :                      bool colNamesVisible)
    7016 ECB             : {
    7017 GIC          38 :     StringInfo  buf = context->buf;
    7018                 :     RangeTblEntry *rte;
    7019 ECB             : 
    7020                 :     /* Insert the WITH clause if given */
    7021 CBC          38 :     get_with_clause(query, context);
    7022                 : 
    7023 ECB             :     /*
    7024                 :      * Start the query with DELETE FROM relname
    7025                 :      */
    7026 GIC          38 :     rte = rt_fetch(query->resultRelation, query->rtable);
    7027 CBC          38 :     Assert(rte->rtekind == RTE_RELATION);
    7028 GIC          38 :     if (PRETTY_INDENT(context))
    7029 ECB             :     {
    7030 GIC          38 :         appendStringInfoChar(buf, ' ');
    7031 CBC          38 :         context->indentLevel += PRETTYINDENT_STD;
    7032                 :     }
    7033              76 :     appendStringInfo(buf, "DELETE FROM %s%s",
    7034 GIC          38 :                      only_marker(rte),
    7035                 :                      generate_relation_name(rte->relid, NIL));
    7036                 : 
    7037                 :     /* Print the relation alias, if needed */
    7038              38 :     get_rte_alias(rte, query->resultRelation, false, context);
    7039                 : 
    7040                 :     /* Add the USING clause if given */
    7041 CBC          38 :     get_from_clause(query, " USING ", context);
    7042                 : 
    7043 ECB             :     /* Add a WHERE clause if given */
    7044 GIC          38 :     if (query->jointree->quals != NULL)
    7045 ECB             :     {
    7046 CBC          38 :         appendContextKeyword(context, " WHERE ",
    7047 ECB             :                              -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
    7048 GIC          38 :         get_rule_expr(query->jointree->quals, context, false);
    7049 ECB             :     }
    7050                 : 
    7051                 :     /* Add RETURNING if present */
    7052 CBC          38 :     if (query->returningList)
    7053 ECB             :     {
    7054 GIC           8 :         appendContextKeyword(context, " RETURNING",
    7055 EUB             :                              -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
    7056 GBC           8 :         get_target_list(query->returningList, context, NULL, colNamesVisible);
    7057                 :     }
    7058 GIC          38 : }
    7059                 : 
    7060                 : 
    7061                 : /* ----------
    7062 EUB             :  * get_utility_query_def            - Parse back a UTILITY parsetree
    7063                 :  * ----------
    7064 ECB             :  */
    7065                 : static void
    7066 GIC           8 : get_utility_query_def(Query *query, deparse_context *context)
    7067                 : {
    7068               8 :     StringInfo  buf = context->buf;
    7069                 : 
    7070               8 :     if (query->utilityStmt && IsA(query->utilityStmt, NotifyStmt))
    7071               8 :     {
    7072               8 :         NotifyStmt *stmt = (NotifyStmt *) query->utilityStmt;
    7073                 : 
    7074               8 :         appendContextKeyword(context, "",
    7075                 :                              0, PRETTYINDENT_STD, 1);
    7076               8 :         appendStringInfo(buf, "NOTIFY %s",
    7077               8 :                          quote_identifier(stmt->conditionname));
    7078               8 :         if (stmt->payload)
    7079                 :         {
    7080 UIC           0 :             appendStringInfoString(buf, ", ");
    7081               0 :             simple_quote_literal(buf, stmt->payload);
    7082                 :         }
    7083                 :     }
    7084                 :     else
    7085                 :     {
    7086 ECB             :         /* Currently only NOTIFY utility commands can appear in rules */
    7087 UIC           0 :         elog(ERROR, "unexpected utility statement type");
    7088 ECB             :     }
    7089 GIC           8 : }
    7090                 : 
    7091                 : /*
    7092                 :  * Display a Var appropriately.
    7093                 :  *
    7094                 :  * In some cases (currently only when recursing into an unnamed join)
    7095                 :  * the Var's varlevelsup has to be interpreted with respect to a context
    7096                 :  * above the current one; levelsup indicates the offset.
    7097                 :  *
    7098                 :  * If istoplevel is true, the Var is at the top level of a SELECT's
    7099                 :  * targetlist, which means we need special treatment of whole-row Vars.
    7100 ECB             :  * Instead of the normal "tab.*", we'll print "tab.*::typename", which is a
    7101                 :  * dirty hack to prevent "tab.*" from being expanded into multiple columns.
    7102 EUB             :  * (The parser will strip the useless coercion, so no inefficiency is added in
    7103                 :  * dump and reload.)  We used to print just "tab" in such cases, but that is
    7104 ECB             :  * ambiguous and will yield the wrong result if "tab" is also a plain column
    7105                 :  * name in the query.
    7106                 :  *
    7107                 :  * Returns the attname of the Var, or NULL if the Var has no attname (because
    7108                 :  * it is a whole-row Var or a subplan output reference).
    7109                 :  */
    7110                 : static char *
    7111 GIC       64306 : get_variable(Var *var, int levelsup, bool istoplevel, deparse_context *context)
    7112                 : {
    7113           64306 :     StringInfo  buf = context->buf;
    7114                 :     RangeTblEntry *rte;
    7115 ECB             :     AttrNumber  attnum;
    7116                 :     int         netlevelsup;
    7117                 :     deparse_namespace *dpns;
    7118                 :     int         varno;
    7119                 :     AttrNumber  varattno;
    7120                 :     deparse_columns *colinfo;
    7121                 :     char       *refname;
    7122                 :     char       *attname;
    7123                 : 
    7124                 :     /* Find appropriate nesting depth */
    7125 GIC       64306 :     netlevelsup = var->varlevelsup + levelsup;
    7126           64306 :     if (netlevelsup >= list_length(context->namespaces))
    7127 UIC           0 :         elog(ERROR, "bogus varlevelsup: %d offset %d",
    7128                 :              var->varlevelsup, levelsup);
    7129 GIC       64306 :     dpns = (deparse_namespace *) list_nth(context->namespaces,
    7130                 :                                           netlevelsup);
    7131                 : 
    7132 ECB             :     /*
    7133                 :      * If we have a syntactic referent for the Var, and we're working from a
    7134                 :      * parse tree, prefer to use the syntactic referent.  Otherwise, fall back
    7135                 :      * on the semantic referent.  (Forcing use of the semantic referent when
    7136                 :      * printing plan trees is a design choice that's perhaps more motivated by
    7137                 :      * backwards compatibility than anything else.  But it does have the
    7138                 :      * advantage of making plans more explicit.)
    7139                 :      */
    7140 CBC       64306 :     if (var->varnosyn > 0 && dpns->plan == NULL)
    7141 ECB             :     {
    7142 CBC       12577 :         varno = var->varnosyn;
    7143 GIC       12577 :         varattno = var->varattnosyn;
    7144                 :     }
    7145 ECB             :     else
    7146                 :     {
    7147 CBC       51729 :         varno = var->varno;
    7148 GIC       51729 :         varattno = var->varattno;
    7149 ECB             :     }
    7150                 : 
    7151                 :     /*
    7152                 :      * Try to find the relevant RTE in this rtable.  In a plan tree, it's
    7153 EUB             :      * likely that varno is OUTER_VAR or INNER_VAR, in which case we must dig
    7154 ECB             :      * down into the subplans, or INDEX_VAR, which is resolved similarly. Also
    7155                 :      * find the aliases previously assigned for this RTE.
    7156 EUB             :      */
    7157 GIC       64306 :     if (varno >= 1 && varno <= list_length(dpns->rtable))
    7158                 :     {
    7159 ECB             :         /*
    7160                 :          * We might have been asked to map child Vars to some parent relation.
    7161                 :          */
    7162 GIC       48323 :         if (context->appendparents && dpns->appendrels)
    7163 ECB             :         {
    7164 CBC        1741 :             int         pvarno = varno;
    7165 GIC        1741 :             AttrNumber  pvarattno = varattno;
    7166            1741 :             AppendRelInfo *appinfo = dpns->appendrels[pvarno];
    7167            1741 :             bool        found = false;
    7168                 : 
    7169                 :             /* Only map up to inheritance parents, not UNION ALL appendrels */
    7170            3539 :             while (appinfo &&
    7171 CBC        1935 :                    rt_fetch(appinfo->parent_relid,
    7172 GIC        1935 :                             dpns->rtable)->rtekind == RTE_RELATION)
    7173 ECB             :             {
    7174 CBC        1798 :                 found = false;
    7175 GIC        1798 :                 if (pvarattno > 0)   /* system columns stay as-is */
    7176                 :                 {
    7177            1661 :                     if (pvarattno > appinfo->num_child_cols)
    7178 LBC           0 :                         break;  /* safety check */
    7179 CBC        1661 :                     pvarattno = appinfo->parent_colnos[pvarattno - 1];
    7180            1661 :                     if (pvarattno == 0)
    7181 LBC           0 :                         break;  /* Var is local to child */
    7182                 :                 }
    7183                 : 
    7184 GIC        1798 :                 pvarno = appinfo->parent_relid;
    7185 CBC        1798 :                 found = true;
    7186                 : 
    7187 ECB             :                 /* If the parent is itself a child, continue up. */
    7188 GIC        1798 :                 Assert(pvarno > 0 && pvarno <= list_length(dpns->rtable));
    7189            1798 :                 appinfo = dpns->appendrels[pvarno];
    7190                 :             }
    7191                 : 
    7192                 :             /*
    7193                 :              * If we found an ancestral rel, and that rel is included in
    7194                 :              * appendparents, print that column not the original one.
    7195                 :              */
    7196            1741 :             if (found && bms_is_member(pvarno, context->appendparents))
    7197                 :             {
    7198            1439 :                 varno = pvarno;
    7199            1439 :                 varattno = pvarattno;
    7200                 :             }
    7201 ECB             :         }
    7202                 : 
    7203 CBC       48323 :         rte = rt_fetch(varno, dpns->rtable);
    7204 GIC       48323 :         refname = (char *) list_nth(dpns->rtable_names, varno - 1);
    7205           48323 :         colinfo = deparse_columns_fetch(varno, dpns);
    7206           48323 :         attnum = varattno;
    7207                 :     }
    7208 ECB             :     else
    7209                 :     {
    7210 GBC       15983 :         resolve_special_varno((Node *) var, context,
    7211                 :                               get_special_variable, NULL);
    7212 GIC       15983 :         return NULL;
    7213 ECB             :     }
    7214                 : 
    7215                 :     /*
    7216                 :      * The planner will sometimes emit Vars referencing resjunk elements of a
    7217                 :      * subquery's target list (this is currently only possible if it chooses
    7218                 :      * to generate a "physical tlist" for a SubqueryScan or CteScan node).
    7219                 :      * Although we prefer to print subquery-referencing Vars using the
    7220                 :      * subquery's alias, that's not possible for resjunk items since they have
    7221 EUB             :      * no alias.  So in that case, drill down to the subplan and print the
    7222 ECB             :      * contents of the referenced tlist item.  This works because in a plan
    7223                 :      * tree, such Vars can only occur in a SubqueryScan or CteScan node, and
    7224 EUB             :      * we'll have set dpns->inner_plan to reference the child plan node.
    7225                 :      */
    7226 CBC       49913 :     if ((rte->rtekind == RTE_SUBQUERY || rte->rtekind == RTE_CTE) &&
    7227            1590 :         attnum > list_length(rte->eref->colnames) &&
    7228 GIC           1 :         dpns->inner_plan)
    7229                 :     {
    7230                 :         TargetEntry *tle;
    7231                 :         deparse_namespace save_dpns;
    7232                 : 
    7233               1 :         tle = get_tle_by_resno(dpns->inner_tlist, attnum);
    7234               1 :         if (!tle)
    7235 UIC           0 :             elog(ERROR, "invalid attnum %d for relation \"%s\"",
    7236                 :                  attnum, rte->eref->aliasname);
    7237                 : 
    7238 GIC           1 :         Assert(netlevelsup == 0);
    7239               1 :         push_child_plan(dpns, dpns->inner_plan, &save_dpns);
    7240                 : 
    7241                 :         /*
    7242 ECB             :          * Force parentheses because our caller probably assumed a Var is a
    7243                 :          * simple expression.
    7244                 :          */
    7245 GBC           1 :         if (!IsA(tle->expr, Var))
    7246 LBC           0 :             appendStringInfoChar(buf, '(');
    7247 GIC           1 :         get_rule_expr((Node *) tle->expr, context, true);
    7248               1 :         if (!IsA(tle->expr, Var))
    7249 UIC           0 :             appendStringInfoChar(buf, ')');
    7250 ECB             : 
    7251 GIC           1 :         pop_child_plan(dpns, &save_dpns);
    7252 CBC           1 :         return NULL;
    7253                 :     }
    7254 EUB             : 
    7255                 :     /*
    7256                 :      * If it's an unnamed join, look at the expansion of the alias variable.
    7257                 :      * If it's a simple reference to one of the input vars, then recursively
    7258                 :      * print the name of that var instead.  When it's not a simple reference,
    7259                 :      * we have to just print the unqualified join column name.  (This can only
    7260                 :      * happen with "dangerous" merged columns in a JOIN USING; we took pains
    7261                 :      * previously to make the unqualified column name unique in such cases.)
    7262                 :      *
    7263                 :      * This wouldn't work in decompiling plan trees, because we don't store
    7264 ECB             :      * joinaliasvars lists after planning; but a plan tree should never
    7265                 :      * contain a join alias variable.
    7266                 :      */
    7267 CBC       48322 :     if (rte->rtekind == RTE_JOIN && rte->alias == NULL)
    7268 ECB             :     {
    7269 CBC          48 :         if (rte->joinaliasvars == NIL)
    7270 UIC           0 :             elog(ERROR, "cannot decompile join alias var in plan tree");
    7271 GIC          48 :         if (attnum > 0)
    7272 ECB             :         {
    7273 EUB             :             Var        *aliasvar;
    7274                 : 
    7275 CBC          48 :             aliasvar = (Var *) list_nth(rte->joinaliasvars, attnum - 1);
    7276                 :             /* we intentionally don't strip implicit coercions here */
    7277 GIC          48 :             if (aliasvar && IsA(aliasvar, Var))
    7278                 :             {
    7279 UIC           0 :                 return get_variable(aliasvar, var->varlevelsup + levelsup,
    7280                 :                                     istoplevel, context);
    7281                 :             }
    7282                 :         }
    7283                 : 
    7284 ECB             :         /*
    7285                 :          * Unnamed join has no refname.  (Note: since it's unnamed, there is
    7286                 :          * no way the user could have referenced it to create a whole-row Var
    7287                 :          * for it.  So we don't have to cover that case below.)
    7288                 :          */
    7289 GIC          48 :         Assert(refname == NULL);
    7290 ECB             :     }
    7291                 : 
    7292 GIC       48322 :     if (attnum == InvalidAttrNumber)
    7293 CBC         379 :         attname = NULL;
    7294 GIC       47943 :     else if (attnum > 0)
    7295 ECB             :     {
    7296                 :         /* Get column name to use from the colinfo struct */
    7297 GIC       47342 :         if (attnum > colinfo->num_cols)
    7298 LBC           0 :             elog(ERROR, "invalid attnum %d for relation \"%s\"",
    7299 ECB             :                  attnum, rte->eref->aliasname);
    7300 GIC       47342 :         attname = colinfo->colnames[attnum - 1];
    7301                 : 
    7302 ECB             :         /*
    7303                 :          * If we find a Var referencing a dropped column, it seems better to
    7304                 :          * print something (anything) than to fail.  In general this should
    7305                 :          * not happen, but it used to be possible for some cases involving
    7306                 :          * functions returning named composite types, and perhaps there are
    7307                 :          * still bugs out there.
    7308                 :          */
    7309 CBC       47342 :         if (attname == NULL)
    7310 GIC           3 :             attname = "?dropped?column?";
    7311                 :     }
    7312                 :     else
    7313                 :     {
    7314                 :         /* System column - name is fixed, get it from the catalog */
    7315             601 :         attname = get_rte_attribute_name(rte, attnum);
    7316                 :     }
    7317                 : 
    7318           48322 :     if (refname && (context->varprefix || attname == NULL))
    7319                 :     {
    7320 CBC       22198 :         appendStringInfoString(buf, quote_identifier(refname));
    7321 GIC       22198 :         appendStringInfoChar(buf, '.');
    7322 ECB             :     }
    7323 GIC       48322 :     if (attname)
    7324           47943 :         appendStringInfoString(buf, quote_identifier(attname));
    7325                 :     else
    7326                 :     {
    7327             379 :         appendStringInfoChar(buf, '*');
    7328 CBC         379 :         if (istoplevel)
    7329              36 :             appendStringInfo(buf, "::%s",
    7330 ECB             :                              format_type_with_typemod(var->vartype,
    7331                 :                                                       var->vartypmod));
    7332                 :     }
    7333                 : 
    7334 GIC       48322 :     return attname;
    7335                 : }
    7336                 : 
    7337                 : /*
    7338                 :  * Deparse a Var which references OUTER_VAR, INNER_VAR, or INDEX_VAR.  This
    7339                 :  * routine is actually a callback for resolve_special_varno, which handles
    7340                 :  * finding the correct TargetEntry.  We get the expression contained in that
    7341 ECB             :  * TargetEntry and just need to deparse it, a job we can throw back on
    7342                 :  * get_rule_expr.
    7343                 :  */
    7344                 : static void
    7345 GIC       15983 : get_special_variable(Node *node, deparse_context *context, void *callback_arg)
    7346                 : {
    7347           15983 :     StringInfo  buf = context->buf;
    7348 ECB             : 
    7349                 :     /*
    7350                 :      * For a non-Var referent, force parentheses because our caller probably
    7351                 :      * assumed a Var is a simple expression.
    7352                 :      */
    7353 CBC       15983 :     if (!IsA(node, Var))
    7354            1506 :         appendStringInfoChar(buf, '(');
    7355 GIC       15983 :     get_rule_expr(node, context, true);
    7356           15983 :     if (!IsA(node, Var))
    7357            1506 :         appendStringInfoChar(buf, ')');
    7358 CBC       15983 : }
    7359 ECB             : 
    7360                 : /*
    7361                 :  * Chase through plan references to special varnos (OUTER_VAR, INNER_VAR,
    7362                 :  * INDEX_VAR) until we find a real Var or some kind of non-Var node; then,
    7363                 :  * invoke the callback provided.
    7364                 :  */
    7365                 : static void
    7366 CBC       44201 : resolve_special_varno(Node *node, deparse_context *context,
    7367                 :                       rsv_callback callback, void *callback_arg)
    7368                 : {
    7369                 :     Var        *var;
    7370                 :     deparse_namespace *dpns;
    7371                 : 
    7372 ECB             :     /* This function is recursive, so let's be paranoid. */
    7373 CBC       44201 :     check_stack_depth();
    7374 EUB             : 
    7375                 :     /* If it's not a Var, invoke the callback. */
    7376 GIC       44201 :     if (!IsA(node, Var))
    7377                 :     {
    7378            1636 :         (*callback) (node, context, callback_arg);
    7379            1636 :         return;
    7380                 :     }
    7381 ECB             : 
    7382                 :     /* Find appropriate nesting depth */
    7383 CBC       42565 :     var = (Var *) node;
    7384           42565 :     dpns = (deparse_namespace *) list_nth(context->namespaces,
    7385           42565 :                                           var->varlevelsup);
    7386 ECB             : 
    7387                 :     /*
    7388                 :      * If varno is special, recurse.  (Don't worry about varnosyn; if we're
    7389                 :      * here, we already decided not to use that.)
    7390                 :      */
    7391 CBC       42565 :     if (var->varno == OUTER_VAR && dpns->outer_tlist)
    7392                 :     {
    7393 ECB             :         TargetEntry *tle;
    7394                 :         deparse_namespace save_dpns;
    7395                 :         Bitmapset  *save_appendparents;
    7396                 : 
    7397 CBC       21079 :         tle = get_tle_by_resno(dpns->outer_tlist, var->varattno);
    7398 GIC       21079 :         if (!tle)
    7399 UIC           0 :             elog(ERROR, "bogus varattno for OUTER_VAR var: %d", var->varattno);
    7400                 : 
    7401                 :         /*
    7402 ECB             :          * If we're descending to the first child of an Append or MergeAppend,
    7403                 :          * update appendparents.  This will affect deparsing of all Vars
    7404 EUB             :          * appearing within the eventually-resolved subexpression.
    7405                 :          */
    7406 CBC       21079 :         save_appendparents = context->appendparents;
    7407 ECB             : 
    7408 GIC       21079 :         if (IsA(dpns->plan, Append))
    7409 CBC        1948 :             context->appendparents = bms_union(context->appendparents,
    7410            1948 :                                                ((Append *) dpns->plan)->apprelids);
    7411 GIC       19131 :         else if (IsA(dpns->plan, MergeAppend))
    7412 CBC         243 :             context->appendparents = bms_union(context->appendparents,
    7413 GIC         243 :                                                ((MergeAppend *) dpns->plan)->apprelids);
    7414                 : 
    7415           21079 :         push_child_plan(dpns, dpns->outer_plan, &save_dpns);
    7416 CBC       21079 :         resolve_special_varno((Node *) tle->expr, context,
    7417 ECB             :                               callback, callback_arg);
    7418 GBC       21079 :         pop_child_plan(dpns, &save_dpns);
    7419 GIC       21079 :         context->appendparents = save_appendparents;
    7420 CBC       21079 :         return;
    7421                 :     }
    7422           21486 :     else if (var->varno == INNER_VAR && dpns->inner_tlist)
    7423                 :     {
    7424 ECB             :         TargetEntry *tle;
    7425 EUB             :         deparse_namespace save_dpns;
    7426                 : 
    7427 GIC        5083 :         tle = get_tle_by_resno(dpns->inner_tlist, var->varattno);
    7428 CBC        5083 :         if (!tle)
    7429 UIC           0 :             elog(ERROR, "bogus varattno for INNER_VAR var: %d", var->varattno);
    7430                 : 
    7431 GIC        5083 :         push_child_plan(dpns, dpns->inner_plan, &save_dpns);
    7432            5083 :         resolve_special_varno((Node *) tle->expr, context,
    7433                 :                               callback, callback_arg);
    7434            5083 :         pop_child_plan(dpns, &save_dpns);
    7435            5083 :         return;
    7436                 :     }
    7437           16403 :     else if (var->varno == INDEX_VAR && dpns->index_tlist)
    7438                 :     {
    7439                 :         TargetEntry *tle;
    7440                 : 
    7441            1926 :         tle = get_tle_by_resno(dpns->index_tlist, var->varattno);
    7442            1926 :         if (!tle)
    7443 UIC           0 :             elog(ERROR, "bogus varattno for INDEX_VAR var: %d", var->varattno);
    7444                 : 
    7445 GIC        1926 :         resolve_special_varno((Node *) tle->expr, context,
    7446                 :                               callback, callback_arg);
    7447            1926 :         return;
    7448                 :     }
    7449 CBC       14477 :     else if (var->varno < 1 || var->varno > list_length(dpns->rtable))
    7450 UIC           0 :         elog(ERROR, "bogus varno: %d", var->varno);
    7451                 : 
    7452                 :     /* Not special.  Just invoke the callback. */
    7453 GIC       14477 :     (*callback) (node, context, callback_arg);
    7454                 : }
    7455                 : 
    7456                 : /*
    7457                 :  * Get the name of a field of an expression of composite type.  The
    7458                 :  * expression is usually a Var, but we handle other cases too.
    7459                 :  *
    7460                 :  * levelsup is an extra offset to interpret the Var's varlevelsup correctly.
    7461                 :  *
    7462                 :  * This is fairly straightforward when the expression has a named composite
    7463                 :  * type; we need only look up the type in the catalogs.  However, the type
    7464                 :  * could also be RECORD.  Since no actual table or view column is allowed to
    7465                 :  * have type RECORD, a Var of type RECORD must refer to a JOIN or FUNCTION RTE
    7466 ECB             :  * or to a subquery output.  We drill down to find the ultimate defining
    7467                 :  * expression and attempt to infer the field name from it.  We ereport if we
    7468                 :  * can't determine the name.
    7469                 :  *
    7470                 :  * Similarly, a PARAM of type RECORD has to refer to some expression of
    7471                 :  * a determinable composite type.
    7472                 :  */
    7473                 : static const char *
    7474 GIC         376 : get_name_for_var_field(Var *var, int fieldno,
    7475                 :                        int levelsup, deparse_context *context)
    7476                 : {
    7477 ECB             :     RangeTblEntry *rte;
    7478                 :     AttrNumber  attnum;
    7479                 :     int         netlevelsup;
    7480                 :     deparse_namespace *dpns;
    7481                 :     int         varno;
    7482                 :     AttrNumber  varattno;
    7483                 :     TupleDesc   tupleDesc;
    7484                 :     Node       *expr;
    7485                 : 
    7486                 :     /*
    7487                 :      * If it's a RowExpr that was expanded from a whole-row Var, use the
    7488                 :      * column names attached to it.  (We could let get_expr_result_tupdesc()
    7489                 :      * handle this, but it's much cheaper to just pull out the name we need.)
    7490                 :      */
    7491 GIC         376 :     if (IsA(var, RowExpr))
    7492 ECB             :     {
    7493 CBC          18 :         RowExpr    *r = (RowExpr *) var;
    7494                 : 
    7495 GIC          18 :         if (fieldno > 0 && fieldno <= list_length(r->colnames))
    7496              18 :             return strVal(list_nth(r->colnames, fieldno - 1));
    7497                 :     }
    7498                 : 
    7499                 :     /*
    7500                 :      * If it's a Param of type RECORD, try to find what the Param refers to.
    7501 ECB             :      */
    7502 CBC         358 :     if (IsA(var, Param))
    7503                 :     {
    7504               6 :         Param      *param = (Param *) var;
    7505                 :         ListCell   *ancestor_cell;
    7506 ECB             : 
    7507 CBC           6 :         expr = find_param_referent(param, context, &dpns, &ancestor_cell);
    7508 GIC           6 :         if (expr)
    7509                 :         {
    7510                 :             /* Found a match, so recurse to decipher the field name */
    7511 ECB             :             deparse_namespace save_dpns;
    7512                 :             const char *result;
    7513 EUB             : 
    7514 GIC           6 :             push_ancestor_plan(dpns, ancestor_cell, &save_dpns);
    7515 CBC           6 :             result = get_name_for_var_field((Var *) expr, fieldno,
    7516                 :                                             0, context);
    7517 GIC           6 :             pop_ancestor_plan(dpns, &save_dpns);
    7518               6 :             return result;
    7519                 :         }
    7520                 :     }
    7521                 : 
    7522                 :     /*
    7523 ECB             :      * If it's a Var of type RECORD, we have to find what the Var refers to;
    7524                 :      * if not, we can use get_expr_result_tupdesc().
    7525                 :      */
    7526 CBC         352 :     if (!IsA(var, Var) ||
    7527 GIC         324 :         var->vartype != RECORDOID)
    7528                 :     {
    7529             271 :         tupleDesc = get_expr_result_tupdesc((Node *) var, false);
    7530 ECB             :         /* Got the tupdesc, so we can extract the field name */
    7531 CBC         271 :         Assert(fieldno >= 1 && fieldno <= tupleDesc->natts);
    7532 GIC         271 :         return NameStr(TupleDescAttr(tupleDesc, fieldno - 1)->attname);
    7533                 :     }
    7534                 : 
    7535                 :     /* Find appropriate nesting depth */
    7536              81 :     netlevelsup = var->varlevelsup + levelsup;
    7537              81 :     if (netlevelsup >= list_length(context->namespaces))
    7538 UIC           0 :         elog(ERROR, "bogus varlevelsup: %d offset %d",
    7539                 :              var->varlevelsup, levelsup);
    7540 GIC          81 :     dpns = (deparse_namespace *) list_nth(context->namespaces,
    7541                 :                                           netlevelsup);
    7542                 : 
    7543 ECB             :     /*
    7544                 :      * If we have a syntactic referent for the Var, and we're working from a
    7545                 :      * parse tree, prefer to use the syntactic referent.  Otherwise, fall back
    7546                 :      * on the semantic referent.  (See comments in get_variable().)
    7547                 :      */
    7548 CBC          81 :     if (var->varnosyn > 0 && dpns->plan == NULL)
    7549                 :     {
    7550 GIC          27 :         varno = var->varnosyn;
    7551              27 :         varattno = var->varattnosyn;
    7552                 :     }
    7553                 :     else
    7554 ECB             :     {
    7555 CBC          54 :         varno = var->varno;
    7556 GBC          54 :         varattno = var->varattno;
    7557                 :     }
    7558 ECB             : 
    7559                 :     /*
    7560                 :      * Try to find the relevant RTE in this rtable.  In a plan tree, it's
    7561                 :      * likely that varno is OUTER_VAR or INNER_VAR, in which case we must dig
    7562                 :      * down into the subplans, or INDEX_VAR, which is resolved similarly.
    7563                 :      *
    7564                 :      * Note: unlike get_variable and resolve_special_varno, we need not worry
    7565                 :      * about inheritance mapping: a child Var should have the same datatype as
    7566                 :      * its parent, and here we're really only interested in the Var's type.
    7567                 :      */
    7568 GIC          81 :     if (varno >= 1 && varno <= list_length(dpns->rtable))
    7569                 :     {
    7570              42 :         rte = rt_fetch(varno, dpns->rtable);
    7571              42 :         attnum = varattno;
    7572                 :     }
    7573 CBC          39 :     else if (varno == OUTER_VAR && dpns->outer_tlist)
    7574 ECB             :     {
    7575 EUB             :         TargetEntry *tle;
    7576                 :         deparse_namespace save_dpns;
    7577 ECB             :         const char *result;
    7578                 : 
    7579 GIC          30 :         tle = get_tle_by_resno(dpns->outer_tlist, varattno);
    7580 CBC          30 :         if (!tle)
    7581 UIC           0 :             elog(ERROR, "bogus varattno for OUTER_VAR var: %d", varattno);
    7582                 : 
    7583 CBC          30 :         Assert(netlevelsup == 0);
    7584              30 :         push_child_plan(dpns, dpns->outer_plan, &save_dpns);
    7585                 : 
    7586 GBC          30 :         result = get_name_for_var_field((Var *) tle->expr, fieldno,
    7587                 :                                         levelsup, context);
    7588                 : 
    7589 GIC          30 :         pop_child_plan(dpns, &save_dpns);
    7590              30 :         return result;
    7591 EUB             :     }
    7592 GBC           9 :     else if (varno == INNER_VAR && dpns->inner_tlist)
    7593 EUB             :     {
    7594                 :         TargetEntry *tle;
    7595                 :         deparse_namespace save_dpns;
    7596                 :         const char *result;
    7597                 : 
    7598 GIC           9 :         tle = get_tle_by_resno(dpns->inner_tlist, varattno);
    7599               9 :         if (!tle)
    7600 UBC           0 :             elog(ERROR, "bogus varattno for INNER_VAR var: %d", varattno);
    7601                 : 
    7602 GIC           9 :         Assert(netlevelsup == 0);
    7603               9 :         push_child_plan(dpns, dpns->inner_plan, &save_dpns);
    7604 EUB             : 
    7605 GIC           9 :         result = get_name_for_var_field((Var *) tle->expr, fieldno,
    7606                 :                                         levelsup, context);
    7607                 : 
    7608 CBC           9 :         pop_child_plan(dpns, &save_dpns);
    7609 GIC           9 :         return result;
    7610                 :     }
    7611 LBC           0 :     else if (varno == INDEX_VAR && dpns->index_tlist)
    7612                 :     {
    7613                 :         TargetEntry *tle;
    7614                 :         const char *result;
    7615                 : 
    7616 UIC           0 :         tle = get_tle_by_resno(dpns->index_tlist, varattno);
    7617               0 :         if (!tle)
    7618               0 :             elog(ERROR, "bogus varattno for INDEX_VAR var: %d", varattno);
    7619                 : 
    7620               0 :         Assert(netlevelsup == 0);
    7621 ECB             : 
    7622 UIC           0 :         result = get_name_for_var_field((Var *) tle->expr, fieldno,
    7623 ECB             :                                         levelsup, context);
    7624                 : 
    7625 UBC           0 :         return result;
    7626                 :     }
    7627                 :     else
    7628                 :     {
    7629 UIC           0 :         elog(ERROR, "bogus varno: %d", varno);
    7630                 :         return NULL;            /* keep compiler quiet */
    7631                 :     }
    7632                 : 
    7633 GIC          42 :     if (attnum == InvalidAttrNumber)
    7634                 :     {
    7635 EUB             :         /* Var is whole-row reference to RTE, so select the right field */
    7636 CBC          12 :         return get_rte_attribute_name(rte, fieldno);
    7637                 :     }
    7638                 : 
    7639 ECB             :     /*
    7640                 :      * This part has essentially the same logic as the parser's
    7641                 :      * expandRecordVariable() function, but we are dealing with a different
    7642                 :      * representation of the input context, and we only need one field name
    7643                 :      * not a TupleDesc.  Also, we need special cases for finding subquery and
    7644                 :      * CTE subplans when deparsing Plan trees.
    7645 EUB             :      */
    7646 GIC          30 :     expr = (Node *) var;        /* default if we can't drill down */
    7647 ECB             : 
    7648 CBC          30 :     switch (rte->rtekind)
    7649                 :     {
    7650 UIC           0 :         case RTE_RELATION:
    7651                 :         case RTE_VALUES:
    7652                 :         case RTE_NAMEDTUPLESTORE:
    7653                 :         case RTE_RESULT:
    7654                 : 
    7655                 :             /*
    7656                 :              * This case should not occur: a column of a table, values list,
    7657                 :              * or ENR shouldn't have type RECORD.  Fall through and fail (most
    7658                 :              * likely) at the bottom.
    7659 ECB             :              */
    7660 UIC           0 :             break;
    7661 GIC           9 :         case RTE_SUBQUERY:
    7662 ECB             :             /* Subselect-in-FROM: examine sub-select's output expr */
    7663                 :             {
    7664 GIC           9 :                 if (rte->subquery)
    7665 ECB             :                 {
    7666 GIC           6 :                     TargetEntry *ste = get_tle_by_resno(rte->subquery->targetList,
    7667                 :                                                         attnum);
    7668 ECB             : 
    7669 CBC           6 :                     if (ste == NULL || ste->resjunk)
    7670 UIC           0 :                         elog(ERROR, "subquery %s does not have attribute %d",
    7671 ECB             :                              rte->eref->aliasname, attnum);
    7672 GIC           6 :                     expr = (Node *) ste->expr;
    7673               6 :                     if (IsA(expr, Var))
    7674                 :                     {
    7675                 :                         /*
    7676                 :                          * Recurse into the sub-select to see what its Var
    7677                 :                          * refers to. We have to build an additional level of
    7678                 :                          * namespace to keep in step with varlevelsup in the
    7679                 :                          * subselect.
    7680                 :                          */
    7681                 :                         deparse_namespace mydpns;
    7682                 :                         const char *result;
    7683                 : 
    7684               6 :                         set_deparse_for_query(&mydpns, rte->subquery,
    7685                 :                                               context->namespaces);
    7686                 : 
    7687               6 :                         context->namespaces = lcons(&mydpns,
    7688 ECB             :                                                     context->namespaces);
    7689 EUB             : 
    7690 GIC           6 :                         result = get_name_for_var_field((Var *) expr, fieldno,
    7691 ECB             :                                                         0, context);
    7692                 : 
    7693 GBC           6 :                         context->namespaces =
    7694 GIC           6 :                             list_delete_first(context->namespaces);
    7695 ECB             : 
    7696 CBC           6 :                         return result;
    7697                 :                     }
    7698 ECB             :                     /* else fall through to inspect the expression */
    7699                 :                 }
    7700                 :                 else
    7701                 :                 {
    7702                 :                     /*
    7703                 :                      * We're deparsing a Plan tree so we don't have complete
    7704                 :                      * RTE entries (in particular, rte->subquery is NULL). But
    7705 EUB             :                      * the only place we'd see a Var directly referencing a
    7706                 :                      * SUBQUERY RTE is in a SubqueryScan plan node, and we can
    7707                 :                      * look into the child plan's tlist instead.
    7708                 :                      */
    7709                 :                     TargetEntry *tle;
    7710                 :                     deparse_namespace save_dpns;
    7711                 :                     const char *result;
    7712                 : 
    7713 GIC           3 :                     if (!dpns->inner_plan)
    7714 UBC           0 :                         elog(ERROR, "failed to find plan for subquery %s",
    7715 EUB             :                              rte->eref->aliasname);
    7716 GBC           3 :                     tle = get_tle_by_resno(dpns->inner_tlist, attnum);
    7717 GIC           3 :                     if (!tle)
    7718 UIC           0 :                         elog(ERROR, "bogus varattno for subquery var: %d",
    7719 EUB             :                              attnum);
    7720 GBC           3 :                     Assert(netlevelsup == 0);
    7721 GIC           3 :                     push_child_plan(dpns, dpns->inner_plan, &save_dpns);
    7722                 : 
    7723               3 :                     result = get_name_for_var_field((Var *) tle->expr, fieldno,
    7724                 :                                                     levelsup, context);
    7725                 : 
    7726               3 :                     pop_child_plan(dpns, &save_dpns);
    7727 GBC           3 :                     return result;
    7728 ECB             :                 }
    7729                 :             }
    7730 UIC           0 :             break;
    7731 LBC           0 :         case RTE_JOIN:
    7732                 :             /* Join RTE --- recursively inspect the alias variable */
    7733 UIC           0 :             if (rte->joinaliasvars == NIL)
    7734               0 :                 elog(ERROR, "cannot decompile join alias var in plan tree");
    7735               0 :             Assert(attnum > 0 && attnum <= list_length(rte->joinaliasvars));
    7736               0 :             expr = (Node *) list_nth(rte->joinaliasvars, attnum - 1);
    7737               0 :             Assert(expr != NULL);
    7738 ECB             :             /* we intentionally don't strip implicit coercions here */
    7739 LBC           0 :             if (IsA(expr, Var))
    7740               0 :                 return get_name_for_var_field((Var *) expr, fieldno,
    7741 UIC           0 :                                               var->varlevelsup + levelsup,
    7742                 :                                               context);
    7743                 :             /* else fall through to inspect the expression */
    7744               0 :             break;
    7745               0 :         case RTE_FUNCTION:
    7746 ECB             :         case RTE_TABLEFUNC:
    7747                 : 
    7748                 :             /*
    7749                 :              * We couldn't get here unless a function is declared with one of
    7750                 :              * its result columns as RECORD, which is not allowed.
    7751                 :              */
    7752 UIC           0 :             break;
    7753 GIC          21 :         case RTE_CTE:
    7754 ECB             :             /* CTE reference: examine subquery's output expr */
    7755                 :             {
    7756 CBC          21 :                 CommonTableExpr *cte = NULL;
    7757 ECB             :                 Index       ctelevelsup;
    7758                 :                 ListCell   *lc;
    7759                 : 
    7760                 :                 /*
    7761 EUB             :                  * Try to find the referenced CTE using the namespace stack.
    7762                 :                  */
    7763 CBC          21 :                 ctelevelsup = rte->ctelevelsup + netlevelsup;
    7764              21 :                 if (ctelevelsup >= list_length(context->namespaces))
    7765 GIC           6 :                     lc = NULL;
    7766                 :                 else
    7767                 :                 {
    7768                 :                     deparse_namespace *ctedpns;
    7769                 : 
    7770                 :                     ctedpns = (deparse_namespace *)
    7771              15 :                         list_nth(context->namespaces, ctelevelsup);
    7772              15 :                     foreach(lc, ctedpns->ctes)
    7773 ECB             :                     {
    7774 GIC           9 :                         cte = (CommonTableExpr *) lfirst(lc);
    7775               9 :                         if (strcmp(cte->ctename, rte->ctename) == 0)
    7776               9 :                             break;
    7777                 :                     }
    7778 ECB             :                 }
    7779 GIC          21 :                 if (lc != NULL)
    7780                 :                 {
    7781 CBC           9 :                     Query      *ctequery = (Query *) cte->ctequery;
    7782 GIC           9 :                     TargetEntry *ste = get_tle_by_resno(GetCTETargetList(cte),
    7783 ECB             :                                                         attnum);
    7784                 : 
    7785 CBC           9 :                     if (ste == NULL || ste->resjunk)
    7786 UIC           0 :                         elog(ERROR, "subquery %s does not have attribute %d",
    7787                 :                              rte->eref->aliasname, attnum);
    7788 CBC           9 :                     expr = (Node *) ste->expr;
    7789 GIC           9 :                     if (IsA(expr, Var))
    7790 ECB             :                     {
    7791                 :                         /*
    7792                 :                          * Recurse into the CTE to see what its Var refers to.
    7793                 :                          * We have to build an additional level of namespace
    7794                 :                          * to keep in step with varlevelsup in the CTE.
    7795                 :                          * Furthermore it could be an outer CTE, so we may
    7796                 :                          * have to delete some levels of namespace.
    7797                 :                          */
    7798 GIC           6 :                         List       *save_nslist = context->namespaces;
    7799                 :                         List       *new_nslist;
    7800                 :                         deparse_namespace mydpns;
    7801                 :                         const char *result;
    7802                 : 
    7803               6 :                         set_deparse_for_query(&mydpns, ctequery,
    7804                 :                                               context->namespaces);
    7805                 : 
    7806               6 :                         new_nslist = list_copy_tail(context->namespaces,
    7807                 :                                                     ctelevelsup);
    7808               6 :                         context->namespaces = lcons(&mydpns, new_nslist);
    7809 ECB             : 
    7810 GBC           6 :                         result = get_name_for_var_field((Var *) expr, fieldno,
    7811                 :                                                         0, context);
    7812 ECB             : 
    7813 CBC           6 :                         context->namespaces = save_nslist;
    7814 EUB             : 
    7815 GIC           6 :                         return result;
    7816 ECB             :                     }
    7817                 :                     /* else fall through to inspect the expression */
    7818                 :                 }
    7819                 :                 else
    7820                 :                 {
    7821                 :                     /*
    7822                 :                      * We're deparsing a Plan tree so we don't have a CTE
    7823                 :                      * list.  But the only places we'd see a Var directly
    7824                 :                      * referencing a CTE RTE are in CteScan or WorkTableScan
    7825                 :                      * plan nodes.  For those cases, set_deparse_plan arranged
    7826                 :                      * for dpns->inner_plan to be the plan node that emits the
    7827                 :                      * CTE or RecursiveUnion result, and we can look at its
    7828                 :                      * tlist instead.
    7829                 :                      */
    7830                 :                     TargetEntry *tle;
    7831                 :                     deparse_namespace save_dpns;
    7832                 :                     const char *result;
    7833                 : 
    7834 GIC          12 :                     if (!dpns->inner_plan)
    7835 LBC           0 :                         elog(ERROR, "failed to find plan for CTE %s",
    7836 ECB             :                              rte->eref->aliasname);
    7837 GIC          12 :                     tle = get_tle_by_resno(dpns->inner_tlist, attnum);
    7838              12 :                     if (!tle)
    7839 UIC           0 :                         elog(ERROR, "bogus varattno for subquery var: %d",
    7840                 :                              attnum);
    7841 GIC          12 :                     Assert(netlevelsup == 0);
    7842              12 :                     push_child_plan(dpns, dpns->inner_plan, &save_dpns);
    7843                 : 
    7844              12 :                     result = get_name_for_var_field((Var *) tle->expr, fieldno,
    7845                 :                                                     levelsup, context);
    7846                 : 
    7847              12 :                     pop_child_plan(dpns, &save_dpns);
    7848 CBC          12 :                     return result;
    7849                 :                 }
    7850                 :             }
    7851 GIC           3 :             break;
    7852 ECB             :     }
    7853                 : 
    7854                 :     /*
    7855                 :      * We now have an expression we can't expand any more, so see if
    7856                 :      * get_expr_result_tupdesc() can do anything with it.
    7857                 :      */
    7858 GIC           3 :     tupleDesc = get_expr_result_tupdesc(expr, false);
    7859                 :     /* Got the tupdesc, so we can extract the field name */
    7860 CBC           3 :     Assert(fieldno >= 1 && fieldno <= tupleDesc->natts);
    7861 GIC           3 :     return NameStr(TupleDescAttr(tupleDesc, fieldno - 1)->attname);
    7862                 : }
    7863                 : 
    7864                 : /*
    7865                 :  * Try to find the referenced expression for a PARAM_EXEC Param that might
    7866 ECB             :  * reference a parameter supplied by an upper NestLoop or SubPlan plan node.
    7867                 :  *
    7868                 :  * If successful, return the expression and set *dpns_p and *ancestor_cell_p
    7869                 :  * appropriately for calling push_ancestor_plan().  If no referent can be
    7870                 :  * found, return NULL.
    7871                 :  */
    7872                 : static Node *
    7873 GIC        2425 : find_param_referent(Param *param, deparse_context *context,
    7874                 :                     deparse_namespace **dpns_p, ListCell **ancestor_cell_p)
    7875                 : {
    7876                 :     /* Initialize output parameters to prevent compiler warnings */
    7877 CBC        2425 :     *dpns_p = NULL;
    7878            2425 :     *ancestor_cell_p = NULL;
    7879                 : 
    7880 ECB             :     /*
    7881                 :      * If it's a PARAM_EXEC parameter, look for a matching NestLoopParam or
    7882                 :      * SubPlan argument.  This will necessarily be in some ancestor of the
    7883                 :      * current expression's Plan node.
    7884                 :      */
    7885 GIC        2425 :     if (param->paramkind == PARAM_EXEC)
    7886 ECB             :     {
    7887                 :         deparse_namespace *dpns;
    7888                 :         Plan       *child_plan;
    7889                 :         ListCell   *lc;
    7890                 : 
    7891 GIC        2012 :         dpns = (deparse_namespace *) linitial(context->namespaces);
    7892            2012 :         child_plan = dpns->plan;
    7893                 : 
    7894            3811 :         foreach(lc, dpns->ancestors)
    7895                 :         {
    7896            3195 :             Node       *ancestor = (Node *) lfirst(lc);
    7897 ECB             :             ListCell   *lc2;
    7898                 : 
    7899                 :             /*
    7900                 :              * NestLoops transmit params to their inner child only.
    7901                 :              */
    7902 GIC        3195 :             if (IsA(ancestor, NestLoop) &&
    7903 GNC        1287 :                 child_plan == innerPlan(ancestor))
    7904                 :             {
    7905 CBC        1248 :                 NestLoop   *nl = (NestLoop *) ancestor;
    7906                 : 
    7907 GIC        1528 :                 foreach(lc2, nl->nestParams)
    7908                 :                 {
    7909            1483 :                     NestLoopParam *nlp = (NestLoopParam *) lfirst(lc2);
    7910                 : 
    7911            1483 :                     if (nlp->paramno == param->paramid)
    7912                 :                     {
    7913                 :                         /* Found a match, so return it */
    7914            1203 :                         *dpns_p = dpns;
    7915 CBC        1203 :                         *ancestor_cell_p = lc;
    7916 GIC        1203 :                         return (Node *) nlp->paramval;
    7917                 :                     }
    7918 ECB             :                 }
    7919                 :             }
    7920                 : 
    7921                 :             /*
    7922                 :              * If ancestor is a SubPlan, check the arguments it provides.
    7923                 :              */
    7924 CBC        1992 :             if (IsA(ancestor, SubPlan))
    7925 GIC          33 :             {
    7926             226 :                 SubPlan    *subplan = (SubPlan *) ancestor;
    7927 EUB             :                 ListCell   *lc3;
    7928                 :                 ListCell   *lc4;
    7929                 : 
    7930 GIC         254 :                 forboth(lc3, subplan->parParam, lc4, subplan->args)
    7931                 :                 {
    7932 CBC         221 :                     int         paramid = lfirst_int(lc3);
    7933 GIC         221 :                     Node       *arg = (Node *) lfirst(lc4);
    7934                 : 
    7935             221 :                     if (paramid == param->paramid)
    7936                 :                     {
    7937                 :                         /*
    7938                 :                          * Found a match, so return it.  But, since Vars in
    7939                 :                          * the arg are to be evaluated in the surrounding
    7940                 :                          * context, we have to point to the next ancestor item
    7941 ECB             :                          * that is *not* a SubPlan.
    7942                 :                          */
    7943                 :                         ListCell   *rest;
    7944                 : 
    7945 GIC         193 :                         for_each_cell(rest, dpns->ancestors,
    7946 ECB             :                                       lnext(dpns->ancestors, lc))
    7947                 :                         {
    7948 GIC         193 :                             Node       *ancestor2 = (Node *) lfirst(rest);
    7949                 : 
    7950             193 :                             if (!IsA(ancestor2, SubPlan))
    7951                 :                             {
    7952             193 :                                 *dpns_p = dpns;
    7953 CBC         193 :                                 *ancestor_cell_p = rest;
    7954 GIC         193 :                                 return arg;
    7955                 :                             }
    7956                 :                         }
    7957 UIC           0 :                         elog(ERROR, "SubPlan cannot be outermost ancestor");
    7958                 :                     }
    7959                 :                 }
    7960                 : 
    7961                 :                 /* SubPlan isn't a kind of Plan, so skip the rest */
    7962 CBC          33 :                 continue;
    7963 ECB             :             }
    7964                 : 
    7965                 :             /*
    7966                 :              * We need not consider the ancestor's initPlan list, since
    7967                 :              * initplans never have any parParams.
    7968                 :              */
    7969                 : 
    7970                 :             /* No luck, crawl up to next ancestor */
    7971 GBC        1766 :             child_plan = (Plan *) ancestor;
    7972 ECB             :         }
    7973 EUB             :     }
    7974                 : 
    7975 ECB             :     /* No referent found */
    7976 GIC        1029 :     return NULL;
    7977 ECB             : }
    7978 EUB             : 
    7979                 : /*
    7980 ECB             :  * Display a Param appropriately.
    7981                 :  */
    7982                 : static void
    7983 GIC        2419 : get_parameter(Param *param, deparse_context *context)
    7984 ECB             : {
    7985                 :     Node       *expr;
    7986                 :     deparse_namespace *dpns;
    7987                 :     ListCell   *ancestor_cell;
    7988                 : 
    7989                 :     /*
    7990                 :      * If it's a PARAM_EXEC parameter, try to locate the expression from which
    7991                 :      * the parameter was computed.  Note that failing to find a referent isn't
    7992                 :      * an error, since the Param might well be a subplan output rather than an
    7993                 :      * input.
    7994                 :      */
    7995 CBC        2419 :     expr = find_param_referent(param, context, &dpns, &ancestor_cell);
    7996            2419 :     if (expr)
    7997                 :     {
    7998 ECB             :         /* Found a match, so print it */
    7999                 :         deparse_namespace save_dpns;
    8000                 :         bool        save_varprefix;
    8001                 :         bool        need_paren;
    8002                 : 
    8003                 :         /* Switch attention to the ancestor plan node */
    8004 GIC        1390 :         push_ancestor_plan(dpns, ancestor_cell, &save_dpns);
    8005                 : 
    8006                 :         /*
    8007                 :          * Force prefixing of Vars, since they won't belong to the relation
    8008                 :          * being scanned in the original plan node.
    8009                 :          */
    8010            1390 :         save_varprefix = context->varprefix;
    8011 CBC        1390 :         context->varprefix = true;
    8012                 : 
    8013 ECB             :         /*
    8014                 :          * A Param's expansion is typically a Var, Aggref, GroupingFunc, or
    8015                 :          * upper-level Param, which wouldn't need extra parentheses.
    8016                 :          * Otherwise, insert parens to ensure the expression looks atomic.
    8017                 :          */
    8018 CBC        1393 :         need_paren = !(IsA(expr, Var) ||
    8019 GIC           3 :                        IsA(expr, Aggref) ||
    8020               3 :                        IsA(expr, GroupingFunc) ||
    8021 LBC           0 :                        IsA(expr, Param));
    8022 GIC        1390 :         if (need_paren)
    8023 LBC           0 :             appendStringInfoChar(context->buf, '(');
    8024 ECB             : 
    8025 GIC        1390 :         get_rule_expr(expr, context, false);
    8026                 : 
    8027 CBC        1390 :         if (need_paren)
    8028 LBC           0 :             appendStringInfoChar(context->buf, ')');
    8029                 : 
    8030 GIC        1390 :         context->varprefix = save_varprefix;
    8031                 : 
    8032            1390 :         pop_ancestor_plan(dpns, &save_dpns);
    8033                 : 
    8034            1390 :         return;
    8035                 :     }
    8036 ECB             : 
    8037                 :     /*
    8038                 :      * If it's an external parameter, see if the outermost namespace provides
    8039                 :      * function argument names.
    8040                 :      */
    8041 GIC        1029 :     if (param->paramkind == PARAM_EXTERN && context->namespaces != NIL)
    8042                 :     {
    8043             413 :         dpns = llast(context->namespaces);
    8044             413 :         if (dpns->argnames &&
    8045              33 :             param->paramid > 0 &&
    8046 CBC          33 :             param->paramid <= dpns->numargs)
    8047                 :         {
    8048              33 :             char       *argname = dpns->argnames[param->paramid - 1];
    8049                 : 
    8050              33 :             if (argname)
    8051                 :             {
    8052 GIC          33 :                 bool        should_qualify = false;
    8053 ECB             :                 ListCell   *lc;
    8054                 : 
    8055                 :                 /*
    8056                 :                  * Qualify the parameter name if there are any other deparse
    8057                 :                  * namespaces with range tables.  This avoids qualifying in
    8058                 :                  * trivial cases like "RETURN a + b", but makes it safe in all
    8059                 :                  * other cases.
    8060                 :                  */
    8061 GBC          75 :                 foreach(lc, context->namespaces)
    8062                 :                 {
    8063 GNC          57 :                     deparse_namespace *depns = lfirst(lc);
    8064                 : 
    8065              57 :                     if (depns->rtable_names != NIL)
    8066                 :                     {
    8067 GIC          15 :                         should_qualify = true;
    8068              15 :                         break;
    8069                 :                     }
    8070                 :                 }
    8071              33 :                 if (should_qualify)
    8072 ECB             :                 {
    8073 GIC          15 :                     appendStringInfoString(context->buf, quote_identifier(dpns->funcname));
    8074 CBC          15 :                     appendStringInfoChar(context->buf, '.');
    8075 EUB             :                 }
    8076                 : 
    8077 CBC          33 :                 appendStringInfoString(context->buf, quote_identifier(argname));
    8078 GIC          33 :                 return;
    8079 ECB             :             }
    8080                 :         }
    8081                 :     }
    8082                 : 
    8083                 :     /*
    8084                 :      * Not PARAM_EXEC, or couldn't find referent: just print $N.
    8085                 :      */
    8086 CBC         996 :     appendStringInfo(context->buf, "$%d", param->paramid);
    8087                 : }
    8088 ECB             : 
    8089                 : /*
    8090                 :  * get_simple_binary_op_name
    8091                 :  *
    8092                 :  * helper function for isSimpleNode
    8093                 :  * will return single char binary operator name, or NULL if it's not
    8094                 :  */
    8095                 : static const char *
    8096 GIC          57 : get_simple_binary_op_name(OpExpr *expr)
    8097                 : {
    8098              57 :     List       *args = expr->args;
    8099                 : 
    8100              57 :     if (list_length(args) == 2)
    8101                 :     {
    8102 ECB             :         /* binary operator */
    8103 GIC          57 :         Node       *arg1 = (Node *) linitial(args);
    8104              57 :         Node       *arg2 = (Node *) lsecond(args);
    8105 EUB             :         const char *op;
    8106                 : 
    8107 GIC          57 :         op = generate_operator_name(expr->opno, exprType(arg1), exprType(arg2));
    8108 CBC          57 :         if (strlen(op) == 1)
    8109 GIC          57 :             return op;
    8110                 :     }
    8111 UIC           0 :     return NULL;
    8112                 : }
    8113                 : 
    8114 ECB             : 
    8115                 : /*
    8116 EUB             :  * isSimpleNode - check if given node is simple (doesn't need parenthesizing)
    8117                 :  *
    8118                 :  *  true   : simple in the context of parent node's type
    8119                 :  *  false  : not simple
    8120                 :  */
    8121                 : static bool
    8122 GIC        2212 : isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
    8123 EUB             : {
    8124 GIC        2212 :     if (!node)
    8125 UBC           0 :         return false;
    8126                 : 
    8127 CBC        2212 :     switch (nodeTag(node))
    8128 ECB             :     {
    8129 GIC        1852 :         case T_Var:
    8130 EUB             :         case T_Const:
    8131                 :         case T_Param:
    8132                 :         case T_CoerceToDomainValue:
    8133                 :         case T_SetToDefault:
    8134                 :         case T_CurrentOfExpr:
    8135                 :             /* single words: always simple */
    8136 GBC        1852 :             return true;
    8137 EUB             : 
    8138 GIC         186 :         case T_SubscriptingRef:
    8139                 :         case T_ArrayExpr:
    8140 ECB             :         case T_RowExpr:
    8141                 :         case T_CoalesceExpr:
    8142                 :         case T_MinMaxExpr:
    8143                 :         case T_XmlExpr:
    8144                 :         case T_NextValueExpr:
    8145                 :         case T_NullIfExpr:
    8146                 :         case T_Aggref:
    8147                 :         case T_GroupingFunc:
    8148                 :         case T_WindowFunc:
    8149                 :         case T_FuncExpr:
    8150                 :         case T_JsonConstructorExpr:
    8151                 :             /* function-like: name(..) or name[..] */
    8152 CBC         186 :             return true;
    8153 ECB             : 
    8154 EUB             :             /* CASE keywords act as parentheses */
    8155 UIC           0 :         case T_CaseExpr:
    8156               0 :             return true;
    8157 ECB             : 
    8158 CBC          24 :         case T_FieldSelect:
    8159 ECB             : 
    8160                 :             /*
    8161                 :              * appears simple since . has top precedence, unless parent is
    8162                 :              * T_FieldSelect itself!
    8163                 :              */
    8164 GBC          24 :             return !IsA(parentNode, FieldSelect);
    8165                 : 
    8166 LBC           0 :         case T_FieldStore:
    8167 ECB             : 
    8168                 :             /*
    8169 EUB             :              * treat like FieldSelect (probably doesn't matter)
    8170                 :              */
    8171 LBC           0 :             return !IsA(parentNode, FieldStore);
    8172 ECB             : 
    8173 UIC           0 :         case T_CoerceToDomain:
    8174 ECB             :             /* maybe simple, check args */
    8175 LBC           0 :             return isSimpleNode((Node *) ((CoerceToDomain *) node)->arg,
    8176                 :                                 node, prettyFlags);
    8177 GIC           3 :         case T_RelabelType:
    8178               3 :             return isSimpleNode((Node *) ((RelabelType *) node)->arg,
    8179                 :                                 node, prettyFlags);
    8180 UIC           0 :         case T_CoerceViaIO:
    8181 LBC           0 :             return isSimpleNode((Node *) ((CoerceViaIO *) node)->arg,
    8182 ECB             :                                 node, prettyFlags);
    8183 UIC           0 :         case T_ArrayCoerceExpr:
    8184 LBC           0 :             return isSimpleNode((Node *) ((ArrayCoerceExpr *) node)->arg,
    8185                 :                                 node, prettyFlags);
    8186 UIC           0 :         case T_ConvertRowtypeExpr:
    8187               0 :             return isSimpleNode((Node *) ((ConvertRowtypeExpr *) node)->arg,
    8188                 :                                 node, prettyFlags);
    8189                 : 
    8190 GIC         126 :         case T_OpExpr:
    8191                 :             {
    8192                 :                 /* depends on parent node type; needs further checking */
    8193             126 :                 if (prettyFlags & PRETTYFLAG_PAREN && IsA(parentNode, OpExpr))
    8194                 :                 {
    8195 ECB             :                     const char *op;
    8196                 :                     const char *parentOp;
    8197                 :                     bool        is_lopriop;
    8198                 :                     bool        is_hipriop;
    8199                 :                     bool        is_lopriparent;
    8200                 :                     bool        is_hipriparent;
    8201                 : 
    8202 CBC          30 :                     op = get_simple_binary_op_name((OpExpr *) node);
    8203              30 :                     if (!op)
    8204 UIC           0 :                         return false;
    8205 ECB             : 
    8206 EUB             :                     /* We know only the basic operators + - and * / % */
    8207 GIC          30 :                     is_lopriop = (strchr("+-", *op) != NULL);
    8208 CBC          30 :                     is_hipriop = (strchr("*/%", *op) != NULL);
    8209 GIC          30 :                     if (!(is_lopriop || is_hipriop))
    8210               3 :                         return false;
    8211                 : 
    8212              27 :                     parentOp = get_simple_binary_op_name((OpExpr *) parentNode);
    8213              27 :                     if (!parentOp)
    8214 UIC           0 :                         return false;
    8215                 : 
    8216 GIC          27 :                     is_lopriparent = (strchr("+-", *parentOp) != NULL);
    8217              27 :                     is_hipriparent = (strchr("*/%", *parentOp) != NULL);
    8218              27 :                     if (!(is_lopriparent || is_hipriparent))
    8219 UIC           0 :                         return false;
    8220 ECB             : 
    8221 CBC          27 :                     if (is_hipriop && is_lopriparent)
    8222               6 :                         return true;    /* op binds tighter than parent */
    8223                 : 
    8224 GIC          21 :                     if (is_lopriop && is_hipriparent)
    8225 CBC          15 :                         return false;
    8226 ECB             : 
    8227                 :                     /*
    8228                 :                      * Operators are same priority --- can skip parens only if
    8229                 :                      * we have (a - b) - c, not a - (b - c).
    8230                 :                      */
    8231 GIC           6 :                     if (node == (Node *) linitial(((OpExpr *) parentNode)->args))
    8232               3 :                         return true;
    8233                 : 
    8234 CBC           3 :                     return false;
    8235 ECB             :                 }
    8236                 :                 /* else do the same stuff as for T_SubLink et al. */
    8237                 :             }
    8238                 :             /* FALLTHROUGH */
    8239                 : 
    8240                 :         case T_SubLink:
    8241                 :         case T_NullTest:
    8242 EUB             :         case T_BooleanTest:
    8243 ECB             :         case T_DistinctExpr:
    8244                 :         case T_JsonIsPredicate:
    8245 CBC         108 :             switch (nodeTag(parentNode))
    8246 EUB             :             {
    8247 CBC          15 :                 case T_FuncExpr:
    8248                 :                     {
    8249                 :                         /* special handling for casts and COERCE_SQL_SYNTAX */
    8250              15 :                         CoercionForm type = ((FuncExpr *) parentNode)->funcformat;
    8251 EUB             : 
    8252 GIC          15 :                         if (type == COERCE_EXPLICIT_CAST ||
    8253               3 :                             type == COERCE_IMPLICIT_CAST ||
    8254 EUB             :                             type == COERCE_SQL_SYNTAX)
    8255 GIC          15 :                             return false;
    8256 UBC           0 :                         return true;    /* own parentheses */
    8257 EUB             :                     }
    8258 GIC          81 :                 case T_BoolExpr:    /* lower precedence */
    8259 EUB             :                 case T_SubscriptingRef: /* other separators */
    8260                 :                 case T_ArrayExpr:   /* other separators */
    8261                 :                 case T_RowExpr: /* other separators */
    8262                 :                 case T_CoalesceExpr:    /* own parentheses */
    8263                 :                 case T_MinMaxExpr:  /* own parentheses */
    8264                 :                 case T_XmlExpr: /* own parentheses */
    8265                 :                 case T_NullIfExpr:  /* other separators */
    8266                 :                 case T_Aggref:  /* own parentheses */
    8267                 :                 case T_GroupingFunc:    /* own parentheses */
    8268                 :                 case T_WindowFunc:  /* own parentheses */
    8269                 :                 case T_CaseExpr:    /* other separators */
    8270 GIC          81 :                     return true;
    8271              12 :                 default:
    8272              12 :                     return false;
    8273 EUB             :             }
    8274                 : 
    8275 GBC           9 :         case T_BoolExpr:
    8276 GIC           9 :             switch (nodeTag(parentNode))
    8277                 :             {
    8278 GBC           9 :                 case T_BoolExpr:
    8279 GIC           9 :                     if (prettyFlags & PRETTYFLAG_PAREN)
    8280 EUB             :                     {
    8281                 :                         BoolExprType type;
    8282                 :                         BoolExprType parentType;
    8283                 : 
    8284 GBC           9 :                         type = ((BoolExpr *) node)->boolop;
    8285 GIC           9 :                         parentType = ((BoolExpr *) parentNode)->boolop;
    8286                 :                         switch (type)
    8287 EUB             :                         {
    8288 GIC           6 :                             case NOT_EXPR:
    8289                 :                             case AND_EXPR:
    8290               6 :                                 if (parentType == AND_EXPR || parentType == OR_EXPR)
    8291               6 :                                     return true;
    8292 UIC           0 :                                 break;
    8293 GIC           3 :                             case OR_EXPR:
    8294               3 :                                 if (parentType == OR_EXPR)
    8295 UIC           0 :                                     return true;
    8296 GIC           3 :                                 break;
    8297                 :                         }
    8298 ECB             :                     }
    8299 GIC           3 :                     return false;
    8300 UIC           0 :                 case T_FuncExpr:
    8301 ECB             :                     {
    8302                 :                         /* special handling for casts and COERCE_SQL_SYNTAX */
    8303 LBC           0 :                         CoercionForm type = ((FuncExpr *) parentNode)->funcformat;
    8304                 : 
    8305 UIC           0 :                         if (type == COERCE_EXPLICIT_CAST ||
    8306               0 :                             type == COERCE_IMPLICIT_CAST ||
    8307 ECB             :                             type == COERCE_SQL_SYNTAX)
    8308 UIC           0 :                             return false;
    8309               0 :                         return true;    /* own parentheses */
    8310 ECB             :                     }
    8311 UIC           0 :                 case T_SubscriptingRef: /* other separators */
    8312 ECB             :                 case T_ArrayExpr:   /* other separators */
    8313                 :                 case T_RowExpr: /* other separators */
    8314                 :                 case T_CoalesceExpr:    /* own parentheses */
    8315                 :                 case T_MinMaxExpr:  /* own parentheses */
    8316                 :                 case T_XmlExpr: /* own parentheses */
    8317                 :                 case T_NullIfExpr:  /* other separators */
    8318                 :                 case T_Aggref:  /* own parentheses */
    8319                 :                 case T_GroupingFunc:    /* own parentheses */
    8320                 :                 case T_WindowFunc:  /* own parentheses */
    8321                 :                 case T_CaseExpr:    /* other separators */
    8322 UIC           0 :                     return true;
    8323               0 :                 default:
    8324               0 :                     return false;
    8325                 :             }
    8326                 : 
    8327 UNC           0 :         case T_JsonValueExpr:
    8328                 :             /* maybe simple, check args */
    8329               0 :             return isSimpleNode((Node *) ((JsonValueExpr *) node)->raw_expr,
    8330                 :                                 node, prettyFlags);
    8331                 : 
    8332 UBC           0 :         default:
    8333               0 :             break;
    8334                 :     }
    8335 EUB             :     /* those we don't know: in dubio complexo */
    8336 UIC           0 :     return false;
    8337 EUB             : }
    8338                 : 
    8339 ECB             : 
    8340                 : /*
    8341                 :  * appendContextKeyword - append a keyword to buffer
    8342                 :  *
    8343                 :  * If prettyPrint is enabled, perform a line break, and adjust indentation.
    8344                 :  * Otherwise, just append the keyword.
    8345 EUB             :  */
    8346                 : static void
    8347 GIC        8815 : appendContextKeyword(deparse_context *context, const char *str,
    8348 ECB             :                      int indentBefore, int indentAfter, int indentPlus)
    8349                 : {
    8350 GIC        8815 :     StringInfo  buf = context->buf;
    8351                 : 
    8352            8815 :     if (PRETTY_INDENT(context))
    8353                 :     {
    8354                 :         int         indentAmount;
    8355                 : 
    8356            8666 :         context->indentLevel += indentBefore;
    8357 ECB             : 
    8358                 :         /* remove any trailing spaces currently in the buffer ... */
    8359 CBC        8666 :         removeStringInfoSpaces(buf);
    8360 ECB             :         /* ... then add a newline and some spaces */
    8361 CBC        8666 :         appendStringInfoChar(buf, '\n');
    8362                 : 
    8363 GIC        8666 :         if (context->indentLevel < PRETTYINDENT_LIMIT)
    8364            8666 :             indentAmount = Max(context->indentLevel, 0) + indentPlus;
    8365                 :         else
    8366                 :         {
    8367                 :             /*
    8368                 :              * If we're indented more than PRETTYINDENT_LIMIT characters, try
    8369                 :              * to conserve horizontal space by reducing the per-level
    8370                 :              * indentation.  For best results the scale factor here should
    8371                 :              * divide all the indent amounts that get added to indentLevel
    8372                 :              * (PRETTYINDENT_STD, etc).  It's important that the indentation
    8373                 :              * not grow unboundedly, else deeply-nested trees use O(N^2)
    8374                 :              * whitespace; so we also wrap modulo PRETTYINDENT_LIMIT.
    8375                 :              */
    8376 LBC           0 :             indentAmount = PRETTYINDENT_LIMIT +
    8377 UIC           0 :                 (context->indentLevel - PRETTYINDENT_LIMIT) /
    8378                 :                 (PRETTYINDENT_STD / 2);
    8379               0 :             indentAmount %= PRETTYINDENT_LIMIT;
    8380                 :             /* scale/wrap logic affects indentLevel, but not indentPlus */
    8381 LBC           0 :             indentAmount += indentPlus;
    8382 ECB             :         }
    8383 GIC        8666 :         appendStringInfoSpaces(buf, indentAmount);
    8384 ECB             : 
    8385 CBC        8666 :         appendStringInfoString(buf, str);
    8386                 : 
    8387            8666 :         context->indentLevel += indentAfter;
    8388 GIC        8666 :         if (context->indentLevel < 0)
    8389 LBC           0 :             context->indentLevel = 0;
    8390 ECB             :     }
    8391                 :     else
    8392 GIC         149 :         appendStringInfoString(buf, str);
    8393            8815 : }
    8394                 : 
    8395                 : /*
    8396                 :  * removeStringInfoSpaces - delete trailing spaces from a buffer.
    8397                 :  *
    8398                 :  * Possibly this should move to stringinfo.c at some point.
    8399                 :  */
    8400                 : static void
    8401            8777 : removeStringInfoSpaces(StringInfo str)
    8402                 : {
    8403           13554 :     while (str->len > 0 && str->data[str->len - 1] == ' ')
    8404            4777 :         str->data[--(str->len)] = '\0';
    8405            8777 : }
    8406                 : 
    8407                 : 
    8408 ECB             : /*
    8409                 :  * get_rule_expr_paren  - deparse expr using get_rule_expr,
    8410                 :  * embracing the string with parentheses if necessary for prettyPrint.
    8411                 :  *
    8412                 :  * Never embrace if prettyFlags=0, because it's done in the calling node.
    8413                 :  *
    8414                 :  * Any node that does *not* embrace its argument node by sql syntax (with
    8415                 :  * parentheses, non-operator keywords like CASE/WHEN/ON, or comma etc) should
    8416                 :  * use get_rule_expr_paren instead of get_rule_expr so parentheses can be
    8417                 :  * added.
    8418                 :  */
    8419                 : static void
    8420 GIC       66059 : get_rule_expr_paren(Node *node, deparse_context *context,
    8421                 :                     bool showimplicit, Node *parentNode)
    8422                 : {
    8423                 :     bool        need_paren;
    8424                 : 
    8425           68268 :     need_paren = PRETTY_PAREN(context) &&
    8426            2209 :         !isSimpleNode(node, parentNode, context->prettyFlags);
    8427 ECB             : 
    8428 GIC       66059 :     if (need_paren)
    8429 CBC          51 :         appendStringInfoChar(context->buf, '(');
    8430 ECB             : 
    8431 CBC       66059 :     get_rule_expr(node, context, showimplicit);
    8432                 : 
    8433           66059 :     if (need_paren)
    8434              51 :         appendStringInfoChar(context->buf, ')');
    8435           66059 : }
    8436                 : 
    8437 ECB             : 
    8438                 : /* ----------
    8439                 :  * get_rule_expr            - Parse back an expression
    8440                 :  *
    8441                 :  * Note: showimplicit determines whether we display any implicit cast that
    8442                 :  * is present at the top of the expression tree.  It is a passed argument,
    8443                 :  * not a field of the context struct, because we change the value as we
    8444                 :  * recurse down into the expression.  In general we suppress implicit casts
    8445                 :  * when the result type is known with certainty (eg, the arguments of an
    8446                 :  * OR must be boolean).  We display implicit casts for arguments of functions
    8447                 :  * and operators, since this is needed to be certain that the same function
    8448                 :  * or operator will be chosen when the expression is re-parsed.
    8449                 :  * ----------
    8450                 :  */
    8451                 : static void
    8452 GIC      131463 : get_rule_expr(Node *node, deparse_context *context,
    8453 ECB             :               bool showimplicit)
    8454                 : {
    8455 CBC      131463 :     StringInfo  buf = context->buf;
    8456 ECB             : 
    8457 CBC      131463 :     if (node == NULL)
    8458 GIC          48 :         return;
    8459 ECB             : 
    8460                 :     /* Guard against excessively long or deeply-nested queries */
    8461 CBC      131415 :     CHECK_FOR_INTERRUPTS();
    8462 GIC      131415 :     check_stack_depth();
    8463                 : 
    8464                 :     /*
    8465                 :      * Each level of get_rule_expr must emit an indivisible term
    8466                 :      * (parenthesized if necessary) to ensure result is reparsed into the same
    8467                 :      * expression tree.  The only exception is that when the input is a List,
    8468                 :      * we emit the component items comma-separated with no surrounding
    8469                 :      * decoration; this is convenient for most callers.
    8470                 :      */
    8471          131415 :     switch (nodeTag(node))
    8472 ECB             :     {
    8473 GIC       58979 :         case T_Var:
    8474 GBC       58979 :             (void) get_variable((Var *) node, 0, false, context);
    8475           58979 :             break;
    8476                 : 
    8477           25743 :         case T_Const:
    8478 GIC       25743 :             get_const_expr((Const *) node, context, 0);
    8479           25743 :             break;
    8480                 : 
    8481            2419 :         case T_Param:
    8482            2419 :             get_parameter((Param *) node, context);
    8483            2419 :             break;
    8484                 : 
    8485             762 :         case T_Aggref:
    8486 CBC         762 :             get_agg_expr((Aggref *) node, context, (Aggref *) node);
    8487             762 :             break;
    8488 ECB             : 
    8489 CBC          26 :         case T_GroupingFunc:
    8490 ECB             :             {
    8491 CBC          26 :                 GroupingFunc *gexpr = (GroupingFunc *) node;
    8492 ECB             : 
    8493 GIC          26 :                 appendStringInfoString(buf, "GROUPING(");
    8494              26 :                 get_rule_expr((Node *) gexpr->args, context, true);
    8495              26 :                 appendStringInfoChar(buf, ')');
    8496                 :             }
    8497              26 :             break;
    8498                 : 
    8499             117 :         case T_WindowFunc:
    8500             117 :             get_windowfunc_expr((WindowFunc *) node, context);
    8501             117 :             break;
    8502                 : 
    8503 CBC          98 :         case T_SubscriptingRef:
    8504                 :             {
    8505 GIC          98 :                 SubscriptingRef *sbsref = (SubscriptingRef *) node;
    8506                 :                 bool        need_parens;
    8507                 : 
    8508                 :                 /*
    8509                 :                  * If the argument is a CaseTestExpr, we must be inside a
    8510                 :                  * FieldStore, ie, we are assigning to an element of an array
    8511                 :                  * within a composite column.  Since we already punted on
    8512                 :                  * displaying the FieldStore's target information, just punt
    8513 ECB             :                  * here too, and display only the assignment source
    8514                 :                  * expression.
    8515                 :                  */
    8516 GIC          98 :                 if (IsA(sbsref->refexpr, CaseTestExpr))
    8517                 :                 {
    8518 UIC           0 :                     Assert(sbsref->refassgnexpr);
    8519               0 :                     get_rule_expr((Node *) sbsref->refassgnexpr,
    8520 ECB             :                                   context, showimplicit);
    8521 UIC           0 :                     break;
    8522                 :                 }
    8523 ECB             : 
    8524                 :                 /*
    8525                 :                  * Parenthesize the argument unless it's a simple Var or a
    8526                 :                  * FieldSelect.  (In particular, if it's another
    8527                 :                  * SubscriptingRef, we *must* parenthesize to avoid
    8528                 :                  * confusion.)
    8529                 :                  */
    8530 GIC         154 :                 need_parens = !IsA(sbsref->refexpr, Var) &&
    8531 CBC          56 :                     !IsA(sbsref->refexpr, FieldSelect);
    8532 GIC          98 :                 if (need_parens)
    8533 CBC          41 :                     appendStringInfoChar(buf, '(');
    8534              98 :                 get_rule_expr((Node *) sbsref->refexpr, context, showimplicit);
    8535 GIC          98 :                 if (need_parens)
    8536 CBC          41 :                     appendStringInfoChar(buf, ')');
    8537                 : 
    8538 ECB             :                 /*
    8539                 :                  * If there's a refassgnexpr, we want to print the node in the
    8540                 :                  * format "container[subscripts] := refassgnexpr".  This is
    8541                 :                  * not legal SQL, so decompilation of INSERT or UPDATE
    8542                 :                  * statements should always use processIndirection as part of
    8543                 :                  * the statement-level syntax.  We should only see this when
    8544                 :                  * EXPLAIN tries to print the targetlist of a plan resulting
    8545                 :                  * from such a statement.
    8546                 :                  */
    8547 CBC          98 :                 if (sbsref->refassgnexpr)
    8548                 :                 {
    8549 ECB             :                     Node       *refassgnexpr;
    8550                 : 
    8551                 :                     /*
    8552                 :                      * Use processIndirection to print this node's subscripts
    8553                 :                      * as well as any additional field selections or
    8554                 :                      * subscripting in immediate descendants.  It returns the
    8555                 :                      * RHS expr that is actually being "assigned".
    8556                 :                      */
    8557 CBC           6 :                     refassgnexpr = processIndirection(node, context);
    8558 GIC           6 :                     appendStringInfoString(buf, " := ");
    8559 CBC           6 :                     get_rule_expr(refassgnexpr, context, showimplicit);
    8560                 :                 }
    8561 ECB             :                 else
    8562                 :                 {
    8563                 :                     /* Just an ordinary container fetch, so print subscripts */
    8564 CBC          92 :                     printSubscripts(sbsref, context);
    8565 ECB             :                 }
    8566                 :             }
    8567 CBC          98 :             break;
    8568                 : 
    8569            5662 :         case T_FuncExpr:
    8570 GIC        5662 :             get_func_expr((FuncExpr *) node, context, showimplicit);
    8571 CBC        5662 :             break;
    8572 ECB             : 
    8573 CBC           9 :         case T_NamedArgExpr:
    8574 ECB             :             {
    8575 GIC           9 :                 NamedArgExpr *na = (NamedArgExpr *) node;
    8576 ECB             : 
    8577 CBC           9 :                 appendStringInfo(buf, "%s => ", quote_identifier(na->name));
    8578               9 :                 get_rule_expr((Node *) na->arg, context, showimplicit);
    8579 ECB             :             }
    8580 GIC           9 :             break;
    8581                 : 
    8582           24672 :         case T_OpExpr:
    8583 CBC       24672 :             get_oper_expr((OpExpr *) node, context);
    8584           24672 :             break;
    8585                 : 
    8586 GIC           9 :         case T_DistinctExpr:
    8587                 :             {
    8588               9 :                 DistinctExpr *expr = (DistinctExpr *) node;
    8589               9 :                 List       *args = expr->args;
    8590               9 :                 Node       *arg1 = (Node *) linitial(args);
    8591               9 :                 Node       *arg2 = (Node *) lsecond(args);
    8592                 : 
    8593               9 :                 if (!PRETTY_PAREN(context))
    8594               6 :                     appendStringInfoChar(buf, '(');
    8595               9 :                 get_rule_expr_paren(arg1, context, true, node);
    8596               9 :                 appendStringInfoString(buf, " IS DISTINCT FROM ");
    8597               9 :                 get_rule_expr_paren(arg2, context, true, node);
    8598 CBC           9 :                 if (!PRETTY_PAREN(context))
    8599               6 :                     appendStringInfoChar(buf, ')');
    8600 ECB             :             }
    8601 GIC           9 :             break;
    8602                 : 
    8603 CBC          10 :         case T_NullIfExpr:
    8604 ECB             :             {
    8605 CBC          10 :                 NullIfExpr *nullifexpr = (NullIfExpr *) node;
    8606                 : 
    8607              10 :                 appendStringInfoString(buf, "NULLIF(");
    8608 GIC          10 :                 get_rule_expr((Node *) nullifexpr->args, context, true);
    8609 CBC          10 :                 appendStringInfoChar(buf, ')');
    8610                 :             }
    8611              10 :             break;
    8612 ECB             : 
    8613 GIC        1186 :         case T_ScalarArrayOpExpr:
    8614                 :             {
    8615 CBC        1186 :                 ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) node;
    8616 GIC        1186 :                 List       *args = expr->args;
    8617 CBC        1186 :                 Node       *arg1 = (Node *) linitial(args);
    8618            1186 :                 Node       *arg2 = (Node *) lsecond(args);
    8619 ECB             : 
    8620 CBC        1186 :                 if (!PRETTY_PAREN(context))
    8621 GIC        1180 :                     appendStringInfoChar(buf, '(');
    8622 CBC        1186 :                 get_rule_expr_paren(arg1, context, true, node);
    8623 GIC        1186 :                 appendStringInfo(buf, " %s %s (",
    8624 ECB             :                                  generate_operator_name(expr->opno,
    8625                 :                                                         exprType(arg1),
    8626                 :                                                         get_base_element_type(exprType(arg2))),
    8627 GIC        1186 :                                  expr->useOr ? "ANY" : "ALL");
    8628 CBC        1186 :                 get_rule_expr_paren(arg2, context, true, node);
    8629 ECB             : 
    8630                 :                 /*
    8631                 :                  * There's inherent ambiguity in "x op ANY/ALL (y)" when y is
    8632                 :                  * a bare sub-SELECT.  Since we're here, the sub-SELECT must
    8633                 :                  * be meant as a scalar sub-SELECT yielding an array value to
    8634                 :                  * be used in ScalarArrayOpExpr; but the grammar will
    8635                 :                  * preferentially interpret such a construct as an ANY/ALL
    8636                 :                  * SubLink.  To prevent misparsing the output that way, insert
    8637                 :                  * a dummy coercion (which will be stripped by parse analysis,
    8638                 :                  * so no inefficiency is added in dump and reload).  This is
    8639                 :                  * indeed most likely what the user wrote to get the construct
    8640                 :                  * accepted in the first place.
    8641                 :                  */
    8642 GIC        1186 :                 if (IsA(arg2, SubLink) &&
    8643 CBC           3 :                     ((SubLink *) arg2)->subLinkType == EXPR_SUBLINK)
    8644               3 :                     appendStringInfo(buf, "::%s",
    8645 ECB             :                                      format_type_with_typemod(exprType(arg2),
    8646                 :                                                               exprTypmod(arg2)));
    8647 CBC        1186 :                 appendStringInfoChar(buf, ')');
    8648            1186 :                 if (!PRETTY_PAREN(context))
    8649            1180 :                     appendStringInfoChar(buf, ')');
    8650 ECB             :             }
    8651 CBC        1186 :             break;
    8652                 : 
    8653            4632 :         case T_BoolExpr:
    8654 ECB             :             {
    8655 CBC        4632 :                 BoolExpr   *expr = (BoolExpr *) node;
    8656 GIC        4632 :                 Node       *first_arg = linitial(expr->args);
    8657 EUB             :                 ListCell   *arg;
    8658                 : 
    8659 GIC        4632 :                 switch (expr->boolop)
    8660                 :                 {
    8661            3772 :                     case AND_EXPR:
    8662 CBC        3772 :                         if (!PRETTY_PAREN(context))
    8663 GIC        3739 :                             appendStringInfoChar(buf, '(');
    8664 CBC        3772 :                         get_rule_expr_paren(first_arg, context,
    8665 ECB             :                                             false, node);
    8666 CBC        8553 :                         for_each_from(arg, expr->args, 1)
    8667                 :                         {
    8668            4781 :                             appendStringInfoString(buf, " AND ");
    8669 GIC        4781 :                             get_rule_expr_paren((Node *) lfirst(arg), context,
    8670 ECB             :                                                 false, node);
    8671                 :                         }
    8672 GIC        3772 :                         if (!PRETTY_PAREN(context))
    8673            3739 :                             appendStringInfoChar(buf, ')');
    8674            3772 :                         break;
    8675                 : 
    8676             737 :                     case OR_EXPR:
    8677             737 :                         if (!PRETTY_PAREN(context))
    8678 CBC         731 :                             appendStringInfoChar(buf, '(');
    8679             737 :                         get_rule_expr_paren(first_arg, context,
    8680                 :                                             false, node);
    8681            1759 :                         for_each_from(arg, expr->args, 1)
    8682                 :                         {
    8683            1022 :                             appendStringInfoString(buf, " OR ");
    8684 GIC        1022 :                             get_rule_expr_paren((Node *) lfirst(arg), context,
    8685 EUB             :                                                 false, node);
    8686                 :                         }
    8687 GBC         737 :                         if (!PRETTY_PAREN(context))
    8688 GIC         731 :                             appendStringInfoChar(buf, ')');
    8689             737 :                         break;
    8690                 : 
    8691             123 :                     case NOT_EXPR:
    8692             123 :                         if (!PRETTY_PAREN(context))
    8693             117 :                             appendStringInfoChar(buf, '(');
    8694             123 :                         appendStringInfoString(buf, "NOT ");
    8695             123 :                         get_rule_expr_paren(first_arg, context,
    8696 EUB             :                                             false, node);
    8697 GBC         123 :                         if (!PRETTY_PAREN(context))
    8698 GIC         117 :                             appendStringInfoChar(buf, ')');
    8699 GBC         123 :                         break;
    8700                 : 
    8701 UBC           0 :                     default:
    8702               0 :                         elog(ERROR, "unrecognized boolop: %d",
    8703                 :                              (int) expr->boolop);
    8704 EUB             :                 }
    8705                 :             }
    8706 GBC        4632 :             break;
    8707                 : 
    8708             191 :         case T_SubLink:
    8709 GIC         191 :             get_sublink_expr((SubLink *) node, context);
    8710 GBC         191 :             break;
    8711                 : 
    8712 CBC         230 :         case T_SubPlan:
    8713                 :             {
    8714             230 :                 SubPlan    *subplan = (SubPlan *) node;
    8715 ECB             : 
    8716                 :                 /*
    8717                 :                  * We cannot see an already-planned subplan in rule deparsing,
    8718                 :                  * only while EXPLAINing a query plan.  We don't try to
    8719                 :                  * reconstruct the original SQL, just reference the subplan
    8720                 :                  * that appears elsewhere in EXPLAIN's result.
    8721                 :                  */
    8722 GIC         230 :                 if (subplan->useHashTable)
    8723              58 :                     appendStringInfo(buf, "(hashed %s)", subplan->plan_name);
    8724                 :                 else
    8725             172 :                     appendStringInfo(buf, "(%s)", subplan->plan_name);
    8726 ECB             :             }
    8727 CBC         230 :             break;
    8728 ECB             : 
    8729 LBC           0 :         case T_AlternativeSubPlan:
    8730 ECB             :             {
    8731 LBC           0 :                 AlternativeSubPlan *asplan = (AlternativeSubPlan *) node;
    8732 ECB             :                 ListCell   *lc;
    8733                 : 
    8734                 :                 /*
    8735                 :                  * This case cannot be reached in normal usage, since no
    8736                 :                  * AlternativeSubPlan can appear either in parsetrees or
    8737                 :                  * finished plan trees.  We keep it just in case somebody
    8738                 :                  * wants to use this code to print planner data structures.
    8739                 :                  */
    8740 UIC           0 :                 appendStringInfoString(buf, "(alternatives: ");
    8741 LBC           0 :                 foreach(lc, asplan->subplans)
    8742                 :                 {
    8743               0 :                     SubPlan    *splan = lfirst_node(SubPlan, lc);
    8744                 : 
    8745               0 :                     if (splan->useHashTable)
    8746 UIC           0 :                         appendStringInfo(buf, "hashed %s", splan->plan_name);
    8747                 :                     else
    8748               0 :                         appendStringInfoString(buf, splan->plan_name);
    8749               0 :                     if (lnext(asplan->subplans, lc))
    8750               0 :                         appendStringInfoString(buf, " or ");
    8751                 :                 }
    8752               0 :                 appendStringInfoChar(buf, ')');
    8753                 :             }
    8754               0 :             break;
    8755                 : 
    8756 GIC         304 :         case T_FieldSelect:
    8757                 :             {
    8758             304 :                 FieldSelect *fselect = (FieldSelect *) node;
    8759             304 :                 Node       *arg = (Node *) fselect->arg;
    8760             304 :                 int         fno = fselect->fieldnum;
    8761                 :                 const char *fieldname;
    8762                 :                 bool        need_parens;
    8763                 : 
    8764                 :                 /*
    8765                 :                  * Parenthesize the argument unless it's an SubscriptingRef or
    8766                 :                  * another FieldSelect.  Note in particular that it would be
    8767 ECB             :                  * WRONG to not parenthesize a Var argument; simplicity is not
    8768                 :                  * the issue here, having the right number of names is.
    8769                 :                  */
    8770 CBC         590 :                 need_parens = !IsA(arg, SubscriptingRef) &&
    8771             286 :                     !IsA(arg, FieldSelect);
    8772             304 :                 if (need_parens)
    8773 GIC         286 :                     appendStringInfoChar(buf, '(');
    8774 CBC         304 :                 get_rule_expr(arg, context, true);
    8775 GIC         304 :                 if (need_parens)
    8776 CBC         286 :                     appendStringInfoChar(buf, ')');
    8777                 : 
    8778 ECB             :                 /*
    8779                 :                  * Get and print the field name.
    8780                 :                  */
    8781 CBC         304 :                 fieldname = get_name_for_var_field((Var *) arg, fno,
    8782 ECB             :                                                    0, context);
    8783 GIC         304 :                 appendStringInfo(buf, ".%s", quote_identifier(fieldname));
    8784                 :             }
    8785 CBC         304 :             break;
    8786                 : 
    8787 GIC           3 :         case T_FieldStore:
    8788                 :             {
    8789 CBC           3 :                 FieldStore *fstore = (FieldStore *) node;
    8790                 :                 bool        need_parens;
    8791                 : 
    8792                 :                 /*
    8793                 :                  * There is no good way to represent a FieldStore as real SQL,
    8794                 :                  * so decompilation of INSERT or UPDATE statements should
    8795 ECB             :                  * always use processIndirection as part of the
    8796                 :                  * statement-level syntax.  We should only get here when
    8797                 :                  * EXPLAIN tries to print the targetlist of a plan resulting
    8798                 :                  * from such a statement.  The plan case is even harder than
    8799                 :                  * ordinary rules would be, because the planner tries to
    8800                 :                  * collapse multiple assignments to the same field or subfield
    8801                 :                  * into one FieldStore; so we can see a list of target fields
    8802                 :                  * not just one, and the arguments could be FieldStores
    8803                 :                  * themselves.  We don't bother to try to print the target
    8804                 :                  * field names; we just print the source arguments, with a
    8805                 :                  * ROW() around them if there's more than one.  This isn't
    8806                 :                  * terribly complete, but it's probably good enough for
    8807                 :                  * EXPLAIN's purposes; especially since anything more would be
    8808                 :                  * either hopelessly confusing or an even poorer
    8809                 :                  * representation of what the plan is actually doing.
    8810                 :                  */
    8811 GIC           3 :                 need_parens = (list_length(fstore->newvals) != 1);
    8812               3 :                 if (need_parens)
    8813               3 :                     appendStringInfoString(buf, "ROW(");
    8814               3 :                 get_rule_expr((Node *) fstore->newvals, context, showimplicit);
    8815               3 :                 if (need_parens)
    8816 CBC           3 :                     appendStringInfoChar(buf, ')');
    8817                 :             }
    8818               3 :             break;
    8819                 : 
    8820            1064 :         case T_RelabelType:
    8821 ECB             :             {
    8822 GIC        1064 :                 RelabelType *relabel = (RelabelType *) node;
    8823 CBC        1064 :                 Node       *arg = (Node *) relabel->arg;
    8824 ECB             : 
    8825 GIC        1064 :                 if (relabel->relabelformat == COERCE_IMPLICIT_CAST &&
    8826            1001 :                     !showimplicit)
    8827 EUB             :                 {
    8828                 :                     /* don't show the implicit cast */
    8829 GIC          30 :                     get_rule_expr_paren(arg, context, false, node);
    8830                 :                 }
    8831 ECB             :                 else
    8832                 :                 {
    8833 GIC        1034 :                     get_coercion_expr(arg, context,
    8834                 :                                       relabel->resulttype,
    8835                 :                                       relabel->resulttypmod,
    8836                 :                                       node);
    8837 ECB             :                 }
    8838                 :             }
    8839 CBC        1064 :             break;
    8840                 : 
    8841             262 :         case T_CoerceViaIO:
    8842 ECB             :             {
    8843 GIC         262 :                 CoerceViaIO *iocoerce = (CoerceViaIO *) node;
    8844 CBC         262 :                 Node       *arg = (Node *) iocoerce->arg;
    8845 ECB             : 
    8846 GIC         262 :                 if (iocoerce->coerceformat == COERCE_IMPLICIT_CAST &&
    8847               6 :                     !showimplicit)
    8848 ECB             :                 {
    8849                 :                     /* don't show the implicit cast */
    8850 GIC           6 :                     get_rule_expr_paren(arg, context, false, node);
    8851                 :                 }
    8852 ECB             :                 else
    8853                 :                 {
    8854 GIC         256 :                     get_coercion_expr(arg, context,
    8855                 :                                       iocoerce->resulttype,
    8856                 :                                       -1,
    8857 ECB             :                                       node);
    8858                 :                 }
    8859                 :             }
    8860 GIC         262 :             break;
    8861 ECB             : 
    8862 CBC          15 :         case T_ArrayCoerceExpr:
    8863                 :             {
    8864              15 :                 ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node;
    8865              15 :                 Node       *arg = (Node *) acoerce->arg;
    8866 ECB             : 
    8867 CBC          15 :                 if (acoerce->coerceformat == COERCE_IMPLICIT_CAST &&
    8868 GIC          15 :                     !showimplicit)
    8869 ECB             :                 {
    8870                 :                     /* don't show the implicit cast */
    8871 UIC           0 :                     get_rule_expr_paren(arg, context, false, node);
    8872 ECB             :                 }
    8873                 :                 else
    8874                 :                 {
    8875 GIC          15 :                     get_coercion_expr(arg, context,
    8876 ECB             :                                       acoerce->resulttype,
    8877                 :                                       acoerce->resulttypmod,
    8878                 :                                       node);
    8879                 :                 }
    8880                 :             }
    8881 CBC          15 :             break;
    8882                 : 
    8883              45 :         case T_ConvertRowtypeExpr:
    8884 ECB             :             {
    8885 GIC          45 :                 ConvertRowtypeExpr *convert = (ConvertRowtypeExpr *) node;
    8886 CBC          45 :                 Node       *arg = (Node *) convert->arg;
    8887                 : 
    8888              45 :                 if (convert->convertformat == COERCE_IMPLICIT_CAST &&
    8889              42 :                     !showimplicit)
    8890                 :                 {
    8891 ECB             :                     /* don't show the implicit cast */
    8892 GIC          12 :                     get_rule_expr_paren(arg, context, false, node);
    8893                 :                 }
    8894                 :                 else
    8895                 :                 {
    8896              33 :                     get_coercion_expr(arg, context,
    8897                 :                                       convert->resulttype, -1,
    8898                 :                                       node);
    8899                 :                 }
    8900                 :             }
    8901              45 :             break;
    8902                 : 
    8903              48 :         case T_CollateExpr:
    8904                 :             {
    8905 CBC          48 :                 CollateExpr *collate = (CollateExpr *) node;
    8906 GIC          48 :                 Node       *arg = (Node *) collate->arg;
    8907 ECB             : 
    8908 GIC          48 :                 if (!PRETTY_PAREN(context))
    8909 CBC          48 :                     appendStringInfoChar(buf, '(');
    8910              48 :                 get_rule_expr_paren(arg, context, showimplicit, node);
    8911 GIC          48 :                 appendStringInfo(buf, " COLLATE %s",
    8912 ECB             :                                  generate_collation_name(collate->collOid));
    8913 GIC          48 :                 if (!PRETTY_PAREN(context))
    8914              48 :                     appendStringInfoChar(buf, ')');
    8915                 :             }
    8916 CBC          48 :             break;
    8917 ECB             : 
    8918 CBC         153 :         case T_CaseExpr:
    8919                 :             {
    8920             153 :                 CaseExpr   *caseexpr = (CaseExpr *) node;
    8921 ECB             :                 ListCell   *temp;
    8922                 : 
    8923 GIC         153 :                 appendContextKeyword(context, "CASE",
    8924 ECB             :                                      0, PRETTYINDENT_VAR, 0);
    8925 CBC         153 :                 if (caseexpr->arg)
    8926 ECB             :                 {
    8927 GIC          51 :                     appendStringInfoChar(buf, ' ');
    8928 CBC          51 :                     get_rule_expr((Node *) caseexpr->arg, context, true);
    8929 ECB             :                 }
    8930 CBC         632 :                 foreach(temp, caseexpr->args)
    8931 ECB             :                 {
    8932 GIC         479 :                     CaseWhen   *when = (CaseWhen *) lfirst(temp);
    8933             479 :                     Node       *w = (Node *) when->expr;
    8934 ECB             : 
    8935 GIC         479 :                     if (caseexpr->arg)
    8936 EUB             :                     {
    8937                 :                         /*
    8938                 :                          * The parser should have produced WHEN clauses of the
    8939                 :                          * form "CaseTestExpr = RHS", possibly with an
    8940                 :                          * implicit coercion inserted above the CaseTestExpr.
    8941                 :                          * For accurate decompilation of rules it's essential
    8942                 :                          * that we show just the RHS.  However in an
    8943                 :                          * expression that's been through the optimizer, the
    8944                 :                          * WHEN clause could be almost anything (since the
    8945                 :                          * equality operator could have been expanded into an
    8946                 :                          * inline function).  If we don't recognize the form
    8947                 :                          * of the WHEN clause, just punt and display it as-is.
    8948                 :                          */
    8949 CBC         197 :                         if (IsA(w, OpExpr))
    8950                 :                         {
    8951             197 :                             List       *args = ((OpExpr *) w)->args;
    8952                 : 
    8953             197 :                             if (list_length(args) == 2 &&
    8954             197 :                                 IsA(strip_implicit_coercions(linitial(args)),
    8955 ECB             :                                     CaseTestExpr))
    8956 GIC         197 :                                 w = (Node *) lsecond(args);
    8957                 :                         }
    8958                 :                     }
    8959                 : 
    8960             479 :                     if (!PRETTY_INDENT(context))
    8961              41 :                         appendStringInfoChar(buf, ' ');
    8962 CBC         479 :                     appendContextKeyword(context, "WHEN ",
    8963 ECB             :                                          0, 0, 0);
    8964 GIC         479 :                     get_rule_expr(w, context, false);
    8965             479 :                     appendStringInfoString(buf, " THEN ");
    8966 CBC         479 :                     get_rule_expr((Node *) when->result, context, true);
    8967                 :                 }
    8968             153 :                 if (!PRETTY_INDENT(context))
    8969 GIC          36 :                     appendStringInfoChar(buf, ' ');
    8970 CBC         153 :                 appendContextKeyword(context, "ELSE ",
    8971 ECB             :                                      0, 0, 0);
    8972 GIC         153 :                 get_rule_expr((Node *) caseexpr->defresult, context, true);
    8973             153 :                 if (!PRETTY_INDENT(context))
    8974              36 :                     appendStringInfoChar(buf, ' ');
    8975             153 :                 appendContextKeyword(context, "END",
    8976                 :                                      -PRETTYINDENT_VAR, 0, 0);
    8977                 :             }
    8978             153 :             break;
    8979                 : 
    8980 UIC           0 :         case T_CaseTestExpr:
    8981 ECB             :             {
    8982                 :                 /*
    8983                 :                  * Normally we should never get here, since for expressions
    8984                 :                  * that can contain this node type we attempt to avoid
    8985                 :                  * recursing to it.  But in an optimized expression we might
    8986                 :                  * be unable to avoid that (see comments for CaseExpr).  If we
    8987                 :                  * do see one, print it as CASE_TEST_EXPR.
    8988                 :                  */
    8989 UIC           0 :                 appendStringInfoString(buf, "CASE_TEST_EXPR");
    8990                 :             }
    8991 LBC           0 :             break;
    8992 ECB             : 
    8993 CBC         181 :         case T_ArrayExpr:
    8994 ECB             :             {
    8995 GIC         181 :                 ArrayExpr  *arrayexpr = (ArrayExpr *) node;
    8996 ECB             : 
    8997 GIC         181 :                 appendStringInfoString(buf, "ARRAY[");
    8998 CBC         181 :                 get_rule_expr((Node *) arrayexpr->elements, context, true);
    8999             181 :                 appendStringInfoChar(buf, ']');
    9000                 : 
    9001 ECB             :                 /*
    9002                 :                  * If the array isn't empty, we assume its elements are
    9003                 :                  * coerced to the desired type.  If it's empty, though, we
    9004                 :                  * need an explicit coercion to the array type.
    9005                 :                  */
    9006 CBC         181 :                 if (arrayexpr->elements == NIL)
    9007 GIC           3 :                     appendStringInfo(buf, "::%s",
    9008 ECB             :                                      format_type_with_typemod(arrayexpr->array_typeid, -1));
    9009                 :             }
    9010 CBC         181 :             break;
    9011                 : 
    9012 GBC          90 :         case T_RowExpr:
    9013                 :             {
    9014              90 :                 RowExpr    *rowexpr = (RowExpr *) node;
    9015              90 :                 TupleDesc   tupdesc = NULL;
    9016 EUB             :                 ListCell   *arg;
    9017                 :                 int         i;
    9018                 :                 char       *sep;
    9019                 : 
    9020                 :                 /*
    9021 ECB             :                  * If it's a named type and not RECORD, we may have to skip
    9022                 :                  * dropped columns and/or claim there are NULLs for added
    9023                 :                  * columns.
    9024                 :                  */
    9025 CBC          90 :                 if (rowexpr->row_typeid != RECORDOID)
    9026                 :                 {
    9027 GIC          24 :                     tupdesc = lookup_rowtype_tupdesc(rowexpr->row_typeid, -1);
    9028 CBC          24 :                     Assert(list_length(rowexpr->args) <= tupdesc->natts);
    9029                 :                 }
    9030 ECB             : 
    9031                 :                 /*
    9032                 :                  * SQL99 allows "ROW" to be omitted when there is more than
    9033                 :                  * one column, but for simplicity we always print it.
    9034                 :                  */
    9035 GIC          90 :                 appendStringInfoString(buf, "ROW(");
    9036              90 :                 sep = "";
    9037              90 :                 i = 0;
    9038             258 :                 foreach(arg, rowexpr->args)
    9039                 :                 {
    9040 CBC         168 :                     Node       *e = (Node *) lfirst(arg);
    9041 ECB             : 
    9042 GIC         168 :                     if (tupdesc == NULL ||
    9043              45 :                         !TupleDescAttr(tupdesc, i)->attisdropped)
    9044                 :                     {
    9045             168 :                         appendStringInfoString(buf, sep);
    9046                 :                         /* Whole-row Vars need special treatment here */
    9047             168 :                         get_rule_expr_toplevel(e, context, true);
    9048             168 :                         sep = ", ";
    9049                 :                     }
    9050 CBC         168 :                     i++;
    9051 ECB             :                 }
    9052 CBC          90 :                 if (tupdesc != NULL)
    9053 ECB             :                 {
    9054 CBC          24 :                     while (i < tupdesc->natts)
    9055 ECB             :                     {
    9056 UIC           0 :                         if (!TupleDescAttr(tupdesc, i)->attisdropped)
    9057 ECB             :                         {
    9058 UIC           0 :                             appendStringInfoString(buf, sep);
    9059 LBC           0 :                             appendStringInfoString(buf, "NULL");
    9060 UIC           0 :                             sep = ", ";
    9061 ECB             :                         }
    9062 UIC           0 :                         i++;
    9063 ECB             :                     }
    9064                 : 
    9065 CBC          24 :                     ReleaseTupleDesc(tupdesc);
    9066                 :                 }
    9067              90 :                 appendStringInfoChar(buf, ')');
    9068 GIC          90 :                 if (rowexpr->row_format == COERCE_EXPLICIT_CAST)
    9069 CBC          18 :                     appendStringInfo(buf, "::%s",
    9070                 :                                      format_type_with_typemod(rowexpr->row_typeid, -1));
    9071 ECB             :             }
    9072 GIC          90 :             break;
    9073 ECB             : 
    9074 GIC          33 :         case T_RowCompareExpr:
    9075 ECB             :             {
    9076 CBC          33 :                 RowCompareExpr *rcexpr = (RowCompareExpr *) node;
    9077 ECB             : 
    9078                 :                 /*
    9079                 :                  * SQL99 allows "ROW" to be omitted when there is more than
    9080                 :                  * one column, but for simplicity we always print it.  Within
    9081                 :                  * a ROW expression, whole-row Vars need special treatment, so
    9082                 :                  * use get_rule_list_toplevel.
    9083                 :                  */
    9084 GIC          33 :                 appendStringInfoString(buf, "(ROW(");
    9085 CBC          33 :                 get_rule_list_toplevel(rcexpr->largs, context, true);
    9086                 : 
    9087 ECB             :                 /*
    9088                 :                  * We assume that the name of the first-column operator will
    9089                 :                  * do for all the rest too.  This is definitely open to
    9090                 :                  * failure, eg if some but not all operators were renamed
    9091                 :                  * since the construct was parsed, but there seems no way to
    9092                 :                  * be perfect.
    9093                 :                  */
    9094 GIC          33 :                 appendStringInfo(buf, ") %s ROW(",
    9095 CBC          33 :                                  generate_operator_name(linitial_oid(rcexpr->opnos),
    9096 GIC          33 :                                                         exprType(linitial(rcexpr->largs)),
    9097 CBC          33 :                                                         exprType(linitial(rcexpr->rargs))));
    9098              33 :                 get_rule_list_toplevel(rcexpr->rargs, context, true);
    9099              33 :                 appendStringInfoString(buf, "))");
    9100 ECB             :             }
    9101 CBC          33 :             break;
    9102 ECB             : 
    9103 CBC         489 :         case T_CoalesceExpr:
    9104 ECB             :             {
    9105 CBC         489 :                 CoalesceExpr *coalesceexpr = (CoalesceExpr *) node;
    9106 ECB             : 
    9107 CBC         489 :                 appendStringInfoString(buf, "COALESCE(");
    9108             489 :                 get_rule_expr((Node *) coalesceexpr->args, context, true);
    9109             489 :                 appendStringInfoChar(buf, ')');
    9110 ECB             :             }
    9111 CBC         489 :             break;
    9112 ECB             : 
    9113 CBC          18 :         case T_MinMaxExpr:
    9114 ECB             :             {
    9115 CBC          18 :                 MinMaxExpr *minmaxexpr = (MinMaxExpr *) node;
    9116 ECB             : 
    9117 CBC          18 :                 switch (minmaxexpr->op)
    9118 EUB             :                 {
    9119 GBC           3 :                     case IS_GREATEST:
    9120 GIC           3 :                         appendStringInfoString(buf, "GREATEST(");
    9121 CBC           3 :                         break;
    9122 GIC          15 :                     case IS_LEAST:
    9123 CBC          15 :                         appendStringInfoString(buf, "LEAST(");
    9124 GBC          15 :                         break;
    9125                 :                 }
    9126 CBC          18 :                 get_rule_expr((Node *) minmaxexpr->args, context, true);
    9127 GIC          18 :                 appendStringInfoChar(buf, ')');
    9128 ECB             :             }
    9129 GIC          18 :             break;
    9130 ECB             : 
    9131 GIC          72 :         case T_XmlExpr:
    9132 ECB             :             {
    9133 CBC          72 :                 XmlExpr    *xexpr = (XmlExpr *) node;
    9134              72 :                 bool        needcomma = false;
    9135 ECB             :                 ListCell   *arg;
    9136                 :                 ListCell   *narg;
    9137                 :                 Const      *con;
    9138 EUB             : 
    9139 GIC          72 :                 switch (xexpr->op)
    9140 ECB             :                 {
    9141 CBC           8 :                     case IS_XMLCONCAT:
    9142 GIC           8 :                         appendStringInfoString(buf, "XMLCONCAT(");
    9143               8 :                         break;
    9144              16 :                     case IS_XMLELEMENT:
    9145 CBC          16 :                         appendStringInfoString(buf, "XMLELEMENT(");
    9146 GIC          16 :                         break;
    9147 CBC           8 :                     case IS_XMLFOREST:
    9148               8 :                         appendStringInfoString(buf, "XMLFOREST(");
    9149 GIC           8 :                         break;
    9150 CBC           8 :                     case IS_XMLPARSE:
    9151 GBC           8 :                         appendStringInfoString(buf, "XMLPARSE(");
    9152               8 :                         break;
    9153 GIC           8 :                     case IS_XMLPI:
    9154 GBC           8 :                         appendStringInfoString(buf, "XMLPI(");
    9155               8 :                         break;
    9156               8 :                     case IS_XMLROOT:
    9157 GIC           8 :                         appendStringInfoString(buf, "XMLROOT(");
    9158 GBC           8 :                         break;
    9159              16 :                     case IS_XMLSERIALIZE:
    9160              16 :                         appendStringInfoString(buf, "XMLSERIALIZE(");
    9161 GIC          16 :                         break;
    9162 UIC           0 :                     case IS_DOCUMENT:
    9163 LBC           0 :                         break;
    9164 EUB             :                 }
    9165 GBC          72 :                 if (xexpr->op == IS_XMLPARSE || xexpr->op == IS_XMLSERIALIZE)
    9166 EUB             :                 {
    9167 GIC          24 :                     if (xexpr->xmloption == XMLOPTION_DOCUMENT)
    9168 UIC           0 :                         appendStringInfoString(buf, "DOCUMENT ");
    9169 ECB             :                     else
    9170 CBC          24 :                         appendStringInfoString(buf, "CONTENT ");
    9171                 :                 }
    9172 GIC          72 :                 if (xexpr->name)
    9173 ECB             :                 {
    9174 GBC          24 :                     appendStringInfo(buf, "NAME %s",
    9175 GIC          24 :                                      quote_identifier(map_xml_name_to_sql_identifier(xexpr->name)));
    9176 CBC          24 :                     needcomma = true;
    9177                 :                 }
    9178              72 :                 if (xexpr->named_args)
    9179                 :                 {
    9180              16 :                     if (xexpr->op != IS_XMLFOREST)
    9181                 :                     {
    9182               8 :                         if (needcomma)
    9183 GIC           8 :                             appendStringInfoString(buf, ", ");
    9184 CBC           8 :                         appendStringInfoString(buf, "XMLATTRIBUTES(");
    9185               8 :                         needcomma = false;
    9186 ECB             :                     }
    9187 GIC          56 :                     forboth(arg, xexpr->named_args, narg, xexpr->arg_names)
    9188                 :                     {
    9189              40 :                         Node       *e = (Node *) lfirst(arg);
    9190              40 :                         char       *argname = strVal(lfirst(narg));
    9191                 : 
    9192              40 :                         if (needcomma)
    9193              24 :                             appendStringInfoString(buf, ", ");
    9194 CBC          40 :                         get_rule_expr((Node *) e, context, true);
    9195              40 :                         appendStringInfo(buf, " AS %s",
    9196 GIC          40 :                                          quote_identifier(map_xml_name_to_sql_identifier(argname)));
    9197 CBC          40 :                         needcomma = true;
    9198                 :                     }
    9199              16 :                     if (xexpr->op != IS_XMLFOREST)
    9200               8 :                         appendStringInfoChar(buf, ')');
    9201 ECB             :                 }
    9202 CBC          72 :                 if (xexpr->args)
    9203 ECB             :                 {
    9204 CBC          64 :                     if (needcomma)
    9205 GBC          24 :                         appendStringInfoString(buf, ", ");
    9206              64 :                     switch (xexpr->op)
    9207                 :                     {
    9208 GIC          48 :                         case IS_XMLCONCAT:
    9209                 :                         case IS_XMLELEMENT:
    9210                 :                         case IS_XMLFOREST:
    9211                 :                         case IS_XMLPI:
    9212 ECB             :                         case IS_XMLSERIALIZE:
    9213                 :                             /* no extra decoration needed */
    9214 CBC          48 :                             get_rule_expr((Node *) xexpr->args, context, true);
    9215              48 :                             break;
    9216               8 :                         case IS_XMLPARSE:
    9217               8 :                             Assert(list_length(xexpr->args) == 2);
    9218 ECB             : 
    9219 CBC           8 :                             get_rule_expr((Node *) linitial(xexpr->args),
    9220 EUB             :                                           context, true);
    9221                 : 
    9222 GIC           8 :                             con = lsecond_node(Const, xexpr->args);
    9223               8 :                             Assert(!con->constisnull);
    9224               8 :                             if (DatumGetBool(con->constvalue))
    9225 LBC           0 :                                 appendStringInfoString(buf,
    9226 ECB             :                                                        " PRESERVE WHITESPACE");
    9227                 :                             else
    9228 CBC           8 :                                 appendStringInfoString(buf,
    9229                 :                                                        " STRIP WHITESPACE");
    9230               8 :                             break;
    9231 GIC           8 :                         case IS_XMLROOT:
    9232 CBC           8 :                             Assert(list_length(xexpr->args) == 3);
    9233                 : 
    9234               8 :                             get_rule_expr((Node *) linitial(xexpr->args),
    9235 ECB             :                                           context, true);
    9236                 : 
    9237 CBC           8 :                             appendStringInfoString(buf, ", VERSION ");
    9238 GIC           8 :                             con = (Const *) lsecond(xexpr->args);
    9239 CBC           8 :                             if (IsA(con, Const) &&
    9240               8 :                                 con->constisnull)
    9241               8 :                                 appendStringInfoString(buf, "NO VALUE");
    9242 ECB             :                             else
    9243 LBC           0 :                                 get_rule_expr((Node *) con, context, false);
    9244 ECB             : 
    9245 GBC           8 :                             con = lthird_node(Const, xexpr->args);
    9246               8 :                             if (con->constisnull)
    9247 EUB             :                                  /* suppress STANDALONE NO VALUE */ ;
    9248                 :                             else
    9249                 :                             {
    9250 GBC           8 :                                 switch (DatumGetInt32(con->constvalue))
    9251 ECB             :                                 {
    9252 CBC           8 :                                     case XML_STANDALONE_YES:
    9253               8 :                                         appendStringInfoString(buf,
    9254 ECB             :                                                                ", STANDALONE YES");
    9255 CBC           8 :                                         break;
    9256 LBC           0 :                                     case XML_STANDALONE_NO:
    9257 UBC           0 :                                         appendStringInfoString(buf,
    9258 EUB             :                                                                ", STANDALONE NO");
    9259 UIC           0 :                                         break;
    9260               0 :                                     case XML_STANDALONE_NO_VALUE:
    9261 LBC           0 :                                         appendStringInfoString(buf,
    9262 ECB             :                                                                ", STANDALONE NO VALUE");
    9263 UIC           0 :                                         break;
    9264 LBC           0 :                                     default:
    9265 UIC           0 :                                         break;
    9266 ECB             :                                 }
    9267                 :                             }
    9268 CBC           8 :                             break;
    9269 LBC           0 :                         case IS_DOCUMENT:
    9270 UIC           0 :                             get_rule_expr_paren((Node *) xexpr->args, context, false, node);
    9271 LBC           0 :                             break;
    9272 ECB             :                     }
    9273                 :                 }
    9274 GIC          72 :                 if (xexpr->op == IS_XMLSERIALIZE)
    9275 CBC          16 :                     appendStringInfo(buf, " AS %s",
    9276                 :                                      format_type_with_typemod(xexpr->type,
    9277                 :                                                               xexpr->typmod));
    9278 GIC          72 :                 if (xexpr->op == IS_DOCUMENT)
    9279 LBC           0 :                     appendStringInfoString(buf, " IS DOCUMENT");
    9280                 :                 else
    9281 GIC          72 :                     appendStringInfoChar(buf, ')');
    9282                 :             }
    9283              72 :             break;
    9284                 : 
    9285 CBC         897 :         case T_NullTest:
    9286                 :             {
    9287             897 :                 NullTest   *ntest = (NullTest *) node;
    9288 ECB             : 
    9289 CBC         897 :                 if (!PRETTY_PAREN(context))
    9290 GIC         873 :                     appendStringInfoChar(buf, '(');
    9291 CBC         897 :                 get_rule_expr_paren((Node *) ntest->arg, context, true, node);
    9292 ECB             : 
    9293                 :                 /*
    9294                 :                  * For scalar inputs, we prefer to print as IS [NOT] NULL,
    9295                 :                  * which is shorter and traditional.  If it's a rowtype input
    9296                 :                  * but we're applying a scalar test, must print IS [NOT]
    9297                 :                  * DISTINCT FROM NULL to be semantically correct.
    9298                 :                  */
    9299 CBC         897 :                 if (ntest->argisrow ||
    9300             888 :                     !type_is_rowtype(exprType((Node *) ntest->arg)))
    9301 ECB             :                 {
    9302 GIC        1776 :                     switch (ntest->nulltesttype)
    9303 EUB             :                     {
    9304 GIC         264 :                         case IS_NULL:
    9305             264 :                             appendStringInfoString(buf, " IS NULL");
    9306 CBC         264 :                             break;
    9307 GIC         624 :                         case IS_NOT_NULL:
    9308 GBC         624 :                             appendStringInfoString(buf, " IS NOT NULL");
    9309 GIC         624 :                             break;
    9310 UBC           0 :                         default:
    9311 UIC           0 :                             elog(ERROR, "unrecognized nulltesttype: %d",
    9312                 :                                  (int) ntest->nulltesttype);
    9313                 :                     }
    9314                 :                 }
    9315                 :                 else
    9316 EUB             :                 {
    9317 GBC           9 :                     switch (ntest->nulltesttype)
    9318 EUB             :                     {
    9319 GIC           3 :                         case IS_NULL:
    9320 GBC           3 :                             appendStringInfoString(buf, " IS NOT DISTINCT FROM NULL");
    9321 GIC           3 :                             break;
    9322 GBC           6 :                         case IS_NOT_NULL:
    9323 GIC           6 :                             appendStringInfoString(buf, " IS DISTINCT FROM NULL");
    9324 CBC           6 :                             break;
    9325 UIC           0 :                         default:
    9326 LBC           0 :                             elog(ERROR, "unrecognized nulltesttype: %d",
    9327                 :                                  (int) ntest->nulltesttype);
    9328                 :                     }
    9329                 :                 }
    9330 GIC         897 :                 if (!PRETTY_PAREN(context))
    9331             873 :                     appendStringInfoChar(buf, ')');
    9332                 :             }
    9333             897 :             break;
    9334 ECB             : 
    9335 CBC          36 :         case T_BooleanTest:
    9336                 :             {
    9337 GIC          36 :                 BooleanTest *btest = (BooleanTest *) node;
    9338                 : 
    9339              36 :                 if (!PRETTY_PAREN(context))
    9340              36 :                     appendStringInfoChar(buf, '(');
    9341 CBC          36 :                 get_rule_expr_paren((Node *) btest->arg, context, false, node);
    9342              36 :                 switch (btest->booltesttype)
    9343 EUB             :                 {
    9344 GIC           6 :                     case IS_TRUE:
    9345 GBC           6 :                         appendStringInfoString(buf, " IS TRUE");
    9346 GIC           6 :                         break;
    9347 CBC          12 :                     case IS_NOT_TRUE:
    9348 GBC          12 :                         appendStringInfoString(buf, " IS NOT TRUE");
    9349 CBC          12 :                         break;
    9350 UIC           0 :                     case IS_FALSE:
    9351 LBC           0 :                         appendStringInfoString(buf, " IS FALSE");
    9352 UBC           0 :                         break;
    9353 UIC           0 :                     case IS_NOT_FALSE:
    9354 LBC           0 :                         appendStringInfoString(buf, " IS NOT FALSE");
    9355 UIC           0 :                         break;
    9356 CBC           9 :                     case IS_UNKNOWN:
    9357               9 :                         appendStringInfoString(buf, " IS UNKNOWN");
    9358 GIC           9 :                         break;
    9359               9 :                     case IS_NOT_UNKNOWN:
    9360               9 :                         appendStringInfoString(buf, " IS NOT UNKNOWN");
    9361 CBC           9 :                         break;
    9362 UIC           0 :                     default:
    9363 LBC           0 :                         elog(ERROR, "unrecognized booltesttype: %d",
    9364 ECB             :                              (int) btest->booltesttype);
    9365                 :                 }
    9366 CBC          36 :                 if (!PRETTY_PAREN(context))
    9367 GIC          36 :                     appendStringInfoChar(buf, ')');
    9368                 :             }
    9369 CBC          36 :             break;
    9370                 : 
    9371              16 :         case T_CoerceToDomain:
    9372                 :             {
    9373              16 :                 CoerceToDomain *ctest = (CoerceToDomain *) node;
    9374 GIC          16 :                 Node       *arg = (Node *) ctest->arg;
    9375                 : 
    9376              16 :                 if (ctest->coercionformat == COERCE_IMPLICIT_CAST &&
    9377 CBC          11 :                     !showimplicit)
    9378                 :                 {
    9379 ECB             :                     /* don't show the implicit cast */
    9380 CBC          11 :                     get_rule_expr(arg, context, false);
    9381                 :                 }
    9382                 :                 else
    9383 ECB             :                 {
    9384 GIC           5 :                     get_coercion_expr(arg, context,
    9385 ECB             :                                       ctest->resulttype,
    9386                 :                                       ctest->resulttypmod,
    9387                 :                                       node);
    9388                 :                 }
    9389                 :             }
    9390 CBC          16 :             break;
    9391                 : 
    9392             140 :         case T_CoerceToDomainValue:
    9393 GIC         140 :             appendStringInfoString(buf, "VALUE");
    9394 CBC         140 :             break;
    9395 ECB             : 
    9396 GIC          32 :         case T_SetToDefault:
    9397 CBC          32 :             appendStringInfoString(buf, "DEFAULT");
    9398              32 :             break;
    9399 ECB             : 
    9400 GIC           9 :         case T_CurrentOfExpr:
    9401 ECB             :             {
    9402 GIC           9 :                 CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
    9403 ECB             : 
    9404 CBC           9 :                 if (cexpr->cursor_name)
    9405               9 :                     appendStringInfo(buf, "CURRENT OF %s",
    9406 GIC           9 :                                      quote_identifier(cexpr->cursor_name));
    9407                 :                 else
    9408 LBC           0 :                     appendStringInfo(buf, "CURRENT OF $%d",
    9409 ECB             :                                      cexpr->cursor_param);
    9410                 :             }
    9411 CBC           9 :             break;
    9412 ECB             : 
    9413 UIC           0 :         case T_NextValueExpr:
    9414                 :             {
    9415               0 :                 NextValueExpr *nvexpr = (NextValueExpr *) node;
    9416                 : 
    9417 ECB             :                 /*
    9418                 :                  * This isn't exactly nextval(), but that seems close enough
    9419                 :                  * for EXPLAIN's purposes.
    9420                 :                  */
    9421 UIC           0 :                 appendStringInfoString(buf, "nextval(");
    9422 UBC           0 :                 simple_quote_literal(buf,
    9423               0 :                                      generate_relation_name(nvexpr->seqid,
    9424                 :                                                             NIL));
    9425 UIC           0 :                 appendStringInfoChar(buf, ')');
    9426                 :             }
    9427               0 :             break;
    9428 ECB             : 
    9429 GIC          12 :         case T_InferenceElem:
    9430 ECB             :             {
    9431 GIC          12 :                 InferenceElem *iexpr = (InferenceElem *) node;
    9432 ECB             :                 bool        save_varprefix;
    9433                 :                 bool        need_parens;
    9434                 : 
    9435                 :                 /*
    9436                 :                  * InferenceElem can only refer to target relation, so a
    9437                 :                  * prefix is not useful, and indeed would cause parse errors.
    9438                 :                  */
    9439 CBC          12 :                 save_varprefix = context->varprefix;
    9440              12 :                 context->varprefix = false;
    9441 ECB             : 
    9442                 :                 /*
    9443                 :                  * Parenthesize the element unless it's a simple Var or a bare
    9444                 :                  * function call.  Follows pg_get_indexdef_worker().
    9445                 :                  */
    9446 GIC          12 :                 need_parens = !IsA(iexpr->expr, Var);
    9447 CBC          12 :                 if (IsA(iexpr->expr, FuncExpr) &&
    9448 LBC           0 :                     ((FuncExpr *) iexpr->expr)->funcformat ==
    9449                 :                     COERCE_EXPLICIT_CALL)
    9450               0 :                     need_parens = false;
    9451                 : 
    9452 CBC          12 :                 if (need_parens)
    9453 UIC           0 :                     appendStringInfoChar(buf, '(');
    9454 GIC          12 :                 get_rule_expr((Node *) iexpr->expr,
    9455                 :                               context, false);
    9456 CBC          12 :                 if (need_parens)
    9457 UIC           0 :                     appendStringInfoChar(buf, ')');
    9458 ECB             : 
    9459 CBC          12 :                 context->varprefix = save_varprefix;
    9460 ECB             : 
    9461 CBC          12 :                 if (iexpr->infercollid)
    9462               6 :                     appendStringInfo(buf, " COLLATE %s",
    9463 ECB             :                                      generate_collation_name(iexpr->infercollid));
    9464                 : 
    9465                 :                 /* Add the operator class name, if not default */
    9466 CBC          12 :                 if (iexpr->inferopclass)
    9467 ECB             :                 {
    9468 CBC           6 :                     Oid         inferopclass = iexpr->inferopclass;
    9469 GIC           6 :                     Oid         inferopcinputtype = get_opclass_input_type(iexpr->inferopclass);
    9470                 : 
    9471 CBC           6 :                     get_opclass_name(inferopclass, inferopcinputtype, buf);
    9472 ECB             :                 }
    9473                 :             }
    9474 CBC          12 :             break;
    9475 ECB             : 
    9476 GIC        1715 :         case T_PartitionBoundSpec:
    9477 ECB             :             {
    9478 GIC        1715 :                 PartitionBoundSpec *spec = (PartitionBoundSpec *) node;
    9479 ECB             :                 ListCell   *cell;
    9480                 :                 char       *sep;
    9481                 : 
    9482 GIC        1715 :                 if (spec->is_default)
    9483                 :                 {
    9484 CBC          76 :                     appendStringInfoString(buf, "DEFAULT");
    9485              76 :                     break;
    9486                 :                 }
    9487 ECB             : 
    9488 CBC        1639 :                 switch (spec->strategy)
    9489 ECB             :                 {
    9490 GIC          91 :                     case PARTITION_STRATEGY_HASH:
    9491              91 :                         Assert(spec->modulus > 0 && spec->remainder >= 0);
    9492 CBC          91 :                         Assert(spec->modulus > spec->remainder);
    9493                 : 
    9494              91 :                         appendStringInfoString(buf, "FOR VALUES");
    9495              91 :                         appendStringInfo(buf, " WITH (modulus %d, remainder %d)",
    9496 ECB             :                                          spec->modulus, spec->remainder);
    9497 GIC          91 :                         break;
    9498 EUB             : 
    9499 GBC         537 :                     case PARTITION_STRATEGY_LIST:
    9500 GIC         537 :                         Assert(spec->listdatums != NIL);
    9501                 : 
    9502             537 :                         appendStringInfoString(buf, "FOR VALUES IN (");
    9503             537 :                         sep = "";
    9504            1483 :                         foreach(cell, spec->listdatums)
    9505                 :                         {
    9506             946 :                             Const      *val = lfirst_node(Const, cell);
    9507                 : 
    9508             946 :                             appendStringInfoString(buf, sep);
    9509             946 :                             get_const_expr(val, context, -1);
    9510             946 :                             sep = ", ";
    9511                 :                         }
    9512                 : 
    9513             537 :                         appendStringInfoChar(buf, ')');
    9514             537 :                         break;
    9515                 : 
    9516 CBC        1011 :                     case PARTITION_STRATEGY_RANGE:
    9517 GIC        1011 :                         Assert(spec->lowerdatums != NIL &&
    9518                 :                                spec->upperdatums != NIL &&
    9519 ECB             :                                list_length(spec->lowerdatums) ==
    9520                 :                                list_length(spec->upperdatums));
    9521                 : 
    9522 CBC        1011 :                         appendStringInfo(buf, "FOR VALUES FROM %s TO %s",
    9523 ECB             :                                          get_range_partbound_string(spec->lowerdatums),
    9524                 :                                          get_range_partbound_string(spec->upperdatums));
    9525 GIC        1011 :                         break;
    9526                 : 
    9527 UIC           0 :                     default:
    9528               0 :                         elog(ERROR, "unrecognized partition strategy: %d",
    9529                 :                              (int) spec->strategy);
    9530                 :                         break;
    9531                 :                 }
    9532                 :             }
    9533 GIC        1639 :             break;
    9534 ECB             : 
    9535 GNC          24 :         case T_JsonValueExpr:
    9536                 :             {
    9537              24 :                 JsonValueExpr *jve = (JsonValueExpr *) node;
    9538                 : 
    9539              24 :                 get_rule_expr((Node *) jve->raw_expr, context, false);
    9540              24 :                 get_json_format(jve->format, context->buf);
    9541                 :             }
    9542              24 :             break;
    9543                 : 
    9544              36 :         case T_JsonConstructorExpr:
    9545              36 :             get_json_constructor((JsonConstructorExpr *) node, context, false);
    9546              36 :             break;
    9547                 : 
    9548              24 :         case T_JsonIsPredicate:
    9549                 :             {
    9550              24 :                 JsonIsPredicate *pred = (JsonIsPredicate *) node;
    9551                 : 
    9552              24 :                 if (!PRETTY_PAREN(context))
    9553              12 :                     appendStringInfoChar(context->buf, '(');
    9554                 : 
    9555              24 :                 get_rule_expr_paren(pred->expr, context, true, node);
    9556                 : 
    9557              24 :                 appendStringInfoString(context->buf, " IS JSON");
    9558                 : 
    9559                 :                 /* TODO: handle FORMAT clause */
    9560                 : 
    9561              24 :                 switch (pred->item_type)
    9562                 :                 {
    9563               6 :                     case JS_TYPE_SCALAR:
    9564               6 :                         appendStringInfoString(context->buf, " SCALAR");
    9565               6 :                         break;
    9566               6 :                     case JS_TYPE_ARRAY:
    9567               6 :                         appendStringInfoString(context->buf, " ARRAY");
    9568               6 :                         break;
    9569               6 :                     case JS_TYPE_OBJECT:
    9570               6 :                         appendStringInfoString(context->buf, " OBJECT");
    9571               6 :                         break;
    9572               6 :                     default:
    9573               6 :                         break;
    9574                 :                 }
    9575                 : 
    9576              24 :                 if (pred->unique_keys)
    9577               6 :                     appendStringInfoString(context->buf, " WITH UNIQUE KEYS");
    9578                 : 
    9579              24 :                 if (!PRETTY_PAREN(context))
    9580              12 :                     appendStringInfoChar(context->buf, ')');
    9581                 :             }
    9582              24 :             break;
    9583                 : 
    9584 GIC         940 :         case T_List:
    9585                 :             {
    9586                 :                 char       *sep;
    9587                 :                 ListCell   *l;
    9588                 : 
    9589 CBC         940 :                 sep = "";
    9590            2658 :                 foreach(l, (List *) node)
    9591                 :                 {
    9592            1718 :                     appendStringInfoString(buf, sep);
    9593 GIC        1718 :                     get_rule_expr((Node *) lfirst(l), context, showimplicit);
    9594 CBC        1718 :                     sep = ", ";
    9595 ECB             :                 }
    9596                 :             }
    9597 GIC         940 :             break;
    9598 ECB             : 
    9599 GIC          12 :         case T_TableFunc:
    9600              12 :             get_tablefunc((TableFunc *) node, context, showimplicit);
    9601              12 :             break;
    9602                 : 
    9603 UIC           0 :         default:
    9604               0 :             elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
    9605                 :             break;
    9606                 :     }
    9607                 : }
    9608                 : 
    9609                 : /*
    9610                 :  * get_rule_expr_toplevel       - Parse back a toplevel expression
    9611                 :  *
    9612                 :  * Same as get_rule_expr(), except that if the expr is just a Var, we pass
    9613 ECB             :  * istoplevel = true not false to get_variable().  This causes whole-row Vars
    9614                 :  * to get printed with decoration that will prevent expansion of "*".
    9615                 :  * We need to use this in contexts such as ROW() and VALUES(), where the
    9616                 :  * parser would expand "foo.*" appearing at top level.  (In principle we'd
    9617                 :  * use this in get_target_list() too, but that has additional worries about
    9618                 :  * whether to print AS, so it needs to invoke get_variable() directly anyway.)
    9619                 :  */
    9620                 : static void
    9621 GIC        1351 : get_rule_expr_toplevel(Node *node, deparse_context *context,
    9622 ECB             :                        bool showimplicit)
    9623                 : {
    9624 CBC        1351 :     if (node && IsA(node, Var))
    9625             514 :         (void) get_variable((Var *) node, 0, true, context);
    9626                 :     else
    9627 GIC         837 :         get_rule_expr(node, context, showimplicit);
    9628            1351 : }
    9629 ECB             : 
    9630                 : /*
    9631                 :  * get_rule_list_toplevel       - Parse back a list of toplevel expressions
    9632                 :  *
    9633                 :  * Apply get_rule_expr_toplevel() to each element of a List.
    9634                 :  *
    9635                 :  * This adds commas between the expressions, but caller is responsible
    9636                 :  * for printing surrounding decoration.
    9637                 :  */
    9638                 : static void
    9639 GBC         186 : get_rule_list_toplevel(List *lst, deparse_context *context,
    9640 ECB             :                        bool showimplicit)
    9641                 : {
    9642                 :     const char *sep;
    9643                 :     ListCell   *lc;
    9644                 : 
    9645 CBC         186 :     sep = "";
    9646             658 :     foreach(lc, lst)
    9647                 :     {
    9648 GIC         472 :         Node       *e = (Node *) lfirst(lc);
    9649                 : 
    9650             472 :         appendStringInfoString(context->buf, sep);
    9651 CBC         472 :         get_rule_expr_toplevel(e, context, showimplicit);
    9652             472 :         sep = ", ";
    9653 ECB             :     }
    9654 GIC         186 : }
    9655 ECB             : 
    9656                 : /*
    9657                 :  * get_rule_expr_funccall       - Parse back a function-call expression
    9658                 :  *
    9659                 :  * Same as get_rule_expr(), except that we guarantee that the output will
    9660                 :  * look like a function call, or like one of the things the grammar treats as
    9661                 :  * equivalent to a function call (see the func_expr_windowless production).
    9662                 :  * This is needed in places where the grammar uses func_expr_windowless and
    9663                 :  * you can't substitute a parenthesized a_expr.  If what we have isn't going
    9664                 :  * to look like a function call, wrap it in a dummy CAST() expression, which
    9665                 :  * will satisfy the grammar --- and, indeed, is likely what the user wrote to
    9666                 :  * produce such a thing.
    9667                 :  */
    9668                 : static void
    9669 CBC         276 : get_rule_expr_funccall(Node *node, deparse_context *context,
    9670 ECB             :                        bool showimplicit)
    9671                 : {
    9672 GIC         276 :     if (looks_like_function(node))
    9673             270 :         get_rule_expr(node, context, showimplicit);
    9674 ECB             :     else
    9675                 :     {
    9676 GIC           6 :         StringInfo  buf = context->buf;
    9677 ECB             : 
    9678 CBC           6 :         appendStringInfoString(buf, "CAST(");
    9679                 :         /* no point in showing any top-level implicit cast */
    9680 GIC           6 :         get_rule_expr(node, context, false);
    9681               6 :         appendStringInfo(buf, " AS %s)",
    9682 ECB             :                          format_type_with_typemod(exprType(node),
    9683                 :                                                   exprTypmod(node)));
    9684                 :     }
    9685 GIC         276 : }
    9686                 : 
    9687 ECB             : /*
    9688                 :  * Helper function to identify node types that satisfy func_expr_windowless.
    9689                 :  * If in doubt, "false" is always a safe answer.
    9690                 :  */
    9691                 : static bool
    9692 GIC         818 : looks_like_function(Node *node)
    9693 ECB             : {
    9694 GIC         818 :     if (node == NULL)
    9695 LBC           0 :         return false;           /* probably shouldn't happen */
    9696 CBC         818 :     switch (nodeTag(node))
    9697 ECB             :     {
    9698 GIC         341 :         case T_FuncExpr:
    9699                 :             /* OK, unless it's going to deparse as a cast */
    9700             401 :             return (((FuncExpr *) node)->funcformat == COERCE_EXPLICIT_CALL ||
    9701              60 :                     ((FuncExpr *) node)->funcformat == COERCE_SQL_SYNTAX);
    9702               3 :         case T_NullIfExpr:
    9703 ECB             :         case T_CoalesceExpr:
    9704                 :         case T_MinMaxExpr:
    9705                 :         case T_XmlExpr:
    9706                 :             /* these are all accepted by func_expr_common_subexpr */
    9707 GIC           3 :             return true;
    9708             474 :         default:
    9709             474 :             break;
    9710                 :     }
    9711             474 :     return false;
    9712                 : }
    9713                 : 
    9714                 : 
    9715                 : /*
    9716                 :  * get_oper_expr            - Parse back an OpExpr node
    9717 ECB             :  */
    9718                 : static void
    9719 CBC       24672 : get_oper_expr(OpExpr *expr, deparse_context *context)
    9720                 : {
    9721           24672 :     StringInfo  buf = context->buf;
    9722 GIC       24672 :     Oid         opno = expr->opno;
    9723           24672 :     List       *args = expr->args;
    9724                 : 
    9725           24672 :     if (!PRETTY_PAREN(context))
    9726           23770 :         appendStringInfoChar(buf, '(');
    9727           24672 :     if (list_length(args) == 2)
    9728 ECB             :     {
    9729                 :         /* binary operator */
    9730 GIC       24657 :         Node       *arg1 = (Node *) linitial(args);
    9731 CBC       24657 :         Node       *arg2 = (Node *) lsecond(args);
    9732 ECB             : 
    9733 GIC       24657 :         get_rule_expr_paren(arg1, context, true, (Node *) expr);
    9734           24657 :         appendStringInfo(buf, " %s ",
    9735                 :                          generate_operator_name(opno,
    9736 ECB             :                                                 exprType(arg1),
    9737                 :                                                 exprType(arg2)));
    9738 CBC       24657 :         get_rule_expr_paren(arg2, context, true, (Node *) expr);
    9739                 :     }
    9740                 :     else
    9741                 :     {
    9742 ECB             :         /* prefix operator */
    9743 GIC          15 :         Node       *arg = (Node *) linitial(args);
    9744                 : 
    9745              15 :         appendStringInfo(buf, "%s ",
    9746                 :                          generate_operator_name(opno,
    9747                 :                                                 InvalidOid,
    9748                 :                                                 exprType(arg)));
    9749              15 :         get_rule_expr_paren(arg, context, true, (Node *) expr);
    9750 ECB             :     }
    9751 GIC       24672 :     if (!PRETTY_PAREN(context))
    9752 CBC       23770 :         appendStringInfoChar(buf, ')');
    9753           24672 : }
    9754                 : 
    9755                 : /*
    9756                 :  * get_func_expr            - Parse back a FuncExpr node
    9757                 :  */
    9758                 : static void
    9759 GIC        5662 : get_func_expr(FuncExpr *expr, deparse_context *context,
    9760 ECB             :               bool showimplicit)
    9761 EUB             : {
    9762 GIC        5662 :     StringInfo  buf = context->buf;
    9763            5662 :     Oid         funcoid = expr->funcid;
    9764 ECB             :     Oid         argtypes[FUNC_MAX_ARGS];
    9765                 :     int         nargs;
    9766                 :     List       *argnames;
    9767                 :     bool        use_variadic;
    9768                 :     ListCell   *l;
    9769                 : 
    9770                 :     /*
    9771                 :      * If the function call came from an implicit coercion, then just show the
    9772                 :      * first argument --- unless caller wants to see implicit coercions.
    9773                 :      */
    9774 GIC        5662 :     if (expr->funcformat == COERCE_IMPLICIT_CAST && !showimplicit)
    9775                 :     {
    9776 CBC         847 :         get_rule_expr_paren((Node *) linitial(expr->args), context,
    9777                 :                             false, (Node *) expr);
    9778 GIC        2125 :         return;
    9779 ECB             :     }
    9780                 : 
    9781                 :     /*
    9782                 :      * If the function call came from a cast, then show the first argument
    9783                 :      * plus an explicit cast operation.
    9784                 :      */
    9785 CBC        4815 :     if (expr->funcformat == COERCE_EXPLICIT_CAST ||
    9786            4560 :         expr->funcformat == COERCE_IMPLICIT_CAST)
    9787 ECB             :     {
    9788 CBC         656 :         Node       *arg = linitial(expr->args);
    9789             656 :         Oid         rettype = expr->funcresulttype;
    9790                 :         int32       coercedTypmod;
    9791 ECB             : 
    9792                 :         /* Get the typmod if this is a length-coercion function */
    9793 GIC         656 :         (void) exprIsLengthCoercion((Node *) expr, &coercedTypmod);
    9794                 : 
    9795             656 :         get_coercion_expr(arg, context,
    9796                 :                           rettype, coercedTypmod,
    9797                 :                           (Node *) expr);
    9798 ECB             : 
    9799 GIC         656 :         return;
    9800                 :     }
    9801 ECB             : 
    9802                 :     /*
    9803                 :      * If the function was called using one of the SQL spec's random special
    9804                 :      * syntaxes, try to reproduce that.  If we don't recognize the function,
    9805                 :      * fall through.
    9806                 :      */
    9807 GIC        4159 :     if (expr->funcformat == COERCE_SQL_SYNTAX)
    9808                 :     {
    9809             625 :         if (get_func_sql_syntax(expr, context))
    9810 CBC         622 :             return;
    9811                 :     }
    9812                 : 
    9813                 :     /*
    9814 ECB             :      * Normal function: display as proname(args).  First we need to extract
    9815                 :      * the argument datatypes.
    9816                 :      */
    9817 CBC        3537 :     if (list_length(expr->args) > FUNC_MAX_ARGS)
    9818 UIC           0 :         ereport(ERROR,
    9819                 :                 (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
    9820                 :                  errmsg("too many arguments")));
    9821 GIC        3537 :     nargs = 0;
    9822            3537 :     argnames = NIL;
    9823            7563 :     foreach(l, expr->args)
    9824                 :     {
    9825            4026 :         Node       *arg = (Node *) lfirst(l);
    9826 ECB             : 
    9827 GIC        4026 :         if (IsA(arg, NamedArgExpr))
    9828               9 :             argnames = lappend(argnames, ((NamedArgExpr *) arg)->name);
    9829            4026 :         argtypes[nargs] = exprType(arg);
    9830 CBC        4026 :         nargs++;
    9831 ECB             :     }
    9832                 : 
    9833 GIC        3537 :     appendStringInfo(buf, "%s(",
    9834 ECB             :                      generate_function_name(funcoid, nargs,
    9835                 :                                             argnames, argtypes,
    9836 GIC        3537 :                                             expr->funcvariadic,
    9837                 :                                             &use_variadic,
    9838                 :                                             context->special_exprkind));
    9839            3537 :     nargs = 0;
    9840            7563 :     foreach(l, expr->args)
    9841 ECB             :     {
    9842 CBC        4026 :         if (nargs++ > 0)
    9843 GIC         809 :             appendStringInfoString(buf, ", ");
    9844            4026 :         if (use_variadic && lnext(expr->args, l) == NULL)
    9845 CBC           3 :             appendStringInfoString(buf, "VARIADIC ");
    9846 GIC        4026 :         get_rule_expr((Node *) lfirst(l), context, true);
    9847 ECB             :     }
    9848 CBC        3537 :     appendStringInfoChar(buf, ')');
    9849 ECB             : }
    9850                 : 
    9851                 : /*
    9852                 :  * get_agg_expr         - Parse back an Aggref node
    9853                 :  */
    9854                 : static void
    9855 CBC         892 : get_agg_expr(Aggref *aggref, deparse_context *context,
    9856                 :              Aggref *original_aggref)
    9857                 : {
    9858 GNC         892 :     get_agg_expr_helper(aggref, context, original_aggref, NULL, NULL,
    9859                 :                         false);
    9860             892 : }
    9861                 : 
    9862                 : /*
    9863                 :  * get_agg_expr_helper      - subroutine for get_agg_expr and
    9864                 :  *                          get_json_agg_constructor
    9865                 :  */
    9866                 : static void
    9867             910 : get_agg_expr_helper(Aggref *aggref, deparse_context *context,
    9868                 :                     Aggref *original_aggref, const char *funcname,
    9869                 :                     const char *options, bool is_json_objectagg)
    9870 ECB             : {
    9871 GIC         910 :     StringInfo  buf = context->buf;
    9872                 :     Oid         argtypes[FUNC_MAX_ARGS];
    9873                 :     int         nargs;
    9874 GNC         910 :     bool        use_variadic = false;
    9875                 : 
    9876                 :     /*
    9877 ECB             :      * For a combining aggregate, we look up and deparse the corresponding
    9878                 :      * partial aggregate instead.  This is necessary because our input
    9879                 :      * argument list has been replaced; the new argument list always has just
    9880                 :      * one element, which will point to a partial Aggref that supplies us with
    9881                 :      * transition states to combine.
    9882                 :      */
    9883 GIC         910 :     if (DO_AGGSPLIT_COMBINE(aggref->aggsplit))
    9884                 :     {
    9885                 :         TargetEntry *tle;
    9886 ECB             : 
    9887 CBC         130 :         Assert(list_length(aggref->args) == 1);
    9888 GIC         130 :         tle = linitial_node(TargetEntry, aggref->args);
    9889             130 :         resolve_special_varno((Node *) tle->expr, context,
    9890                 :                               get_agg_combine_expr, original_aggref);
    9891             130 :         return;
    9892                 :     }
    9893 ECB             : 
    9894                 :     /*
    9895                 :      * Mark as PARTIAL, if appropriate.  We look to the original aggref so as
    9896                 :      * to avoid printing this when recursing from the code just above.
    9897                 :      */
    9898 GIC         780 :     if (DO_AGGSPLIT_SKIPFINAL(original_aggref->aggsplit))
    9899 CBC          30 :         appendStringInfoString(buf, "PARTIAL ");
    9900 ECB             : 
    9901                 :     /* Extract the argument types as seen by the parser */
    9902 CBC         780 :     nargs = get_aggregate_argtypes(aggref, argtypes);
    9903                 : 
    9904 GNC         780 :     if (!funcname)
    9905             762 :         funcname = generate_function_name(aggref->aggfnoid, nargs, NIL,
    9906             762 :                                           argtypes, aggref->aggvariadic,
    9907                 :                                           &use_variadic,
    9908                 :                                           context->special_exprkind);
    9909                 : 
    9910 ECB             :     /* Print the aggregate name, schema-qualified if needed */
    9911 GNC         780 :     appendStringInfo(buf, "%s(%s", funcname,
    9912 GBC         780 :                      (aggref->aggdistinct != NIL) ? "DISTINCT " : "");
    9913                 : 
    9914 CBC         780 :     if (AGGKIND_IS_ORDERED_SET(aggref->aggkind))
    9915                 :     {
    9916                 :         /*
    9917 ECB             :          * Ordered-set aggregates do not use "*" syntax.  Also, we needn't
    9918                 :          * worry about inserting VARIADIC.  So we can just dump the direct
    9919                 :          * args as-is.
    9920                 :          */
    9921 CBC          14 :         Assert(!aggref->aggvariadic);
    9922 GIC          14 :         get_rule_expr((Node *) aggref->aggdirectargs, context, true);
    9923              14 :         Assert(aggref->aggorder != NIL);
    9924              14 :         appendStringInfoString(buf, ") WITHIN GROUP (ORDER BY ");
    9925 CBC          14 :         get_rule_orderby(aggref->aggorder, aggref->args, false, context);
    9926                 :     }
    9927 ECB             :     else
    9928                 :     {
    9929                 :         /* aggstar can be set only in zero-argument aggregates */
    9930 GIC         766 :         if (aggref->aggstar)
    9931             112 :             appendStringInfoChar(buf, '*');
    9932 ECB             :         else
    9933                 :         {
    9934                 :             ListCell   *l;
    9935                 :             int         i;
    9936                 : 
    9937 CBC         654 :             i = 0;
    9938            1387 :             foreach(l, aggref->args)
    9939                 :             {
    9940 GIC         733 :                 TargetEntry *tle = (TargetEntry *) lfirst(l);
    9941 CBC         733 :                 Node       *arg = (Node *) tle->expr;
    9942                 : 
    9943 GIC         733 :                 Assert(!IsA(arg, NamedArgExpr));
    9944             733 :                 if (tle->resjunk)
    9945              19 :                     continue;
    9946             714 :                 if (i++ > 0)
    9947                 :                 {
    9948 GNC          60 :                     if (is_json_objectagg)
    9949                 :                     {
    9950                 :                         /*
    9951                 :                          * the ABSENT ON NULL and WITH UNIQUE args are printed
    9952                 :                          * separately, so ignore them here
    9953                 :                          */
    9954               6 :                         if (i > 2)
    9955 UNC           0 :                             break;
    9956                 : 
    9957 GNC           6 :                         appendStringInfoString(buf, " : ");
    9958                 :                     }
    9959                 :                     else
    9960              54 :                         appendStringInfoString(buf, ", ");
    9961                 :                 }
    9962 GIC         714 :                 if (use_variadic && i == nargs)
    9963               4 :                     appendStringInfoString(buf, "VARIADIC ");
    9964 CBC         714 :                 get_rule_expr(arg, context, true);
    9965                 :             }
    9966                 :         }
    9967 ECB             : 
    9968 GIC         766 :         if (aggref->aggorder != NIL)
    9969 ECB             :         {
    9970 GBC          35 :             appendStringInfoString(buf, " ORDER BY ");
    9971 GIC          35 :             get_rule_orderby(aggref->aggorder, aggref->args, false, context);
    9972 ECB             :         }
    9973                 :     }
    9974                 : 
    9975 GNC         780 :     if (options)
    9976              18 :         appendStringInfoString(buf, options);
    9977                 : 
    9978 GIC         780 :     if (aggref->aggfilter != NULL)
    9979                 :     {
    9980              23 :         appendStringInfoString(buf, ") FILTER (WHERE ");
    9981              23 :         get_rule_expr((Node *) aggref->aggfilter, context, false);
    9982                 :     }
    9983 ECB             : 
    9984 GIC         780 :     appendStringInfoChar(buf, ')');
    9985 ECB             : }
    9986                 : 
    9987                 : /*
    9988                 :  * This is a helper function for get_agg_expr().  It's used when we deparse
    9989                 :  * a combining Aggref; resolve_special_varno locates the corresponding partial
    9990                 :  * Aggref and then calls this.
    9991                 :  */
    9992                 : static void
    9993 GIC         130 : get_agg_combine_expr(Node *node, deparse_context *context, void *callback_arg)
    9994 ECB             : {
    9995                 :     Aggref     *aggref;
    9996 GIC         130 :     Aggref     *original_aggref = callback_arg;
    9997                 : 
    9998 CBC         130 :     if (!IsA(node, Aggref))
    9999 UIC           0 :         elog(ERROR, "combining Aggref does not point to an Aggref");
   10000                 : 
   10001 GIC         130 :     aggref = (Aggref *) node;
   10002             130 :     get_agg_expr(aggref, context, original_aggref);
   10003             130 : }
   10004 ECB             : 
   10005 EUB             : /*
   10006                 :  * get_windowfunc_expr  - Parse back a WindowFunc node
   10007                 :  */
   10008 ECB             : static void
   10009 CBC         117 : get_windowfunc_expr(WindowFunc *wfunc, deparse_context *context)
   10010                 : {
   10011 GNC         117 :     get_windowfunc_expr_helper(wfunc, context, NULL, NULL, false);
   10012             117 : }
   10013                 : 
   10014                 : 
   10015                 : /*
   10016                 :  * get_windowfunc_expr_helper   - subroutine for get_windowfunc_expr and
   10017                 :  *                              get_json_agg_constructor
   10018                 :  */
   10019                 : static void
   10020             123 : get_windowfunc_expr_helper(WindowFunc *wfunc, deparse_context *context,
   10021                 :                            const char *funcname, const char *options,
   10022                 :                            bool is_json_objectagg)
   10023 ECB             : {
   10024 GIC         123 :     StringInfo  buf = context->buf;
   10025 ECB             :     Oid         argtypes[FUNC_MAX_ARGS];
   10026                 :     int         nargs;
   10027                 :     List       *argnames;
   10028 EUB             :     ListCell   *l;
   10029 ECB             : 
   10030 CBC         123 :     if (list_length(wfunc->args) > FUNC_MAX_ARGS)
   10031 UIC           0 :         ereport(ERROR,
   10032                 :                 (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
   10033 ECB             :                  errmsg("too many arguments")));
   10034 CBC         123 :     nargs = 0;
   10035 GIC         123 :     argnames = NIL;
   10036             192 :     foreach(l, wfunc->args)
   10037                 :     {
   10038 CBC          69 :         Node       *arg = (Node *) lfirst(l);
   10039                 : 
   10040 GIC          69 :         if (IsA(arg, NamedArgExpr))
   10041 LBC           0 :             argnames = lappend(argnames, ((NamedArgExpr *) arg)->name);
   10042 CBC          69 :         argtypes[nargs] = exprType(arg);
   10043 GIC          69 :         nargs++;
   10044                 :     }
   10045 ECB             : 
   10046 GNC         123 :     if (!funcname)
   10047             117 :         funcname = generate_function_name(wfunc->winfnoid, nargs, argnames,
   10048                 :                                           argtypes, false, NULL,
   10049                 :                                           context->special_exprkind);
   10050                 : 
   10051             123 :     appendStringInfo(buf, "%s(", funcname);
   10052                 : 
   10053                 :     /* winstar can be set only in zero-argument aggregates */
   10054 CBC         123 :     if (wfunc->winstar)
   10055 GIC          12 :         appendStringInfoChar(buf, '*');
   10056                 :     else
   10057                 :     {
   10058 GNC         111 :         if (is_json_objectagg)
   10059                 :         {
   10060               3 :             get_rule_expr((Node *) linitial(wfunc->args), context, false);
   10061               3 :             appendStringInfoString(buf, " : ");
   10062               3 :             get_rule_expr((Node *) lsecond(wfunc->args), context, false);
   10063                 :         }
   10064                 :         else
   10065             108 :             get_rule_expr((Node *) wfunc->args, context, true);
   10066                 :     }
   10067                 : 
   10068             123 :     if (options)
   10069               6 :         appendStringInfoString(buf, options);
   10070 ECB             : 
   10071 GIC         123 :     if (wfunc->aggfilter != NULL)
   10072 ECB             :     {
   10073 UIC           0 :         appendStringInfoString(buf, ") FILTER (WHERE ");
   10074 UBC           0 :         get_rule_expr((Node *) wfunc->aggfilter, context, false);
   10075 EUB             :     }
   10076                 : 
   10077 GIC         123 :     appendStringInfoString(buf, ") OVER ");
   10078 ECB             : 
   10079 GIC         123 :     foreach(l, context->windowClause)
   10080 ECB             :     {
   10081 GIC          21 :         WindowClause *wc = (WindowClause *) lfirst(l);
   10082 ECB             : 
   10083 GIC          21 :         if (wc->winref == wfunc->winref)
   10084 ECB             :         {
   10085 GIC          21 :             if (wc->name)
   10086 LBC           0 :                 appendStringInfoString(buf, quote_identifier(wc->name));
   10087 EUB             :             else
   10088 GIC          21 :                 get_rule_windowspec(wc, context->windowTList, context);
   10089 CBC          21 :             break;
   10090 ECB             :         }
   10091                 :     }
   10092 GIC         123 :     if (l == NULL)
   10093 ECB             :     {
   10094 GIC         102 :         if (context->windowClause)
   10095 LBC           0 :             elog(ERROR, "could not find window clause for winref %u",
   10096 EUB             :                  wfunc->winref);
   10097                 : 
   10098                 :         /*
   10099                 :          * In EXPLAIN, we don't have window context information available, so
   10100                 :          * we have to settle for this:
   10101                 :          */
   10102 GIC         102 :         appendStringInfoString(buf, "(?)");
   10103 ECB             :     }
   10104 GIC         123 : }
   10105 ECB             : 
   10106                 : /*
   10107                 :  * get_func_sql_syntax_time
   10108                 :  *
   10109                 :  * Parse back argument of SQL-syntax function call related to a time or a
   10110                 :  * timestamp.  These require a specific handling when their typmod is given
   10111                 :  * by the function caller through their SQL keyword.
   10112                 :  */
   10113                 : static void
   10114 GNC         366 : get_func_sql_syntax_time(List *args, deparse_context *context)
   10115                 : {
   10116             366 :     StringInfo  buf = context->buf;
   10117                 :     Const      *cons;
   10118                 : 
   10119             366 :     if (list_length(args) != 1)
   10120              24 :         return;
   10121                 : 
   10122             342 :     cons = (Const *) linitial(args);
   10123             342 :     Assert(IsA(cons, Const));
   10124                 : 
   10125             342 :     if (!cons->constisnull)
   10126                 :     {
   10127             333 :         appendStringInfoString(buf, "(");
   10128             333 :         get_rule_expr((Node *) cons, context, false);
   10129             333 :         appendStringInfoString(buf, ")");
   10130                 :     }
   10131                 : }
   10132                 : 
   10133                 : /*
   10134                 :  * get_func_sql_syntax      - Parse back a SQL-syntax function call
   10135                 :  *
   10136                 :  * Returns true if we successfully deparsed, false if we did not
   10137                 :  * recognize the function.
   10138                 :  */
   10139                 : static bool
   10140 GIC         625 : get_func_sql_syntax(FuncExpr *expr, deparse_context *context)
   10141                 : {
   10142 CBC         625 :     StringInfo  buf = context->buf;
   10143 GIC         625 :     Oid         funcoid = expr->funcid;
   10144 ECB             : 
   10145 GIC         625 :     switch (funcoid)
   10146                 :     {
   10147 CBC           6 :         case F_TIMEZONE_INTERVAL_TIMESTAMP:
   10148 ECB             :         case F_TIMEZONE_INTERVAL_TIMESTAMPTZ:
   10149                 :         case F_TIMEZONE_INTERVAL_TIMETZ:
   10150                 :         case F_TIMEZONE_TEXT_TIMESTAMP:
   10151                 :         case F_TIMEZONE_TEXT_TIMESTAMPTZ:
   10152                 :         case F_TIMEZONE_TEXT_TIMETZ:
   10153                 :             /* AT TIME ZONE ... note reversed argument order */
   10154 GIC           6 :             appendStringInfoChar(buf, '(');
   10155 CBC           6 :             get_rule_expr_paren((Node *) lsecond(expr->args), context, false,
   10156 ECB             :                                 (Node *) expr);
   10157 CBC           6 :             appendStringInfoString(buf, " AT TIME ZONE ");
   10158 GIC           6 :             get_rule_expr_paren((Node *) linitial(expr->args), context, false,
   10159                 :                                 (Node *) expr);
   10160               6 :             appendStringInfoChar(buf, ')');
   10161               6 :             return true;
   10162                 : 
   10163               3 :         case F_OVERLAPS_TIMESTAMPTZ_INTERVAL_TIMESTAMPTZ_INTERVAL:
   10164                 :         case F_OVERLAPS_TIMESTAMPTZ_INTERVAL_TIMESTAMPTZ_TIMESTAMPTZ:
   10165                 :         case F_OVERLAPS_TIMESTAMPTZ_TIMESTAMPTZ_TIMESTAMPTZ_INTERVAL:
   10166                 :         case F_OVERLAPS_TIMESTAMPTZ_TIMESTAMPTZ_TIMESTAMPTZ_TIMESTAMPTZ:
   10167                 :         case F_OVERLAPS_TIMESTAMP_INTERVAL_TIMESTAMP_INTERVAL:
   10168 ECB             :         case F_OVERLAPS_TIMESTAMP_INTERVAL_TIMESTAMP_TIMESTAMP:
   10169                 :         case F_OVERLAPS_TIMESTAMP_TIMESTAMP_TIMESTAMP_INTERVAL:
   10170                 :         case F_OVERLAPS_TIMESTAMP_TIMESTAMP_TIMESTAMP_TIMESTAMP:
   10171                 :         case F_OVERLAPS_TIMETZ_TIMETZ_TIMETZ_TIMETZ:
   10172                 :         case F_OVERLAPS_TIME_INTERVAL_TIME_INTERVAL:
   10173                 :         case F_OVERLAPS_TIME_INTERVAL_TIME_TIME:
   10174                 :         case F_OVERLAPS_TIME_TIME_TIME_INTERVAL:
   10175                 :         case F_OVERLAPS_TIME_TIME_TIME_TIME:
   10176                 :             /* (x1, x2) OVERLAPS (y1, y2) */
   10177 GIC           3 :             appendStringInfoString(buf, "((");
   10178               3 :             get_rule_expr((Node *) linitial(expr->args), context, false);
   10179               3 :             appendStringInfoString(buf, ", ");
   10180               3 :             get_rule_expr((Node *) lsecond(expr->args), context, false);
   10181               3 :             appendStringInfoString(buf, ") OVERLAPS (");
   10182 CBC           3 :             get_rule_expr((Node *) lthird(expr->args), context, false);
   10183               3 :             appendStringInfoString(buf, ", ");
   10184 GIC           3 :             get_rule_expr((Node *) lfourth(expr->args), context, false);
   10185 CBC           3 :             appendStringInfoString(buf, "))");
   10186               3 :             return true;
   10187                 : 
   10188               3 :         case F_EXTRACT_TEXT_DATE:
   10189 ECB             :         case F_EXTRACT_TEXT_TIME:
   10190                 :         case F_EXTRACT_TEXT_TIMETZ:
   10191                 :         case F_EXTRACT_TEXT_TIMESTAMP:
   10192                 :         case F_EXTRACT_TEXT_TIMESTAMPTZ:
   10193                 :         case F_EXTRACT_TEXT_INTERVAL:
   10194                 :             /* EXTRACT (x FROM y) */
   10195 GIC           3 :             appendStringInfoString(buf, "EXTRACT(");
   10196                 :             {
   10197               3 :                 Const      *con = (Const *) linitial(expr->args);
   10198                 : 
   10199               3 :                 Assert(IsA(con, Const) &&
   10200                 :                        con->consttype == TEXTOID &&
   10201                 :                        !con->constisnull);
   10202               3 :                 appendStringInfoString(buf, TextDatumGetCString(con->constvalue));
   10203                 :             }
   10204               3 :             appendStringInfoString(buf, " FROM ");
   10205 CBC           3 :             get_rule_expr((Node *) lsecond(expr->args), context, false);
   10206               3 :             appendStringInfoChar(buf, ')');
   10207               3 :             return true;
   10208 ECB             : 
   10209 CBC           6 :         case F_IS_NORMALIZED:
   10210 ECB             :             /* IS xxx NORMALIZED */
   10211 CBC           6 :             appendStringInfoString(buf, "(");
   10212               6 :             get_rule_expr_paren((Node *) linitial(expr->args), context, false,
   10213 ECB             :                                 (Node *) expr);
   10214 CBC           6 :             appendStringInfoString(buf, " IS");
   10215 GIC           6 :             if (list_length(expr->args) == 2)
   10216 ECB             :             {
   10217 GIC           3 :                 Const      *con = (Const *) lsecond(expr->args);
   10218                 : 
   10219               3 :                 Assert(IsA(con, Const) &&
   10220                 :                        con->consttype == TEXTOID &&
   10221                 :                        !con->constisnull);
   10222               3 :                 appendStringInfo(buf, " %s",
   10223 CBC           3 :                                  TextDatumGetCString(con->constvalue));
   10224                 :             }
   10225               6 :             appendStringInfoString(buf, " NORMALIZED)");
   10226 GIC           6 :             return true;
   10227 ECB             : 
   10228 GIC           3 :         case F_PG_COLLATION_FOR:
   10229                 :             /* COLLATION FOR */
   10230 CBC           3 :             appendStringInfoString(buf, "COLLATION FOR (");
   10231 GIC           3 :             get_rule_expr((Node *) linitial(expr->args), context, false);
   10232 CBC           3 :             appendStringInfoChar(buf, ')');
   10233               3 :             return true;
   10234 ECB             : 
   10235 CBC           6 :         case F_NORMALIZE:
   10236                 :             /* NORMALIZE() */
   10237               6 :             appendStringInfoString(buf, "NORMALIZE(");
   10238 GIC           6 :             get_rule_expr((Node *) linitial(expr->args), context, false);
   10239 CBC           6 :             if (list_length(expr->args) == 2)
   10240 ECB             :             {
   10241 GIC           3 :                 Const      *con = (Const *) lsecond(expr->args);
   10242 ECB             : 
   10243 CBC           3 :                 Assert(IsA(con, Const) &&
   10244                 :                        con->consttype == TEXTOID &&
   10245 ECB             :                        !con->constisnull);
   10246 GIC           3 :                 appendStringInfo(buf, ", %s",
   10247 CBC           3 :                                  TextDatumGetCString(con->constvalue));
   10248                 :             }
   10249 GIC           6 :             appendStringInfoChar(buf, ')');
   10250 CBC           6 :             return true;
   10251 ECB             : 
   10252 GIC           6 :         case F_OVERLAY_BIT_BIT_INT4:
   10253 ECB             :         case F_OVERLAY_BIT_BIT_INT4_INT4:
   10254                 :         case F_OVERLAY_BYTEA_BYTEA_INT4:
   10255                 :         case F_OVERLAY_BYTEA_BYTEA_INT4_INT4:
   10256                 :         case F_OVERLAY_TEXT_TEXT_INT4:
   10257                 :         case F_OVERLAY_TEXT_TEXT_INT4_INT4:
   10258                 :             /* OVERLAY() */
   10259 CBC           6 :             appendStringInfoString(buf, "OVERLAY(");
   10260               6 :             get_rule_expr((Node *) linitial(expr->args), context, false);
   10261               6 :             appendStringInfoString(buf, " PLACING ");
   10262 GIC           6 :             get_rule_expr((Node *) lsecond(expr->args), context, false);
   10263 CBC           6 :             appendStringInfoString(buf, " FROM ");
   10264 GIC           6 :             get_rule_expr((Node *) lthird(expr->args), context, false);
   10265 CBC           6 :             if (list_length(expr->args) == 4)
   10266 ECB             :             {
   10267 CBC           3 :                 appendStringInfoString(buf, " FOR ");
   10268 GIC           3 :                 get_rule_expr((Node *) lfourth(expr->args), context, false);
   10269 ECB             :             }
   10270 GIC           6 :             appendStringInfoChar(buf, ')');
   10271 CBC           6 :             return true;
   10272                 : 
   10273 GIC           3 :         case F_POSITION_BIT_BIT:
   10274 ECB             :         case F_POSITION_BYTEA_BYTEA:
   10275                 :         case F_POSITION_TEXT_TEXT:
   10276                 :             /* POSITION() ... extra parens since args are b_expr not a_expr */
   10277 CBC           3 :             appendStringInfoString(buf, "POSITION((");
   10278               3 :             get_rule_expr((Node *) lsecond(expr->args), context, false);
   10279 GIC           3 :             appendStringInfoString(buf, ") IN (");
   10280 CBC           3 :             get_rule_expr((Node *) linitial(expr->args), context, false);
   10281 GIC           3 :             appendStringInfoString(buf, "))");
   10282               3 :             return true;
   10283                 : 
   10284               3 :         case F_SUBSTRING_BIT_INT4:
   10285                 :         case F_SUBSTRING_BIT_INT4_INT4:
   10286                 :         case F_SUBSTRING_BYTEA_INT4:
   10287 ECB             :         case F_SUBSTRING_BYTEA_INT4_INT4:
   10288                 :         case F_SUBSTRING_TEXT_INT4:
   10289                 :         case F_SUBSTRING_TEXT_INT4_INT4:
   10290                 :             /* SUBSTRING FROM/FOR (i.e., integer-position variants) */
   10291 CBC           3 :             appendStringInfoString(buf, "SUBSTRING(");
   10292               3 :             get_rule_expr((Node *) linitial(expr->args), context, false);
   10293               3 :             appendStringInfoString(buf, " FROM ");
   10294 GIC           3 :             get_rule_expr((Node *) lsecond(expr->args), context, false);
   10295 CBC           3 :             if (list_length(expr->args) == 3)
   10296 ECB             :             {
   10297 GIC           3 :                 appendStringInfoString(buf, " FOR ");
   10298 CBC           3 :                 get_rule_expr((Node *) lthird(expr->args), context, false);
   10299 ECB             :             }
   10300 GIC           3 :             appendStringInfoChar(buf, ')');
   10301 CBC           3 :             return true;
   10302                 : 
   10303 GIC           3 :         case F_SUBSTRING_TEXT_TEXT_TEXT:
   10304                 :             /* SUBSTRING SIMILAR/ESCAPE */
   10305 CBC           3 :             appendStringInfoString(buf, "SUBSTRING(");
   10306               3 :             get_rule_expr((Node *) linitial(expr->args), context, false);
   10307               3 :             appendStringInfoString(buf, " SIMILAR ");
   10308               3 :             get_rule_expr((Node *) lsecond(expr->args), context, false);
   10309               3 :             appendStringInfoString(buf, " ESCAPE ");
   10310               3 :             get_rule_expr((Node *) lthird(expr->args), context, false);
   10311 GIC           3 :             appendStringInfoChar(buf, ')');
   10312 CBC           3 :             return true;
   10313                 : 
   10314 GIC           6 :         case F_BTRIM_BYTEA_BYTEA:
   10315                 :         case F_BTRIM_TEXT:
   10316                 :         case F_BTRIM_TEXT_TEXT:
   10317                 :             /* TRIM() */
   10318               6 :             appendStringInfoString(buf, "TRIM(BOTH");
   10319 CBC           6 :             if (list_length(expr->args) == 2)
   10320 ECB             :             {
   10321 CBC           6 :                 appendStringInfoChar(buf, ' ');
   10322               6 :                 get_rule_expr((Node *) lsecond(expr->args), context, false);
   10323 ECB             :             }
   10324 GIC           6 :             appendStringInfoString(buf, " FROM ");
   10325 CBC           6 :             get_rule_expr((Node *) linitial(expr->args), context, false);
   10326               6 :             appendStringInfoChar(buf, ')');
   10327 GIC           6 :             return true;
   10328 ECB             : 
   10329 CBC           6 :         case F_LTRIM_BYTEA_BYTEA:
   10330                 :         case F_LTRIM_TEXT:
   10331 ECB             :         case F_LTRIM_TEXT_TEXT:
   10332                 :             /* TRIM() */
   10333 CBC           6 :             appendStringInfoString(buf, "TRIM(LEADING");
   10334               6 :             if (list_length(expr->args) == 2)
   10335 ECB             :             {
   10336 CBC           6 :                 appendStringInfoChar(buf, ' ');
   10337               6 :                 get_rule_expr((Node *) lsecond(expr->args), context, false);
   10338 ECB             :             }
   10339 CBC           6 :             appendStringInfoString(buf, " FROM ");
   10340               6 :             get_rule_expr((Node *) linitial(expr->args), context, false);
   10341 GIC           6 :             appendStringInfoChar(buf, ')');
   10342 CBC           6 :             return true;
   10343                 : 
   10344 GIC           6 :         case F_RTRIM_BYTEA_BYTEA:
   10345                 :         case F_RTRIM_TEXT:
   10346 ECB             :         case F_RTRIM_TEXT_TEXT:
   10347                 :             /* TRIM() */
   10348 GIC           6 :             appendStringInfoString(buf, "TRIM(TRAILING");
   10349 CBC           6 :             if (list_length(expr->args) == 2)
   10350 ECB             :             {
   10351 GIC           3 :                 appendStringInfoChar(buf, ' ');
   10352 CBC           3 :                 get_rule_expr((Node *) lsecond(expr->args), context, false);
   10353 ECB             :             }
   10354 CBC           6 :             appendStringInfoString(buf, " FROM ");
   10355               6 :             get_rule_expr((Node *) linitial(expr->args), context, false);
   10356 GIC           6 :             appendStringInfoChar(buf, ')');
   10357 CBC           6 :             return true;
   10358                 : 
   10359 GNC           6 :         case F_CURRENT_CATALOG:
   10360               6 :             appendStringInfoString(buf, "CURRENT_CATALOG");
   10361               6 :             return true;
   10362               6 :         case F_CURRENT_ROLE:
   10363               6 :             appendStringInfoString(buf, "CURRENT_ROLE");
   10364               6 :             return true;
   10365               6 :         case F_CURRENT_SCHEMA:
   10366               6 :             appendStringInfoString(buf, "CURRENT_SCHEMA");
   10367               6 :             return true;
   10368             141 :         case F_CURRENT_USER:
   10369             141 :             appendStringInfoString(buf, "CURRENT_USER");
   10370             141 :             return true;
   10371               6 :         case F_USER:
   10372               6 :             appendStringInfoString(buf, "USER");
   10373               6 :             return true;
   10374              16 :         case F_SESSION_USER:
   10375              16 :             appendStringInfoString(buf, "SESSION_USER");
   10376              16 :             return true;
   10377               6 :         case F_SYSTEM_USER:
   10378               6 :             appendStringInfoString(buf, "SYSTEM_USER");
   10379               6 :             return true;
   10380                 : 
   10381               9 :         case F_CURRENT_DATE:
   10382               9 :             appendStringInfoString(buf, "CURRENT_DATE");
   10383               9 :             return true;
   10384              12 :         case F_CURRENT_TIME:
   10385              12 :             appendStringInfoString(buf, "CURRENT_TIME");
   10386              12 :             get_func_sql_syntax_time(expr->args, context);
   10387              12 :             return true;
   10388             318 :         case F_CURRENT_TIMESTAMP:
   10389             318 :             appendStringInfoString(buf, "CURRENT_TIMESTAMP");
   10390             318 :             get_func_sql_syntax_time(expr->args, context);
   10391             318 :             return true;
   10392              12 :         case F_LOCALTIME:
   10393              12 :             appendStringInfoString(buf, "LOCALTIME");
   10394              12 :             get_func_sql_syntax_time(expr->args, context);
   10395              12 :             return true;
   10396              24 :         case F_LOCALTIMESTAMP:
   10397              24 :             appendStringInfoString(buf, "LOCALTIMESTAMP");
   10398              24 :             get_func_sql_syntax_time(expr->args, context);
   10399              24 :             return true;
   10400                 : 
   10401 UIC           0 :         case F_XMLEXISTS:
   10402                 :             /* XMLEXISTS ... extra parens because args are c_expr */
   10403 LBC           0 :             appendStringInfoString(buf, "XMLEXISTS((");
   10404               0 :             get_rule_expr((Node *) linitial(expr->args), context, false);
   10405 UIC           0 :             appendStringInfoString(buf, ") PASSING (");
   10406 LBC           0 :             get_rule_expr((Node *) lsecond(expr->args), context, false);
   10407               0 :             appendStringInfoString(buf, "))");
   10408 UIC           0 :             return true;
   10409 ECB             :     }
   10410 CBC           3 :     return false;
   10411 ECB             : }
   10412                 : 
   10413                 : /* ----------
   10414                 :  * get_coercion_expr
   10415                 :  *
   10416                 :  *  Make a string representation of a value coerced to a specific type
   10417                 :  * ----------
   10418                 :  */
   10419                 : static void
   10420 GIC        1999 : get_coercion_expr(Node *arg, deparse_context *context,
   10421 ECB             :                   Oid resulttype, int32 resulttypmod,
   10422                 :                   Node *parentNode)
   10423                 : {
   10424 CBC        1999 :     StringInfo  buf = context->buf;
   10425 ECB             : 
   10426                 :     /*
   10427                 :      * Since parse_coerce.c doesn't immediately collapse application of
   10428                 :      * length-coercion functions to constants, what we'll typically see in
   10429                 :      * such cases is a Const with typmod -1 and a length-coercion function
   10430                 :      * right above it.  Avoid generating redundant output. However, beware of
   10431                 :      * suppressing casts when the user actually wrote something like
   10432                 :      * 'foo'::text::char(3).
   10433                 :      *
   10434                 :      * Note: it might seem that we are missing the possibility of needing to
   10435                 :      * print a COLLATE clause for such a Const.  However, a Const could only
   10436                 :      * have nondefault collation in a post-constant-folding tree, in which the
   10437                 :      * length coercion would have been folded too.  See also the special
   10438                 :      * handling of CollateExpr in coerce_to_target_type(): any collation
   10439                 :      * marking will be above the coercion node, not below it.
   10440                 :      */
   10441 CBC        1999 :     if (arg && IsA(arg, Const) &&
   10442             225 :         ((Const *) arg)->consttype == resulttype &&
   10443              12 :         ((Const *) arg)->consttypmod == -1)
   10444 ECB             :     {
   10445                 :         /* Show the constant without normal ::typename decoration */
   10446 CBC          12 :         get_const_expr((Const *) arg, context, -1);
   10447 ECB             :     }
   10448                 :     else
   10449                 :     {
   10450 GIC        1987 :         if (!PRETTY_PAREN(context))
   10451 CBC        1823 :             appendStringInfoChar(buf, '(');
   10452            1987 :         get_rule_expr_paren(arg, context, false, parentNode);
   10453            1987 :         if (!PRETTY_PAREN(context))
   10454            1823 :             appendStringInfoChar(buf, ')');
   10455 ECB             :     }
   10456                 : 
   10457                 :     /*
   10458                 :      * Never emit resulttype(arg) functional notation. A pg_proc entry could
   10459                 :      * take precedence, and a resulttype in pg_temp would require schema
   10460                 :      * qualification that format_type_with_typemod() would usually omit. We've
   10461                 :      * standardized on arg::resulttype, but CAST(arg AS resulttype) notation
   10462                 :      * would work fine.
   10463                 :      */
   10464 CBC        1999 :     appendStringInfo(buf, "::%s",
   10465 ECB             :                      format_type_with_typemod(resulttype, resulttypmod));
   10466 CBC        1999 : }
   10467 ECB             : 
   10468                 : /* ----------
   10469                 :  * get_const_expr
   10470                 :  *
   10471 EUB             :  *  Make a string representation of a Const
   10472                 :  *
   10473                 :  * showtype can be -1 to never show "::typename" decoration, or +1 to always
   10474                 :  * show it, or 0 to show it only if the constant wouldn't be assumed to be
   10475                 :  * the right type by default.
   10476                 :  *
   10477                 :  * If the Const's collation isn't default for its type, show that too.
   10478                 :  * We mustn't do this when showtype is -1 (since that means the caller will
   10479                 :  * print "::typename", and we can't put a COLLATE clause in between).  It's
   10480 ECB             :  * caller's responsibility that collation isn't missed in such cases.
   10481                 :  * ----------
   10482                 :  */
   10483                 : static void
   10484 GIC       28960 : get_const_expr(Const *constval, deparse_context *context, int showtype)
   10485                 : {
   10486           28960 :     StringInfo  buf = context->buf;
   10487                 :     Oid         typoutput;
   10488                 :     bool        typIsVarlena;
   10489                 :     char       *extval;
   10490 CBC       28960 :     bool        needlabel = false;
   10491                 : 
   10492 GIC       28960 :     if (constval->constisnull)
   10493                 :     {
   10494 ECB             :         /*
   10495                 :          * Always label the type of a NULL constant to prevent misdecisions
   10496                 :          * about type when reparsing.
   10497                 :          */
   10498 GIC         360 :         appendStringInfoString(buf, "NULL");
   10499             360 :         if (showtype >= 0)
   10500                 :         {
   10501             338 :             appendStringInfo(buf, "::%s",
   10502                 :                              format_type_with_typemod(constval->consttype,
   10503                 :                                                       constval->consttypmod));
   10504             338 :             get_const_collation(constval, context);
   10505                 :         }
   10506            3555 :         return;
   10507                 :     }
   10508                 : 
   10509           28600 :     getTypeOutputInfo(constval->consttype,
   10510                 :                       &typoutput, &typIsVarlena);
   10511 ECB             : 
   10512 CBC       28600 :     extval = OidOutputFunctionCall(typoutput, constval->constvalue);
   10513 ECB             : 
   10514 GIC       28600 :     switch (constval->consttype)
   10515                 :     {
   10516 CBC       16499 :         case INT4OID:
   10517                 : 
   10518                 :             /*
   10519                 :              * INT4 can be printed without any decoration, unless it is
   10520 ECB             :              * negative; in that case print it as '-nnn'::integer to ensure
   10521                 :              * that the output will re-parse as a constant, not as a constant
   10522                 :              * plus operator.  In most cases we could get away with printing
   10523                 :              * (-nnn) instead, because of the way that gram.y handles negative
   10524                 :              * literals; but that doesn't work for INT_MIN, and it doesn't
   10525                 :              * seem that much prettier anyway.
   10526                 :              */
   10527 GIC       16499 :             if (extval[0] != '-')
   10528           16243 :                 appendStringInfoString(buf, extval);
   10529                 :             else
   10530                 :             {
   10531             256 :                 appendStringInfo(buf, "'%s'", extval);
   10532             256 :                 needlabel = true;   /* we must attach a cast */
   10533                 :             }
   10534 CBC       16499 :             break;
   10535                 : 
   10536             508 :         case NUMERICOID:
   10537                 : 
   10538                 :             /*
   10539                 :              * NUMERIC can be printed without quotes if it looks like a float
   10540                 :              * constant (not an integer, and not Infinity or NaN) and doesn't
   10541                 :              * have a leading sign (for the same reason as for INT4).
   10542                 :              */
   10543 GIC         508 :             if (isdigit((unsigned char) extval[0]) &&
   10544             508 :                 strcspn(extval, "eE.") != strlen(extval))
   10545                 :             {
   10546             180 :                 appendStringInfoString(buf, extval);
   10547                 :             }
   10548                 :             else
   10549                 :             {
   10550             328 :                 appendStringInfo(buf, "'%s'", extval);
   10551             328 :                 needlabel = true;   /* we must attach a cast */
   10552                 :             }
   10553             508 :             break;
   10554 ECB             : 
   10555 GIC         669 :         case BOOLOID:
   10556 CBC         669 :             if (strcmp(extval, "t") == 0)
   10557 GIC         354 :                 appendStringInfoString(buf, "true");
   10558                 :             else
   10559             315 :                 appendStringInfoString(buf, "false");
   10560 CBC         669 :             break;
   10561                 : 
   10562           10924 :         default:
   10563 GIC       10924 :             simple_quote_literal(buf, extval);
   10564           10924 :             break;
   10565                 :     }
   10566                 : 
   10567           28600 :     pfree(extval);
   10568 ECB             : 
   10569 CBC       28600 :     if (showtype < 0)
   10570 GIC        3195 :         return;
   10571 ECB             : 
   10572                 :     /*
   10573                 :      * For showtype == 0, append ::typename unless the constant will be
   10574                 :      * implicitly typed as the right type when it is read in.
   10575                 :      *
   10576                 :      * XXX this code has to be kept in sync with the behavior of the parser,
   10577                 :      * especially make_const.
   10578                 :      */
   10579 CBC       25405 :     switch (constval->consttype)
   10580                 :     {
   10581 GIC         685 :         case BOOLOID:
   10582 ECB             :         case UNKNOWNOID:
   10583                 :             /* These types can be left unlabeled */
   10584 CBC         685 :             needlabel = false;
   10585 GIC         685 :             break;
   10586 CBC       14466 :         case INT4OID:
   10587                 :             /* We determined above whether a label is needed */
   10588 GIC       14466 :             break;
   10589             508 :         case NUMERICOID:
   10590                 : 
   10591                 :             /*
   10592                 :              * Float-looking constants will be typed as numeric, which we
   10593                 :              * checked above; but if there's a nondefault typmod we need to
   10594                 :              * show it.
   10595                 :              */
   10596             508 :             needlabel |= (constval->consttypmod >= 0);
   10597 CBC         508 :             break;
   10598            9746 :         default:
   10599 GIC        9746 :             needlabel = true;
   10600            9746 :             break;
   10601 ECB             :     }
   10602 CBC       25405 :     if (needlabel || showtype > 0)
   10603 GIC       10323 :         appendStringInfo(buf, "::%s",
   10604 ECB             :                          format_type_with_typemod(constval->consttype,
   10605                 :                                                   constval->consttypmod));
   10606                 : 
   10607 GIC       25405 :     get_const_collation(constval, context);
   10608                 : }
   10609                 : 
   10610                 : /*
   10611                 :  * helper for get_const_expr: append COLLATE if needed
   10612                 :  */
   10613 ECB             : static void
   10614 CBC       25743 : get_const_collation(Const *constval, deparse_context *context)
   10615                 : {
   10616           25743 :     StringInfo  buf = context->buf;
   10617                 : 
   10618 GIC       25743 :     if (OidIsValid(constval->constcollid))
   10619                 :     {
   10620 CBC        3672 :         Oid         typcollation = get_typcollation(constval->consttype);
   10621 ECB             : 
   10622 GIC        3672 :         if (constval->constcollid != typcollation)
   10623 ECB             :         {
   10624 GIC          35 :             appendStringInfo(buf, " COLLATE %s",
   10625 ECB             :                              generate_collation_name(constval->constcollid));
   10626                 :         }
   10627                 :     }
   10628 GIC       25743 : }
   10629 ECB             : 
   10630                 : /*
   10631                 :  * get_json_format          - Parse back a JsonFormat node
   10632                 :  */
   10633                 : static void
   10634 GNC          24 : get_json_format(JsonFormat *format, StringInfo buf)
   10635                 : {
   10636              24 :     if (format->format_type == JS_FORMAT_DEFAULT)
   10637 UNC           0 :         return;
   10638                 : 
   10639 GNC          24 :     appendStringInfoString(buf,
   10640              24 :                            format->format_type == JS_FORMAT_JSONB ?
   10641                 :                            " FORMAT JSONB" : " FORMAT JSON");
   10642                 : 
   10643              24 :     if (format->encoding != JS_ENC_DEFAULT)
   10644                 :     {
   10645                 :         const char *encoding;
   10646                 : 
   10647 UNC           0 :         encoding =
   10648               0 :             format->encoding == JS_ENC_UTF16 ? "UTF16" :
   10649               0 :             format->encoding == JS_ENC_UTF32 ? "UTF32" : "UTF8";
   10650                 : 
   10651               0 :         appendStringInfo(buf, " ENCODING %s", encoding);
   10652                 :     }
   10653                 : }
   10654                 : 
   10655                 : /*
   10656                 :  * get_json_returning       - Parse back a JsonReturning structure
   10657                 :  */
   10658                 : static void
   10659 GNC          36 : get_json_returning(JsonReturning *returning, StringInfo buf,
   10660                 :                    bool json_format_by_default)
   10661                 : {
   10662              36 :     if (!OidIsValid(returning->typid))
   10663 UNC           0 :         return;
   10664                 : 
   10665 GNC          36 :     appendStringInfo(buf, " RETURNING %s",
   10666                 :                      format_type_with_typemod(returning->typid,
   10667                 :                                               returning->typmod));
   10668                 : 
   10669              72 :     if (!json_format_by_default ||
   10670              36 :         returning->format->format_type !=
   10671              36 :         (returning->typid == JSONBOID ? JS_FORMAT_JSONB : JS_FORMAT_JSON))
   10672 UNC           0 :         get_json_format(returning->format, buf);
   10673                 : }
   10674                 : 
   10675                 : /*
   10676                 :  * get_json_constructor     - Parse back a JsonConstructorExpr node
   10677                 :  */
   10678                 : static void
   10679 GNC          36 : get_json_constructor(JsonConstructorExpr *ctor, deparse_context *context,
   10680                 :                      bool showimplicit)
   10681                 : {
   10682              36 :     StringInfo  buf = context->buf;
   10683                 :     const char *funcname;
   10684                 :     bool        is_json_object;
   10685                 :     int         curridx;
   10686                 :     ListCell   *lc;
   10687                 : 
   10688              36 :     if (ctor->type == JSCTOR_JSON_OBJECTAGG)
   10689                 :     {
   10690               9 :         get_json_agg_constructor(ctor, context, "JSON_OBJECTAGG", true);
   10691               9 :         return;
   10692                 :     }
   10693              27 :     else if (ctor->type == JSCTOR_JSON_ARRAYAGG)
   10694                 :     {
   10695              15 :         get_json_agg_constructor(ctor, context, "JSON_ARRAYAGG", false);
   10696              15 :         return;
   10697                 :     }
   10698                 : 
   10699              12 :     switch (ctor->type)
   10700                 :     {
   10701               6 :         case JSCTOR_JSON_OBJECT:
   10702               6 :             funcname = "JSON_OBJECT";
   10703               6 :             break;
   10704               6 :         case JSCTOR_JSON_ARRAY:
   10705               6 :             funcname = "JSON_ARRAY";
   10706               6 :             break;
   10707 UNC           0 :         default:
   10708               0 :             elog(ERROR, "invalid JsonConstructorType %d", ctor->type);
   10709                 :     }
   10710                 : 
   10711 GNC          12 :     appendStringInfo(buf, "%s(", funcname);
   10712                 : 
   10713              12 :     is_json_object = ctor->type == JSCTOR_JSON_OBJECT;
   10714              48 :     foreach(lc, ctor->args)
   10715                 :     {
   10716              36 :         curridx = foreach_current_index(lc);
   10717              36 :         if (curridx > 0)
   10718                 :         {
   10719                 :             const char *sep;
   10720                 : 
   10721              24 :             sep = (is_json_object && (curridx % 2) != 0) ? " : " : ", ";
   10722              24 :             appendStringInfoString(buf, sep);
   10723                 :         }
   10724                 : 
   10725              36 :         get_rule_expr((Node *) lfirst(lc), context, true);
   10726                 :     }
   10727                 : 
   10728              12 :     get_json_constructor_options(ctor, buf);
   10729              12 :     appendStringInfo(buf, ")");
   10730                 : }
   10731                 : 
   10732                 : /*
   10733                 :  * Append options, if any, to the JSON constructor being deparsed
   10734                 :  */
   10735                 : static void
   10736              36 : get_json_constructor_options(JsonConstructorExpr *ctor, StringInfo buf)
   10737                 : {
   10738              36 :     if (ctor->absent_on_null)
   10739                 :     {
   10740              12 :         if (ctor->type == JSCTOR_JSON_OBJECT ||
   10741              12 :             ctor->type == JSCTOR_JSON_OBJECTAGG)
   10742 UNC           0 :             appendStringInfoString(buf, " ABSENT ON NULL");
   10743                 :     }
   10744                 :     else
   10745                 :     {
   10746 GNC          24 :         if (ctor->type == JSCTOR_JSON_ARRAY ||
   10747              24 :             ctor->type == JSCTOR_JSON_ARRAYAGG)
   10748               9 :             appendStringInfoString(buf, " NULL ON NULL");
   10749                 :     }
   10750                 : 
   10751              36 :     if (ctor->unique)
   10752               9 :         appendStringInfoString(buf, " WITH UNIQUE KEYS");
   10753                 : 
   10754              36 :     get_json_returning(ctor->returning, buf, true);
   10755              36 : }
   10756                 : 
   10757                 : /*
   10758                 :  * get_json_agg_constructor - Parse back an aggregate JsonConstructorExpr node
   10759                 :  */
   10760                 : static void
   10761              24 : get_json_agg_constructor(JsonConstructorExpr *ctor, deparse_context *context,
   10762                 :                          const char *funcname, bool is_json_objectagg)
   10763                 : {
   10764                 :     StringInfoData options;
   10765                 : 
   10766              24 :     initStringInfo(&options);
   10767              24 :     get_json_constructor_options(ctor, &options);
   10768                 : 
   10769              24 :     if (IsA(ctor->func, Aggref))
   10770              18 :         get_agg_expr_helper((Aggref *) ctor->func, context,
   10771              18 :                             (Aggref *) ctor->func,
   10772              18 :                             funcname, options.data, is_json_objectagg);
   10773               6 :     else if (IsA(ctor->func, WindowFunc))
   10774               6 :         get_windowfunc_expr_helper((WindowFunc *) ctor->func, context,
   10775               6 :                                    funcname, options.data,
   10776                 :                                    is_json_objectagg);
   10777                 :     else
   10778 UNC           0 :         elog(ERROR, "invalid JsonConstructorExpr underlying node type: %d",
   10779                 :              nodeTag(ctor->func));
   10780 GNC          24 : }
   10781                 : 
   10782 ECB             : /*
   10783                 :  * simple_quote_literal - Format a string as a SQL literal, append to buf
   10784                 :  */
   10785                 : static void
   10786 CBC       11451 : simple_quote_literal(StringInfo buf, const char *val)
   10787                 : {
   10788                 :     const char *valptr;
   10789 ECB             : 
   10790                 :     /*
   10791                 :      * We form the string literal according to the prevailing setting of
   10792                 :      * standard_conforming_strings; we never use E''. User is responsible for
   10793                 :      * making sure result is used correctly.
   10794                 :      */
   10795 GIC       11451 :     appendStringInfoChar(buf, '\'');
   10796          118056 :     for (valptr = val; *valptr; valptr++)
   10797                 :     {
   10798          106605 :         char        ch = *valptr;
   10799                 : 
   10800          106605 :         if (SQL_STR_DOUBLE(ch, !standard_conforming_strings))
   10801 CBC         153 :             appendStringInfoChar(buf, ch);
   10802 GIC      106605 :         appendStringInfoChar(buf, ch);
   10803 ECB             :     }
   10804 GIC       11451 :     appendStringInfoChar(buf, '\'');
   10805           11451 : }
   10806 ECB             : 
   10807                 : 
   10808                 : /* ----------
   10809                 :  * get_sublink_expr         - Parse back a sublink
   10810                 :  * ----------
   10811                 :  */
   10812                 : static void
   10813 GIC         191 : get_sublink_expr(SubLink *sublink, deparse_context *context)
   10814                 : {
   10815             191 :     StringInfo  buf = context->buf;
   10816             191 :     Query      *query = (Query *) (sublink->subselect);
   10817             191 :     char       *opname = NULL;
   10818 ECB             :     bool        need_paren;
   10819                 : 
   10820 CBC         191 :     if (sublink->subLinkType == ARRAY_SUBLINK)
   10821               6 :         appendStringInfoString(buf, "ARRAY(");
   10822 ECB             :     else
   10823 GIC         185 :         appendStringInfoChar(buf, '(');
   10824 ECB             : 
   10825                 :     /*
   10826                 :      * Note that we print the name of only the first operator, when there are
   10827                 :      * multiple combining operators.  This is an approximation that could go
   10828                 :      * wrong in various scenarios (operators in different schemas, renamed
   10829                 :      * operators, etc) but there is not a whole lot we can do about it, since
   10830                 :      * the syntax allows only one operator to be shown.
   10831                 :      */
   10832 GIC         191 :     if (sublink->testexpr)
   10833                 :     {
   10834               9 :         if (IsA(sublink->testexpr, OpExpr))
   10835                 :         {
   10836 ECB             :             /* single combining operator */
   10837 GIC           3 :             OpExpr     *opexpr = (OpExpr *) sublink->testexpr;
   10838 ECB             : 
   10839 GIC           3 :             get_rule_expr(linitial(opexpr->args), context, true);
   10840 CBC           3 :             opname = generate_operator_name(opexpr->opno,
   10841 GIC           3 :                                             exprType(linitial(opexpr->args)),
   10842 CBC           3 :                                             exprType(lsecond(opexpr->args)));
   10843                 :         }
   10844               6 :         else if (IsA(sublink->testexpr, BoolExpr))
   10845                 :         {
   10846 ECB             :             /* multiple combining operators, = or <> cases */
   10847                 :             char       *sep;
   10848                 :             ListCell   *l;
   10849                 : 
   10850 CBC           3 :             appendStringInfoChar(buf, '(');
   10851 GIC           3 :             sep = "";
   10852               9 :             foreach(l, ((BoolExpr *) sublink->testexpr)->args)
   10853                 :             {
   10854               6 :                 OpExpr     *opexpr = lfirst_node(OpExpr, l);
   10855                 : 
   10856 CBC           6 :                 appendStringInfoString(buf, sep);
   10857 GIC           6 :                 get_rule_expr(linitial(opexpr->args), context, true);
   10858 CBC           6 :                 if (!opname)
   10859 GBC           3 :                     opname = generate_operator_name(opexpr->opno,
   10860 GIC           3 :                                                     exprType(linitial(opexpr->args)),
   10861 CBC           3 :                                                     exprType(lsecond(opexpr->args)));
   10862               6 :                 sep = ", ";
   10863                 :             }
   10864 GIC           3 :             appendStringInfoChar(buf, ')');
   10865 ECB             :         }
   10866 GIC           3 :         else if (IsA(sublink->testexpr, RowCompareExpr))
   10867                 :         {
   10868                 :             /* multiple combining operators, < <= > >= cases */
   10869 GBC           3 :             RowCompareExpr *rcexpr = (RowCompareExpr *) sublink->testexpr;
   10870 EUB             : 
   10871 GBC           3 :             appendStringInfoChar(buf, '(');
   10872 GIC           3 :             get_rule_expr((Node *) rcexpr->largs, context, true);
   10873 GBC           3 :             opname = generate_operator_name(linitial_oid(rcexpr->opnos),
   10874 GIC           3 :                                             exprType(linitial(rcexpr->largs)),
   10875               3 :                                             exprType(linitial(rcexpr->rargs)));
   10876               3 :             appendStringInfoChar(buf, ')');
   10877                 :         }
   10878                 :         else
   10879 UIC           0 :             elog(ERROR, "unrecognized testexpr type: %d",
   10880                 :                  (int) nodeTag(sublink->testexpr));
   10881 ECB             :     }
   10882                 : 
   10883 GIC         191 :     need_paren = true;
   10884 ECB             : 
   10885 GBC         191 :     switch (sublink->subLinkType)
   10886                 :     {
   10887 CBC          85 :         case EXISTS_SUBLINK:
   10888 GIC          85 :             appendStringInfoString(buf, "EXISTS ");
   10889              85 :             break;
   10890                 : 
   10891 CBC           6 :         case ANY_SUBLINK:
   10892               6 :             if (strcmp(opname, "=") == 0) /* Represent = ANY as IN */
   10893               3 :                 appendStringInfoString(buf, " IN ");
   10894 EUB             :             else
   10895 GIC           3 :                 appendStringInfo(buf, " %s ANY ", opname);
   10896               6 :             break;
   10897                 : 
   10898               3 :         case ALL_SUBLINK:
   10899               3 :             appendStringInfo(buf, " %s ALL ", opname);
   10900               3 :             break;
   10901 ECB             : 
   10902 UIC           0 :         case ROWCOMPARE_SUBLINK:
   10903               0 :             appendStringInfo(buf, " %s ", opname);
   10904 LBC           0 :             break;
   10905                 : 
   10906 GIC          97 :         case EXPR_SUBLINK:
   10907                 :         case MULTIEXPR_SUBLINK:
   10908                 :         case ARRAY_SUBLINK:
   10909              97 :             need_paren = false;
   10910 CBC          97 :             break;
   10911                 : 
   10912 LBC           0 :         case CTE_SUBLINK:       /* shouldn't occur in a SubLink */
   10913 ECB             :         default:
   10914 UIC           0 :             elog(ERROR, "unrecognized sublink type: %d",
   10915 ECB             :                  (int) sublink->subLinkType);
   10916                 :             break;
   10917                 :     }
   10918                 : 
   10919 GIC         191 :     if (need_paren)
   10920              94 :         appendStringInfoChar(buf, '(');
   10921 ECB             : 
   10922 GIC         191 :     get_query_def(query, buf, context->namespaces, NULL, false,
   10923 ECB             :                   context->prettyFlags, context->wrapColumn,
   10924                 :                   context->indentLevel);
   10925                 : 
   10926 CBC         191 :     if (need_paren)
   10927              94 :         appendStringInfoString(buf, "))");
   10928 ECB             :     else
   10929 GBC          97 :         appendStringInfoChar(buf, ')');
   10930             191 : }
   10931                 : 
   10932                 : 
   10933 ECB             : /* ----------
   10934                 :  * get_tablefunc            - Parse back a table function
   10935                 :  * ----------
   10936                 :  */
   10937                 : static void
   10938 CBC          25 : get_tablefunc(TableFunc *tf, deparse_context *context, bool showimplicit)
   10939 ECB             : {
   10940 GIC          25 :     StringInfo  buf = context->buf;
   10941                 : 
   10942                 :     /* XMLTABLE is the only existing implementation.  */
   10943 ECB             : 
   10944 CBC          25 :     appendStringInfoString(buf, "XMLTABLE(");
   10945                 : 
   10946 GIC          25 :     if (tf->ns_uris != NIL)
   10947 ECB             :     {
   10948                 :         ListCell   *lc1,
   10949                 :                    *lc2;
   10950 CBC           5 :         bool        first = true;
   10951 ECB             : 
   10952 GIC           5 :         appendStringInfoString(buf, "XMLNAMESPACES (");
   10953              10 :         forboth(lc1, tf->ns_uris, lc2, tf->ns_names)
   10954                 :         {
   10955               5 :             Node       *expr = (Node *) lfirst(lc1);
   10956               5 :             String     *ns_node = lfirst_node(String, lc2);
   10957                 : 
   10958 CBC           5 :             if (!first)
   10959 UIC           0 :                 appendStringInfoString(buf, ", ");
   10960 ECB             :             else
   10961 GIC           5 :                 first = false;
   10962 ECB             : 
   10963 CBC           5 :             if (ns_node != NULL)
   10964 EUB             :             {
   10965 GIC           5 :                 get_rule_expr(expr, context, showimplicit);
   10966               5 :                 appendStringInfo(buf, " AS %s", strVal(ns_node));
   10967                 :             }
   10968 ECB             :             else
   10969                 :             {
   10970 LBC           0 :                 appendStringInfoString(buf, "DEFAULT ");
   10971 UIC           0 :                 get_rule_expr(expr, context, showimplicit);
   10972                 :             }
   10973 ECB             :         }
   10974 CBC           5 :         appendStringInfoString(buf, "), ");
   10975                 :     }
   10976 ECB             : 
   10977 CBC          25 :     appendStringInfoChar(buf, '(');
   10978 GIC          25 :     get_rule_expr((Node *) tf->rowexpr, context, showimplicit);
   10979              25 :     appendStringInfoString(buf, ") PASSING (");
   10980              25 :     get_rule_expr((Node *) tf->docexpr, context, showimplicit);
   10981              25 :     appendStringInfoChar(buf, ')');
   10982                 : 
   10983 CBC          25 :     if (tf->colexprs != NIL)
   10984                 :     {
   10985                 :         ListCell   *l1;
   10986                 :         ListCell   *l2;
   10987                 :         ListCell   *l3;
   10988 ECB             :         ListCell   *l4;
   10989                 :         ListCell   *l5;
   10990 GIC          25 :         int         colnum = 0;
   10991 ECB             : 
   10992 CBC          25 :         appendStringInfoString(buf, " COLUMNS ");
   10993             172 :         forfive(l1, tf->colnames, l2, tf->coltypes, l3, tf->coltypmods,
   10994 ECB             :                 l4, tf->colexprs, l5, tf->coldefexprs)
   10995                 :         {
   10996 CBC         147 :             char       *colname = strVal(lfirst(l1));
   10997             147 :             Oid         typid = lfirst_oid(l2);
   10998 GIC         147 :             int32       typmod = lfirst_int(l3);
   10999             147 :             Node       *colexpr = (Node *) lfirst(l4);
   11000 GBC         147 :             Node       *coldefexpr = (Node *) lfirst(l5);
   11001 GIC         147 :             bool        ordinality = (tf->ordinalitycol == colnum);
   11002 CBC         147 :             bool        notnull = bms_is_member(colnum, tf->notnulls);
   11003                 : 
   11004 GIC         147 :             if (colnum > 0)
   11005             122 :                 appendStringInfoString(buf, ", ");
   11006             147 :             colnum++;
   11007                 : 
   11008 CBC         277 :             appendStringInfo(buf, "%s %s", quote_identifier(colname),
   11009                 :                              ordinality ? "FOR ORDINALITY" :
   11010 GIC         130 :                              format_type_with_typemod(typid, typmod));
   11011             147 :             if (ordinality)
   11012              17 :                 continue;
   11013                 : 
   11014             130 :             if (coldefexpr != NULL)
   11015                 :             {
   11016              17 :                 appendStringInfoString(buf, " DEFAULT (");
   11017 CBC          17 :                 get_rule_expr((Node *) coldefexpr, context, showimplicit);
   11018              17 :                 appendStringInfoChar(buf, ')');
   11019                 :             }
   11020             130 :             if (colexpr != NULL)
   11021                 :             {
   11022             124 :                 appendStringInfoString(buf, " PATH (");
   11023             124 :                 get_rule_expr((Node *) colexpr, context, showimplicit);
   11024             124 :                 appendStringInfoChar(buf, ')');
   11025                 :             }
   11026             130 :             if (notnull)
   11027              17 :                 appendStringInfoString(buf, " NOT NULL");
   11028                 :         }
   11029                 :     }
   11030                 : 
   11031 GIC          25 :     appendStringInfoChar(buf, ')');
   11032              25 : }
   11033                 : 
   11034                 : /* ----------
   11035 ECB             :  * get_from_clause          - Parse back a FROM clause
   11036                 :  *
   11037                 :  * "prefix" is the keyword that denotes the start of the list of FROM
   11038                 :  * elements. It is FROM when used to parse back SELECT and UPDATE, but
   11039                 :  * is USING when parsing back DELETE.
   11040                 :  * ----------
   11041                 :  */
   11042                 : static void
   11043 CBC        1932 : get_from_clause(Query *query, const char *prefix, deparse_context *context)
   11044                 : {
   11045            1932 :     StringInfo  buf = context->buf;
   11046 GIC        1932 :     bool        first = true;
   11047                 :     ListCell   *l;
   11048                 : 
   11049                 :     /*
   11050                 :      * We use the query's jointree as a guide to what to print.  However, we
   11051                 :      * must ignore auto-added RTEs that are marked not inFromCl. (These can
   11052                 :      * only appear at the top level of the jointree, so it's sufficient to
   11053                 :      * check here.)  This check also ensures we ignore the rule pseudo-RTEs
   11054 ECB             :      * for NEW and OLD.
   11055                 :      */
   11056 CBC        3860 :     foreach(l, query->jointree->fromlist)
   11057                 :     {
   11058 GIC        1928 :         Node       *jtnode = (Node *) lfirst(l);
   11059 ECB             : 
   11060 GIC        1928 :         if (IsA(jtnode, RangeTblRef))
   11061 ECB             :         {
   11062 CBC        1593 :             int         varno = ((RangeTblRef *) jtnode)->rtindex;
   11063            1593 :             RangeTblEntry *rte = rt_fetch(varno, query->rtable);
   11064 ECB             : 
   11065 GIC        1593 :             if (!rte->inFromCl)
   11066 CBC         185 :                 continue;
   11067                 :         }
   11068                 : 
   11069 GIC        1743 :         if (first)
   11070                 :         {
   11071            1591 :             appendContextKeyword(context, prefix,
   11072 ECB             :                                  -PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
   11073 CBC        1591 :             first = false;
   11074 ECB             : 
   11075 GIC        1591 :             get_from_clause_item(jtnode, query, context);
   11076 ECB             :         }
   11077                 :         else
   11078                 :         {
   11079                 :             StringInfoData itembuf;
   11080                 : 
   11081 CBC         152 :             appendStringInfoString(buf, ", ");
   11082 ECB             : 
   11083                 :             /*
   11084                 :              * Put the new FROM item's text into itembuf so we can decide
   11085                 :              * after we've got it whether or not it needs to go on a new line.
   11086                 :              */
   11087 GIC         152 :             initStringInfo(&itembuf);
   11088 CBC         152 :             context->buf = &itembuf;
   11089                 : 
   11090 GIC         152 :             get_from_clause_item(jtnode, query, context);
   11091 ECB             : 
   11092                 :             /* Restore context's output buffer */
   11093 CBC         152 :             context->buf = buf;
   11094 ECB             : 
   11095                 :             /* Consider line-wrapping if enabled */
   11096 CBC         152 :             if (PRETTY_INDENT(context) && context->wrapColumn >= 0)
   11097 ECB             :             {
   11098                 :                 /* Does the new item start with a new line? */
   11099 GIC         152 :                 if (itembuf.len > 0 && itembuf.data[0] == '\n')
   11100                 :                 {
   11101 EUB             :                     /* If so, we shouldn't add anything */
   11102                 :                     /* instead, remove any trailing spaces currently in buf */
   11103 UIC           0 :                     removeStringInfoSpaces(buf);
   11104                 :                 }
   11105 ECB             :                 else
   11106                 :                 {
   11107                 :                     char       *trailing_nl;
   11108                 : 
   11109                 :                     /* Locate the start of the current line in the buffer */
   11110 CBC         152 :                     trailing_nl = strrchr(buf->data, '\n');
   11111             152 :                     if (trailing_nl == NULL)
   11112 UIC           0 :                         trailing_nl = buf->data;
   11113 ECB             :                     else
   11114 CBC         152 :                         trailing_nl++;
   11115 ECB             : 
   11116                 :                     /*
   11117                 :                      * Add a newline, plus some indentation, if the new item
   11118                 :                      * would cause an overflow.
   11119                 :                      */
   11120 CBC         152 :                     if (strlen(trailing_nl) + itembuf.len > context->wrapColumn)
   11121             152 :                         appendContextKeyword(context, "", -PRETTYINDENT_STD,
   11122 ECB             :                                              PRETTYINDENT_STD,
   11123                 :                                              PRETTYINDENT_VAR);
   11124 EUB             :                 }
   11125                 :             }
   11126                 : 
   11127                 :             /* Add the new item */
   11128 CBC         152 :             appendBinaryStringInfo(buf, itembuf.data, itembuf.len);
   11129                 : 
   11130                 :             /* clean up */
   11131             152 :             pfree(itembuf.data);
   11132 ECB             :         }
   11133                 :     }
   11134 GBC        1932 : }
   11135                 : 
   11136 EUB             : static void
   11137 GIC        2743 : get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
   11138                 : {
   11139            2743 :     StringInfo  buf = context->buf;
   11140            2743 :     deparse_namespace *dpns = (deparse_namespace *) linitial(context->namespaces);
   11141 ECB             : 
   11142 CBC        2743 :     if (IsA(jtnode, RangeTblRef))
   11143                 :     {
   11144            2243 :         int         varno = ((RangeTblRef *) jtnode)->rtindex;
   11145 GIC        2243 :         RangeTblEntry *rte = rt_fetch(varno, query->rtable);
   11146            2243 :         deparse_columns *colinfo = deparse_columns_fetch(varno, dpns);
   11147            2243 :         RangeTblFunction *rtfunc1 = NULL;
   11148 ECB             : 
   11149 CBC        2243 :         if (rte->lateral)
   11150 GIC          32 :             appendStringInfoString(buf, "LATERAL ");
   11151 ECB             : 
   11152                 :         /* Print the FROM item proper */
   11153 GIC        2243 :         switch (rte->rtekind)
   11154                 :         {
   11155            1752 :             case RTE_RELATION:
   11156                 :                 /* Normal relation RTE */
   11157            3504 :                 appendStringInfo(buf, "%s%s",
   11158            1752 :                                  only_marker(rte),
   11159                 :                                  generate_relation_name(rte->relid,
   11160 ECB             :                                                         context->namespaces));
   11161 GIC        1752 :                 break;
   11162 CBC         119 :             case RTE_SUBQUERY:
   11163                 :                 /* Subquery RTE */
   11164 GIC         119 :                 appendStringInfoChar(buf, '(');
   11165             119 :                 get_query_def(rte->subquery, buf, context->namespaces, NULL,
   11166 ECB             :                               true,
   11167                 :                               context->prettyFlags, context->wrapColumn,
   11168                 :                               context->indentLevel);
   11169 GIC         119 :                 appendStringInfoChar(buf, ')');
   11170             119 :                 break;
   11171             267 :             case RTE_FUNCTION:
   11172 ECB             :                 /* Function RTE */
   11173 GIC         267 :                 rtfunc1 = (RangeTblFunction *) linitial(rte->functions);
   11174 ECB             : 
   11175                 :                 /*
   11176                 :                  * Omit ROWS FROM() syntax for just one function, unless it
   11177                 :                  * has both a coldeflist and WITH ORDINALITY. If it has both,
   11178                 :                  * we must use ROWS FROM() syntax to avoid ambiguity about
   11179                 :                  * whether the coldeflist includes the ordinality column.
   11180                 :                  */
   11181 GBC         267 :                 if (list_length(rte->functions) == 1 &&
   11182 GIC         252 :                     (rtfunc1->funccolnames == NIL || !rte->funcordinality))
   11183 ECB             :                 {
   11184 GIC         252 :                     get_rule_expr_funccall(rtfunc1->funcexpr, context, true);
   11185 ECB             :                     /* we'll print the coldeflist below, if it has one */
   11186                 :                 }
   11187                 :                 else
   11188                 :                 {
   11189                 :                     bool        all_unnest;
   11190                 :                     ListCell   *lc;
   11191                 : 
   11192 EUB             :                     /*
   11193                 :                      * If all the function calls in the list are to unnest,
   11194                 :                      * and none need a coldeflist, then collapse the list back
   11195                 :                      * down to UNNEST(args).  (If we had more than one
   11196 ECB             :                      * built-in unnest function, this would get more
   11197                 :                      * difficult.)
   11198                 :                      *
   11199                 :                      * XXX This is pretty ugly, since it makes not-terribly-
   11200                 :                      * future-proof assumptions about what the parser would do
   11201                 :                      * with the output; but the alternative is to emit our
   11202                 :                      * nonstandard ROWS FROM() notation for what might have
   11203                 :                      * been a perfectly spec-compliant multi-argument
   11204                 :                      * UNNEST().
   11205                 :                      */
   11206 GIC          15 :                     all_unnest = true;
   11207              39 :                     foreach(lc, rte->functions)
   11208                 :                     {
   11209              33 :                         RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
   11210                 : 
   11211              33 :                         if (!IsA(rtfunc->funcexpr, FuncExpr) ||
   11212 CBC          33 :                             ((FuncExpr *) rtfunc->funcexpr)->funcid != F_UNNEST_ANYARRAY ||
   11213 GIC          24 :                             rtfunc->funccolnames != NIL)
   11214 ECB             :                         {
   11215 CBC           9 :                             all_unnest = false;
   11216 GIC           9 :                             break;
   11217                 :                         }
   11218 ECB             :                     }
   11219                 : 
   11220 CBC          15 :                     if (all_unnest)
   11221 ECB             :                     {
   11222 CBC           6 :                         List       *allargs = NIL;
   11223 ECB             : 
   11224 CBC          24 :                         foreach(lc, rte->functions)
   11225                 :                         {
   11226              18 :                             RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
   11227              18 :                             List       *args = ((FuncExpr *) rtfunc->funcexpr)->args;
   11228 ECB             : 
   11229 GIC          18 :                             allargs = list_concat(allargs, args);
   11230 ECB             :                         }
   11231                 : 
   11232 CBC           6 :                         appendStringInfoString(buf, "UNNEST(");
   11233               6 :                         get_rule_expr((Node *) allargs, context, true);
   11234               6 :                         appendStringInfoChar(buf, ')');
   11235                 :                     }
   11236 ECB             :                     else
   11237                 :                     {
   11238 CBC           9 :                         int         funcno = 0;
   11239 ECB             : 
   11240 CBC           9 :                         appendStringInfoString(buf, "ROWS FROM(");
   11241 GIC          33 :                         foreach(lc, rte->functions)
   11242 ECB             :                         {
   11243 GIC          24 :                             RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
   11244 ECB             : 
   11245 CBC          24 :                             if (funcno > 0)
   11246              15 :                                 appendStringInfoString(buf, ", ");
   11247 GIC          24 :                             get_rule_expr_funccall(rtfunc->funcexpr, context, true);
   11248 CBC          24 :                             if (rtfunc->funccolnames != NIL)
   11249 ECB             :                             {
   11250                 :                                 /* Reconstruct the column definition list */
   11251 GIC           3 :                                 appendStringInfoString(buf, " AS ");
   11252               3 :                                 get_from_clause_coldeflist(rtfunc,
   11253 ECB             :                                                            NULL,
   11254                 :                                                            context);
   11255                 :                             }
   11256 GIC          24 :                             funcno++;
   11257                 :                         }
   11258               9 :                         appendStringInfoChar(buf, ')');
   11259                 :                     }
   11260                 :                     /* prevent printing duplicate coldeflist below */
   11261              15 :                     rtfunc1 = NULL;
   11262                 :                 }
   11263             267 :                 if (rte->funcordinality)
   11264               9 :                     appendStringInfoString(buf, " WITH ORDINALITY");
   11265 CBC         267 :                 break;
   11266 GIC          13 :             case RTE_TABLEFUNC:
   11267 CBC          13 :                 get_tablefunc(rte->tablefunc, context, true);
   11268              13 :                 break;
   11269 GIC           6 :             case RTE_VALUES:
   11270                 :                 /* Values list RTE */
   11271               6 :                 appendStringInfoChar(buf, '(');
   11272               6 :                 get_values_def(rte->values_lists, context);
   11273               6 :                 appendStringInfoChar(buf, ')');
   11274               6 :                 break;
   11275              86 :             case RTE_CTE:
   11276              86 :                 appendStringInfoString(buf, quote_identifier(rte->ctename));
   11277              86 :                 break;
   11278 LBC           0 :             default:
   11279 UIC           0 :                 elog(ERROR, "unrecognized RTE kind: %d", (int) rte->rtekind);
   11280 ECB             :                 break;
   11281                 :         }
   11282                 : 
   11283                 :         /* Print the relation alias, if needed */
   11284 CBC        2243 :         get_rte_alias(rte, varno, false, context);
   11285 ECB             : 
   11286                 :         /* Print the column definitions or aliases, if needed */
   11287 CBC        2243 :         if (rtfunc1 && rtfunc1->funccolnames != NIL)
   11288 ECB             :         {
   11289                 :             /* Reconstruct the columndef list, which is also the aliases */
   11290 UIC           0 :             get_from_clause_coldeflist(rtfunc1, colinfo, context);
   11291 ECB             :         }
   11292                 :         else
   11293                 :         {
   11294                 :             /* Else print column aliases as needed */
   11295 CBC        2243 :             get_column_alias_list(colinfo, context);
   11296                 :         }
   11297 ECB             : 
   11298                 :         /* Tablesample clause must go after any alias */
   11299 GIC        2243 :         if (rte->rtekind == RTE_RELATION && rte->tablesample)
   11300              16 :             get_tablesample_def(rte->tablesample, context);
   11301                 :     }
   11302             500 :     else if (IsA(jtnode, JoinExpr))
   11303 ECB             :     {
   11304 GIC         500 :         JoinExpr   *j = (JoinExpr *) jtnode;
   11305             500 :         deparse_columns *colinfo = deparse_columns_fetch(j->rtindex, dpns);
   11306                 :         bool        need_paren_on_right;
   11307                 : 
   11308            1219 :         need_paren_on_right = PRETTY_PAREN(context) &&
   11309 CBC         500 :             !IsA(j->rarg, RangeTblRef) &&
   11310 LBC           0 :             !(IsA(j->rarg, JoinExpr) && ((JoinExpr *) j->rarg)->alias != NULL);
   11311                 : 
   11312 CBC         500 :         if (!PRETTY_PAREN(context) || j->alias != NULL)
   11313 GIC         335 :             appendStringInfoChar(buf, '(');
   11314                 : 
   11315 CBC         500 :         get_from_clause_item(j->larg, query, context);
   11316                 : 
   11317 GIC         500 :         switch (j->jointype)
   11318 ECB             :         {
   11319 GIC         302 :             case JOIN_INNER:
   11320             302 :                 if (j->quals)
   11321 CBC         281 :                     appendContextKeyword(context, " JOIN ",
   11322                 :                                          -PRETTYINDENT_STD,
   11323                 :                                          PRETTYINDENT_STD,
   11324                 :                                          PRETTYINDENT_JOIN);
   11325 EUB             :                 else
   11326 GIC          21 :                     appendContextKeyword(context, " CROSS JOIN ",
   11327                 :                                          -PRETTYINDENT_STD,
   11328                 :                                          PRETTYINDENT_STD,
   11329                 :                                          PRETTYINDENT_JOIN);
   11330             302 :                 break;
   11331             147 :             case JOIN_LEFT:
   11332 CBC         147 :                 appendContextKeyword(context, " LEFT JOIN ",
   11333 ECB             :                                      -PRETTYINDENT_STD,
   11334 EUB             :                                      PRETTYINDENT_STD,
   11335                 :                                      PRETTYINDENT_JOIN);
   11336 CBC         147 :                 break;
   11337 GIC          51 :             case JOIN_FULL:
   11338              51 :                 appendContextKeyword(context, " FULL JOIN ",
   11339                 :                                      -PRETTYINDENT_STD,
   11340                 :                                      PRETTYINDENT_STD,
   11341                 :                                      PRETTYINDENT_JOIN);
   11342 CBC          51 :                 break;
   11343 LBC           0 :             case JOIN_RIGHT:
   11344 UIC           0 :                 appendContextKeyword(context, " RIGHT JOIN ",
   11345                 :                                      -PRETTYINDENT_STD,
   11346                 :                                      PRETTYINDENT_STD,
   11347                 :                                      PRETTYINDENT_JOIN);
   11348               0 :                 break;
   11349               0 :             default:
   11350 LBC           0 :                 elog(ERROR, "unrecognized join type: %d",
   11351                 :                      (int) j->jointype);
   11352                 :         }
   11353 ECB             : 
   11354 GIC         500 :         if (need_paren_on_right)
   11355 UIC           0 :             appendStringInfoChar(buf, '(');
   11356 CBC         500 :         get_from_clause_item(j->rarg, query, context);
   11357 GIC         500 :         if (need_paren_on_right)
   11358 UIC           0 :             appendStringInfoChar(buf, ')');
   11359 ECB             : 
   11360 GIC         500 :         if (j->usingClause)
   11361 ECB             :         {
   11362                 :             ListCell   *lc;
   11363 GIC         212 :             bool        first = true;
   11364 ECB             : 
   11365 GIC         212 :             appendStringInfoString(buf, " USING (");
   11366 ECB             :             /* Use the assigned names, not what's in usingClause */
   11367 CBC         502 :             foreach(lc, colinfo->usingNames)
   11368 ECB             :             {
   11369 CBC         290 :                 char       *colname = (char *) lfirst(lc);
   11370                 : 
   11371             290 :                 if (first)
   11372             212 :                     first = false;
   11373                 :                 else
   11374 GIC          78 :                     appendStringInfoString(buf, ", ");
   11375 CBC         290 :                 appendStringInfoString(buf, quote_identifier(colname));
   11376                 :             }
   11377             212 :             appendStringInfoChar(buf, ')');
   11378                 : 
   11379             212 :             if (j->join_using_alias)
   11380               6 :                 appendStringInfo(buf, " AS %s",
   11381 GIC           6 :                                  quote_identifier(j->join_using_alias->aliasname));
   11382                 :         }
   11383 CBC         288 :         else if (j->quals)
   11384 ECB             :         {
   11385 GIC         264 :             appendStringInfoString(buf, " ON ");
   11386 CBC         264 :             if (!PRETTY_PAREN(context))
   11387             261 :                 appendStringInfoChar(buf, '(');
   11388 GIC         264 :             get_rule_expr(j->quals, context, false);
   11389             264 :             if (!PRETTY_PAREN(context))
   11390             261 :                 appendStringInfoChar(buf, ')');
   11391 ECB             :         }
   11392 CBC          24 :         else if (j->jointype != JOIN_INNER)
   11393 ECB             :         {
   11394                 :             /* If we didn't say CROSS JOIN above, we must provide an ON */
   11395 CBC           3 :             appendStringInfoString(buf, " ON TRUE");
   11396                 :         }
   11397                 : 
   11398 GIC         500 :         if (!PRETTY_PAREN(context) || j->alias != NULL)
   11399             335 :             appendStringInfoChar(buf, ')');
   11400                 : 
   11401                 :         /* Yes, it's correct to put alias after the right paren ... */
   11402             500 :         if (j->alias != NULL)
   11403 ECB             :         {
   11404                 :             /*
   11405                 :              * Note that it's correct to emit an alias clause if and only if
   11406                 :              * there was one originally.  Otherwise we'd be converting a named
   11407                 :              * join to unnamed or vice versa, which creates semantic
   11408                 :              * subtleties we don't want.  However, we might print a different
   11409                 :              * alias name than was there originally.
   11410                 :              */
   11411 GIC          54 :             appendStringInfo(buf, " %s",
   11412              54 :                              quote_identifier(get_rtable_name(j->rtindex,
   11413                 :                                                               context)));
   11414              54 :             get_column_alias_list(colinfo, context);
   11415                 :         }
   11416                 :     }
   11417                 :     else
   11418 UIC           0 :         elog(ERROR, "unrecognized node type: %d",
   11419                 :              (int) nodeTag(jtnode));
   11420 GIC        2743 : }
   11421                 : 
   11422                 : /*
   11423                 :  * get_rte_alias - print the relation's alias, if needed
   11424                 :  *
   11425                 :  * If printed, the alias is preceded by a space, or by " AS " if use_as is true.
   11426                 :  */
   11427                 : static void
   11428 CBC        2507 : get_rte_alias(RangeTblEntry *rte, int varno, bool use_as,
   11429 ECB             :               deparse_context *context)
   11430                 : {
   11431 CBC        2507 :     deparse_namespace *dpns = (deparse_namespace *) linitial(context->namespaces);
   11432 GIC        2507 :     char       *refname = get_rtable_name(varno, context);
   11433 CBC        2507 :     deparse_columns *colinfo = deparse_columns_fetch(varno, dpns);
   11434            2507 :     bool        printalias = false;
   11435 ECB             : 
   11436 GIC        2507 :     if (rte->alias != NULL)
   11437 ECB             :     {
   11438                 :         /* Always print alias if user provided one */
   11439 GIC        1007 :         printalias = true;
   11440                 :     }
   11441            1500 :     else if (colinfo->printaliases)
   11442 ECB             :     {
   11443                 :         /* Always print alias if we need to print column aliases */
   11444 CBC         126 :         printalias = true;
   11445                 :     }
   11446            1374 :     else if (rte->rtekind == RTE_RELATION)
   11447                 :     {
   11448 ECB             :         /*
   11449                 :          * No need to print alias if it's same as relation name (this would
   11450                 :          * normally be the case, but not if set_rtable_names had to resolve a
   11451                 :          * conflict).
   11452                 :          */
   11453 GIC        1274 :         if (strcmp(refname, get_relation_name(rte->relid)) != 0)
   11454 CBC          19 :             printalias = true;
   11455 ECB             :     }
   11456 CBC         100 :     else if (rte->rtekind == RTE_FUNCTION)
   11457                 :     {
   11458                 :         /*
   11459                 :          * For a function RTE, always print alias.  This covers possible
   11460 ECB             :          * renaming of the function and/or instability of the FigureColname
   11461                 :          * rules for things that aren't simple functions.  Note we'd need to
   11462                 :          * force it anyway for the columndef list case.
   11463                 :          */
   11464 UIC           0 :         printalias = true;
   11465 ECB             :     }
   11466 GIC         100 :     else if (rte->rtekind == RTE_SUBQUERY ||
   11467 CBC          88 :              rte->rtekind == RTE_VALUES)
   11468 ECB             :     {
   11469                 :         /*
   11470                 :          * For a subquery, always print alias.  This makes the output
   11471                 :          * SQL-spec-compliant, even though we allow such aliases to be omitted
   11472                 :          * on input.
   11473                 :          */
   11474 CBC          18 :         printalias = true;
   11475                 :     }
   11476 GIC          82 :     else if (rte->rtekind == RTE_CTE)
   11477 ECB             :     {
   11478                 :         /*
   11479                 :          * No need to print alias if it's same as CTE name (this would
   11480                 :          * normally be the case, but not if set_rtable_names had to resolve a
   11481                 :          * conflict).
   11482                 :          */
   11483 GIC          69 :         if (strcmp(refname, rte->ctename) != 0)
   11484 CBC          11 :             printalias = true;
   11485                 :     }
   11486                 : 
   11487            2507 :     if (printalias)
   11488 GIC        1181 :         appendStringInfo(context->buf, "%s%s",
   11489 ECB             :                          use_as ? " AS " : " ",
   11490                 :                          quote_identifier(refname));
   11491 CBC        2507 : }
   11492 ECB             : 
   11493                 : /*
   11494                 :  * get_column_alias_list - print column alias list for an RTE
   11495                 :  *
   11496                 :  * Caller must already have printed the relation's alias name.
   11497                 :  */
   11498                 : static void
   11499 CBC        2297 : get_column_alias_list(deparse_columns *colinfo, deparse_context *context)
   11500 ECB             : {
   11501 CBC        2297 :     StringInfo  buf = context->buf;
   11502 ECB             :     int         i;
   11503 CBC        2297 :     bool        first = true;
   11504 EUB             : 
   11505                 :     /* Don't print aliases if not needed */
   11506 GIC        2297 :     if (!colinfo->printaliases)
   11507            1853 :         return;
   11508                 : 
   11509            2898 :     for (i = 0; i < colinfo->num_new_cols; i++)
   11510 ECB             :     {
   11511 GIC        2454 :         char       *colname = colinfo->new_colnames[i];
   11512                 : 
   11513 CBC        2454 :         if (first)
   11514                 :         {
   11515 GIC         444 :             appendStringInfoChar(buf, '(');
   11516 GBC         444 :             first = false;
   11517                 :         }
   11518                 :         else
   11519 GIC        2010 :             appendStringInfoString(buf, ", ");
   11520            2454 :         appendStringInfoString(buf, quote_identifier(colname));
   11521 ECB             :     }
   11522 GIC         444 :     if (!first)
   11523             444 :         appendStringInfoChar(buf, ')');
   11524                 : }
   11525 ECB             : 
   11526                 : /*
   11527                 :  * get_from_clause_coldeflist - reproduce FROM clause coldeflist
   11528                 :  *
   11529                 :  * When printing a top-level coldeflist (which is syntactically also the
   11530                 :  * relation's column alias list), use column names from colinfo.  But when
   11531                 :  * printing a coldeflist embedded inside ROWS FROM(), we prefer to use the
   11532                 :  * original coldeflist's names, which are available in rtfunc->funccolnames.
   11533                 :  * Pass NULL for colinfo to select the latter behavior.
   11534                 :  *
   11535                 :  * The coldeflist is appended immediately (no space) to buf.  Caller is
   11536 EUB             :  * responsible for ensuring that an alias or AS is present before it.
   11537                 :  */
   11538 ECB             : static void
   11539 CBC           3 : get_from_clause_coldeflist(RangeTblFunction *rtfunc,
   11540                 :                            deparse_columns *colinfo,
   11541 ECB             :                            deparse_context *context)
   11542                 : {
   11543 CBC           3 :     StringInfo  buf = context->buf;
   11544                 :     ListCell   *l1;
   11545 ECB             :     ListCell   *l2;
   11546                 :     ListCell   *l3;
   11547                 :     ListCell   *l4;
   11548                 :     int         i;
   11549                 : 
   11550 GIC           3 :     appendStringInfoChar(buf, '(');
   11551                 : 
   11552 CBC           3 :     i = 0;
   11553 GIC          12 :     forfour(l1, rtfunc->funccoltypes,
   11554                 :             l2, rtfunc->funccoltypmods,
   11555                 :             l3, rtfunc->funccolcollations,
   11556 ECB             :             l4, rtfunc->funccolnames)
   11557                 :     {
   11558 CBC           9 :         Oid         atttypid = lfirst_oid(l1);
   11559 GIC           9 :         int32       atttypmod = lfirst_int(l2);
   11560               9 :         Oid         attcollation = lfirst_oid(l3);
   11561                 :         char       *attname;
   11562 ECB             : 
   11563 CBC           9 :         if (colinfo)
   11564 LBC           0 :             attname = colinfo->colnames[i];
   11565                 :         else
   11566 GIC           9 :             attname = strVal(lfirst(l4));
   11567                 : 
   11568 CBC           9 :         Assert(attname);        /* shouldn't be any dropped columns here */
   11569 EUB             : 
   11570 GBC           9 :         if (i > 0)
   11571 GIC           6 :             appendStringInfoString(buf, ", ");
   11572               9 :         appendStringInfo(buf, "%s %s",
   11573                 :                          quote_identifier(attname),
   11574 EUB             :                          format_type_with_typemod(atttypid, atttypmod));
   11575 GBC          12 :         if (OidIsValid(attcollation) &&
   11576               3 :             attcollation != get_typcollation(atttypid))
   11577 UIC           0 :             appendStringInfo(buf, " COLLATE %s",
   11578                 :                              generate_collation_name(attcollation));
   11579                 : 
   11580 CBC           9 :         i++;
   11581 EUB             :     }
   11582 ECB             : 
   11583 CBC           3 :     appendStringInfoChar(buf, ')');
   11584 GBC           3 : }
   11585                 : 
   11586 ECB             : /*
   11587                 :  * get_tablesample_def          - print a TableSampleClause
   11588                 :  */
   11589                 : static void
   11590 GIC          16 : get_tablesample_def(TableSampleClause *tablesample, deparse_context *context)
   11591 ECB             : {
   11592 GIC          16 :     StringInfo  buf = context->buf;
   11593 ECB             :     Oid         argtypes[1];
   11594                 :     int         nargs;
   11595                 :     ListCell   *l;
   11596                 : 
   11597                 :     /*
   11598                 :      * We should qualify the handler's function name if it wouldn't be
   11599                 :      * resolved by lookup in the current search path.
   11600                 :      */
   11601 CBC          16 :     argtypes[0] = INTERNALOID;
   11602 GIC          16 :     appendStringInfo(buf, " TABLESAMPLE %s (",
   11603 ECB             :                      generate_function_name(tablesample->tsmhandler, 1,
   11604                 :                                             NIL, argtypes,
   11605                 :                                             false, NULL, EXPR_KIND_NONE));
   11606                 : 
   11607 CBC          16 :     nargs = 0;
   11608 GIC          32 :     foreach(l, tablesample->args)
   11609 ECB             :     {
   11610 GIC          16 :         if (nargs++ > 0)
   11611 LBC           0 :             appendStringInfoString(buf, ", ");
   11612 CBC          16 :         get_rule_expr((Node *) lfirst(l), context, false);
   11613 ECB             :     }
   11614 CBC          16 :     appendStringInfoChar(buf, ')');
   11615 ECB             : 
   11616 CBC          16 :     if (tablesample->repeatable != NULL)
   11617                 :     {
   11618               8 :         appendStringInfoString(buf, " REPEATABLE (");
   11619 GIC           8 :         get_rule_expr((Node *) tablesample->repeatable, context, false);
   11620               8 :         appendStringInfoChar(buf, ')');
   11621 ECB             :     }
   11622 GIC          16 : }
   11623                 : 
   11624 ECB             : /*
   11625                 :  * get_opclass_name         - fetch name of an index operator class
   11626                 :  *
   11627                 :  * The opclass name is appended (after a space) to buf.
   11628                 :  *
   11629                 :  * Output is suppressed if the opclass is the default for the given
   11630                 :  * actual_datatype.  (If you don't want this behavior, just pass
   11631                 :  * InvalidOid for actual_datatype.)
   11632                 :  */
   11633                 : static void
   11634 GIC        4810 : get_opclass_name(Oid opclass, Oid actual_datatype,
   11635                 :                  StringInfo buf)
   11636                 : {
   11637 ECB             :     HeapTuple   ht_opc;
   11638                 :     Form_pg_opclass opcrec;
   11639                 :     char       *opcname;
   11640                 :     char       *nspname;
   11641                 : 
   11642 GIC        4810 :     ht_opc = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
   11643            4810 :     if (!HeapTupleIsValid(ht_opc))
   11644 UBC           0 :         elog(ERROR, "cache lookup failed for opclass %u", opclass);
   11645 GIC        4810 :     opcrec = (Form_pg_opclass) GETSTRUCT(ht_opc);
   11646 ECB             : 
   11647 GIC        9602 :     if (!OidIsValid(actual_datatype) ||
   11648            4792 :         GetDefaultOpClass(actual_datatype, opcrec->opcmethod) != opclass)
   11649                 :     {
   11650                 :         /* Okay, we need the opclass name.  Do we need to qualify it? */
   11651             277 :         opcname = NameStr(opcrec->opcname);
   11652             277 :         if (OpclassIsVisible(opclass))
   11653             277 :             appendStringInfo(buf, " %s", quote_identifier(opcname));
   11654 ECB             :         else
   11655                 :         {
   11656 UIC           0 :             nspname = get_namespace_name_or_temp(opcrec->opcnamespace);
   11657 LBC           0 :             appendStringInfo(buf, " %s.%s",
   11658 ECB             :                              quote_identifier(nspname),
   11659                 :                              quote_identifier(opcname));
   11660                 :         }
   11661                 :     }
   11662 CBC        4810 :     ReleaseSysCache(ht_opc);
   11663 GIC        4810 : }
   11664                 : 
   11665 ECB             : /*
   11666                 :  * generate_opclass_name
   11667                 :  *      Compute the name to display for an opclass specified by OID
   11668                 :  *
   11669                 :  * The result includes all necessary quoting and schema-prefixing.
   11670                 :  */
   11671                 : char *
   11672 CBC           3 : generate_opclass_name(Oid opclass)
   11673                 : {
   11674                 :     StringInfoData buf;
   11675                 : 
   11676 GIC           3 :     initStringInfo(&buf);
   11677               3 :     get_opclass_name(opclass, InvalidOid, &buf);
   11678                 : 
   11679 CBC           3 :     return &buf.data[1];        /* get_opclass_name() prepends space */
   11680 ECB             : }
   11681                 : 
   11682                 : /*
   11683                 :  * processIndirection - take care of array and subfield assignment
   11684                 :  *
   11685                 :  * We strip any top-level FieldStore or assignment SubscriptingRef nodes that
   11686                 :  * appear in the input, printing them as decoration for the base column
   11687                 :  * name (which we assume the caller just printed).  We might also need to
   11688                 :  * strip CoerceToDomain nodes, but only ones that appear above assignment
   11689                 :  * nodes.
   11690 EUB             :  *
   11691                 :  * Returns the subexpression that's to be assigned.
   11692 ECB             :  */
   11693                 : static Node *
   11694 GIC         558 : processIndirection(Node *node, deparse_context *context)
   11695                 : {
   11696             558 :     StringInfo  buf = context->buf;
   11697             558 :     CoerceToDomain *cdomain = NULL;
   11698                 : 
   11699                 :     for (;;)
   11700 ECB             :     {
   11701 GIC         645 :         if (node == NULL)
   11702 LBC           0 :             break;
   11703 GIC         645 :         if (IsA(node, FieldStore))
   11704                 :         {
   11705              36 :             FieldStore *fstore = (FieldStore *) node;
   11706                 :             Oid         typrelid;
   11707                 :             char       *fieldname;
   11708                 : 
   11709 ECB             :             /* lookup tuple type */
   11710 CBC          36 :             typrelid = get_typ_typrelid(fstore->resulttype);
   11711 GIC          36 :             if (!OidIsValid(typrelid))
   11712 UIC           0 :                 elog(ERROR, "argument type %s of FieldStore is not a tuple type",
   11713 ECB             :                      format_type_be(fstore->resulttype));
   11714                 : 
   11715                 :             /*
   11716                 :              * Print the field name.  There should only be one target field in
   11717                 :              * stored rules.  There could be more than that in executable
   11718                 :              * target lists, but this function cannot be used for that case.
   11719                 :              */
   11720 GIC          36 :             Assert(list_length(fstore->fieldnums) == 1);
   11721              36 :             fieldname = get_attname(typrelid,
   11722              36 :                                     linitial_int(fstore->fieldnums), false);
   11723              36 :             appendStringInfo(buf, ".%s", quote_identifier(fieldname));
   11724                 : 
   11725 ECB             :             /*
   11726                 :              * We ignore arg since it should be an uninteresting reference to
   11727                 :              * the target column or subcolumn.
   11728                 :              */
   11729 CBC          36 :             node = (Node *) linitial(fstore->newvals);
   11730                 :         }
   11731 GIC         609 :         else if (IsA(node, SubscriptingRef))
   11732 ECB             :         {
   11733 CBC          39 :             SubscriptingRef *sbsref = (SubscriptingRef *) node;
   11734                 : 
   11735              39 :             if (sbsref->refassgnexpr == NULL)
   11736 UIC           0 :                 break;
   11737 ECB             : 
   11738 GIC          39 :             printSubscripts(sbsref, context);
   11739 ECB             : 
   11740                 :             /*
   11741                 :              * We ignore refexpr since it should be an uninteresting reference
   11742                 :              * to the target column or subcolumn.
   11743                 :              */
   11744 GIC          39 :             node = (Node *) sbsref->refassgnexpr;
   11745 ECB             :         }
   11746 CBC         570 :         else if (IsA(node, CoerceToDomain))
   11747                 :         {
   11748              12 :             cdomain = (CoerceToDomain *) node;
   11749 ECB             :             /* If it's an explicit domain coercion, we're done */
   11750 GIC          12 :             if (cdomain->coercionformat != COERCE_IMPLICIT_CAST)
   11751 UIC           0 :                 break;
   11752                 :             /* Tentatively descend past the CoerceToDomain */
   11753 GIC          12 :             node = (Node *) cdomain->arg;
   11754                 :         }
   11755                 :         else
   11756             558 :             break;
   11757                 :     }
   11758                 : 
   11759                 :     /*
   11760                 :      * If we descended past a CoerceToDomain whose argument turned out not to
   11761                 :      * be a FieldStore or array assignment, back up to the CoerceToDomain.
   11762                 :      * (This is not enough to be fully correct if there are nested implicit
   11763                 :      * CoerceToDomains, but such cases shouldn't ever occur.)
   11764                 :      */
   11765 CBC         558 :     if (cdomain && node == (Node *) cdomain->arg)
   11766 UIC           0 :         node = (Node *) cdomain;
   11767                 : 
   11768 GIC         558 :     return node;
   11769 ECB             : }
   11770                 : 
   11771                 : static void
   11772 GIC         131 : printSubscripts(SubscriptingRef *sbsref, deparse_context *context)
   11773                 : {
   11774             131 :     StringInfo  buf = context->buf;
   11775                 :     ListCell   *lowlist_item;
   11776 ECB             :     ListCell   *uplist_item;
   11777                 : 
   11778 CBC         131 :     lowlist_item = list_head(sbsref->reflowerindexpr);   /* could be NULL */
   11779             262 :     foreach(uplist_item, sbsref->refupperindexpr)
   11780                 :     {
   11781 GIC         131 :         appendStringInfoChar(buf, '[');
   11782             131 :         if (lowlist_item)
   11783                 :         {
   11784 ECB             :             /* If subexpression is NULL, get_rule_expr prints nothing */
   11785 LBC           0 :             get_rule_expr((Node *) lfirst(lowlist_item), context, false);
   11786               0 :             appendStringInfoChar(buf, ':');
   11787 UIC           0 :             lowlist_item = lnext(sbsref->reflowerindexpr, lowlist_item);
   11788                 :         }
   11789 ECB             :         /* If subexpression is NULL, get_rule_expr prints nothing */
   11790 GBC         131 :         get_rule_expr((Node *) lfirst(uplist_item), context, false);
   11791 GIC         131 :         appendStringInfoChar(buf, ']');
   11792 ECB             :     }
   11793 GIC         131 : }
   11794 ECB             : 
   11795                 : /*
   11796                 :  * quote_identifier         - Quote an identifier only if needed
   11797                 :  *
   11798                 :  * When quotes are needed, we palloc the required space; slightly
   11799                 :  * space-wasteful but well worth it for notational simplicity.
   11800                 :  */
   11801                 : const char *
   11802 CBC     1056314 : quote_identifier(const char *ident)
   11803 EUB             : {
   11804                 :     /*
   11805                 :      * Can avoid quoting if ident starts with a lowercase letter or underscore
   11806 ECB             :      * and contains only lowercase letters, digits, and underscores, *and* is
   11807                 :      * not any SQL keyword.  Otherwise, supply quotes.
   11808                 :      */
   11809 CBC     1056314 :     int         nquotes = 0;
   11810 ECB             :     bool        safe;
   11811                 :     const char *ptr;
   11812                 :     char       *result;
   11813                 :     char       *optr;
   11814                 : 
   11815                 :     /*
   11816                 :      * would like to use <ctype.h> macros here, but they might yield unwanted
   11817                 :      * locale-specific results...
   11818                 :      */
   11819 GIC     1056314 :     safe = ((ident[0] >= 'a' && ident[0] <= 'z') || ident[0] == '_');
   11820                 : 
   11821         8625457 :     for (ptr = ident; *ptr; ptr++)
   11822                 :     {
   11823         7569143 :         char        ch = *ptr;
   11824                 : 
   11825         7569143 :         if ((ch >= 'a' && ch <= 'z') ||
   11826          843761 :             (ch >= '0' && ch <= '9') ||
   11827 ECB             :             (ch == '_'))
   11828                 :         {
   11829                 :             /* okay */
   11830                 :         }
   11831                 :         else
   11832                 :         {
   11833 CBC       23897 :             safe = false;
   11834           23897 :             if (ch == '"')
   11835 GIC           6 :                 nquotes++;
   11836 ECB             :         }
   11837 EUB             :     }
   11838 ECB             : 
   11839 GIC     1056314 :     if (quote_all_identifiers)
   11840 CBC        5564 :         safe = false;
   11841                 : 
   11842         1056314 :     if (safe)
   11843                 :     {
   11844 ECB             :         /*
   11845                 :          * Check for keyword.  We quote keywords except for unreserved ones.
   11846                 :          * (In some cases we could avoid quoting a col_name or type_func_name
   11847                 :          * keyword, but it seems much harder than it's worth to tell that.)
   11848                 :          *
   11849                 :          * Note: ScanKeywordLookup() does case-insensitive comparison, but
   11850                 :          * that's fine, since we already know we have all-lower-case.
   11851                 :          */
   11852 GIC     1041297 :         int         kwnum = ScanKeywordLookup(ident, &ScanKeywords);
   11853                 : 
   11854         1041297 :         if (kwnum >= 0 && ScanKeywordCategories[kwnum] != UNRESERVED_KEYWORD)
   11855            1046 :             safe = false;
   11856                 :     }
   11857                 : 
   11858         1056314 :     if (safe)
   11859         1040251 :         return ident;           /* no change needed */
   11860 ECB             : 
   11861 GIC       16063 :     result = (char *) palloc(strlen(ident) + nquotes + 2 + 1);
   11862                 : 
   11863           16063 :     optr = result;
   11864           16063 :     *optr++ = '"';
   11865           97533 :     for (ptr = ident; *ptr; ptr++)
   11866                 :     {
   11867           81470 :         char        ch = *ptr;
   11868 ECB             : 
   11869 CBC       81470 :         if (ch == '"')
   11870 GBC           6 :             *optr++ = '"';
   11871 CBC       81470 :         *optr++ = ch;
   11872                 :     }
   11873           16063 :     *optr++ = '"';
   11874           16063 :     *optr = '\0';
   11875                 : 
   11876 GIC       16063 :     return result;
   11877 ECB             : }
   11878                 : 
   11879                 : /*
   11880                 :  * quote_qualified_identifier   - Quote a possibly-qualified identifier
   11881                 :  *
   11882 EUB             :  * Return a name of the form qualifier.ident, or just ident if qualifier
   11883                 :  * is NULL, quoting each component if necessary.  The result is palloc'd.
   11884                 :  */
   11885                 : char *
   11886 GIC      488282 : quote_qualified_identifier(const char *qualifier,
   11887                 :                            const char *ident)
   11888 ECB             : {
   11889                 :     StringInfoData buf;
   11890                 : 
   11891 GIC      488282 :     initStringInfo(&buf);
   11892          488282 :     if (qualifier)
   11893          200798 :         appendStringInfo(&buf, "%s.", quote_identifier(qualifier));
   11894          488282 :     appendStringInfoString(&buf, quote_identifier(ident));
   11895          488282 :     return buf.data;
   11896                 : }
   11897                 : 
   11898 ECB             : /*
   11899                 :  * get_relation_name
   11900                 :  *      Get the unqualified name of a relation specified by OID
   11901                 :  *
   11902                 :  * This differs from the underlying get_rel_name() function in that it will
   11903                 :  * throw error instead of silently returning NULL if the OID is bad.
   11904                 :  */
   11905                 : static char *
   11906 GIC        6844 : get_relation_name(Oid relid)
   11907                 : {
   11908            6844 :     char       *relname = get_rel_name(relid);
   11909                 : 
   11910            6844 :     if (!relname)
   11911 UIC           0 :         elog(ERROR, "cache lookup failed for relation %u", relid);
   11912 GIC        6844 :     return relname;
   11913                 : }
   11914                 : 
   11915                 : /*
   11916                 :  * generate_relation_name
   11917                 :  *      Compute the name to display for a relation specified by OID
   11918                 :  *
   11919                 :  * The result includes all necessary quoting and schema-prefixing.
   11920 ECB             :  *
   11921                 :  * If namespaces isn't NIL, it must be a list of deparse_namespace nodes.
   11922                 :  * We will forcibly qualify the relation name if it equals any CTE name
   11923                 :  * visible in the namespace list.
   11924                 :  */
   11925                 : static char *
   11926 GIC        3210 : generate_relation_name(Oid relid, List *namespaces)
   11927 ECB             : {
   11928 EUB             :     HeapTuple   tp;
   11929 ECB             :     Form_pg_class reltup;
   11930                 :     bool        need_qual;
   11931                 :     ListCell   *nslist;
   11932                 :     char       *relname;
   11933                 :     char       *nspname;
   11934                 :     char       *result;
   11935                 : 
   11936 CBC        3210 :     tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
   11937            3210 :     if (!HeapTupleIsValid(tp))
   11938 UBC           0 :         elog(ERROR, "cache lookup failed for relation %u", relid);
   11939 GIC        3210 :     reltup = (Form_pg_class) GETSTRUCT(tp);
   11940            3210 :     relname = NameStr(reltup->relname);
   11941                 : 
   11942                 :     /* Check for conflicting CTE name */
   11943            3210 :     need_qual = false;
   11944            5383 :     foreach(nslist, namespaces)
   11945                 :     {
   11946 CBC        2173 :         deparse_namespace *dpns = (deparse_namespace *) lfirst(nslist);
   11947 ECB             :         ListCell   *ctlist;
   11948                 : 
   11949 CBC        2203 :         foreach(ctlist, dpns->ctes)
   11950                 :         {
   11951 GIC          30 :             CommonTableExpr *cte = (CommonTableExpr *) lfirst(ctlist);
   11952                 : 
   11953              30 :             if (strcmp(cte->ctename, relname) == 0)
   11954                 :             {
   11955 LBC           0 :                 need_qual = true;
   11956 UIC           0 :                 break;
   11957 ECB             :             }
   11958                 :         }
   11959 CBC        2173 :         if (need_qual)
   11960 UIC           0 :             break;
   11961 ECB             :     }
   11962 EUB             : 
   11963                 :     /* Otherwise, qualify the name if not visible in search path */
   11964 CBC        3210 :     if (!need_qual)
   11965 GIC        3210 :         need_qual = !RelationIsVisible(relid);
   11966                 : 
   11967            3210 :     if (need_qual)
   11968            1079 :         nspname = get_namespace_name_or_temp(reltup->relnamespace);
   11969                 :     else
   11970 CBC        2131 :         nspname = NULL;
   11971                 : 
   11972            3210 :     result = quote_qualified_identifier(nspname, relname);
   11973                 : 
   11974            3210 :     ReleaseSysCache(tp);
   11975                 : 
   11976            3210 :     return result;
   11977 EUB             : }
   11978                 : 
   11979 ECB             : /*
   11980                 :  * generate_qualified_relation_name
   11981                 :  *      Compute the name to display for a relation specified by OID
   11982                 :  *
   11983                 :  * As above, but unconditionally schema-qualify the name.
   11984                 :  */
   11985                 : static char *
   11986 GIC        3205 : generate_qualified_relation_name(Oid relid)
   11987                 : {
   11988                 :     HeapTuple   tp;
   11989                 :     Form_pg_class reltup;
   11990                 :     char       *relname;
   11991 ECB             :     char       *nspname;
   11992 EUB             :     char       *result;
   11993                 : 
   11994 CBC        3205 :     tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
   11995 GIC        3205 :     if (!HeapTupleIsValid(tp))
   11996 UIC           0 :         elog(ERROR, "cache lookup failed for relation %u", relid);
   11997 GIC        3205 :     reltup = (Form_pg_class) GETSTRUCT(tp);
   11998 CBC        3205 :     relname = NameStr(reltup->relname);
   11999                 : 
   12000            3205 :     nspname = get_namespace_name_or_temp(reltup->relnamespace);
   12001 GIC        3205 :     if (!nspname)
   12002 UIC           0 :         elog(ERROR, "cache lookup failed for namespace %u",
   12003                 :              reltup->relnamespace);
   12004 ECB             : 
   12005 CBC        3205 :     result = quote_qualified_identifier(nspname, relname);
   12006                 : 
   12007            3205 :     ReleaseSysCache(tp);
   12008 ECB             : 
   12009 GIC        3205 :     return result;
   12010                 : }
   12011 EUB             : 
   12012                 : /*
   12013                 :  * generate_function_name
   12014                 :  *      Compute the name to display for a function specified by OID,
   12015                 :  *      given that it is being called with the specified actual arg names and
   12016 ECB             :  *      types.  (Those matter because of ambiguous-function resolution rules.)
   12017                 :  *
   12018                 :  * If we're dealing with a potentially variadic function (in practice, this
   12019                 :  * means a FuncExpr or Aggref, not some other way of calling a function), then
   12020                 :  * has_variadic must specify whether variadic arguments have been merged,
   12021                 :  * and *use_variadic_p will be set to indicate whether to print VARIADIC in
   12022                 :  * the output.  For non-FuncExpr cases, has_variadic should be false and
   12023                 :  * use_variadic_p can be NULL.
   12024                 :  *
   12025                 :  * The result includes all necessary quoting and schema-prefixing.
   12026                 :  */
   12027                 : static char *
   12028 CBC        5107 : generate_function_name(Oid funcid, int nargs, List *argnames, Oid *argtypes,
   12029                 :                        bool has_variadic, bool *use_variadic_p,
   12030                 :                        ParseExprKind special_exprkind)
   12031                 : {
   12032                 :     char       *result;
   12033                 :     HeapTuple   proctup;
   12034                 :     Form_pg_proc procform;
   12035 ECB             :     char       *proname;
   12036                 :     bool        use_variadic;
   12037                 :     char       *nspname;
   12038                 :     FuncDetailCode p_result;
   12039                 :     Oid         p_funcid;
   12040                 :     Oid         p_rettype;
   12041                 :     bool        p_retset;
   12042                 :     int         p_nvargs;
   12043                 :     Oid         p_vatype;
   12044                 :     Oid        *p_true_typeids;
   12045 CBC        5107 :     bool        force_qualify = false;
   12046                 : 
   12047            5107 :     proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
   12048 GIC        5107 :     if (!HeapTupleIsValid(proctup))
   12049 LBC           0 :         elog(ERROR, "cache lookup failed for function %u", funcid);
   12050 GIC        5107 :     procform = (Form_pg_proc) GETSTRUCT(proctup);
   12051 CBC        5107 :     proname = NameStr(procform->proname);
   12052 ECB             : 
   12053                 :     /*
   12054                 :      * Due to parser hacks to avoid needing to reserve CUBE, we need to force
   12055                 :      * qualification in some special cases.
   12056                 :      */
   12057 GIC        5107 :     if (special_exprkind == EXPR_KIND_GROUP_BY)
   12058                 :     {
   12059 LBC           0 :         if (strcmp(proname, "cube") == 0 || strcmp(proname, "rollup") == 0)
   12060               0 :             force_qualify = true;
   12061 ECB             :     }
   12062                 : 
   12063                 :     /*
   12064                 :      * Determine whether VARIADIC should be printed.  We must do this first
   12065                 :      * since it affects the lookup rules in func_get_detail().
   12066                 :      *
   12067                 :      * We always print VARIADIC if the function has a merged variadic-array
   12068                 :      * argument.  Note that this is always the case for functions taking a
   12069                 :      * VARIADIC argument type other than VARIADIC ANY.  If we omitted VARIADIC
   12070                 :      * and printed the array elements as separate arguments, the call could
   12071                 :      * match a newer non-VARIADIC function.
   12072                 :      */
   12073 GIC        5107 :     if (use_variadic_p)
   12074                 :     {
   12075                 :         /* Parser should not have set funcvariadic unless fn is variadic */
   12076            4299 :         Assert(!has_variadic || OidIsValid(procform->provariadic));
   12077            4299 :         use_variadic = has_variadic;
   12078 CBC        4299 :         *use_variadic_p = use_variadic;
   12079                 :     }
   12080 ECB             :     else
   12081                 :     {
   12082 GIC         808 :         Assert(!has_variadic);
   12083             808 :         use_variadic = false;
   12084 ECB             :     }
   12085                 : 
   12086                 :     /*
   12087                 :      * The idea here is to schema-qualify only if the parser would fail to
   12088                 :      * resolve the correct function given the unqualified func name with the
   12089                 :      * specified argtypes and VARIADIC flag.  But if we already decided to
   12090                 :      * force qualification, then we can skip the lookup and pretend we didn't
   12091                 :      * find it.
   12092                 :      */
   12093 CBC        5107 :     if (!force_qualify)
   12094 GIC        5107 :         p_result = func_get_detail(list_make1(makeString(proname)),
   12095 ECB             :                                    NIL, argnames, nargs, argtypes,
   12096 CBC        5107 :                                    !use_variadic, true, false,
   12097 ECB             :                                    &p_funcid, &p_rettype,
   12098                 :                                    &p_retset, &p_nvargs, &p_vatype,
   12099 CBC        5107 :                                    &p_true_typeids, NULL);
   12100 ECB             :     else
   12101                 :     {
   12102 LBC           0 :         p_result = FUNCDETAIL_NOTFOUND;
   12103 UIC           0 :         p_funcid = InvalidOid;
   12104                 :     }
   12105                 : 
   12106 GIC        5107 :     if ((p_result == FUNCDETAIL_NORMAL ||
   12107             589 :          p_result == FUNCDETAIL_AGGREGATE ||
   12108            4569 :          p_result == FUNCDETAIL_WINDOWFUNC) &&
   12109            4569 :         p_funcid == funcid)
   12110            4569 :         nspname = NULL;
   12111                 :     else
   12112 CBC         538 :         nspname = get_namespace_name_or_temp(procform->pronamespace);
   12113                 : 
   12114 GIC        5107 :     result = quote_qualified_identifier(nspname, proname);
   12115                 : 
   12116            5107 :     ReleaseSysCache(proctup);
   12117 ECB             : 
   12118 CBC        5107 :     return result;
   12119 ECB             : }
   12120                 : 
   12121                 : /*
   12122                 :  * generate_operator_name
   12123                 :  *      Compute the name to display for an operator specified by OID,
   12124                 :  *      given that it is being called with the specified actual arg types.
   12125                 :  *      (Arg types matter because of ambiguous-operator resolution rules.
   12126                 :  *      Pass InvalidOid for unused arg of a unary operator.)
   12127                 :  *
   12128                 :  * The result includes all necessary quoting and schema-prefixing,
   12129                 :  * plus the OPERATOR() decoration needed to use a qualified operator name
   12130                 :  * in an expression.
   12131                 :  */
   12132                 : static char *
   12133 GIC       26028 : generate_operator_name(Oid operid, Oid arg1, Oid arg2)
   12134 ECB             : {
   12135                 :     StringInfoData buf;
   12136                 :     HeapTuple   opertup;
   12137 EUB             :     Form_pg_operator operform;
   12138 ECB             :     char       *oprname;
   12139                 :     char       *nspname;
   12140                 :     Operator    p_result;
   12141                 : 
   12142 GIC       26028 :     initStringInfo(&buf);
   12143                 : 
   12144           26028 :     opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operid));
   12145           26028 :     if (!HeapTupleIsValid(opertup))
   12146 UIC           0 :         elog(ERROR, "cache lookup failed for operator %u", operid);
   12147 GIC       26028 :     operform = (Form_pg_operator) GETSTRUCT(opertup);
   12148           26028 :     oprname = NameStr(operform->oprname);
   12149                 : 
   12150                 :     /*
   12151                 :      * The idea here is to schema-qualify only if the parser would fail to
   12152 ECB             :      * resolve the correct operator given the unqualified op name with the
   12153                 :      * specified argtypes.
   12154                 :      */
   12155 GIC       26028 :     switch (operform->oprkind)
   12156                 :     {
   12157           26013 :         case 'b':
   12158           26013 :             p_result = oper(NULL, list_make1(makeString(oprname)), arg1, arg2,
   12159                 :                             true, -1);
   12160           26013 :             break;
   12161              15 :         case 'l':
   12162 CBC          15 :             p_result = left_oper(NULL, list_make1(makeString(oprname)), arg2,
   12163 ECB             :                                  true, -1);
   12164 GBC          15 :             break;
   12165 LBC           0 :         default:
   12166               0 :             elog(ERROR, "unrecognized oprkind: %d", operform->oprkind);
   12167                 :             p_result = NULL;    /* keep compiler quiet */
   12168                 :             break;
   12169 ECB             :     }
   12170                 : 
   12171 GIC       26028 :     if (p_result != NULL && oprid(p_result) == operid)
   12172 CBC       26023 :         nspname = NULL;
   12173                 :     else
   12174                 :     {
   12175               5 :         nspname = get_namespace_name_or_temp(operform->oprnamespace);
   12176 GIC           5 :         appendStringInfo(&buf, "OPERATOR(%s.", quote_identifier(nspname));
   12177 ECB             :     }
   12178                 : 
   12179 CBC       26028 :     appendStringInfoString(&buf, oprname);
   12180                 : 
   12181 GBC       26028 :     if (nspname)
   12182               5 :         appendStringInfoChar(&buf, ')');
   12183                 : 
   12184 GIC       26028 :     if (p_result != NULL)
   12185 CBC       26023 :         ReleaseSysCache(p_result);
   12186 EUB             : 
   12187 GIC       26028 :     ReleaseSysCache(opertup);
   12188                 : 
   12189           26028 :     return buf.data;
   12190 ECB             : }
   12191                 : 
   12192                 : /*
   12193                 :  * generate_operator_clause --- generate a binary-operator WHERE clause
   12194                 :  *
   12195                 :  * This is used for internally-generated-and-executed SQL queries, where
   12196                 :  * precision is essential and readability is secondary.  The basic
   12197                 :  * requirement is to append "leftop op rightop" to buf, where leftop and
   12198                 :  * rightop are given as strings and are assumed to yield types leftoptype
   12199                 :  * and rightoptype; the operator is identified by OID.  The complexity
   12200                 :  * comes from needing to be sure that the parser will select the desired
   12201                 :  * operator when the query is parsed.  We always name the operator using
   12202                 :  * OPERATOR(schema.op) syntax, so as to avoid search-path uncertainties.
   12203                 :  * We have to emit casts too, if either input isn't already the input type
   12204                 :  * of the operator; else we are at the mercy of the parser's heuristics for
   12205                 :  * ambiguous-operator resolution.  The caller must ensure that leftop and
   12206                 :  * rightop are suitable arguments for a cast operation; it's best to insert
   12207                 :  * parentheses if they aren't just variables or parameters.
   12208                 :  */
   12209                 : void
   12210 GIC        2508 : generate_operator_clause(StringInfo buf,
   12211                 :                          const char *leftop, Oid leftoptype,
   12212 ECB             :                          Oid opoid,
   12213                 :                          const char *rightop, Oid rightoptype)
   12214                 : {
   12215                 :     HeapTuple   opertup;
   12216                 :     Form_pg_operator operform;
   12217                 :     char       *oprname;
   12218                 :     char       *nspname;
   12219                 : 
   12220 CBC        2508 :     opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(opoid));
   12221            2508 :     if (!HeapTupleIsValid(opertup))
   12222 UBC           0 :         elog(ERROR, "cache lookup failed for operator %u", opoid);
   12223 CBC        2508 :     operform = (Form_pg_operator) GETSTRUCT(opertup);
   12224            2508 :     Assert(operform->oprkind == 'b');
   12225 GIC        2508 :     oprname = NameStr(operform->oprname);
   12226 ECB             : 
   12227 CBC        2508 :     nspname = get_namespace_name(operform->oprnamespace);
   12228 EUB             : 
   12229 GIC        2508 :     appendStringInfoString(buf, leftop);
   12230            2508 :     if (leftoptype != operform->oprleft)
   12231 CBC          21 :         add_cast_to(buf, operform->oprleft);
   12232 GIC        2508 :     appendStringInfo(buf, " OPERATOR(%s.", quote_identifier(nspname));
   12233 CBC        2508 :     appendStringInfoString(buf, oprname);
   12234 GIC        2508 :     appendStringInfo(buf, ") %s", rightop);
   12235 CBC        2508 :     if (rightoptype != operform->oprright)
   12236 GIC          30 :         add_cast_to(buf, operform->oprright);
   12237                 : 
   12238            2508 :     ReleaseSysCache(opertup);
   12239            2508 : }
   12240                 : 
   12241                 : /*
   12242                 :  * Add a cast specification to buf.  We spell out the type name the hard way,
   12243                 :  * intentionally not using format_type_be().  This is to avoid corner cases
   12244                 :  * for CHARACTER, BIT, and perhaps other types, where specifying the type
   12245                 :  * using SQL-standard syntax results in undesirable data truncation.  By
   12246                 :  * doing it this way we can be certain that the cast will have default (-1)
   12247                 :  * target typmod.
   12248                 :  */
   12249                 : static void
   12250              51 : add_cast_to(StringInfo buf, Oid typid)
   12251                 : {
   12252                 :     HeapTuple   typetup;
   12253                 :     Form_pg_type typform;
   12254 ECB             :     char       *typname;
   12255                 :     char       *nspname;
   12256                 : 
   12257 GIC          51 :     typetup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
   12258              51 :     if (!HeapTupleIsValid(typetup))
   12259 UIC           0 :         elog(ERROR, "cache lookup failed for type %u", typid);
   12260 GIC          51 :     typform = (Form_pg_type) GETSTRUCT(typetup);
   12261                 : 
   12262              51 :     typname = NameStr(typform->typname);
   12263              51 :     nspname = get_namespace_name_or_temp(typform->typnamespace);
   12264                 : 
   12265              51 :     appendStringInfo(buf, "::%s.%s",
   12266                 :                      quote_identifier(nspname), quote_identifier(typname));
   12267                 : 
   12268              51 :     ReleaseSysCache(typetup);
   12269              51 : }
   12270                 : 
   12271 ECB             : /*
   12272                 :  * generate_qualified_type_name
   12273                 :  *      Compute the name to display for a type specified by OID
   12274                 :  *
   12275 EUB             :  * This is different from format_type_be() in that we unconditionally
   12276 ECB             :  * schema-qualify the name.  That also means no special syntax for
   12277                 :  * SQL-standard type names ... although in current usage, this should
   12278                 :  * only get used for domains, so such cases wouldn't occur anyway.
   12279                 :  */
   12280                 : static char *
   12281 GIC           7 : generate_qualified_type_name(Oid typid)
   12282                 : {
   12283 ECB             :     HeapTuple   tp;
   12284                 :     Form_pg_type typtup;
   12285 EUB             :     char       *typname;
   12286                 :     char       *nspname;
   12287                 :     char       *result;
   12288                 : 
   12289 GIC           7 :     tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
   12290               7 :     if (!HeapTupleIsValid(tp))
   12291 UIC           0 :         elog(ERROR, "cache lookup failed for type %u", typid);
   12292 GIC           7 :     typtup = (Form_pg_type) GETSTRUCT(tp);
   12293               7 :     typname = NameStr(typtup->typname);
   12294                 : 
   12295               7 :     nspname = get_namespace_name_or_temp(typtup->typnamespace);
   12296               7 :     if (!nspname)
   12297 UIC           0 :         elog(ERROR, "cache lookup failed for namespace %u",
   12298                 :              typtup->typnamespace);
   12299 ECB             : 
   12300 GIC           7 :     result = quote_qualified_identifier(nspname, typname);
   12301                 : 
   12302 CBC           7 :     ReleaseSysCache(tp);
   12303 ECB             : 
   12304 CBC           7 :     return result;
   12305                 : }
   12306                 : 
   12307                 : /*
   12308 ECB             :  * generate_collation_name
   12309                 :  *      Compute the name to display for a collation specified by OID
   12310                 :  *
   12311                 :  * The result includes all necessary quoting and schema-prefixing.
   12312                 :  */
   12313                 : char *
   12314 GIC         155 : generate_collation_name(Oid collid)
   12315                 : {
   12316                 :     HeapTuple   tp;
   12317                 :     Form_pg_collation colltup;
   12318                 :     char       *collname;
   12319 ECB             :     char       *nspname;
   12320                 :     char       *result;
   12321                 : 
   12322 CBC         155 :     tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(collid));
   12323 GIC         155 :     if (!HeapTupleIsValid(tp))
   12324 UIC           0 :         elog(ERROR, "cache lookup failed for collation %u", collid);
   12325 CBC         155 :     colltup = (Form_pg_collation) GETSTRUCT(tp);
   12326 GIC         155 :     collname = NameStr(colltup->collname);
   12327                 : 
   12328 GBC         155 :     if (!CollationIsVisible(collid))
   12329 UBC           0 :         nspname = get_namespace_name_or_temp(colltup->collnamespace);
   12330                 :     else
   12331 GIC         155 :         nspname = NULL;
   12332 ECB             : 
   12333 CBC         155 :     result = quote_qualified_identifier(nspname, collname);
   12334 ECB             : 
   12335 CBC         155 :     ReleaseSysCache(tp);
   12336 ECB             : 
   12337 GIC         155 :     return result;
   12338 ECB             : }
   12339                 : 
   12340                 : /*
   12341                 :  * Given a C string, produce a TEXT datum.
   12342                 :  *
   12343                 :  * We assume that the input was palloc'd and may be freed.
   12344                 :  */
   12345                 : static text *
   12346 GIC       18304 : string_to_text(char *str)
   12347                 : {
   12348                 :     text       *result;
   12349                 : 
   12350           18304 :     result = cstring_to_text(str);
   12351           18304 :     pfree(str);
   12352           18304 :     return result;
   12353                 : }
   12354                 : 
   12355                 : /*
   12356                 :  * Generate a C string representing a relation options from text[] datum.
   12357                 :  */
   12358                 : static void
   12359 CBC         120 : get_reloptions(StringInfo buf, Datum reloptions)
   12360                 : {
   12361                 :     Datum      *options;
   12362                 :     int         noptions;
   12363                 :     int         i;
   12364                 : 
   12365 GNC         120 :     deconstruct_array_builtin(DatumGetArrayTypeP(reloptions), TEXTOID,
   12366                 :                               &options, NULL, &noptions);
   12367 ECB             : 
   12368 GIC         250 :     for (i = 0; i < noptions; i++)
   12369 ECB             :     {
   12370 CBC         130 :         char       *option = TextDatumGetCString(options[i]);
   12371 EUB             :         char       *name;
   12372 ECB             :         char       *separator;
   12373                 :         char       *value;
   12374                 : 
   12375                 :         /*
   12376                 :          * Each array element should have the form name=value.  If the "=" is
   12377                 :          * missing for some reason, treat it like an empty value.
   12378                 :          */
   12379 GIC         130 :         name = option;
   12380 CBC         130 :         separator = strchr(option, '=');
   12381 GIC         130 :         if (separator)
   12382 ECB             :         {
   12383 CBC         130 :             *separator = '\0';
   12384 GIC         130 :             value = separator + 1;
   12385 ECB             :         }
   12386                 :         else
   12387 LBC           0 :             value = "";
   12388                 : 
   12389 CBC         130 :         if (i > 0)
   12390 GBC          10 :             appendStringInfoString(buf, ", ");
   12391             130 :         appendStringInfo(buf, "%s=", quote_identifier(name));
   12392                 : 
   12393                 :         /*
   12394                 :          * In general we need to quote the value; but to avoid unnecessary
   12395                 :          * clutter, do not quote if it is an identifier that would not need
   12396 ECB             :          * quoting.  (We could also allow numbers, but that is a bit trickier
   12397                 :          * than it looks --- for example, are leading zeroes significant?  We
   12398                 :          * don't want to assume very much here about what custom reloptions
   12399                 :          * might mean.)
   12400                 :          */
   12401 CBC         130 :         if (quote_identifier(value) == value)
   12402 GIC           4 :             appendStringInfoString(buf, value);
   12403                 :         else
   12404 CBC         126 :             simple_quote_literal(buf, value);
   12405                 : 
   12406             130 :         pfree(option);
   12407 ECB             :     }
   12408 GIC         120 : }
   12409 ECB             : 
   12410                 : /*
   12411                 :  * Generate a C string representing a relation's reloptions, or NULL if none.
   12412                 :  */
   12413                 : static char *
   12414 CBC        2949 : flatten_reloptions(Oid relid)
   12415                 : {
   12416 GIC        2949 :     char       *result = NULL;
   12417                 :     HeapTuple   tuple;
   12418                 :     Datum       reloptions;
   12419                 :     bool        isnull;
   12420                 : 
   12421            2949 :     tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
   12422            2949 :     if (!HeapTupleIsValid(tuple))
   12423 UIC           0 :         elog(ERROR, "cache lookup failed for relation %u", relid);
   12424                 : 
   12425 GIC        2949 :     reloptions = SysCacheGetAttr(RELOID, tuple,
   12426                 :                                  Anum_pg_class_reloptions, &isnull);
   12427            2949 :     if (!isnull)
   12428                 :     {
   12429                 :         StringInfoData buf;
   12430                 : 
   12431             105 :         initStringInfo(&buf);
   12432             105 :         get_reloptions(&buf, reloptions);
   12433                 : 
   12434             105 :         result = buf.data;
   12435 ECB             :     }
   12436                 : 
   12437 GIC        2949 :     ReleaseSysCache(tuple);
   12438                 : 
   12439            2949 :     return result;
   12440                 : }
   12441                 : 
   12442                 : /*
   12443                 :  * get_range_partbound_string
   12444                 :  *      A C string representation of one range partition bound
   12445 ECB             :  */
   12446                 : char *
   12447 GBC        2034 : get_range_partbound_string(List *bound_datums)
   12448 ECB             : {
   12449                 :     deparse_context context;
   12450 CBC        2034 :     StringInfo  buf = makeStringInfo();
   12451                 :     ListCell   *cell;
   12452 ECB             :     char       *sep;
   12453                 : 
   12454 CBC        2034 :     memset(&context, 0, sizeof(deparse_context));
   12455            2034 :     context.buf = buf;
   12456 ECB             : 
   12457 CBC        2034 :     appendStringInfoChar(buf, '(');
   12458            2034 :     sep = "";
   12459            4464 :     foreach(cell, bound_datums)
   12460 ECB             :     {
   12461                 :         PartitionRangeDatum *datum =
   12462 GIC        2430 :         lfirst_node(PartitionRangeDatum, cell);
   12463 ECB             : 
   12464 CBC        2430 :         appendStringInfoString(buf, sep);
   12465 GIC        2430 :         if (datum->kind == PARTITION_RANGE_DATUM_MINVALUE)
   12466             111 :             appendStringInfoString(buf, "MINVALUE");
   12467            2319 :         else if (datum->kind == PARTITION_RANGE_DATUM_MAXVALUE)
   12468              60 :             appendStringInfoString(buf, "MAXVALUE");
   12469                 :         else
   12470                 :         {
   12471            2259 :             Const      *val = castNode(Const, datum->value);
   12472                 : 
   12473            2259 :             get_const_expr(val, &context, -1);
   12474                 :         }
   12475 CBC        2430 :         sep = ", ";
   12476                 :     }
   12477 GIC        2034 :     appendStringInfoChar(buf, ')');
   12478                 : 
   12479            2034 :     return buf->data;
   12480                 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a