00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "postgres.h"
00021
00022 #include "access/printtup.h"
00023 #include "lib/stringinfo.h"
00024 #include "nodes/print.h"
00025 #include "optimizer/clauses.h"
00026 #include "parser/parsetree.h"
00027 #include "utils/lsyscache.h"
00028
00029
00030
00031
00032
00033
00034 void
00035 print(const void *obj)
00036 {
00037 char *s;
00038 char *f;
00039
00040 s = nodeToString(obj);
00041 f = format_node_dump(s);
00042 pfree(s);
00043 printf("%s\n", f);
00044 fflush(stdout);
00045 pfree(f);
00046 }
00047
00048
00049
00050
00051
00052 void
00053 pprint(const void *obj)
00054 {
00055 char *s;
00056 char *f;
00057
00058 s = nodeToString(obj);
00059 f = pretty_format_node_dump(s);
00060 pfree(s);
00061 printf("%s\n", f);
00062 fflush(stdout);
00063 pfree(f);
00064 }
00065
00066
00067
00068
00069
00070 void
00071 elog_node_display(int lev, const char *title, const void *obj, bool pretty)
00072 {
00073 char *s;
00074 char *f;
00075
00076 s = nodeToString(obj);
00077 if (pretty)
00078 f = pretty_format_node_dump(s);
00079 else
00080 f = format_node_dump(s);
00081 pfree(s);
00082 ereport(lev,
00083 (errmsg_internal("%s:", title),
00084 errdetail_internal("%s", f)));
00085 pfree(f);
00086 }
00087
00088
00089
00090
00091
00092
00093
00094
00095 char *
00096 format_node_dump(const char *dump)
00097 {
00098 #define LINELEN 78
00099 char line[LINELEN + 1];
00100 StringInfoData str;
00101 int i;
00102 int j;
00103 int k;
00104
00105 initStringInfo(&str);
00106 i = 0;
00107 for (;;)
00108 {
00109 for (j = 0; j < LINELEN && dump[i] != '\0'; i++, j++)
00110 line[j] = dump[i];
00111 if (dump[i] == '\0')
00112 break;
00113 if (dump[i] == ' ')
00114 {
00115
00116 i++;
00117 }
00118 else
00119 {
00120 for (k = j - 1; k > 0; k--)
00121 if (line[k] == ' ')
00122 break;
00123 if (k > 0)
00124 {
00125
00126 i -= (j - k - 1);
00127 j = k;
00128 }
00129 }
00130 line[j] = '\0';
00131 appendStringInfo(&str, "%s\n", line);
00132 }
00133 if (j > 0)
00134 {
00135 line[j] = '\0';
00136 appendStringInfo(&str, "%s\n", line);
00137 }
00138 return str.data;
00139 #undef LINELEN
00140 }
00141
00142
00143
00144
00145
00146
00147
00148
00149 char *
00150 pretty_format_node_dump(const char *dump)
00151 {
00152 #define INDENTSTOP 3
00153 #define MAXINDENT 60
00154 #define LINELEN 78
00155 char line[LINELEN + 1];
00156 StringInfoData str;
00157 int indentLev;
00158 int indentDist;
00159 int i;
00160 int j;
00161
00162 initStringInfo(&str);
00163 indentLev = 0;
00164 indentDist = 0;
00165 i = 0;
00166 for (;;)
00167 {
00168 for (j = 0; j < indentDist; j++)
00169 line[j] = ' ';
00170 for (; j < LINELEN && dump[i] != '\0'; i++, j++)
00171 {
00172 line[j] = dump[i];
00173 switch (line[j])
00174 {
00175 case '}':
00176 if (j != indentDist)
00177 {
00178
00179 line[j] = '\0';
00180 appendStringInfo(&str, "%s\n", line);
00181 }
00182
00183 line[indentDist] = '}';
00184 line[indentDist + 1] = '\0';
00185 appendStringInfo(&str, "%s\n", line);
00186
00187 if (indentLev > 0)
00188 {
00189 indentLev--;
00190 indentDist = Min(indentLev * INDENTSTOP, MAXINDENT);
00191 }
00192 j = indentDist - 1;
00193
00194
00195 while (dump[i + 1] == ' ')
00196 i++;
00197 break;
00198 case ')':
00199
00200 if (dump[i + 1] != ')')
00201 {
00202 line[j + 1] = '\0';
00203 appendStringInfo(&str, "%s\n", line);
00204 j = indentDist - 1;
00205 while (dump[i + 1] == ' ')
00206 i++;
00207 }
00208 break;
00209 case '{':
00210
00211 if (j != indentDist)
00212 {
00213 line[j] = '\0';
00214 appendStringInfo(&str, "%s\n", line);
00215 }
00216
00217 indentLev++;
00218 indentDist = Min(indentLev * INDENTSTOP, MAXINDENT);
00219 for (j = 0; j < indentDist; j++)
00220 line[j] = ' ';
00221 line[j] = dump[i];
00222 break;
00223 case ':':
00224
00225 if (j != indentDist)
00226 {
00227 line[j] = '\0';
00228 appendStringInfo(&str, "%s\n", line);
00229 }
00230 j = indentDist;
00231 line[j] = dump[i];
00232 break;
00233 }
00234 }
00235 line[j] = '\0';
00236 if (dump[i] == '\0')
00237 break;
00238 appendStringInfo(&str, "%s\n", line);
00239 }
00240 if (j > 0)
00241 appendStringInfo(&str, "%s\n", line);
00242 return str.data;
00243 #undef INDENTSTOP
00244 #undef MAXINDENT
00245 #undef LINELEN
00246 }
00247
00248
00249
00250
00251
00252 void
00253 print_rt(const List *rtable)
00254 {
00255 const ListCell *l;
00256 int i = 1;
00257
00258 printf("resno\trefname \trelid\tinFromCl\n");
00259 printf("-----\t---------\t-----\t--------\n");
00260 foreach(l, rtable)
00261 {
00262 RangeTblEntry *rte = lfirst(l);
00263
00264 switch (rte->rtekind)
00265 {
00266 case RTE_RELATION:
00267 printf("%d\t%s\t%u\t%c",
00268 i, rte->eref->aliasname, rte->relid, rte->relkind);
00269 break;
00270 case RTE_SUBQUERY:
00271 printf("%d\t%s\t[subquery]",
00272 i, rte->eref->aliasname);
00273 break;
00274 case RTE_JOIN:
00275 printf("%d\t%s\t[join]",
00276 i, rte->eref->aliasname);
00277 break;
00278 case RTE_FUNCTION:
00279 printf("%d\t%s\t[rangefunction]",
00280 i, rte->eref->aliasname);
00281 break;
00282 case RTE_VALUES:
00283 printf("%d\t%s\t[values list]",
00284 i, rte->eref->aliasname);
00285 break;
00286 case RTE_CTE:
00287 printf("%d\t%s\t[cte]",
00288 i, rte->eref->aliasname);
00289 break;
00290 default:
00291 printf("%d\t%s\t[unknown rtekind]",
00292 i, rte->eref->aliasname);
00293 }
00294
00295 printf("\t%s\t%s\n",
00296 (rte->inh ? "inh" : ""),
00297 (rte->inFromCl ? "inFromCl" : ""));
00298 i++;
00299 }
00300 }
00301
00302
00303
00304
00305
00306
00307 void
00308 print_expr(const Node *expr, const List *rtable)
00309 {
00310 if (expr == NULL)
00311 {
00312 printf("<>");
00313 return;
00314 }
00315
00316 if (IsA(expr, Var))
00317 {
00318 const Var *var = (const Var *) expr;
00319 char *relname,
00320 *attname;
00321
00322 switch (var->varno)
00323 {
00324 case INNER_VAR:
00325 relname = "INNER";
00326 attname = "?";
00327 break;
00328 case OUTER_VAR:
00329 relname = "OUTER";
00330 attname = "?";
00331 break;
00332 case INDEX_VAR:
00333 relname = "INDEX";
00334 attname = "?";
00335 break;
00336 default:
00337 {
00338 RangeTblEntry *rte;
00339
00340 Assert(var->varno > 0 &&
00341 (int) var->varno <= list_length(rtable));
00342 rte = rt_fetch(var->varno, rtable);
00343 relname = rte->eref->aliasname;
00344 attname = get_rte_attribute_name(rte, var->varattno);
00345 }
00346 break;
00347 }
00348 printf("%s.%s", relname, attname);
00349 }
00350 else if (IsA(expr, Const))
00351 {
00352 const Const *c = (const Const *) expr;
00353 Oid typoutput;
00354 bool typIsVarlena;
00355 char *outputstr;
00356
00357 if (c->constisnull)
00358 {
00359 printf("NULL");
00360 return;
00361 }
00362
00363 getTypeOutputInfo(c->consttype,
00364 &typoutput, &typIsVarlena);
00365
00366 outputstr = OidOutputFunctionCall(typoutput, c->constvalue);
00367 printf("%s", outputstr);
00368 pfree(outputstr);
00369 }
00370 else if (IsA(expr, OpExpr))
00371 {
00372 const OpExpr *e = (const OpExpr *) expr;
00373 char *opname;
00374
00375 opname = get_opname(e->opno);
00376 if (list_length(e->args) > 1)
00377 {
00378 print_expr(get_leftop((const Expr *) e), rtable);
00379 printf(" %s ", ((opname != NULL) ? opname : "(invalid operator)"));
00380 print_expr(get_rightop((const Expr *) e), rtable);
00381 }
00382 else
00383 {
00384
00385 printf("%s ", ((opname != NULL) ? opname : "(invalid operator)"));
00386 print_expr(get_leftop((const Expr *) e), rtable);
00387 }
00388 }
00389 else if (IsA(expr, FuncExpr))
00390 {
00391 const FuncExpr *e = (const FuncExpr *) expr;
00392 char *funcname;
00393 ListCell *l;
00394
00395 funcname = get_func_name(e->funcid);
00396 printf("%s(", ((funcname != NULL) ? funcname : "(invalid function)"));
00397 foreach(l, e->args)
00398 {
00399 print_expr(lfirst(l), rtable);
00400 if (lnext(l))
00401 printf(",");
00402 }
00403 printf(")");
00404 }
00405 else
00406 printf("unknown expr");
00407 }
00408
00409
00410
00411
00412
00413 void
00414 print_pathkeys(const List *pathkeys, const List *rtable)
00415 {
00416 const ListCell *i;
00417
00418 printf("(");
00419 foreach(i, pathkeys)
00420 {
00421 PathKey *pathkey = (PathKey *) lfirst(i);
00422 EquivalenceClass *eclass;
00423 ListCell *k;
00424 bool first = true;
00425
00426 eclass = pathkey->pk_eclass;
00427
00428 while (eclass->ec_merged)
00429 eclass = eclass->ec_merged;
00430
00431 printf("(");
00432 foreach(k, eclass->ec_members)
00433 {
00434 EquivalenceMember *mem = (EquivalenceMember *) lfirst(k);
00435
00436 if (first)
00437 first = false;
00438 else
00439 printf(", ");
00440 print_expr((Node *) mem->em_expr, rtable);
00441 }
00442 printf(")");
00443 if (lnext(i))
00444 printf(", ");
00445 }
00446 printf(")\n");
00447 }
00448
00449
00450
00451
00452
00453 void
00454 print_tl(const List *tlist, const List *rtable)
00455 {
00456 const ListCell *tl;
00457
00458 printf("(\n");
00459 foreach(tl, tlist)
00460 {
00461 TargetEntry *tle = (TargetEntry *) lfirst(tl);
00462
00463 printf("\t%d %s\t", tle->resno,
00464 tle->resname ? tle->resname : "<null>");
00465 if (tle->ressortgroupref != 0)
00466 printf("(%u):\t", tle->ressortgroupref);
00467 else
00468 printf(" :\t");
00469 print_expr((Node *) tle->expr, rtable);
00470 printf("\n");
00471 }
00472 printf(")\n");
00473 }
00474
00475
00476
00477
00478
00479 void
00480 print_slot(TupleTableSlot *slot)
00481 {
00482 if (TupIsNull(slot))
00483 {
00484 printf("tuple is null.\n");
00485 return;
00486 }
00487 if (!slot->tts_tupleDescriptor)
00488 {
00489 printf("no tuple descriptor.\n");
00490 return;
00491 }
00492
00493 debugtup(slot, NULL);
00494 }