Line data Source code
1 : /* 2 : * tablespace.c 3 : * 4 : * tablespace functions 5 : * 6 : * Copyright (c) 2010-2025, 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 16 : init_tablespaces(void) 20 : { 21 16 : get_tablespace_paths(); 22 : 23 16 : set_tablespace_directory_suffix(&old_cluster); 24 16 : set_tablespace_directory_suffix(&new_cluster); 25 : 26 16 : if (os_info.num_old_tablespaces > 0 && 27 0 : strcmp(old_cluster.tablespace_suffix, new_cluster.tablespace_suffix) == 0) 28 0 : pg_fatal("Cannot upgrade to/from the same system catalog version when\n" 29 : "using tablespaces."); 30 16 : } 31 : 32 : 33 : /* 34 : * get_tablespace_paths() 35 : * 36 : * Scans pg_tablespace and returns a malloc'ed array of all tablespace 37 : * paths. It's the caller's responsibility to free the array. 38 : */ 39 : static void 40 16 : get_tablespace_paths(void) 41 : { 42 16 : PGconn *conn = connectToServer(&old_cluster, "template1"); 43 : PGresult *res; 44 : int tblnum; 45 : int i_spclocation; 46 : char query[QUERY_ALLOC]; 47 : 48 16 : snprintf(query, sizeof(query), 49 : "SELECT pg_catalog.pg_tablespace_location(oid) AS spclocation " 50 : "FROM pg_catalog.pg_tablespace " 51 : "WHERE spcname != 'pg_default' AND " 52 : " spcname != 'pg_global'"); 53 : 54 16 : res = executeQueryOrDie(conn, "%s", query); 55 : 56 16 : if ((os_info.num_old_tablespaces = PQntuples(res)) != 0) 57 0 : os_info.old_tablespaces = 58 0 : (char **) pg_malloc(os_info.num_old_tablespaces * sizeof(char *)); 59 : else 60 16 : os_info.old_tablespaces = NULL; 61 : 62 16 : i_spclocation = PQfnumber(res, "spclocation"); 63 : 64 16 : for (tblnum = 0; tblnum < os_info.num_old_tablespaces; tblnum++) 65 : { 66 : struct stat statBuf; 67 : 68 0 : os_info.old_tablespaces[tblnum] = pg_strdup(PQgetvalue(res, tblnum, i_spclocation)); 69 : 70 : /* 71 : * Check that the tablespace path exists and is a directory. 72 : * Effectively, this is checking only for tables/indexes in 73 : * non-existent tablespace directories. Databases located in 74 : * non-existent tablespaces already throw a backend error. 75 : * Non-existent tablespace directories can occur when a data directory 76 : * that contains user tablespaces is moved as part of pg_upgrade 77 : * preparation and the symbolic links are not updated. 78 : */ 79 0 : if (stat(os_info.old_tablespaces[tblnum], &statBuf) != 0) 80 : { 81 0 : if (errno == ENOENT) 82 0 : report_status(PG_FATAL, 83 : "tablespace directory \"%s\" does not exist", 84 0 : os_info.old_tablespaces[tblnum]); 85 : else 86 0 : report_status(PG_FATAL, 87 : "could not stat tablespace directory \"%s\": %m", 88 0 : os_info.old_tablespaces[tblnum]); 89 : } 90 0 : if (!S_ISDIR(statBuf.st_mode)) 91 0 : report_status(PG_FATAL, 92 : "tablespace path \"%s\" is not a directory", 93 0 : os_info.old_tablespaces[tblnum]); 94 : } 95 : 96 16 : PQclear(res); 97 : 98 16 : PQfinish(conn); 99 16 : } 100 : 101 : 102 : static void 103 32 : set_tablespace_directory_suffix(ClusterInfo *cluster) 104 : { 105 : /* This cluster has a version-specific subdirectory */ 106 : 107 : /* The leading slash is needed to start a new directory. */ 108 64 : cluster->tablespace_suffix = psprintf("/PG_%s_%d", 109 32 : cluster->major_version_str, 110 : cluster->controldata.cat_ver); 111 32 : }