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