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

            Line data    Source code
       1              : /*
       2              :  *      tablespace.c
       3              :  *
       4              :  *      tablespace functions
       5              :  *
       6              :  *      Copyright (c) 2010-2026, PostgreSQL Global Development Group
       7              :  *      src/bin/pg_upgrade/tablespace.c
       8              :  */
       9              : 
      10              : #include "postgres_fe.h"
      11              : 
      12              : #include "pg_upgrade.h"
      13              : 
      14              : static void get_tablespace_paths(void);
      15              : static void set_tablespace_directory_suffix(ClusterInfo *cluster);
      16              : 
      17              : 
      18              : void
      19            0 : init_tablespaces(void)
      20              : {
      21            0 :         get_tablespace_paths();
      22              : 
      23            0 :         set_tablespace_directory_suffix(&old_cluster);
      24            0 :         set_tablespace_directory_suffix(&new_cluster);
      25              : 
      26            0 :         if (old_cluster.num_tablespaces > 0 &&
      27            0 :                 strcmp(old_cluster.tablespace_suffix, new_cluster.tablespace_suffix) == 0)
      28              :         {
      29            0 :                 for (int i = 0; i < old_cluster.num_tablespaces; i++)
      30              :                 {
      31              :                         /*
      32              :                          * In-place tablespaces are okay for same-version upgrades because
      33              :                          * their paths will differ between clusters.
      34              :                          */
      35            0 :                         if (strcmp(old_cluster.tablespaces[i], new_cluster.tablespaces[i]) == 0)
      36            0 :                                 pg_fatal("Cannot upgrade to/from the same system catalog version when\n"
      37              :                                                  "using tablespaces.");
      38            0 :                 }
      39            0 :         }
      40            0 : }
      41              : 
      42              : 
      43              : /*
      44              :  * get_tablespace_paths()
      45              :  *
      46              :  * Scans pg_tablespace and returns a malloc'ed array of all tablespace
      47              :  * paths. It's the caller's responsibility to free the array.
      48              :  */
      49              : static void
      50            0 : get_tablespace_paths(void)
      51              : {
      52            0 :         PGconn     *conn = connectToServer(&old_cluster, "template1");
      53            0 :         PGresult   *res;
      54            0 :         int                     tblnum;
      55            0 :         int                     i_spclocation;
      56            0 :         char            query[QUERY_ALLOC];
      57              : 
      58            0 :         snprintf(query, sizeof(query),
      59              :                          "SELECT pg_catalog.pg_tablespace_location(oid) AS spclocation "
      60              :                          "FROM     pg_catalog.pg_tablespace "
      61              :                          "WHERE    spcname != 'pg_default' AND "
      62              :                          "         spcname != 'pg_global'");
      63              : 
      64            0 :         res = executeQueryOrDie(conn, "%s", query);
      65              : 
      66            0 :         old_cluster.num_tablespaces = PQntuples(res);
      67            0 :         new_cluster.num_tablespaces = PQntuples(res);
      68              : 
      69            0 :         if (PQntuples(res) != 0)
      70              :         {
      71            0 :                 old_cluster.tablespaces =
      72            0 :                         (char **) pg_malloc(old_cluster.num_tablespaces * sizeof(char *));
      73            0 :                 new_cluster.tablespaces =
      74            0 :                         (char **) pg_malloc(new_cluster.num_tablespaces * sizeof(char *));
      75            0 :         }
      76              :         else
      77              :         {
      78            0 :                 old_cluster.tablespaces = NULL;
      79            0 :                 new_cluster.tablespaces = NULL;
      80              :         }
      81              : 
      82            0 :         i_spclocation = PQfnumber(res, "spclocation");
      83              : 
      84            0 :         for (tblnum = 0; tblnum < old_cluster.num_tablespaces; tblnum++)
      85              :         {
      86            0 :                 struct stat statBuf;
      87            0 :                 char       *spcloc = PQgetvalue(res, tblnum, i_spclocation);
      88              : 
      89              :                 /*
      90              :                  * For now, we do not expect non-in-place tablespaces to move during
      91              :                  * upgrade.  If that changes, it will likely become necessary to run
      92              :                  * the above query on the new cluster, too.
      93              :                  *
      94              :                  * pg_tablespace_location() returns absolute paths for non-in-place
      95              :                  * tablespaces and relative paths for in-place ones, so we use
      96              :                  * is_absolute_path() to distinguish between them.
      97              :                  */
      98            0 :                 if (is_absolute_path(PQgetvalue(res, tblnum, i_spclocation)))
      99              :                 {
     100            0 :                         old_cluster.tablespaces[tblnum] = pg_strdup(spcloc);
     101            0 :                         new_cluster.tablespaces[tblnum] = old_cluster.tablespaces[tblnum];
     102            0 :                 }
     103              :                 else
     104              :                 {
     105            0 :                         old_cluster.tablespaces[tblnum] = psprintf("%s/%s", old_cluster.pgdata, spcloc);
     106            0 :                         new_cluster.tablespaces[tblnum] = psprintf("%s/%s", new_cluster.pgdata, spcloc);
     107              :                 }
     108              : 
     109              :                 /*
     110              :                  * Check that the tablespace path exists and is a directory.
     111              :                  * Effectively, this is checking only for tables/indexes in
     112              :                  * non-existent tablespace directories.  Databases located in
     113              :                  * non-existent tablespaces already throw a backend error.
     114              :                  * Non-existent tablespace directories can occur when a data directory
     115              :                  * that contains user tablespaces is moved as part of pg_upgrade
     116              :                  * preparation and the symbolic links are not updated.
     117              :                  */
     118            0 :                 if (stat(old_cluster.tablespaces[tblnum], &statBuf) != 0)
     119              :                 {
     120            0 :                         if (errno == ENOENT)
     121            0 :                                 report_status(PG_FATAL,
     122              :                                                           "tablespace directory \"%s\" does not exist",
     123            0 :                                                           old_cluster.tablespaces[tblnum]);
     124              :                         else
     125            0 :                                 report_status(PG_FATAL,
     126              :                                                           "could not stat tablespace directory \"%s\": %m",
     127            0 :                                                           old_cluster.tablespaces[tblnum]);
     128            0 :                 }
     129            0 :                 if (!S_ISDIR(statBuf.st_mode))
     130            0 :                         report_status(PG_FATAL,
     131              :                                                   "tablespace path \"%s\" is not a directory",
     132            0 :                                                   old_cluster.tablespaces[tblnum]);
     133            0 :         }
     134              : 
     135            0 :         PQclear(res);
     136              : 
     137            0 :         PQfinish(conn);
     138            0 : }
     139              : 
     140              : 
     141              : static void
     142            0 : set_tablespace_directory_suffix(ClusterInfo *cluster)
     143              : {
     144              :         /* This cluster has a version-specific subdirectory */
     145              : 
     146              :         /* The leading slash is needed to start a new directory. */
     147            0 :         cluster->tablespace_suffix = psprintf("/PG_%s_%d",
     148            0 :                                                                                   cluster->major_version_str,
     149            0 :                                                                                   cluster->controldata.cat_ver);
     150            0 : }
        

Generated by: LCOV version 2.3.2-1