LCOV - code coverage report
Current view: top level - src/bin/pg_upgrade - function.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 0.0 % 102 0
Test Date: 2026-01-26 10:56:24 Functions: 0.0 % 4 0
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*
       2              :  *      function.c
       3              :  *
       4              :  *      server-side function support
       5              :  *
       6              :  *      Copyright (c) 2010-2026, PostgreSQL Global Development Group
       7              :  *      src/bin/pg_upgrade/function.c
       8              :  */
       9              : 
      10              : #include "postgres_fe.h"
      11              : 
      12              : #include "access/transam.h"
      13              : #include "catalog/pg_language_d.h"
      14              : #include "common/int.h"
      15              : #include "pg_upgrade.h"
      16              : 
      17              : /*
      18              :  * qsort comparator for pointers to library names
      19              :  *
      20              :  * We sort first by name length, then alphabetically for names of the
      21              :  * same length, then database array index.  This is to ensure that, eg,
      22              :  * "hstore_plpython" sorts after both "hstore" and "plpython"; otherwise
      23              :  * transform modules will probably fail their LOAD tests.  (The backend
      24              :  * ought to cope with that consideration, but it doesn't yet, and even
      25              :  * when it does it'll still be a good idea to have a predictable order of
      26              :  * probing here.)
      27              :  */
      28              : static int
      29            0 : library_name_compare(const void *p1, const void *p2)
      30              : {
      31            0 :         const char *str1 = ((const LibraryInfo *) p1)->name;
      32            0 :         const char *str2 = ((const LibraryInfo *) p2)->name;
      33            0 :         size_t          slen1 = strlen(str1);
      34            0 :         size_t          slen2 = strlen(str2);
      35            0 :         int                     cmp = strcmp(str1, str2);
      36              : 
      37            0 :         if (slen1 != slen2)
      38            0 :                 return pg_cmp_size(slen1, slen2);
      39            0 :         if (cmp != 0)
      40            0 :                 return cmp;
      41            0 :         return pg_cmp_s32(((const LibraryInfo *) p1)->dbnum,
      42            0 :                                           ((const LibraryInfo *) p2)->dbnum);
      43            0 : }
      44              : 
      45              : /*
      46              :  * Private state for get_loadable_libraries()'s UpgradeTask.
      47              :  */
      48              : struct loadable_libraries_state
      49              : {
      50              :         PGresult  **ress;                       /* results for each database */
      51              :         int                     totaltups;              /* number of tuples in all results */
      52              : };
      53              : 
      54              : /*
      55              :  * Callback function for processing results of query for
      56              :  * get_loadable_libraries()'s UpgradeTask.  This function stores the results
      57              :  * for later use within get_loadable_libraries().
      58              :  */
      59              : static void
      60            0 : process_loadable_libraries(DbInfo *dbinfo, PGresult *res, void *arg)
      61              : {
      62            0 :         struct loadable_libraries_state *state = (struct loadable_libraries_state *) arg;
      63              : 
      64            0 :         state->ress[dbinfo - old_cluster.dbarr.dbs] = res;
      65            0 :         state->totaltups += PQntuples(res);
      66            0 : }
      67              : 
      68              : /*
      69              :  * get_loadable_libraries()
      70              :  *
      71              :  *      Fetch the names of all old libraries containing either C-language functions
      72              :  *      or are corresponding to logical replication output plugins.
      73              :  *
      74              :  *      We will later check that they all exist in the new installation.
      75              :  */
      76              : void
      77            0 : get_loadable_libraries(void)
      78              : {
      79            0 :         int                     totaltups;
      80            0 :         int                     dbnum;
      81            0 :         int                     n_libinfos;
      82            0 :         UpgradeTask *task = upgrade_task_create();
      83            0 :         struct loadable_libraries_state state;
      84            0 :         char       *query;
      85              : 
      86            0 :         state.ress = (PGresult **) pg_malloc(old_cluster.dbarr.ndbs * sizeof(PGresult *));
      87            0 :         state.totaltups = 0;
      88              : 
      89            0 :         query = psprintf("SELECT DISTINCT probin "
      90              :                                          "FROM pg_catalog.pg_proc "
      91              :                                          "WHERE prolang = %u AND "
      92              :                                          "probin IS NOT NULL AND "
      93              :                                          "oid >= %u",
      94              :                                          ClanguageId,
      95              :                                          FirstNormalObjectId);
      96              : 
      97            0 :         upgrade_task_add_step(task, query, process_loadable_libraries,
      98              :                                                   false, &state);
      99              : 
     100            0 :         upgrade_task_run(task, &old_cluster);
     101            0 :         upgrade_task_free(task);
     102              : 
     103              :         /*
     104              :          * Allocate memory for required libraries and logical replication output
     105              :          * plugins.
     106              :          */
     107            0 :         n_libinfos = state.totaltups + count_old_cluster_logical_slots();
     108            0 :         os_info.libraries = (LibraryInfo *) pg_malloc(sizeof(LibraryInfo) * n_libinfos);
     109            0 :         totaltups = 0;
     110              : 
     111            0 :         for (dbnum = 0; dbnum < old_cluster.dbarr.ndbs; dbnum++)
     112              :         {
     113            0 :                 PGresult   *res = state.ress[dbnum];
     114            0 :                 int                     ntups;
     115            0 :                 int                     rowno;
     116            0 :                 LogicalSlotInfoArr *slot_arr = &old_cluster.dbarr.dbs[dbnum].slot_arr;
     117              : 
     118            0 :                 ntups = PQntuples(res);
     119            0 :                 for (rowno = 0; rowno < ntups; rowno++)
     120              :                 {
     121            0 :                         char       *lib = PQgetvalue(res, rowno, 0);
     122              : 
     123            0 :                         os_info.libraries[totaltups].name = pg_strdup(lib);
     124            0 :                         os_info.libraries[totaltups].dbnum = dbnum;
     125              : 
     126            0 :                         totaltups++;
     127            0 :                 }
     128            0 :                 PQclear(res);
     129              : 
     130              :                 /*
     131              :                  * Store the names of output plugins as well. There is a possibility
     132              :                  * that duplicated plugins are set, but the consumer function
     133              :                  * check_loadable_libraries() will avoid checking the same library, so
     134              :                  * we do not have to consider their uniqueness here.
     135              :                  */
     136            0 :                 for (int slotno = 0; slotno < slot_arr->nslots; slotno++)
     137              :                 {
     138            0 :                         if (slot_arr->slots[slotno].invalid)
     139            0 :                                 continue;
     140              : 
     141            0 :                         os_info.libraries[totaltups].name = pg_strdup(slot_arr->slots[slotno].plugin);
     142            0 :                         os_info.libraries[totaltups].dbnum = dbnum;
     143              : 
     144            0 :                         totaltups++;
     145            0 :                 }
     146            0 :         }
     147              : 
     148            0 :         pg_free(state.ress);
     149            0 :         pg_free(query);
     150              : 
     151            0 :         os_info.num_libraries = totaltups;
     152            0 : }
     153              : 
     154              : 
     155              : /*
     156              :  * check_loadable_libraries()
     157              :  *
     158              :  *      Check that the new cluster contains all required libraries.
     159              :  *      We do this by actually trying to LOAD each one, thereby testing
     160              :  *      compatibility as well as presence.
     161              :  */
     162              : void
     163            0 : check_loadable_libraries(void)
     164              : {
     165            0 :         PGconn     *conn = connectToServer(&new_cluster, "template1");
     166            0 :         int                     libnum;
     167            0 :         int                     was_load_failure = false;
     168            0 :         FILE       *script = NULL;
     169            0 :         char            output_path[MAXPGPATH];
     170              : 
     171            0 :         prep_status("Checking for presence of required libraries");
     172              : 
     173            0 :         snprintf(output_path, sizeof(output_path), "%s/%s",
     174            0 :                          log_opts.basedir, "loadable_libraries.txt");
     175              : 
     176              :         /*
     177              :          * Now we want to sort the library names into order.  This avoids multiple
     178              :          * probes of the same library, and ensures that libraries are probed in a
     179              :          * consistent order, which is important for reproducible behavior if one
     180              :          * library depends on another.
     181              :          */
     182            0 :         qsort(os_info.libraries, os_info.num_libraries,
     183              :                   sizeof(LibraryInfo), library_name_compare);
     184              : 
     185            0 :         for (libnum = 0; libnum < os_info.num_libraries; libnum++)
     186              :         {
     187            0 :                 char       *lib = os_info.libraries[libnum].name;
     188            0 :                 int                     llen = strlen(lib);
     189            0 :                 char            cmd[7 + 2 * MAXPGPATH + 1];
     190            0 :                 PGresult   *res;
     191              : 
     192              :                 /* Did the library name change?  Probe it. */
     193            0 :                 if (libnum == 0 || strcmp(lib, os_info.libraries[libnum - 1].name) != 0)
     194              :                 {
     195            0 :                         strcpy(cmd, "LOAD '");
     196            0 :                         PQescapeStringConn(conn, cmd + strlen(cmd), lib, llen, NULL);
     197            0 :                         strcat(cmd, "'");
     198              : 
     199            0 :                         res = PQexec(conn, cmd);
     200              : 
     201            0 :                         if (PQresultStatus(res) != PGRES_COMMAND_OK)
     202              :                         {
     203            0 :                                 was_load_failure = true;
     204              : 
     205            0 :                                 if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
     206            0 :                                         pg_fatal("could not open file \"%s\": %m", output_path);
     207            0 :                                 fprintf(script, _("could not load library \"%s\": %s"),
     208            0 :                                                 lib,
     209            0 :                                                 PQerrorMessage(conn));
     210            0 :                         }
     211              :                         else
     212            0 :                                 was_load_failure = false;
     213              : 
     214            0 :                         PQclear(res);
     215            0 :                 }
     216              : 
     217            0 :                 if (was_load_failure)
     218            0 :                         fprintf(script, _("In database: %s\n"),
     219            0 :                                         old_cluster.dbarr.dbs[os_info.libraries[libnum].dbnum].db_name);
     220            0 :         }
     221              : 
     222            0 :         PQfinish(conn);
     223              : 
     224            0 :         if (script)
     225              :         {
     226            0 :                 fclose(script);
     227            0 :                 pg_log(PG_REPORT, "fatal");
     228            0 :                 pg_fatal("Your installation references loadable libraries that are missing from the\n"
     229              :                                  "new installation.  You can add these libraries to the new installation,\n"
     230              :                                  "or remove the functions using them from the old installation.  A list of\n"
     231              :                                  "problem libraries is in the file:\n"
     232            0 :                                  "    %s", output_path);
     233              :         }
     234              :         else
     235            0 :                 check_ok();
     236            0 : }
        

Generated by: LCOV version 2.3.2-1