diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 12:19:15 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 12:19:15 +0000 |
commit | 6eb9c5a5657d1fe77b55cc261450f3538d35a94d (patch) | |
tree | 657d8194422a5daccecfd42d654b8a245ef7b4c8 /src/backend/nodes/print.c | |
parent | Initial commit. (diff) | |
download | postgresql-13-6eb9c5a5657d1fe77b55cc261450f3538d35a94d.tar.xz postgresql-13-6eb9c5a5657d1fe77b55cc261450f3538d35a94d.zip |
Adding upstream version 13.4.upstream/13.4upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/backend/nodes/print.c')
-rw-r--r-- | src/backend/nodes/print.c | 507 |
1 files changed, 507 insertions, 0 deletions
diff --git a/src/backend/nodes/print.c b/src/backend/nodes/print.c new file mode 100644 index 0000000..4247672 --- /dev/null +++ b/src/backend/nodes/print.c @@ -0,0 +1,507 @@ +/*------------------------------------------------------------------------- + * + * print.c + * various print routines (used mostly for debugging) + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/backend/nodes/print.c + * + * HISTORY + * AUTHOR DATE MAJOR EVENT + * Andrew Yu Oct 26, 1994 file creation + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include "access/printtup.h" +#include "lib/stringinfo.h" +#include "nodes/nodeFuncs.h" +#include "nodes/pathnodes.h" +#include "nodes/print.h" +#include "parser/parsetree.h" +#include "utils/lsyscache.h" + + +/* + * print + * print contents of Node to stdout + */ +void +print(const void *obj) +{ + char *s; + char *f; + + s = nodeToString(obj); + f = format_node_dump(s); + pfree(s); + printf("%s\n", f); + fflush(stdout); + pfree(f); +} + +/* + * pprint + * pretty-print contents of Node to stdout + */ +void +pprint(const void *obj) +{ + char *s; + char *f; + + s = nodeToString(obj); + f = pretty_format_node_dump(s); + pfree(s); + printf("%s\n", f); + fflush(stdout); + pfree(f); +} + +/* + * elog_node_display + * send pretty-printed contents of Node to postmaster log + */ +void +elog_node_display(int lev, const char *title, const void *obj, bool pretty) +{ + char *s; + char *f; + + s = nodeToString(obj); + if (pretty) + f = pretty_format_node_dump(s); + else + f = format_node_dump(s); + pfree(s); + ereport(lev, + (errmsg_internal("%s:", title), + errdetail_internal("%s", f))); + pfree(f); +} + +/* + * Format a nodeToString output for display on a terminal. + * + * The result is a palloc'd string. + * + * This version just tries to break at whitespace. + */ +char * +format_node_dump(const char *dump) +{ +#define LINELEN 78 + char line[LINELEN + 1]; + StringInfoData str; + int i; + int j; + int k; + + initStringInfo(&str); + i = 0; + for (;;) + { + for (j = 0; j < LINELEN && dump[i] != '\0'; i++, j++) + line[j] = dump[i]; + if (dump[i] == '\0') + break; + if (dump[i] == ' ') + { + /* ok to break at adjacent space */ + i++; + } + else + { + for (k = j - 1; k > 0; k--) + if (line[k] == ' ') + break; + if (k > 0) + { + /* back up; will reprint all after space */ + i -= (j - k - 1); + j = k; + } + } + line[j] = '\0'; + appendStringInfo(&str, "%s\n", line); + } + if (j > 0) + { + line[j] = '\0'; + appendStringInfo(&str, "%s\n", line); + } + return str.data; +#undef LINELEN +} + +/* + * Format a nodeToString output for display on a terminal. + * + * The result is a palloc'd string. + * + * This version tries to indent intelligently. + */ +char * +pretty_format_node_dump(const char *dump) +{ +#define INDENTSTOP 3 +#define MAXINDENT 60 +#define LINELEN 78 + char line[LINELEN + 1]; + StringInfoData str; + int indentLev; + int indentDist; + int i; + int j; + + initStringInfo(&str); + indentLev = 0; /* logical indent level */ + indentDist = 0; /* physical indent distance */ + i = 0; + for (;;) + { + for (j = 0; j < indentDist; j++) + line[j] = ' '; + for (; j < LINELEN && dump[i] != '\0'; i++, j++) + { + line[j] = dump[i]; + switch (line[j]) + { + case '}': + if (j != indentDist) + { + /* print data before the } */ + line[j] = '\0'; + appendStringInfo(&str, "%s\n", line); + } + /* print the } at indentDist */ + line[indentDist] = '}'; + line[indentDist + 1] = '\0'; + appendStringInfo(&str, "%s\n", line); + /* outdent */ + if (indentLev > 0) + { + indentLev--; + indentDist = Min(indentLev * INDENTSTOP, MAXINDENT); + } + j = indentDist - 1; + /* j will equal indentDist on next loop iteration */ + /* suppress whitespace just after } */ + while (dump[i + 1] == ' ') + i++; + break; + case ')': + /* force line break after ), unless another ) follows */ + if (dump[i + 1] != ')') + { + line[j + 1] = '\0'; + appendStringInfo(&str, "%s\n", line); + j = indentDist - 1; + while (dump[i + 1] == ' ') + i++; + } + break; + case '{': + /* force line break before { */ + if (j != indentDist) + { + line[j] = '\0'; + appendStringInfo(&str, "%s\n", line); + } + /* indent */ + indentLev++; + indentDist = Min(indentLev * INDENTSTOP, MAXINDENT); + for (j = 0; j < indentDist; j++) + line[j] = ' '; + line[j] = dump[i]; + break; + case ':': + /* force line break before : */ + if (j != indentDist) + { + line[j] = '\0'; + appendStringInfo(&str, "%s\n", line); + } + j = indentDist; + line[j] = dump[i]; + break; + } + } + line[j] = '\0'; + if (dump[i] == '\0') + break; + appendStringInfo(&str, "%s\n", line); + } + if (j > 0) + appendStringInfo(&str, "%s\n", line); + return str.data; +#undef INDENTSTOP +#undef MAXINDENT +#undef LINELEN +} + +/* + * print_rt + * print contents of range table + */ +void +print_rt(const List *rtable) +{ + const ListCell *l; + int i = 1; + + printf("resno\trefname \trelid\tinFromCl\n"); + printf("-----\t---------\t-----\t--------\n"); + foreach(l, rtable) + { + RangeTblEntry *rte = lfirst(l); + + switch (rte->rtekind) + { + case RTE_RELATION: + printf("%d\t%s\t%u\t%c", + i, rte->eref->aliasname, rte->relid, rte->relkind); + break; + case RTE_SUBQUERY: + printf("%d\t%s\t[subquery]", + i, rte->eref->aliasname); + break; + case RTE_JOIN: + printf("%d\t%s\t[join]", + i, rte->eref->aliasname); + break; + case RTE_FUNCTION: + printf("%d\t%s\t[rangefunction]", + i, rte->eref->aliasname); + break; + case RTE_TABLEFUNC: + printf("%d\t%s\t[table function]", + i, rte->eref->aliasname); + break; + case RTE_VALUES: + printf("%d\t%s\t[values list]", + i, rte->eref->aliasname); + break; + case RTE_CTE: + printf("%d\t%s\t[cte]", + i, rte->eref->aliasname); + break; + case RTE_NAMEDTUPLESTORE: + printf("%d\t%s\t[tuplestore]", + i, rte->eref->aliasname); + break; + case RTE_RESULT: + printf("%d\t%s\t[result]", + i, rte->eref->aliasname); + break; + default: + printf("%d\t%s\t[unknown rtekind]", + i, rte->eref->aliasname); + } + + printf("\t%s\t%s\n", + (rte->inh ? "inh" : ""), + (rte->inFromCl ? "inFromCl" : "")); + i++; + } +} + + +/* + * print_expr + * print an expression + */ +void +print_expr(const Node *expr, const List *rtable) +{ + if (expr == NULL) + { + printf("<>"); + return; + } + + if (IsA(expr, Var)) + { + const Var *var = (const Var *) expr; + char *relname, + *attname; + + switch (var->varno) + { + case INNER_VAR: + relname = "INNER"; + attname = "?"; + break; + case OUTER_VAR: + relname = "OUTER"; + attname = "?"; + break; + case INDEX_VAR: + relname = "INDEX"; + attname = "?"; + break; + default: + { + RangeTblEntry *rte; + + Assert(var->varno > 0 && + (int) var->varno <= list_length(rtable)); + rte = rt_fetch(var->varno, rtable); + relname = rte->eref->aliasname; + attname = get_rte_attribute_name(rte, var->varattno); + } + break; + } + printf("%s.%s", relname, attname); + } + else if (IsA(expr, Const)) + { + const Const *c = (const Const *) expr; + Oid typoutput; + bool typIsVarlena; + char *outputstr; + + if (c->constisnull) + { + printf("NULL"); + return; + } + + getTypeOutputInfo(c->consttype, + &typoutput, &typIsVarlena); + + outputstr = OidOutputFunctionCall(typoutput, c->constvalue); + printf("%s", outputstr); + pfree(outputstr); + } + else if (IsA(expr, OpExpr)) + { + const OpExpr *e = (const OpExpr *) expr; + char *opname; + + opname = get_opname(e->opno); + if (list_length(e->args) > 1) + { + print_expr(get_leftop((const Expr *) e), rtable); + printf(" %s ", ((opname != NULL) ? opname : "(invalid operator)")); + print_expr(get_rightop((const Expr *) e), rtable); + } + else + { + /* we print prefix and postfix ops the same... */ + printf("%s ", ((opname != NULL) ? opname : "(invalid operator)")); + print_expr(get_leftop((const Expr *) e), rtable); + } + } + else if (IsA(expr, FuncExpr)) + { + const FuncExpr *e = (const FuncExpr *) expr; + char *funcname; + ListCell *l; + + funcname = get_func_name(e->funcid); + printf("%s(", ((funcname != NULL) ? funcname : "(invalid function)")); + foreach(l, e->args) + { + print_expr(lfirst(l), rtable); + if (lnext(e->args, l)) + printf(","); + } + printf(")"); + } + else + printf("unknown expr"); +} + +/* + * print_pathkeys - + * pathkeys list of PathKeys + */ +void +print_pathkeys(const List *pathkeys, const List *rtable) +{ + const ListCell *i; + + printf("("); + foreach(i, pathkeys) + { + PathKey *pathkey = (PathKey *) lfirst(i); + EquivalenceClass *eclass; + ListCell *k; + bool first = true; + + eclass = pathkey->pk_eclass; + /* chase up, in case pathkey is non-canonical */ + while (eclass->ec_merged) + eclass = eclass->ec_merged; + + printf("("); + foreach(k, eclass->ec_members) + { + EquivalenceMember *mem = (EquivalenceMember *) lfirst(k); + + if (first) + first = false; + else + printf(", "); + print_expr((Node *) mem->em_expr, rtable); + } + printf(")"); + if (lnext(pathkeys, i)) + printf(", "); + } + printf(")\n"); +} + +/* + * print_tl + * print targetlist in a more legible way. + */ +void +print_tl(const List *tlist, const List *rtable) +{ + const ListCell *tl; + + printf("(\n"); + foreach(tl, tlist) + { + TargetEntry *tle = (TargetEntry *) lfirst(tl); + + printf("\t%d %s\t", tle->resno, + tle->resname ? tle->resname : "<null>"); + if (tle->ressortgroupref != 0) + printf("(%u):\t", tle->ressortgroupref); + else + printf(" :\t"); + print_expr((Node *) tle->expr, rtable); + printf("\n"); + } + printf(")\n"); +} + +/* + * print_slot + * print out the tuple with the given TupleTableSlot + */ +void +print_slot(TupleTableSlot *slot) +{ + if (TupIsNull(slot)) + { + printf("tuple is null.\n"); + return; + } + if (!slot->tts_tupleDescriptor) + { + printf("no tuple descriptor.\n"); + return; + } + + debugtup(slot, NULL); +} |