LCOV - code coverage report
Current view: top level - contrib/pg_plan_advice - pg_plan_advice.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 98.8 % 166 164
Test Date: 2026-01-26 10:56:24 Functions: 100.0 % 13 13
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 92.4 % 79 73

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * pg_plan_advice.c
       4                 :             :  *        main entrypoints for generating and applying planner advice
       5                 :             :  *
       6                 :             :  * Copyright (c) 2016-2024, PostgreSQL Global Development Group
       7                 :             :  *
       8                 :             :  *        contrib/pg_plan_advice/pg_plan_advice.c
       9                 :             :  *
      10                 :             :  *-------------------------------------------------------------------------
      11                 :             :  */
      12                 :             : #include "postgres.h"
      13                 :             : 
      14                 :             : #include "pg_plan_advice.h"
      15                 :             : #include "pgpa_ast.h"
      16                 :             : #include "pgpa_collector.h"
      17                 :             : #include "pgpa_identifier.h"
      18                 :             : #include "pgpa_output.h"
      19                 :             : #include "pgpa_planner.h"
      20                 :             : #include "pgpa_trove.h"
      21                 :             : #include "pgpa_walker.h"
      22                 :             : 
      23                 :             : #include "commands/defrem.h"
      24                 :             : #include "commands/explain.h"
      25                 :             : #include "commands/explain_format.h"
      26                 :             : #include "commands/explain_state.h"
      27                 :             : #include "funcapi.h"
      28                 :             : #include "optimizer/planner.h"
      29                 :             : #include "storage/dsm_registry.h"
      30                 :             : #include "utils/guc.h"
      31                 :             : 
      32                 :         795 : PG_MODULE_MAGIC;
      33                 :             : 
      34                 :             : static pgpa_shared_state *pgpa_state = NULL;
      35                 :             : static dsa_area *pgpa_dsa_area = NULL;
      36                 :             : 
      37                 :             : /* GUC variables */
      38                 :             : char       *pg_plan_advice_advice = NULL;
      39                 :             : bool            pg_plan_advice_always_store_advice_details = false;
      40                 :             : static bool pg_plan_advice_always_explain_supplied_advice = true;
      41                 :             : bool            pg_plan_advice_local_collector = false;
      42                 :             : int                     pg_plan_advice_local_collection_limit = 0;
      43                 :             : bool            pg_plan_advice_shared_collector = false;
      44                 :             : int                     pg_plan_advice_shared_collection_limit = 0;
      45                 :             : bool            pg_plan_advice_trace_mask = false;
      46                 :             : 
      47                 :             : /* Saved hook value */
      48                 :             : static explain_per_plan_hook_type prev_explain_per_plan = NULL;
      49                 :             : 
      50                 :             : /* Other file-level globals */
      51                 :             : static int      es_extension_id;
      52                 :             : static MemoryContext pgpa_memory_context = NULL;
      53                 :             : 
      54                 :             : static void pgpa_init_shared_state(void *ptr, void *arg);
      55                 :             : static void pg_plan_advice_explain_option_handler(ExplainState *es,
      56                 :             :                                                                                                   DefElem *opt,
      57                 :             :                                                                                                   ParseState *pstate);
      58                 :             : static void pg_plan_advice_explain_per_plan_hook(PlannedStmt *plannedstmt,
      59                 :             :                                                                                                  IntoClause *into,
      60                 :             :                                                                                                  ExplainState *es,
      61                 :             :                                                                                                  const char *queryString,
      62                 :             :                                                                                                  ParamListInfo params,
      63                 :             :                                                                                                  QueryEnvironment *queryEnv);
      64                 :             : static bool pg_plan_advice_advice_check_hook(char **newval, void **extra,
      65                 :             :                                                                                          GucSource source);
      66                 :             : static DefElem *find_defelem_by_defname(List *deflist, char *defname);
      67                 :             : 
      68                 :             : /*
      69                 :             :  * Initialize this module.
      70                 :             :  */
      71                 :             : void
      72                 :         795 : _PG_init(void)
      73                 :             : {
      74                 :         795 :         DefineCustomStringVariable("pg_plan_advice.advice",
      75                 :             :                                                            "advice to apply during query planning",
      76                 :             :                                                            NULL,
      77                 :             :                                                            &pg_plan_advice_advice,
      78                 :             :                                                            NULL,
      79                 :             :                                                            PGC_USERSET,
      80                 :             :                                                            0,
      81                 :             :                                                            pg_plan_advice_advice_check_hook,
      82                 :             :                                                            NULL,
      83                 :             :                                                            NULL);
      84                 :             : 
      85                 :         795 :         DefineCustomBoolVariable("pg_plan_advice.always_explain_supplied_advice",
      86                 :             :                                                          "EXPLAIN output includes supplied advice even without EXPLAIN (PLAN_ADVICE)",
      87                 :             :                                                          NULL,
      88                 :             :                                                          &pg_plan_advice_always_explain_supplied_advice,
      89                 :             :                                                          true,
      90                 :             :                                                          PGC_USERSET,
      91                 :             :                                                          0,
      92                 :             :                                                          NULL,
      93                 :             :                                                          NULL,
      94                 :             :                                                          NULL);
      95                 :             : 
      96                 :         795 :         DefineCustomBoolVariable("pg_plan_advice.always_store_advice_details",
      97                 :             :                                                          "Generate advice strings even when seemingly not required",
      98                 :             :                                                          "Use this option to see generated advice for prepared queries.",
      99                 :             :                                                          &pg_plan_advice_always_store_advice_details,
     100                 :             :                                                          false,
     101                 :             :                                                          PGC_USERSET,
     102                 :             :                                                          0,
     103                 :             :                                                          NULL,
     104                 :             :                                                          NULL,
     105                 :             :                                                          NULL);
     106                 :             : 
     107                 :         795 :         DefineCustomBoolVariable("pg_plan_advice.local_collector",
     108                 :             :                                                          "Enable the local advice collector.",
     109                 :             :                                                          NULL,
     110                 :             :                                                          &pg_plan_advice_local_collector,
     111                 :             :                                                          false,
     112                 :             :                                                          PGC_USERSET,
     113                 :             :                                                          0,
     114                 :             :                                                          NULL,
     115                 :             :                                                          NULL,
     116                 :             :                                                          NULL);
     117                 :             : 
     118                 :         795 :         DefineCustomIntVariable("pg_plan_advice.local_collection_limit",
     119                 :             :                                                         "# of advice entries to retain in per-backend memory",
     120                 :             :                                                         NULL,
     121                 :             :                                                         &pg_plan_advice_local_collection_limit,
     122                 :             :                                                         0,
     123                 :             :                                                         0, INT_MAX,
     124                 :             :                                                         PGC_USERSET,
     125                 :             :                                                         0,
     126                 :             :                                                         NULL,
     127                 :             :                                                         NULL,
     128                 :             :                                                         NULL);
     129                 :             : 
     130                 :         795 :         DefineCustomBoolVariable("pg_plan_advice.shared_collector",
     131                 :             :                                                          "Enable the shared advice collector.",
     132                 :             :                                                          NULL,
     133                 :             :                                                          &pg_plan_advice_shared_collector,
     134                 :             :                                                          false,
     135                 :             :                                                          PGC_SUSET,
     136                 :             :                                                          0,
     137                 :             :                                                          NULL,
     138                 :             :                                                          NULL,
     139                 :             :                                                          NULL);
     140                 :             : 
     141                 :         795 :         DefineCustomIntVariable("pg_plan_advice.shared_collection_limit",
     142                 :             :                                                         "# of advice entries to retain in shared memory",
     143                 :             :                                                         NULL,
     144                 :             :                                                         &pg_plan_advice_shared_collection_limit,
     145                 :             :                                                         0,
     146                 :             :                                                         0, INT_MAX,
     147                 :             :                                                         PGC_SUSET,
     148                 :             :                                                         0,
     149                 :             :                                                         NULL,
     150                 :             :                                                         NULL,
     151                 :             :                                                         NULL);
     152                 :             : 
     153                 :         795 :         DefineCustomBoolVariable("pg_plan_advice.trace_mask",
     154                 :             :                                                          "Emit debugging messages showing the computed strategy mask for each relation",
     155                 :             :                                                          NULL,
     156                 :             :                                                          &pg_plan_advice_trace_mask,
     157                 :             :                                                          false,
     158                 :             :                                                          PGC_USERSET,
     159                 :             :                                                          0,
     160                 :             :                                                          NULL,
     161                 :             :                                                          NULL,
     162                 :             :                                                          NULL);
     163                 :             : 
     164                 :         795 :         MarkGUCPrefixReserved("pg_plan_advice");
     165                 :             : 
     166                 :             :         /* Get an ID that we can use to cache data in an ExplainState. */
     167                 :         795 :         es_extension_id = GetExplainExtensionId("pg_plan_advice");
     168                 :             : 
     169                 :             :         /* Register the new EXPLAIN options implemented by this module. */
     170                 :         795 :         RegisterExtensionExplainOption("plan_advice",
     171                 :             :                                                                    pg_plan_advice_explain_option_handler);
     172                 :             : 
     173                 :             :         /* Install hooks */
     174                 :         795 :         pgpa_planner_install_hooks();
     175                 :         795 :         prev_explain_per_plan = explain_per_plan_hook;
     176                 :         795 :         explain_per_plan_hook = pg_plan_advice_explain_per_plan_hook;
     177                 :         795 : }
     178                 :             : 
     179                 :             : /*
     180                 :             :  * Initialize shared state when first created.
     181                 :             :  */
     182                 :             : static void
     183                 :           1 : pgpa_init_shared_state(void *ptr, void *arg)
     184                 :             : {
     185                 :           1 :         pgpa_shared_state *state = (pgpa_shared_state *) ptr;
     186                 :             : 
     187                 :           1 :         LWLockInitialize(&state->lock, LWLockNewTrancheId("pg_plan_advice_lock"));
     188                 :           1 :         state->dsa_tranche = LWLockNewTrancheId("pg_plan_advice_dsa");
     189                 :           1 :         state->area = DSA_HANDLE_INVALID;
     190                 :           1 :         state->shared_collector = InvalidDsaPointer;
     191                 :           1 : }
     192                 :             : 
     193                 :             : /*
     194                 :             :  * Return a pointer to a memory context where long-lived data managed by this
     195                 :             :  * module can be stored.
     196                 :             :  */
     197                 :             : MemoryContext
     198                 :        2256 : pg_plan_advice_get_mcxt(void)
     199                 :             : {
     200         [ +  + ]:        2256 :         if (pgpa_memory_context == NULL)
     201                 :         255 :                 pgpa_memory_context = AllocSetContextCreate(TopMemoryContext,
     202                 :             :                                                                                                         "pg_plan_advice",
     203                 :             :                                                                                                         ALLOCSET_DEFAULT_SIZES);
     204                 :             : 
     205                 :        2256 :         return pgpa_memory_context;
     206                 :             : }
     207                 :             : 
     208                 :             : /*
     209                 :             :  * Get a pointer to our shared state.
     210                 :             :  *
     211                 :             :  * If no shared state exists, create and initialize it. If it does exist but
     212                 :             :  * this backend has not yet accessed it, attach to it. Otherwise, just return
     213                 :             :  * our cached pointer.
     214                 :             :  *
     215                 :             :  * Along the way, make sure the relevant LWLock tranches are registered.
     216                 :             :  */
     217                 :             : pgpa_shared_state *
     218                 :       22584 : pg_plan_advice_attach(void)
     219                 :             : {
     220         [ +  + ]:       22584 :         if (pgpa_state == NULL)
     221                 :             :         {
     222                 :         254 :                 bool            found;
     223                 :             : 
     224                 :         254 :                 pgpa_state =
     225                 :         254 :                         GetNamedDSMSegment("pg_plan_advice", sizeof(pgpa_shared_state),
     226                 :             :                                                            pgpa_init_shared_state, &found, NULL);
     227                 :         254 :         }
     228                 :             : 
     229                 :       22584 :         return pgpa_state;
     230                 :             : }
     231                 :             : 
     232                 :             : /*
     233                 :             :  * Return a pointer to pg_plan_advice's DSA area, creating it if needed.
     234                 :             :  */
     235                 :             : dsa_area *
     236                 :       44638 : pg_plan_advice_dsa_area(void)
     237                 :             : {
     238         [ +  + ]:       44638 :         if (pgpa_dsa_area == NULL)
     239                 :             :         {
     240                 :         254 :                 pgpa_shared_state *state = pg_plan_advice_attach();
     241                 :         254 :                 dsa_handle      area_handle;
     242                 :         254 :                 MemoryContext oldcontext;
     243                 :             : 
     244                 :         254 :                 oldcontext = MemoryContextSwitchTo(pg_plan_advice_get_mcxt());
     245                 :             : 
     246                 :         254 :                 LWLockAcquire(&state->lock, LW_EXCLUSIVE);
     247                 :         254 :                 area_handle = state->area;
     248         [ +  + ]:         254 :                 if (area_handle == DSA_HANDLE_INVALID)
     249                 :             :                 {
     250                 :           1 :                         pgpa_dsa_area = dsa_create(state->dsa_tranche);
     251                 :           1 :                         dsa_pin(pgpa_dsa_area);
     252                 :           1 :                         state->area = dsa_get_handle(pgpa_dsa_area);
     253                 :           1 :                         LWLockRelease(&state->lock);
     254                 :           1 :                 }
     255                 :             :                 else
     256                 :             :                 {
     257                 :         253 :                         LWLockRelease(&state->lock);
     258                 :         253 :                         pgpa_dsa_area = dsa_attach(area_handle);
     259                 :             :                 }
     260                 :             : 
     261                 :         254 :                 dsa_pin_mapping(pgpa_dsa_area);
     262                 :             : 
     263                 :         254 :                 MemoryContextSwitchTo(oldcontext);
     264                 :         254 :         }
     265                 :             : 
     266                 :       44638 :         return pgpa_dsa_area;
     267                 :             : }
     268                 :             : 
     269                 :             : /*
     270                 :             :  * Was the PLAN_ADVICE option specified and not set to false?
     271                 :             :  */
     272                 :             : bool
     273                 :        3784 : pg_plan_advice_should_explain(ExplainState *es)
     274                 :             : {
     275                 :        3784 :         bool       *plan_advice = NULL;
     276                 :             : 
     277         [ +  + ]:        3784 :         if (es != NULL)
     278                 :        3744 :                 plan_advice = GetExplainExtensionState(es, es_extension_id);
     279         [ +  + ]:        3784 :         return plan_advice != NULL && *plan_advice;
     280                 :        3784 : }
     281                 :             : 
     282                 :             : /*
     283                 :             :  * Handler for EXPLAIN (PLAN_ADVICE).
     284                 :             :  */
     285                 :             : static void
     286                 :         122 : pg_plan_advice_explain_option_handler(ExplainState *es, DefElem *opt,
     287                 :             :                                                                           ParseState *pstate)
     288                 :             : {
     289                 :         122 :         bool       *plan_advice;
     290                 :             : 
     291                 :         122 :         plan_advice = GetExplainExtensionState(es, es_extension_id);
     292                 :             : 
     293         [ -  + ]:         122 :         if (plan_advice == NULL)
     294                 :             :         {
     295                 :         122 :                 plan_advice = palloc0_object(bool);
     296                 :         122 :                 SetExplainExtensionState(es, es_extension_id, plan_advice);
     297                 :         122 :         }
     298                 :             : 
     299                 :         122 :         *plan_advice = defGetBoolean(opt);
     300                 :         122 : }
     301                 :             : 
     302                 :             : /*
     303                 :             :  * Display a string that is likely to consist of multiple lines in EXPLAIN
     304                 :             :  * output.
     305                 :             :  */
     306                 :             : static void
     307                 :         234 : pg_plan_advice_explain_text_multiline(ExplainState *es, char *qlabel,
     308                 :             :                                                                           char *value)
     309                 :             : {
     310                 :         234 :         char       *s;
     311                 :             : 
     312                 :             :         /* For non-text formats, it's best not to add any special handling. */
     313         [ +  + ]:         234 :         if (es->format != EXPLAIN_FORMAT_TEXT)
     314                 :             :         {
     315                 :           1 :                 ExplainPropertyText(qlabel, value, es);
     316                 :           1 :                 return;
     317                 :             :         }
     318                 :             : 
     319                 :             :         /* In text format, if there is no data, display nothing. */
     320         [ +  + ]:         233 :         if (*value == '\0')
     321                 :           1 :                 return;
     322                 :             : 
     323                 :             :         /*
     324                 :             :          * It looks nicest to indent each line of the advice separately, beginning
     325                 :             :          * on the line below the label.
     326                 :             :          */
     327                 :         232 :         ExplainIndentText(es);
     328                 :         232 :         appendStringInfo(es->str, "%s:\n", qlabel);
     329                 :         232 :         es->indent++;
     330         [ +  + ]:         723 :         while ((s = strchr(value, '\n')) != NULL)
     331                 :             :         {
     332                 :         491 :                 ExplainIndentText(es);
     333                 :         491 :                 appendBinaryStringInfo(es->str, value, (s - value) + 1);
     334                 :         491 :                 value = s + 1;
     335                 :             :         }
     336                 :             : 
     337                 :             :         /* Don't interpret a terminal newline as a request for an empty line. */
     338         [ +  + ]:         232 :         if (*value != '\0')
     339                 :             :         {
     340                 :         121 :                 ExplainIndentText(es);
     341                 :         121 :                 appendStringInfo(es->str, "%s\n", value);
     342                 :         121 :         }
     343                 :             : 
     344                 :         232 :         es->indent--;
     345         [ -  + ]:         234 : }
     346                 :             : 
     347                 :             : /*
     348                 :             :  * Add advice feedback to the EXPLAIN output.
     349                 :             :  */
     350                 :             : static void
     351                 :         113 : pg_plan_advice_explain_feedback(ExplainState *es, List *feedback)
     352                 :             : {
     353                 :         113 :         StringInfoData buf;
     354                 :             : 
     355                 :         113 :         initStringInfo(&buf);
     356   [ +  +  +  +  :         359 :         foreach_node(DefElem, item, feedback)
             +  +  +  + ]
     357                 :             :         {
     358                 :         133 :                 int                     flags = defGetInt32(item);
     359                 :             : 
     360                 :         133 :                 appendStringInfo(&buf, "%s /* ", item->defname);
     361         [ +  + ]:         133 :                 if ((flags & PGPA_TE_MATCH_FULL) != 0)
     362                 :             :                 {
     363         [ -  + ]:         113 :                         Assert((flags & PGPA_TE_MATCH_PARTIAL) != 0);
     364                 :         113 :                         appendStringInfo(&buf, "matched");
     365                 :         113 :                 }
     366         [ +  + ]:          20 :                 else if ((flags & PGPA_TE_MATCH_PARTIAL) != 0)
     367                 :           4 :                         appendStringInfo(&buf, "partially matched");
     368                 :             :                 else
     369                 :          16 :                         appendStringInfo(&buf, "not matched");
     370         [ +  + ]:         133 :                 if ((flags & PGPA_TE_INAPPLICABLE) != 0)
     371                 :           4 :                         appendStringInfo(&buf, ", inapplicable");
     372         [ +  + ]:         133 :                 if ((flags & PGPA_TE_CONFLICTING) != 0)
     373                 :          14 :                         appendStringInfo(&buf, ", conflicting");
     374         [ +  + ]:         133 :                 if ((flags & PGPA_TE_FAILED) != 0)
     375                 :          30 :                         appendStringInfo(&buf, ", failed");
     376                 :         133 :                 appendStringInfo(&buf, " */\n");
     377                 :         246 :         }
     378                 :             : 
     379                 :         226 :         pg_plan_advice_explain_text_multiline(es, "Supplied Plan Advice",
     380                 :         113 :                                                                                   buf.data);
     381                 :         113 : }
     382                 :             : 
     383                 :             : /*
     384                 :             :  * Add relevant details, if any, to the EXPLAIN output for a single plan.
     385                 :             :  */
     386                 :             : static void
     387                 :        3610 : pg_plan_advice_explain_per_plan_hook(PlannedStmt *plannedstmt,
     388                 :             :                                                                          IntoClause *into,
     389                 :             :                                                                          ExplainState *es,
     390                 :             :                                                                          const char *queryString,
     391                 :             :                                                                          ParamListInfo params,
     392                 :             :                                                                          QueryEnvironment *queryEnv)
     393                 :             : {
     394                 :        3610 :         bool            should_explain;
     395                 :        3610 :         DefElem    *pgpa_item;
     396                 :        3610 :         List       *pgpa_list;
     397                 :             : 
     398         [ +  - ]:        3610 :         if (prev_explain_per_plan)
     399                 :           0 :                 prev_explain_per_plan(plannedstmt, into, es, queryString, params,
     400                 :           0 :                                                           queryEnv);
     401                 :             : 
     402                 :             :         /* Should an advice string be part of the EXPLAIN output? */
     403                 :        3610 :         should_explain = pg_plan_advice_should_explain(es);
     404                 :             : 
     405                 :             :         /* Find any data pgpa_planner_shutdown stashed in the PlannedStmt. */
     406                 :        3610 :         pgpa_item = find_defelem_by_defname(plannedstmt->extension_state,
     407                 :             :                                                                                 "pg_plan_advice");
     408         [ +  + ]:        3610 :         pgpa_list = pgpa_item == NULL ? NULL : (List *) pgpa_item->arg;
     409                 :             : 
     410                 :             :         /*
     411                 :             :          * By default, if there is a record of attempting to apply advice during
     412                 :             :          * query planning, we always output that information, but the user can set
     413                 :             :          * pg_plan_advice.always_explain_supplied_advice = false to suppress that
     414                 :             :          * behavior. If they do, we'll only display it when the PLAN_ADVICE option
     415                 :             :          * was specified and not set to false.
     416                 :             :          *
     417                 :             :          * NB: If we're explaining a query planned beforehand -- i.e. a prepared
     418                 :             :          * statement -- the application of query advice may not have been
     419                 :             :          * recorded, and therefore this won't be able to show anything. Use
     420                 :             :          * pg_plan_advice.always_store_advice_details = true to work around this.
     421                 :             :          */
     422   [ +  +  +  +  :        3610 :         if (pgpa_list != NULL && (pg_plan_advice_always_explain_supplied_advice ||
                   -  + ]
     423                 :        3472 :                                                           should_explain))
     424                 :             :         {
     425                 :         133 :                 DefElem    *feedback;
     426                 :             : 
     427                 :         133 :                 feedback = find_defelem_by_defname(pgpa_list, "feedback");
     428         [ +  + ]:         133 :                 if (feedback != NULL)
     429                 :         113 :                         pg_plan_advice_explain_feedback(es, (List *) feedback->arg);
     430                 :         133 :         }
     431                 :             : 
     432                 :             :         /*
     433                 :             :          * If the PLAN_ADVICE option was specified -- and not sent to FALSE --
     434                 :             :          * show generated advice.
     435                 :             :          */
     436         [ +  + ]:        3610 :         if (should_explain)
     437                 :             :         {
     438                 :         122 :                 DefElem    *advice_string_item;
     439                 :         122 :                 char       *advice_string = NULL;
     440                 :             : 
     441                 :         122 :                 advice_string_item =
     442                 :         122 :                         find_defelem_by_defname(pgpa_list, "advice_string");
     443         [ +  + ]:         122 :                 if (advice_string_item != NULL)
     444                 :             :                 {
     445                 :         121 :                         advice_string = strVal(advice_string_item->arg);
     446                 :         242 :                         pg_plan_advice_explain_text_multiline(es, "Generated Plan Advice",
     447                 :         121 :                                                                                                   advice_string);
     448                 :         121 :                 }
     449                 :         122 :         }
     450                 :        3610 : }
     451                 :             : 
     452                 :             : /*
     453                 :             :  * Check hook for pg_plan_advice.advice
     454                 :             :  */
     455                 :             : static bool
     456                 :        2654 : pg_plan_advice_advice_check_hook(char **newval, void **extra, GucSource source)
     457                 :             : {
     458                 :        2654 :         MemoryContext oldcontext;
     459                 :        2654 :         MemoryContext tmpcontext;
     460                 :        2654 :         char       *error;
     461                 :             : 
     462         [ +  + ]:        2654 :         if (*newval == NULL)
     463                 :        1269 :                 return true;
     464                 :             : 
     465                 :        1385 :         tmpcontext = AllocSetContextCreate(CurrentMemoryContext,
     466                 :             :                                                                            "pg_plan_advice.advice",
     467                 :             :                                                                            ALLOCSET_DEFAULT_SIZES);
     468                 :        1385 :         oldcontext = MemoryContextSwitchTo(tmpcontext);
     469                 :             : 
     470                 :             :         /*
     471                 :             :          * It would be nice to save the parse tree that we construct here for
     472                 :             :          * eventual use when planning with this advice, but *extra can only point
     473                 :             :          * to a single guc_malloc'd chunk, and our parse tree involves an
     474                 :             :          * arbitrary number of memory allocations.
     475                 :             :          */
     476                 :        1385 :         (void) pgpa_parse(*newval, &error);
     477                 :             : 
     478         [ +  + ]:        1385 :         if (error != NULL)
     479                 :             :         {
     480                 :          17 :                 GUC_check_errdetail("Could not parse advice: %s", error);
     481                 :          17 :                 return false;
     482                 :             :         }
     483                 :             : 
     484                 :        1368 :         MemoryContextSwitchTo(oldcontext);
     485                 :        1368 :         MemoryContextDelete(tmpcontext);
     486                 :             : 
     487                 :        1368 :         return true;
     488                 :        2654 : }
     489                 :             : 
     490                 :             : /*
     491                 :             :  * Search a list of DefElem objects for a given defname.
     492                 :             :  */
     493                 :             : static DefElem *
     494                 :        3865 : find_defelem_by_defname(List *deflist, char *defname)
     495                 :             : {
     496   [ +  +  +  +  :        7851 :         foreach_node(DefElem, item, deflist)
          +  +  +  +  +  
             +  -  +  + ]
     497                 :             :         {
     498         [ +  + ]:        3960 :                 if (strcmp(item->defname, defname) == 0)
     499                 :        3839 :                         return item;
     500                 :         147 :         }
     501                 :             : 
     502                 :          26 :         return NULL;
     503                 :        3865 : }
        

Generated by: LCOV version 2.3.2-1