LCOV - differential code coverage report
Current view: top level - src/backend/commands - explain_format.c (source / functions) Coverage Total Hit UBC CBC
Current: c70b6db34ffeab48beef1fb4ce61bcad3772b8dd vs 06473f5a344df8c9594ead90a609b86f6724cff8 Lines: 76.3 % 329 251 78 251
Current Date: 2025-09-06 07:49:51 +0900 Functions: 100.0 % 22 22 22
Baseline: lcov-20250906-005545-baseline Branches: 58.6 % 157 92 65 92
Baseline Date: 2025-09-05 08:21:35 +0100 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(30,360] days: 76.3 % 329 251 78 251
Function coverage date bins:
(30,360] days: 100.0 % 22 22 22
Branch coverage date bins:
(30,360] days: 58.6 % 157 92 65 92

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : /*-------------------------------------------------------------------------
                                  2                 :                :  *
                                  3                 :                :  * explain_format.c
                                  4                 :                :  *    Format routines for explaining query execution plans
                                  5                 :                :  *
                                  6                 :                :  * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
                                  7                 :                :  * Portions Copyright (c) 1994-5, Regents of the University of California
                                  8                 :                :  *
                                  9                 :                :  * IDENTIFICATION
                                 10                 :                :  *    src/backend/commands/explain_format.c
                                 11                 :                :  *
                                 12                 :                :  *-------------------------------------------------------------------------
                                 13                 :                :  */
                                 14                 :                : #include "postgres.h"
                                 15                 :                : 
                                 16                 :                : #include "commands/explain.h"
                                 17                 :                : #include "commands/explain_format.h"
                                 18                 :                : #include "commands/explain_state.h"
                                 19                 :                : #include "utils/json.h"
                                 20                 :                : #include "utils/xml.h"
                                 21                 :                : 
                                 22                 :                : /* OR-able flags for ExplainXMLTag() */
                                 23                 :                : #define X_OPENING 0
                                 24                 :                : #define X_CLOSING 1
                                 25                 :                : #define X_CLOSE_IMMEDIATE 2
                                 26                 :                : #define X_NOWHITESPACE 4
                                 27                 :                : 
                                 28                 :                : static void ExplainJSONLineEnding(ExplainState *es);
                                 29                 :                : static void ExplainXMLTag(const char *tagname, int flags, ExplainState *es);
                                 30                 :                : static void ExplainYAMLLineStarting(ExplainState *es);
                                 31                 :                : static void escape_yaml(StringInfo buf, const char *str);
                                 32                 :                : 
                                 33                 :                : /*
                                 34                 :                :  * Explain a property, such as sort keys or targets, that takes the form of
                                 35                 :                :  * a list of unlabeled items.  "data" is a list of C strings.
                                 36                 :                :  */
                                 37                 :                : void
  191 rhaas@postgresql.org       38                 :CBC        8477 : ExplainPropertyList(const char *qlabel, List *data, ExplainState *es)
                                 39                 :                : {
                                 40                 :                :     ListCell   *lc;
                                 41                 :           8477 :     bool        first = true;
                                 42                 :                : 
                                 43   [ +  +  +  -  :           8477 :     switch (es->format)
                                                 - ]
                                 44                 :                :     {
                                 45                 :           8394 :         case EXPLAIN_FORMAT_TEXT:
                                 46                 :           8394 :             ExplainIndentText(es);
                                 47                 :           8394 :             appendStringInfo(es->str, "%s: ", qlabel);
                                 48   [ +  -  +  +  :          25655 :             foreach(lc, data)
                                              +  + ]
                                 49                 :                :             {
                                 50         [ +  + ]:          17261 :                 if (!first)
                                 51                 :           8867 :                     appendStringInfoString(es->str, ", ");
                                 52                 :          17261 :                 appendStringInfoString(es->str, (const char *) lfirst(lc));
                                 53                 :          17261 :                 first = false;
                                 54                 :                :             }
                                 55                 :           8394 :             appendStringInfoChar(es->str, '\n');
                                 56                 :           8394 :             break;
                                 57                 :                : 
                                 58                 :              2 :         case EXPLAIN_FORMAT_XML:
                                 59                 :              2 :             ExplainXMLTag(qlabel, X_OPENING, es);
                                 60   [ +  -  +  +  :              5 :             foreach(lc, data)
                                              +  + ]
                                 61                 :                :             {
                                 62                 :                :                 char       *str;
                                 63                 :                : 
                                 64                 :              3 :                 appendStringInfoSpaces(es->str, es->indent * 2 + 2);
                                 65                 :              3 :                 appendStringInfoString(es->str, "<Item>");
                                 66                 :              3 :                 str = escape_xml((const char *) lfirst(lc));
                                 67                 :              3 :                 appendStringInfoString(es->str, str);
                                 68                 :              3 :                 pfree(str);
                                 69                 :              3 :                 appendStringInfoString(es->str, "</Item>\n");
                                 70                 :                :             }
                                 71                 :              2 :             ExplainXMLTag(qlabel, X_CLOSING, es);
                                 72                 :              2 :             break;
                                 73                 :                : 
                                 74                 :             81 :         case EXPLAIN_FORMAT_JSON:
                                 75                 :             81 :             ExplainJSONLineEnding(es);
                                 76                 :             81 :             appendStringInfoSpaces(es->str, es->indent * 2);
                                 77                 :             81 :             escape_json(es->str, qlabel);
                                 78                 :             81 :             appendStringInfoString(es->str, ": [");
                                 79   [ +  -  +  +  :            333 :             foreach(lc, data)
                                              +  + ]
                                 80                 :                :             {
                                 81         [ +  + ]:            252 :                 if (!first)
                                 82                 :            171 :                     appendStringInfoString(es->str, ", ");
                                 83                 :            252 :                 escape_json(es->str, (const char *) lfirst(lc));
                                 84                 :            252 :                 first = false;
                                 85                 :                :             }
                                 86                 :             81 :             appendStringInfoChar(es->str, ']');
                                 87                 :             81 :             break;
                                 88                 :                : 
  191 rhaas@postgresql.org       89                 :UBC           0 :         case EXPLAIN_FORMAT_YAML:
                                 90                 :              0 :             ExplainYAMLLineStarting(es);
                                 91                 :              0 :             appendStringInfo(es->str, "%s: ", qlabel);
                                 92   [ #  #  #  #  :              0 :             foreach(lc, data)
                                              #  # ]
                                 93                 :                :             {
                                 94                 :              0 :                 appendStringInfoChar(es->str, '\n');
                                 95                 :              0 :                 appendStringInfoSpaces(es->str, es->indent * 2 + 2);
                                 96                 :              0 :                 appendStringInfoString(es->str, "- ");
                                 97                 :              0 :                 escape_yaml(es->str, (const char *) lfirst(lc));
                                 98                 :                :             }
                                 99                 :              0 :             break;
                                100                 :                :     }
  191 rhaas@postgresql.org      101                 :CBC        8477 : }
                                102                 :                : 
                                103                 :                : /*
                                104                 :                :  * Explain a property that takes the form of a list of unlabeled items within
                                105                 :                :  * another list.  "data" is a list of C strings.
                                106                 :                :  */
                                107                 :                : void
                                108                 :            292 : ExplainPropertyListNested(const char *qlabel, List *data, ExplainState *es)
                                109                 :                : {
                                110                 :                :     ListCell   *lc;
                                111                 :            292 :     bool        first = true;
                                112                 :                : 
                                113   [ +  -  -  - ]:            292 :     switch (es->format)
                                114                 :                :     {
                                115                 :            292 :         case EXPLAIN_FORMAT_TEXT:
                                116                 :                :         case EXPLAIN_FORMAT_XML:
                                117                 :            292 :             ExplainPropertyList(qlabel, data, es);
                                118                 :            292 :             return;
                                119                 :                : 
  191 rhaas@postgresql.org      120                 :UBC           0 :         case EXPLAIN_FORMAT_JSON:
                                121                 :              0 :             ExplainJSONLineEnding(es);
                                122                 :              0 :             appendStringInfoSpaces(es->str, es->indent * 2);
                                123                 :              0 :             appendStringInfoChar(es->str, '[');
                                124   [ #  #  #  #  :              0 :             foreach(lc, data)
                                              #  # ]
                                125                 :                :             {
                                126         [ #  # ]:              0 :                 if (!first)
                                127                 :              0 :                     appendStringInfoString(es->str, ", ");
                                128                 :              0 :                 escape_json(es->str, (const char *) lfirst(lc));
                                129                 :              0 :                 first = false;
                                130                 :                :             }
                                131                 :              0 :             appendStringInfoChar(es->str, ']');
                                132                 :              0 :             break;
                                133                 :                : 
                                134                 :              0 :         case EXPLAIN_FORMAT_YAML:
                                135                 :              0 :             ExplainYAMLLineStarting(es);
                                136                 :              0 :             appendStringInfoString(es->str, "- [");
                                137   [ #  #  #  #  :              0 :             foreach(lc, data)
                                              #  # ]
                                138                 :                :             {
                                139         [ #  # ]:              0 :                 if (!first)
                                140                 :              0 :                     appendStringInfoString(es->str, ", ");
                                141                 :              0 :                 escape_yaml(es->str, (const char *) lfirst(lc));
                                142                 :              0 :                 first = false;
                                143                 :                :             }
                                144                 :              0 :             appendStringInfoChar(es->str, ']');
                                145                 :              0 :             break;
                                146                 :                :     }
                                147                 :                : }
                                148                 :                : 
                                149                 :                : /*
                                150                 :                :  * Explain a simple property.
                                151                 :                :  *
                                152                 :                :  * If "numeric" is true, the value is a number (or other value that
                                153                 :                :  * doesn't need quoting in JSON).
                                154                 :                :  *
                                155                 :                :  * If unit is non-NULL the text format will display it after the value.
                                156                 :                :  *
                                157                 :                :  * This usually should not be invoked directly, but via one of the datatype
                                158                 :                :  * specific routines ExplainPropertyText, ExplainPropertyInteger, etc.
                                159                 :                :  */
                                160                 :                : static void
  191 rhaas@postgresql.org      161                 :CBC       38807 : ExplainProperty(const char *qlabel, const char *unit, const char *value,
                                162                 :                :                 bool numeric, ExplainState *es)
                                163                 :                : {
                                164   [ +  +  +  +  :          38807 :     switch (es->format)
                                                 - ]
                                165                 :                :     {
                                166                 :          24085 :         case EXPLAIN_FORMAT_TEXT:
                                167                 :          24085 :             ExplainIndentText(es);
                                168         [ +  + ]:          24085 :             if (unit)
                                169                 :           2370 :                 appendStringInfo(es->str, "%s: %s %s\n", qlabel, value, unit);
                                170                 :                :             else
                                171                 :          21715 :                 appendStringInfo(es->str, "%s: %s\n", qlabel, value);
                                172                 :          24085 :             break;
                                173                 :                : 
                                174                 :            215 :         case EXPLAIN_FORMAT_XML:
                                175                 :                :             {
                                176                 :                :                 char       *str;
                                177                 :                : 
                                178                 :            215 :                 appendStringInfoSpaces(es->str, es->indent * 2);
                                179                 :            215 :                 ExplainXMLTag(qlabel, X_OPENING | X_NOWHITESPACE, es);
                                180                 :            215 :                 str = escape_xml(value);
                                181                 :            215 :                 appendStringInfoString(es->str, str);
                                182                 :            215 :                 pfree(str);
                                183                 :            215 :                 ExplainXMLTag(qlabel, X_CLOSING | X_NOWHITESPACE, es);
                                184                 :            215 :                 appendStringInfoChar(es->str, '\n');
                                185                 :                :             }
                                186                 :            215 :             break;
                                187                 :                : 
                                188                 :          14321 :         case EXPLAIN_FORMAT_JSON:
                                189                 :          14321 :             ExplainJSONLineEnding(es);
                                190                 :          14321 :             appendStringInfoSpaces(es->str, es->indent * 2);
                                191                 :          14321 :             escape_json(es->str, qlabel);
                                192                 :          14321 :             appendStringInfoString(es->str, ": ");
                                193         [ +  + ]:          14321 :             if (numeric)
                                194                 :          12468 :                 appendStringInfoString(es->str, value);
                                195                 :                :             else
                                196                 :           1853 :                 escape_json(es->str, value);
                                197                 :          14321 :             break;
                                198                 :                : 
                                199                 :            186 :         case EXPLAIN_FORMAT_YAML:
                                200                 :            186 :             ExplainYAMLLineStarting(es);
                                201                 :            186 :             appendStringInfo(es->str, "%s: ", qlabel);
                                202         [ +  + ]:            186 :             if (numeric)
                                203                 :            165 :                 appendStringInfoString(es->str, value);
                                204                 :                :             else
                                205                 :             21 :                 escape_yaml(es->str, value);
                                206                 :            186 :             break;
                                207                 :                :     }
                                208                 :          38807 : }
                                209                 :                : 
                                210                 :                : /*
                                211                 :                :  * Explain a string-valued property.
                                212                 :                :  */
                                213                 :                : void
                                214                 :          21433 : ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
                                215                 :                : {
                                216                 :          21433 :     ExplainProperty(qlabel, NULL, value, false, es);
                                217                 :          21433 : }
                                218                 :                : 
                                219                 :                : /*
                                220                 :                :  * Explain an integer-valued property.
                                221                 :                :  */
                                222                 :                : void
                                223                 :           7662 : ExplainPropertyInteger(const char *qlabel, const char *unit, int64 value,
                                224                 :                :                        ExplainState *es)
                                225                 :                : {
                                226                 :                :     char        buf[32];
                                227                 :                : 
                                228                 :           7662 :     snprintf(buf, sizeof(buf), INT64_FORMAT, value);
                                229                 :           7662 :     ExplainProperty(qlabel, unit, buf, true, es);
                                230                 :           7662 : }
                                231                 :                : 
                                232                 :                : /*
                                233                 :                :  * Explain an unsigned integer-valued property.
                                234                 :                :  */
                                235                 :                : void
                                236                 :            779 : ExplainPropertyUInteger(const char *qlabel, const char *unit, uint64 value,
                                237                 :                :                         ExplainState *es)
                                238                 :                : {
                                239                 :                :     char        buf[32];
                                240                 :                : 
                                241                 :            779 :     snprintf(buf, sizeof(buf), UINT64_FORMAT, value);
                                242                 :            779 :     ExplainProperty(qlabel, unit, buf, true, es);
                                243                 :            779 : }
                                244                 :                : 
                                245                 :                : /*
                                246                 :                :  * Explain a float-valued property, using the specified number of
                                247                 :                :  * fractional digits.
                                248                 :                :  */
                                249                 :                : void
                                250                 :           7029 : ExplainPropertyFloat(const char *qlabel, const char *unit, double value,
                                251                 :                :                      int ndigits, ExplainState *es)
                                252                 :                : {
                                253                 :                :     char       *buf;
                                254                 :                : 
                                255                 :           7029 :     buf = psprintf("%.*f", ndigits, value);
                                256                 :           7029 :     ExplainProperty(qlabel, unit, buf, true, es);
                                257                 :           7029 :     pfree(buf);
                                258                 :           7029 : }
                                259                 :                : 
                                260                 :                : /*
                                261                 :                :  * Explain a bool-valued property.
                                262                 :                :  */
                                263                 :                : void
                                264                 :           1904 : ExplainPropertyBool(const char *qlabel, bool value, ExplainState *es)
                                265                 :                : {
                                266         [ +  + ]:           1904 :     ExplainProperty(qlabel, NULL, value ? "true" : "false", true, es);
                                267                 :           1904 : }
                                268                 :                : 
                                269                 :                : /*
                                270                 :                :  * Open a group of related objects.
                                271                 :                :  *
                                272                 :                :  * objtype is the type of the group object, labelname is its label within
                                273                 :                :  * a containing object (if any).
                                274                 :                :  *
                                275                 :                :  * If labeled is true, the group members will be labeled properties,
                                276                 :                :  * while if it's false, they'll be unlabeled objects.
                                277                 :                :  */
                                278                 :                : void
                                279                 :          79315 : ExplainOpenGroup(const char *objtype, const char *labelname,
                                280                 :                :                  bool labeled, ExplainState *es)
                                281                 :                : {
                                282   [ +  +  +  +  :          79315 :     switch (es->format)
                                                 - ]
                                283                 :                :     {
                                284                 :          77774 :         case EXPLAIN_FORMAT_TEXT:
                                285                 :                :             /* nothing to do */
                                286                 :          77774 :             break;
                                287                 :                : 
                                288                 :             27 :         case EXPLAIN_FORMAT_XML:
                                289                 :             27 :             ExplainXMLTag(objtype, X_OPENING, es);
                                290                 :             27 :             es->indent++;
                                291                 :             27 :             break;
                                292                 :                : 
                                293                 :           1490 :         case EXPLAIN_FORMAT_JSON:
                                294                 :           1490 :             ExplainJSONLineEnding(es);
                                295                 :           1490 :             appendStringInfoSpaces(es->str, 2 * es->indent);
                                296         [ +  + ]:           1490 :             if (labelname)
                                297                 :                :             {
                                298                 :            939 :                 escape_json(es->str, labelname);
                                299                 :            939 :                 appendStringInfoString(es->str, ": ");
                                300                 :                :             }
                                301         [ +  + ]:           1490 :             appendStringInfoChar(es->str, labeled ? '{' : '[');
                                302                 :                : 
                                303                 :                :             /*
                                304                 :                :              * In JSON format, the grouping_stack is an integer list.  0 means
                                305                 :                :              * we've emitted nothing at this grouping level, 1 means we've
                                306                 :                :              * emitted something (and so the next item needs a comma). See
                                307                 :                :              * ExplainJSONLineEnding().
                                308                 :                :              */
                                309                 :           1490 :             es->grouping_stack = lcons_int(0, es->grouping_stack);
                                310                 :           1490 :             es->indent++;
                                311                 :           1490 :             break;
                                312                 :                : 
                                313                 :             24 :         case EXPLAIN_FORMAT_YAML:
                                314                 :                : 
                                315                 :                :             /*
                                316                 :                :              * In YAML format, the grouping stack is an integer list.  0 means
                                317                 :                :              * we've emitted nothing at this grouping level AND this grouping
                                318                 :                :              * level is unlabeled and must be marked with "- ".  See
                                319                 :                :              * ExplainYAMLLineStarting().
                                320                 :                :              */
                                321                 :             24 :             ExplainYAMLLineStarting(es);
                                322         [ +  + ]:             24 :             if (labelname)
                                323                 :                :             {
                                324                 :             18 :                 appendStringInfo(es->str, "%s: ", labelname);
                                325                 :             18 :                 es->grouping_stack = lcons_int(1, es->grouping_stack);
                                326                 :                :             }
                                327                 :                :             else
                                328                 :                :             {
                                329                 :              6 :                 appendStringInfoString(es->str, "- ");
                                330                 :              6 :                 es->grouping_stack = lcons_int(0, es->grouping_stack);
                                331                 :                :             }
                                332                 :             24 :             es->indent++;
                                333                 :             24 :             break;
                                334                 :                :     }
                                335                 :          79315 : }
                                336                 :                : 
                                337                 :                : /*
                                338                 :                :  * Close a group of related objects.
                                339                 :                :  * Parameters must match the corresponding ExplainOpenGroup call.
                                340                 :                :  */
                                341                 :                : void
                                342                 :          79315 : ExplainCloseGroup(const char *objtype, const char *labelname,
                                343                 :                :                   bool labeled, ExplainState *es)
                                344                 :                : {
                                345   [ +  +  +  +  :          79315 :     switch (es->format)
                                                 - ]
                                346                 :                :     {
                                347                 :          77774 :         case EXPLAIN_FORMAT_TEXT:
                                348                 :                :             /* nothing to do */
                                349                 :          77774 :             break;
                                350                 :                : 
                                351                 :             27 :         case EXPLAIN_FORMAT_XML:
                                352                 :             27 :             es->indent--;
                                353                 :             27 :             ExplainXMLTag(objtype, X_CLOSING, es);
                                354                 :             27 :             break;
                                355                 :                : 
                                356                 :           1490 :         case EXPLAIN_FORMAT_JSON:
                                357                 :           1490 :             es->indent--;
                                358                 :           1490 :             appendStringInfoChar(es->str, '\n');
                                359                 :           1490 :             appendStringInfoSpaces(es->str, 2 * es->indent);
                                360         [ +  + ]:           1490 :             appendStringInfoChar(es->str, labeled ? '}' : ']');
                                361                 :           1490 :             es->grouping_stack = list_delete_first(es->grouping_stack);
                                362                 :           1490 :             break;
                                363                 :                : 
                                364                 :             24 :         case EXPLAIN_FORMAT_YAML:
                                365                 :             24 :             es->indent--;
                                366                 :             24 :             es->grouping_stack = list_delete_first(es->grouping_stack);
                                367                 :             24 :             break;
                                368                 :                :     }
                                369                 :          79315 : }
                                370                 :                : 
                                371                 :                : /*
                                372                 :                :  * Open a group of related objects, without emitting actual data.
                                373                 :                :  *
                                374                 :                :  * Prepare the formatting state as though we were beginning a group with
                                375                 :                :  * the identified properties, but don't actually emit anything.  Output
                                376                 :                :  * subsequent to this call can be redirected into a separate output buffer,
                                377                 :                :  * and then eventually appended to the main output buffer after doing a
                                378                 :                :  * regular ExplainOpenGroup call (with the same parameters).
                                379                 :                :  *
                                380                 :                :  * The extra "depth" parameter is the new group's depth compared to current.
                                381                 :                :  * It could be more than one, in case the eventual output will be enclosed
                                382                 :                :  * in additional nesting group levels.  We assume we don't need to track
                                383                 :                :  * formatting state for those levels while preparing this group's output.
                                384                 :                :  *
                                385                 :                :  * There is no ExplainCloseSetAsideGroup --- in current usage, we always
                                386                 :                :  * pop this state with ExplainSaveGroup.
                                387                 :                :  */
                                388                 :                : void
                                389                 :             36 : ExplainOpenSetAsideGroup(const char *objtype, const char *labelname,
                                390                 :                :                          bool labeled, int depth, ExplainState *es)
                                391                 :                : {
                                392   [ +  -  +  -  :             36 :     switch (es->format)
                                                 - ]
                                393                 :                :     {
                                394                 :             12 :         case EXPLAIN_FORMAT_TEXT:
                                395                 :                :             /* nothing to do */
                                396                 :             12 :             break;
                                397                 :                : 
  191 rhaas@postgresql.org      398                 :UBC           0 :         case EXPLAIN_FORMAT_XML:
                                399                 :              0 :             es->indent += depth;
                                400                 :              0 :             break;
                                401                 :                : 
  191 rhaas@postgresql.org      402                 :CBC          24 :         case EXPLAIN_FORMAT_JSON:
                                403                 :             24 :             es->grouping_stack = lcons_int(0, es->grouping_stack);
                                404                 :             24 :             es->indent += depth;
                                405                 :             24 :             break;
                                406                 :                : 
  191 rhaas@postgresql.org      407                 :UBC           0 :         case EXPLAIN_FORMAT_YAML:
                                408         [ #  # ]:              0 :             if (labelname)
                                409                 :              0 :                 es->grouping_stack = lcons_int(1, es->grouping_stack);
                                410                 :                :             else
                                411                 :              0 :                 es->grouping_stack = lcons_int(0, es->grouping_stack);
                                412                 :              0 :             es->indent += depth;
                                413                 :              0 :             break;
                                414                 :                :     }
  191 rhaas@postgresql.org      415                 :CBC          36 : }
                                416                 :                : 
                                417                 :                : /*
                                418                 :                :  * Pop one level of grouping state, allowing for a re-push later.
                                419                 :                :  *
                                420                 :                :  * This is typically used after ExplainOpenSetAsideGroup; pass the
                                421                 :                :  * same "depth" used for that.
                                422                 :                :  *
                                423                 :                :  * This should not emit any output.  If state needs to be saved,
                                424                 :                :  * save it at *state_save.  Currently, an integer save area is sufficient
                                425                 :                :  * for all formats, but we might need to revisit that someday.
                                426                 :                :  */
                                427                 :                : void
                                428                 :             72 : ExplainSaveGroup(ExplainState *es, int depth, int *state_save)
                                429                 :                : {
                                430   [ +  -  +  -  :             72 :     switch (es->format)
                                                 - ]
                                431                 :                :     {
                                432                 :             12 :         case EXPLAIN_FORMAT_TEXT:
                                433                 :                :             /* nothing to do */
                                434                 :             12 :             break;
                                435                 :                : 
  191 rhaas@postgresql.org      436                 :UBC           0 :         case EXPLAIN_FORMAT_XML:
                                437                 :              0 :             es->indent -= depth;
                                438                 :              0 :             break;
                                439                 :                : 
  191 rhaas@postgresql.org      440                 :CBC          60 :         case EXPLAIN_FORMAT_JSON:
                                441                 :             60 :             es->indent -= depth;
                                442                 :             60 :             *state_save = linitial_int(es->grouping_stack);
                                443                 :             60 :             es->grouping_stack = list_delete_first(es->grouping_stack);
                                444                 :             60 :             break;
                                445                 :                : 
  191 rhaas@postgresql.org      446                 :UBC           0 :         case EXPLAIN_FORMAT_YAML:
                                447                 :              0 :             es->indent -= depth;
                                448                 :              0 :             *state_save = linitial_int(es->grouping_stack);
                                449                 :              0 :             es->grouping_stack = list_delete_first(es->grouping_stack);
                                450                 :              0 :             break;
                                451                 :                :     }
  191 rhaas@postgresql.org      452                 :CBC          72 : }
                                453                 :                : 
                                454                 :                : /*
                                455                 :                :  * Re-push one level of grouping state, undoing the effects of ExplainSaveGroup.
                                456                 :                :  */
                                457                 :                : void
                                458                 :             36 : ExplainRestoreGroup(ExplainState *es, int depth, int *state_save)
                                459                 :                : {
                                460   [ -  -  +  -  :             36 :     switch (es->format)
                                                 - ]
                                461                 :                :     {
  191 rhaas@postgresql.org      462                 :UBC           0 :         case EXPLAIN_FORMAT_TEXT:
                                463                 :                :             /* nothing to do */
                                464                 :              0 :             break;
                                465                 :                : 
                                466                 :              0 :         case EXPLAIN_FORMAT_XML:
                                467                 :              0 :             es->indent += depth;
                                468                 :              0 :             break;
                                469                 :                : 
  191 rhaas@postgresql.org      470                 :CBC          36 :         case EXPLAIN_FORMAT_JSON:
                                471                 :             36 :             es->grouping_stack = lcons_int(*state_save, es->grouping_stack);
                                472                 :             36 :             es->indent += depth;
                                473                 :             36 :             break;
                                474                 :                : 
  191 rhaas@postgresql.org      475                 :UBC           0 :         case EXPLAIN_FORMAT_YAML:
                                476                 :              0 :             es->grouping_stack = lcons_int(*state_save, es->grouping_stack);
                                477                 :              0 :             es->indent += depth;
                                478                 :              0 :             break;
                                479                 :                :     }
  191 rhaas@postgresql.org      480                 :CBC          36 : }
                                481                 :                : 
                                482                 :                : /*
                                483                 :                :  * Emit a "dummy" group that never has any members.
                                484                 :                :  *
                                485                 :                :  * objtype is the type of the group object, labelname is its label within
                                486                 :                :  * a containing object (if any).
                                487                 :                :  */
                                488                 :                : void
                                489                 :             15 : ExplainDummyGroup(const char *objtype, const char *labelname, ExplainState *es)
                                490                 :                : {
                                491   [ +  -  -  -  :             15 :     switch (es->format)
                                                 - ]
                                492                 :                :     {
                                493                 :             15 :         case EXPLAIN_FORMAT_TEXT:
                                494                 :                :             /* nothing to do */
                                495                 :             15 :             break;
                                496                 :                : 
  191 rhaas@postgresql.org      497                 :UBC           0 :         case EXPLAIN_FORMAT_XML:
                                498                 :              0 :             ExplainXMLTag(objtype, X_CLOSE_IMMEDIATE, es);
                                499                 :              0 :             break;
                                500                 :                : 
                                501                 :              0 :         case EXPLAIN_FORMAT_JSON:
                                502                 :              0 :             ExplainJSONLineEnding(es);
                                503                 :              0 :             appendStringInfoSpaces(es->str, 2 * es->indent);
                                504         [ #  # ]:              0 :             if (labelname)
                                505                 :                :             {
                                506                 :              0 :                 escape_json(es->str, labelname);
                                507                 :              0 :                 appendStringInfoString(es->str, ": ");
                                508                 :                :             }
                                509                 :              0 :             escape_json(es->str, objtype);
                                510                 :              0 :             break;
                                511                 :                : 
                                512                 :              0 :         case EXPLAIN_FORMAT_YAML:
                                513                 :              0 :             ExplainYAMLLineStarting(es);
                                514         [ #  # ]:              0 :             if (labelname)
                                515                 :                :             {
                                516                 :              0 :                 escape_yaml(es->str, labelname);
                                517                 :              0 :                 appendStringInfoString(es->str, ": ");
                                518                 :                :             }
                                519                 :                :             else
                                520                 :                :             {
                                521                 :              0 :                 appendStringInfoString(es->str, "- ");
                                522                 :                :             }
                                523                 :              0 :             escape_yaml(es->str, objtype);
                                524                 :              0 :             break;
                                525                 :                :     }
  191 rhaas@postgresql.org      526                 :CBC          15 : }
                                527                 :                : 
                                528                 :                : /*
                                529                 :                :  * Emit the start-of-output boilerplate.
                                530                 :                :  *
                                531                 :                :  * This is just enough different from processing a subgroup that we need
                                532                 :                :  * a separate pair of subroutines.
                                533                 :                :  */
                                534                 :                : void
                                535                 :          12034 : ExplainBeginOutput(ExplainState *es)
                                536                 :                : {
                                537   [ +  +  +  +  :          12034 :     switch (es->format)
                                                 - ]
                                538                 :                :     {
                                539                 :          11881 :         case EXPLAIN_FORMAT_TEXT:
                                540                 :                :             /* nothing to do */
                                541                 :          11881 :             break;
                                542                 :                : 
                                543                 :              4 :         case EXPLAIN_FORMAT_XML:
                                544                 :              4 :             appendStringInfoString(es->str,
                                545                 :                :                                    "<explain xmlns=\"http://www.postgresql.org/2009/explain\">\n");
                                546                 :              4 :             es->indent++;
                                547                 :              4 :             break;
                                548                 :                : 
                                549                 :            143 :         case EXPLAIN_FORMAT_JSON:
                                550                 :                :             /* top-level structure is an array of plans */
                                551                 :            143 :             appendStringInfoChar(es->str, '[');
                                552                 :            143 :             es->grouping_stack = lcons_int(0, es->grouping_stack);
                                553                 :            143 :             es->indent++;
                                554                 :            143 :             break;
                                555                 :                : 
                                556                 :              6 :         case EXPLAIN_FORMAT_YAML:
                                557                 :              6 :             es->grouping_stack = lcons_int(0, es->grouping_stack);
                                558                 :              6 :             break;
                                559                 :                :     }
                                560                 :          12034 : }
                                561                 :                : 
                                562                 :                : /*
                                563                 :                :  * Emit the end-of-output boilerplate.
                                564                 :                :  */
                                565                 :                : void
                                566                 :          11975 : ExplainEndOutput(ExplainState *es)
                                567                 :                : {
                                568   [ +  +  +  +  :          11975 :     switch (es->format)
                                                 - ]
                                569                 :                :     {
                                570                 :          11822 :         case EXPLAIN_FORMAT_TEXT:
                                571                 :                :             /* nothing to do */
                                572                 :          11822 :             break;
                                573                 :                : 
                                574                 :              4 :         case EXPLAIN_FORMAT_XML:
                                575                 :              4 :             es->indent--;
                                576                 :              4 :             appendStringInfoString(es->str, "</explain>");
                                577                 :              4 :             break;
                                578                 :                : 
                                579                 :            143 :         case EXPLAIN_FORMAT_JSON:
                                580                 :            143 :             es->indent--;
                                581                 :            143 :             appendStringInfoString(es->str, "\n]");
                                582                 :            143 :             es->grouping_stack = list_delete_first(es->grouping_stack);
                                583                 :            143 :             break;
                                584                 :                : 
                                585                 :              6 :         case EXPLAIN_FORMAT_YAML:
                                586                 :              6 :             es->grouping_stack = list_delete_first(es->grouping_stack);
                                587                 :              6 :             break;
                                588                 :                :     }
                                589                 :          11975 : }
                                590                 :                : 
                                591                 :                : /*
                                592                 :                :  * Put an appropriate separator between multiple plans
                                593                 :                :  */
                                594                 :                : void
                                595                 :              6 : ExplainSeparatePlans(ExplainState *es)
                                596                 :                : {
                                597      [ +  -  - ]:              6 :     switch (es->format)
                                598                 :                :     {
                                599                 :              6 :         case EXPLAIN_FORMAT_TEXT:
                                600                 :                :             /* add a blank line */
                                601                 :              6 :             appendStringInfoChar(es->str, '\n');
                                602                 :              6 :             break;
                                603                 :                : 
  191 rhaas@postgresql.org      604                 :UBC           0 :         case EXPLAIN_FORMAT_XML:
                                605                 :                :         case EXPLAIN_FORMAT_JSON:
                                606                 :                :         case EXPLAIN_FORMAT_YAML:
                                607                 :                :             /* nothing to do */
                                608                 :              0 :             break;
                                609                 :                :     }
  191 rhaas@postgresql.org      610                 :CBC           6 : }
                                611                 :                : 
                                612                 :                : /*
                                613                 :                :  * Emit opening or closing XML tag.
                                614                 :                :  *
                                615                 :                :  * "flags" must contain X_OPENING, X_CLOSING, or X_CLOSE_IMMEDIATE.
                                616                 :                :  * Optionally, OR in X_NOWHITESPACE to suppress the whitespace we'd normally
                                617                 :                :  * add.
                                618                 :                :  *
                                619                 :                :  * XML restricts tag names more than our other output formats, eg they can't
                                620                 :                :  * contain white space or slashes.  Replace invalid characters with dashes,
                                621                 :                :  * so that for example "I/O Read Time" becomes "I-O-Read-Time".
                                622                 :                :  */
                                623                 :                : static void
                                624                 :            488 : ExplainXMLTag(const char *tagname, int flags, ExplainState *es)
                                625                 :                : {
                                626                 :                :     const char *s;
                                627                 :            488 :     const char *valid = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.";
                                628                 :                : 
                                629         [ +  + ]:            488 :     if ((flags & X_NOWHITESPACE) == 0)
                                630                 :             58 :         appendStringInfoSpaces(es->str, 2 * es->indent);
                                631         [ -  + ]:            488 :     appendStringInfoCharMacro(es->str, '<');
                                632         [ +  + ]:            488 :     if ((flags & X_CLOSING) != 0)
                                633         [ -  + ]:            244 :         appendStringInfoCharMacro(es->str, '/');
                                634         [ +  + ]:           6612 :     for (s = tagname; *s; s++)
                                635         [ +  + ]:           6124 :         appendStringInfoChar(es->str, strchr(valid, *s) ? *s : '-');
                                636         [ -  + ]:            488 :     if ((flags & X_CLOSE_IMMEDIATE) != 0)
  191 rhaas@postgresql.org      637                 :UBC           0 :         appendStringInfoString(es->str, " /");
  191 rhaas@postgresql.org      638         [ -  + ]:CBC         488 :     appendStringInfoCharMacro(es->str, '>');
                                639         [ +  + ]:            488 :     if ((flags & X_NOWHITESPACE) == 0)
                                640         [ -  + ]:             58 :         appendStringInfoCharMacro(es->str, '\n');
                                641                 :            488 : }
                                642                 :                : 
                                643                 :                : /*
                                644                 :                :  * Indent a text-format line.
                                645                 :                :  *
                                646                 :                :  * We indent by two spaces per indentation level.  However, when emitting
                                647                 :                :  * data for a parallel worker there might already be data on the current line
                                648                 :                :  * (cf. ExplainOpenWorker); in that case, don't indent any more.
                                649                 :                :  */
                                650                 :                : void
                                651                 :          66331 : ExplainIndentText(ExplainState *es)
                                652                 :                : {
                                653         [ -  + ]:          66331 :     Assert(es->format == EXPLAIN_FORMAT_TEXT);
                                654   [ +  +  +  + ]:          66331 :     if (es->str->len == 0 || es->str->data[es->str->len - 1] == '\n')
                                655                 :          66319 :         appendStringInfoSpaces(es->str, es->indent * 2);
                                656                 :          66331 : }
                                657                 :                : 
                                658                 :                : /*
                                659                 :                :  * Emit a JSON line ending.
                                660                 :                :  *
                                661                 :                :  * JSON requires a comma after each property but the last.  To facilitate this,
                                662                 :                :  * in JSON format, the text emitted for each property begins just prior to the
                                663                 :                :  * preceding line-break (and comma, if applicable).
                                664                 :                :  */
                                665                 :                : static void
                                666                 :          15892 : ExplainJSONLineEnding(ExplainState *es)
                                667                 :                : {
                                668         [ -  + ]:          15892 :     Assert(es->format == EXPLAIN_FORMAT_JSON);
                                669         [ +  + ]:          15892 :     if (linitial_int(es->grouping_stack) != 0)
                                670                 :          14576 :         appendStringInfoChar(es->str, ',');
                                671                 :                :     else
                                672                 :           1316 :         linitial_int(es->grouping_stack) = 1;
                                673                 :          15892 :     appendStringInfoChar(es->str, '\n');
                                674                 :          15892 : }
                                675                 :                : 
                                676                 :                : /*
                                677                 :                :  * Indent a YAML line.
                                678                 :                :  *
                                679                 :                :  * YAML lines are ordinarily indented by two spaces per indentation level.
                                680                 :                :  * The text emitted for each property begins just prior to the preceding
                                681                 :                :  * line-break, except for the first property in an unlabeled group, for which
                                682                 :                :  * it begins immediately after the "- " that introduces the group.  The first
                                683                 :                :  * property of the group appears on the same line as the opening "- ".
                                684                 :                :  */
                                685                 :                : static void
                                686                 :            210 : ExplainYAMLLineStarting(ExplainState *es)
                                687                 :                : {
                                688         [ -  + ]:            210 :     Assert(es->format == EXPLAIN_FORMAT_YAML);
                                689         [ +  + ]:            210 :     if (linitial_int(es->grouping_stack) == 0)
                                690                 :                :     {
                                691                 :             12 :         linitial_int(es->grouping_stack) = 1;
                                692                 :                :     }
                                693                 :                :     else
                                694                 :                :     {
                                695                 :            198 :         appendStringInfoChar(es->str, '\n');
                                696                 :            198 :         appendStringInfoSpaces(es->str, es->indent * 2);
                                697                 :                :     }
                                698                 :            210 : }
                                699                 :                : 
                                700                 :                : /*
                                701                 :                :  * YAML is a superset of JSON; unfortunately, the YAML quoting rules are
                                702                 :                :  * ridiculously complicated -- as documented in sections 5.3 and 7.3.3 of
                                703                 :                :  * http://yaml.org/spec/1.2/spec.html -- so we chose to just quote everything.
                                704                 :                :  * Empty strings, strings with leading or trailing whitespace, and strings
                                705                 :                :  * containing a variety of special characters must certainly be quoted or the
                                706                 :                :  * output is invalid; and other seemingly harmless strings like "0xa" or
                                707                 :                :  * "true" must be quoted, lest they be interpreted as a hexadecimal or Boolean
                                708                 :                :  * constant rather than a string.
                                709                 :                :  */
                                710                 :                : static void
                                711                 :             21 : escape_yaml(StringInfo buf, const char *str)
                                712                 :                : {
                                713                 :             21 :     escape_json(buf, str);
                                714                 :             21 : }
        

Generated by: LCOV version 2.4-beta