* print.c
* various print routines (used mostly for debugging)
*
- * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/print.c,v 1.66 2004/05/08 21:21:18 tgl Exp $
+ * src/backend/nodes/print.c
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
#include "postgres.h"
#include "access/printtup.h"
-#include "catalog/pg_type.h"
#include "lib/stringinfo.h"
+#include "nodes/nodeFuncs.h"
#include "nodes/print.h"
-#include "optimizer/clauses.h"
+#include "nodes/relation.h"
#include "parser/parsetree.h"
#include "utils/lsyscache.h"
-#include "utils/syscache.h"
-static char *plannode_type(Plan *p);
/*
* print
* print contents of Node to stdout
*/
void
-print(void *obj)
+print(const void *obj)
{
char *s;
char *f;
* pretty-print contents of Node to stdout
*/
void
-pprint(void *obj)
+pprint(const void *obj)
{
char *s;
char *f;
* send pretty-printed contents of Node to postmaster log
*/
void
-elog_node_display(int lev, const char *title, void *obj, bool pretty)
+elog_node_display(int lev, const char *title, const void *obj, bool pretty)
{
char *s;
char *f;
pfree(s);
ereport(lev,
(errmsg_internal("%s:", title),
- errdetail("%s", f)));
+ errdetail_internal("%s", f)));
pfree(f);
}
j = indentDist - 1;
/* j will equal indentDist on next loop iteration */
/* suppress whitespace just after } */
- while (dump[i+1] == ' ')
+ while (dump[i + 1] == ' ')
i++;
break;
case ')':
/* force line break after ), unless another ) follows */
- if (dump[i+1] != ')')
+ if (dump[i + 1] != ')')
{
line[j + 1] = '\0';
appendStringInfo(&str, "%s\n", line);
j = indentDist - 1;
- while (dump[i+1] == ' ')
+ while (dump[i + 1] == ' ')
i++;
}
break;
* print contents of range table
*/
void
-print_rt(List *rtable)
+print_rt(const List *rtable)
{
- List *l;
+ const ListCell *l;
int i = 1;
printf("resno\trefname \trelid\tinFromCl\n");
switch (rte->rtekind)
{
case RTE_RELATION:
- printf("%d\t%s\t%u",
- i, rte->eref->aliasname, rte->relid);
+ 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_JOIN:
- printf("%d\t%s\t[join]",
+ 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_SPECIAL:
- printf("%d\t%s\t[special]",
+ 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:
* print an expression
*/
void
-print_expr(Node *expr, List *rtable)
+print_expr(const Node *expr, const List *rtable)
{
if (expr == NULL)
{
if (IsA(expr, Var))
{
- Var *var = (Var *) expr;
+ const Var *var = (const Var *) expr;
char *relname,
*attname;
switch (var->varno)
{
- case INNER:
+ case INNER_VAR:
relname = "INNER";
attname = "?";
break;
- case OUTER:
+ case OUTER_VAR:
relname = "OUTER";
attname = "?";
break;
+ case INDEX_VAR:
+ relname = "INDEX";
+ attname = "?";
+ break;
default:
{
RangeTblEntry *rte;
Assert(var->varno > 0 &&
- (int) var->varno <= length(rtable));
+ (int) var->varno <= list_length(rtable));
rte = rt_fetch(var->varno, rtable);
relname = rte->eref->aliasname;
attname = get_rte_attribute_name(rte, var->varattno);
}
else if (IsA(expr, Const))
{
- Const *c = (Const *) expr;
- HeapTuple typeTup;
+ const Const *c = (const Const *) expr;
Oid typoutput;
- Oid typelem;
+ bool typIsVarlena;
char *outputstr;
if (c->constisnull)
return;
}
- typeTup = SearchSysCache(TYPEOID,
- ObjectIdGetDatum(c->consttype),
- 0, 0, 0);
- if (!HeapTupleIsValid(typeTup))
- elog(ERROR, "cache lookup failed for type %u", c->consttype);
- typoutput = ((Form_pg_type) GETSTRUCT(typeTup))->typoutput;
- typelem = ((Form_pg_type) GETSTRUCT(typeTup))->typelem;
- ReleaseSysCache(typeTup);
-
- outputstr = DatumGetCString(OidFunctionCall3(typoutput,
- c->constvalue,
- ObjectIdGetDatum(typelem),
- Int32GetDatum(-1)));
+ getTypeOutputInfo(c->consttype,
+ &typoutput, &typIsVarlena);
+
+ outputstr = OidOutputFunctionCall(typoutput, c->constvalue);
printf("%s", outputstr);
pfree(outputstr);
}
else if (IsA(expr, OpExpr))
{
- OpExpr *e = (OpExpr *) expr;
+ const OpExpr *e = (const OpExpr *) expr;
char *opname;
opname = get_opname(e->opno);
- if (length(e->args) > 1)
+ if (list_length(e->args) > 1)
{
- print_expr(get_leftop((Expr *) e), rtable);
+ print_expr(get_leftop((const Expr *) e), rtable);
printf(" %s ", ((opname != NULL) ? opname : "(invalid operator)"));
- print_expr(get_rightop((Expr *) e), rtable);
+ 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((Expr *) e), rtable);
+ print_expr(get_leftop((const Expr *) e), rtable);
}
}
else if (IsA(expr, FuncExpr))
{
- FuncExpr *e = (FuncExpr *) expr;
+ const FuncExpr *e = (const FuncExpr *) expr;
char *funcname;
- List *l;
+ ListCell *l;
funcname = get_func_name(e->funcid);
printf("%s(", ((funcname != NULL) ? funcname : "(invalid function)"));
/*
* print_pathkeys -
- * pathkeys list of list of PathKeyItems
+ * pathkeys list of PathKeys
*/
void
-print_pathkeys(List *pathkeys, List *rtable)
+print_pathkeys(const List *pathkeys, const List *rtable)
{
- List *i,
- *k;
+ const ListCell *i;
printf("(");
foreach(i, pathkeys)
{
- List *pathkey = lfirst(i);
+ 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, pathkey)
+ foreach(k, eclass->ec_members)
{
- PathKeyItem *item = lfirst(k);
+ EquivalenceMember *mem = (EquivalenceMember *) lfirst(k);
- print_expr(item->key, rtable);
- if (lnext(k))
+ if (first)
+ first = false;
+ else
printf(", ");
+ print_expr((Node *) mem->em_expr, rtable);
}
printf(")");
if (lnext(i))
* print targetlist in a more legible way.
*/
void
-print_tl(List *tlist, List *rtable)
+print_tl(const List *tlist, const List *rtable)
{
- List *tl;
+ const ListCell *tl;
printf("(\n");
foreach(tl, tlist)
{
- TargetEntry *tle = lfirst(tl);
+ TargetEntry *tle = (TargetEntry *) lfirst(tl);
- printf("\t%d %s\t", tle->resdom->resno,
- tle->resdom->resname ? tle->resdom->resname : "<null>");
- if (tle->resdom->ressortgroupref != 0)
- printf("(%u):\t", tle->resdom->ressortgroupref);
+ 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);
void
print_slot(TupleTableSlot *slot)
{
- if (!slot->val)
+ if (TupIsNull(slot))
{
printf("tuple is null.\n");
return;
}
- if (!slot->ttc_tupleDescriptor)
+ if (!slot->tts_tupleDescriptor)
{
printf("no tuple descriptor.\n");
return;
}
- debugtup(slot->val, slot->ttc_tupleDescriptor, NULL);
-}
-
-static char *
-plannode_type(Plan *p)
-{
- switch (nodeTag(p))
- {
- case T_Plan:
- return "PLAN";
- case T_Result:
- return "RESULT";
- case T_Append:
- return "APPEND";
- case T_Scan:
- return "SCAN";
- case T_SeqScan:
- return "SEQSCAN";
- case T_IndexScan:
- return "INDEXSCAN";
- case T_TidScan:
- return "TIDSCAN";
- case T_SubqueryScan:
- return "SUBQUERYSCAN";
- case T_FunctionScan:
- return "FUNCTIONSCAN";
- case T_Join:
- return "JOIN";
- case T_NestLoop:
- return "NESTLOOP";
- case T_MergeJoin:
- return "MERGEJOIN";
- case T_HashJoin:
- return "HASHJOIN";
- case T_Material:
- return "MATERIAL";
- case T_Sort:
- return "SORT";
- case T_Agg:
- return "AGG";
- case T_Unique:
- return "UNIQUE";
- case T_SetOp:
- return "SETOP";
- case T_Limit:
- return "LIMIT";
- case T_Hash:
- return "HASH";
- case T_Group:
- return "GROUP";
- default:
- return "UNKNOWN";
- }
-}
-
-/*
- * Recursively prints a simple text description of the plan tree
- */
-void
-print_plan_recursive(Plan *p, Query *parsetree, int indentLevel, char *label)
-{
- int i;
- char extraInfo[NAMEDATALEN + 100];
-
- if (!p)
- return;
- for (i = 0; i < indentLevel; i++)
- printf(" ");
- printf("%s%s :c=%.2f..%.2f :r=%.0f :w=%d ", label, plannode_type(p),
- p->startup_cost, p->total_cost,
- p->plan_rows, p->plan_width);
- if (IsA(p, Scan) ||
- IsA(p, SeqScan))
- {
- RangeTblEntry *rte;
-
- rte = rt_fetch(((Scan *) p)->scanrelid, parsetree->rtable);
- StrNCpy(extraInfo, rte->eref->aliasname, NAMEDATALEN);
- }
- else if (IsA(p, IndexScan))
- {
- RangeTblEntry *rte;
-
- rte = rt_fetch(((IndexScan *) p)->scan.scanrelid, parsetree->rtable);
- StrNCpy(extraInfo, rte->eref->aliasname, NAMEDATALEN);
- }
- else if (IsA(p, FunctionScan))
- {
- RangeTblEntry *rte;
-
- rte = rt_fetch(((FunctionScan *) p)->scan.scanrelid, parsetree->rtable);
- StrNCpy(extraInfo, rte->eref->aliasname, NAMEDATALEN);
- }
- else
- extraInfo[0] = '\0';
- if (extraInfo[0] != '\0')
- printf(" ( %s )\n", extraInfo);
- else
- printf("\n");
- print_plan_recursive(p->lefttree, parsetree, indentLevel + 3, "l: ");
- print_plan_recursive(p->righttree, parsetree, indentLevel + 3, "r: ");
-
- if (IsA(p, Append))
- {
- List *lst;
- int whichplan = 0;
- Append *appendplan = (Append *) p;
-
- foreach(lst, appendplan->appendplans)
- {
- Plan *subnode = (Plan *) lfirst(lst);
-
- /*
- * I don't think we need to fiddle with the range table here,
- * bjm
- */
- print_plan_recursive(subnode, parsetree, indentLevel + 3, "a: ");
-
- whichplan++;
- }
- }
-}
-
-/* print_plan
- prints just the plan node types */
-
-void
-print_plan(Plan *p, Query *parsetree)
-{
- print_plan_recursive(p, parsetree, 0, "");
+ debugtup(slot, NULL);
}