00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "postgres_fe.h"
00011
00012 #include "pg_upgrade.h"
00013
00014 #include "access/transam.h"
00015
00016
00017 static void create_rel_filename_map(const char *old_data, const char *new_data,
00018 const DbInfo *old_db, const DbInfo *new_db,
00019 const RelInfo *old_rel, const RelInfo *new_rel,
00020 FileNameMap *map);
00021 static void free_db_and_rel_infos(DbInfoArr *db_arr);
00022 static void get_db_infos(ClusterInfo *cluster);
00023 static void get_rel_infos(ClusterInfo *cluster, DbInfo *dbinfo);
00024 static void free_rel_infos(RelInfoArr *rel_arr);
00025 static void print_db_infos(DbInfoArr *dbinfo);
00026 static void print_rel_infos(RelInfoArr *rel_arr);
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 FileNameMap *
00037 gen_db_file_maps(DbInfo *old_db, DbInfo *new_db,
00038 int *nmaps, const char *old_pgdata, const char *new_pgdata)
00039 {
00040 FileNameMap *maps;
00041 int relnum;
00042 int num_maps = 0;
00043
00044 maps = (FileNameMap *) pg_malloc(sizeof(FileNameMap) *
00045 old_db->rel_arr.nrels);
00046
00047 for (relnum = 0; relnum < Min(old_db->rel_arr.nrels, new_db->rel_arr.nrels);
00048 relnum++)
00049 {
00050 RelInfo *old_rel = &old_db->rel_arr.rels[relnum];
00051 RelInfo *new_rel = &new_db->rel_arr.rels[relnum];
00052
00053 if (old_rel->reloid != new_rel->reloid)
00054 pg_log(PG_FATAL, "Mismatch of relation OID in database \"%s\": old OID %d, new OID %d\n",
00055 old_db->db_name, old_rel->reloid, new_rel->reloid);
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068 if (strcmp(old_rel->nspname, new_rel->nspname) != 0 ||
00069 ((GET_MAJOR_VERSION(old_cluster.major_version) >= 900 ||
00070 strcmp(old_rel->nspname, "pg_toast") != 0) &&
00071 strcmp(old_rel->relname, new_rel->relname) != 0))
00072 pg_log(PG_FATAL, "Mismatch of relation names in database \"%s\": "
00073 "old name \"%s.%s\", new name \"%s.%s\"\n",
00074 old_db->db_name, old_rel->nspname, old_rel->relname,
00075 new_rel->nspname, new_rel->relname);
00076
00077 create_rel_filename_map(old_pgdata, new_pgdata, old_db, new_db,
00078 old_rel, new_rel, maps + num_maps);
00079 num_maps++;
00080 }
00081
00082
00083 if (old_db->rel_arr.nrels != new_db->rel_arr.nrels)
00084 pg_log(PG_FATAL, "old and new databases \"%s\" have a different number of relations\n",
00085 old_db->db_name);
00086
00087 *nmaps = num_maps;
00088 return maps;
00089 }
00090
00091
00092
00093
00094
00095
00096
00097 static void
00098 create_rel_filename_map(const char *old_data, const char *new_data,
00099 const DbInfo *old_db, const DbInfo *new_db,
00100 const RelInfo *old_rel, const RelInfo *new_rel,
00101 FileNameMap *map)
00102 {
00103 if (strlen(old_rel->tablespace) == 0)
00104 {
00105
00106
00107
00108
00109 strlcpy(map->old_tablespace, old_data, sizeof(map->old_tablespace));
00110 strlcpy(map->new_tablespace, new_data, sizeof(map->new_tablespace));
00111 strlcpy(map->old_tablespace_suffix, "/base", sizeof(map->old_tablespace_suffix));
00112 strlcpy(map->new_tablespace_suffix, "/base", sizeof(map->new_tablespace_suffix));
00113 }
00114 else
00115 {
00116
00117 strlcpy(map->old_tablespace, old_rel->tablespace, sizeof(map->old_tablespace));
00118 strlcpy(map->new_tablespace, new_rel->tablespace, sizeof(map->new_tablespace));
00119 strlcpy(map->old_tablespace_suffix, old_cluster.tablespace_suffix,
00120 sizeof(map->old_tablespace_suffix));
00121 strlcpy(map->new_tablespace_suffix, new_cluster.tablespace_suffix,
00122 sizeof(map->new_tablespace_suffix));
00123 }
00124
00125 map->old_db_oid = old_db->db_oid;
00126 map->new_db_oid = new_db->db_oid;
00127
00128
00129
00130
00131
00132 map->old_relfilenode = old_rel->relfilenode;
00133
00134
00135 map->new_relfilenode = new_rel->relfilenode;
00136
00137
00138 map->nspname = old_rel->nspname;
00139 map->relname = old_rel->relname;
00140 }
00141
00142
00143 void
00144 print_maps(FileNameMap *maps, int n_maps, const char *db_name)
00145 {
00146 if (log_opts.verbose)
00147 {
00148 int mapnum;
00149
00150 pg_log(PG_VERBOSE, "mappings for database \"%s\":\n", db_name);
00151
00152 for (mapnum = 0; mapnum < n_maps; mapnum++)
00153 pg_log(PG_VERBOSE, "%s.%s: %u to %u\n",
00154 maps[mapnum].nspname, maps[mapnum].relname,
00155 maps[mapnum].old_relfilenode,
00156 maps[mapnum].new_relfilenode);
00157
00158 pg_log(PG_VERBOSE, "\n\n");
00159 }
00160 }
00161
00162
00163
00164
00165
00166
00167
00168
00169 void
00170 get_db_and_rel_infos(ClusterInfo *cluster)
00171 {
00172 int dbnum;
00173
00174 if (cluster->dbarr.dbs != NULL)
00175 free_db_and_rel_infos(&cluster->dbarr);
00176
00177 get_db_infos(cluster);
00178
00179 for (dbnum = 0; dbnum < cluster->dbarr.ndbs; dbnum++)
00180 get_rel_infos(cluster, &cluster->dbarr.dbs[dbnum]);
00181
00182 pg_log(PG_VERBOSE, "\n%s databases:\n", CLUSTER_NAME(cluster));
00183 if (log_opts.verbose)
00184 print_db_infos(&cluster->dbarr);
00185 }
00186
00187
00188
00189
00190
00191
00192
00193
00194 static void
00195 get_db_infos(ClusterInfo *cluster)
00196 {
00197 PGconn *conn = connectToServer(cluster, "template1");
00198 PGresult *res;
00199 int ntups;
00200 int tupnum;
00201 DbInfo *dbinfos;
00202 int i_datname,
00203 i_oid,
00204 i_spclocation;
00205 char query[QUERY_ALLOC];
00206
00207 snprintf(query, sizeof(query),
00208 "SELECT d.oid, d.datname, %s "
00209 "FROM pg_catalog.pg_database d "
00210 " LEFT OUTER JOIN pg_catalog.pg_tablespace t "
00211 " ON d.dattablespace = t.oid "
00212 "WHERE d.datallowconn = true "
00213
00214 "ORDER BY 2",
00215
00216 (GET_MAJOR_VERSION(cluster->major_version) <= 901) ?
00217 "t.spclocation" : "pg_catalog.pg_tablespace_location(t.oid) AS spclocation");
00218
00219 res = executeQueryOrDie(conn, "%s", query);
00220
00221 i_oid = PQfnumber(res, "oid");
00222 i_datname = PQfnumber(res, "datname");
00223 i_spclocation = PQfnumber(res, "spclocation");
00224
00225 ntups = PQntuples(res);
00226 dbinfos = (DbInfo *) pg_malloc(sizeof(DbInfo) * ntups);
00227
00228 for (tupnum = 0; tupnum < ntups; tupnum++)
00229 {
00230 dbinfos[tupnum].db_oid = atooid(PQgetvalue(res, tupnum, i_oid));
00231 dbinfos[tupnum].db_name = pg_strdup(PQgetvalue(res, tupnum, i_datname));
00232 snprintf(dbinfos[tupnum].db_tblspace, sizeof(dbinfos[tupnum].db_tblspace), "%s",
00233 PQgetvalue(res, tupnum, i_spclocation));
00234 }
00235 PQclear(res);
00236
00237 PQfinish(conn);
00238
00239 cluster->dbarr.dbs = dbinfos;
00240 cluster->dbarr.ndbs = ntups;
00241 }
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253 static void
00254 get_rel_infos(ClusterInfo *cluster, DbInfo *dbinfo)
00255 {
00256 PGconn *conn = connectToServer(cluster,
00257 dbinfo->db_name);
00258 PGresult *res;
00259 RelInfo *relinfos;
00260 int ntups;
00261 int relnum;
00262 int num_rels = 0;
00263 char *nspname = NULL;
00264 char *relname = NULL;
00265 int i_spclocation,
00266 i_nspname,
00267 i_relname,
00268 i_oid,
00269 i_relfilenode,
00270 i_reltablespace;
00271 char query[QUERY_ALLOC];
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281 snprintf(query, sizeof(query),
00282 "CREATE TEMPORARY TABLE info_rels (reloid) AS SELECT c.oid "
00283 "FROM pg_catalog.pg_class c JOIN pg_catalog.pg_namespace n "
00284 " ON c.relnamespace = n.oid "
00285 "LEFT OUTER JOIN pg_catalog.pg_index i "
00286 " ON c.oid = i.indexrelid "
00287 "WHERE relkind IN ('r', 'm', 'i'%s) AND "
00288
00289
00290 " i.indisvalid IS DISTINCT FROM false AND "
00291 " i.indisready IS DISTINCT FROM false AND "
00292
00293 " ((n.nspname !~ '^pg_temp_' AND "
00294 " n.nspname !~ '^pg_toast_temp_' AND "
00295
00296 " n.nspname NOT IN ('pg_catalog', 'information_schema', "
00297 " 'binary_upgrade', 'pg_toast') AND "
00298 " c.oid >= %u) "
00299 " OR (n.nspname = 'pg_catalog' AND "
00300 " relname IN ('pg_largeobject', 'pg_largeobject_loid_pn_index'%s) ));",
00301
00302 (GET_MAJOR_VERSION(old_cluster.major_version) <= 803) ?
00303 "" : ", 'S'",
00304 FirstNormalObjectId,
00305
00306 (GET_MAJOR_VERSION(old_cluster.major_version) <= 804) ?
00307 "" : ", 'pg_largeobject_metadata', 'pg_largeobject_metadata_oid_index'");
00308
00309 PQclear(executeQueryOrDie(conn, "%s", query));
00310
00311
00312
00313
00314
00315 PQclear(executeQueryOrDie(conn,
00316 "INSERT INTO info_rels "
00317 "SELECT reltoastrelid "
00318 "FROM info_rels i JOIN pg_catalog.pg_class c "
00319 " ON i.reloid = c.oid"));
00320 PQclear(executeQueryOrDie(conn,
00321 "INSERT INTO info_rels "
00322 "SELECT reltoastidxid "
00323 "FROM info_rels i JOIN pg_catalog.pg_class c "
00324 " ON i.reloid = c.oid"));
00325
00326 snprintf(query, sizeof(query),
00327 "SELECT c.oid, n.nspname, c.relname, "
00328 " c.relfilenode, c.reltablespace, %s "
00329 "FROM info_rels i JOIN pg_catalog.pg_class c "
00330 " ON i.reloid = c.oid "
00331 " JOIN pg_catalog.pg_namespace n "
00332 " ON c.relnamespace = n.oid "
00333 " LEFT OUTER JOIN pg_catalog.pg_tablespace t "
00334 " ON c.reltablespace = t.oid "
00335
00336 "ORDER BY 1;",
00337
00338 (GET_MAJOR_VERSION(cluster->major_version) <= 901) ?
00339 "t.spclocation" : "pg_catalog.pg_tablespace_location(t.oid) AS spclocation");
00340
00341 res = executeQueryOrDie(conn, "%s", query);
00342
00343 ntups = PQntuples(res);
00344
00345 relinfos = (RelInfo *) pg_malloc(sizeof(RelInfo) * ntups);
00346
00347 i_oid = PQfnumber(res, "oid");
00348 i_nspname = PQfnumber(res, "nspname");
00349 i_relname = PQfnumber(res, "relname");
00350 i_relfilenode = PQfnumber(res, "relfilenode");
00351 i_reltablespace = PQfnumber(res, "reltablespace");
00352 i_spclocation = PQfnumber(res, "spclocation");
00353
00354 for (relnum = 0; relnum < ntups; relnum++)
00355 {
00356 RelInfo *curr = &relinfos[num_rels++];
00357 const char *tblspace;
00358
00359 curr->reloid = atooid(PQgetvalue(res, relnum, i_oid));
00360
00361 nspname = PQgetvalue(res, relnum, i_nspname);
00362 curr->nspname = pg_strdup(nspname);
00363
00364 relname = PQgetvalue(res, relnum, i_relname);
00365 curr->relname = pg_strdup(relname);
00366
00367 curr->relfilenode = atooid(PQgetvalue(res, relnum, i_relfilenode));
00368
00369 if (atooid(PQgetvalue(res, relnum, i_reltablespace)) != 0)
00370
00371 tblspace = PQgetvalue(res, relnum, i_spclocation);
00372 else
00373
00374 tblspace = dbinfo->db_tblspace;
00375
00376 strlcpy(curr->tablespace, tblspace, sizeof(curr->tablespace));
00377 }
00378 PQclear(res);
00379
00380 PQfinish(conn);
00381
00382 dbinfo->rel_arr.rels = relinfos;
00383 dbinfo->rel_arr.nrels = num_rels;
00384 }
00385
00386
00387 static void
00388 free_db_and_rel_infos(DbInfoArr *db_arr)
00389 {
00390 int dbnum;
00391
00392 for (dbnum = 0; dbnum < db_arr->ndbs; dbnum++)
00393 {
00394 free_rel_infos(&db_arr->dbs[dbnum].rel_arr);
00395 pg_free(db_arr->dbs[dbnum].db_name);
00396 }
00397 pg_free(db_arr->dbs);
00398 db_arr->dbs = NULL;
00399 db_arr->ndbs = 0;
00400 }
00401
00402
00403 static void
00404 free_rel_infos(RelInfoArr *rel_arr)
00405 {
00406 int relnum;
00407
00408 for (relnum = 0; relnum < rel_arr->nrels; relnum++)
00409 {
00410 pg_free(rel_arr->rels[relnum].nspname);
00411 pg_free(rel_arr->rels[relnum].relname);
00412 }
00413 pg_free(rel_arr->rels);
00414 rel_arr->nrels = 0;
00415 }
00416
00417
00418 static void
00419 print_db_infos(DbInfoArr *db_arr)
00420 {
00421 int dbnum;
00422
00423 for (dbnum = 0; dbnum < db_arr->ndbs; dbnum++)
00424 {
00425 pg_log(PG_VERBOSE, "Database: %s\n", db_arr->dbs[dbnum].db_name);
00426 print_rel_infos(&db_arr->dbs[dbnum].rel_arr);
00427 pg_log(PG_VERBOSE, "\n\n");
00428 }
00429 }
00430
00431
00432 static void
00433 print_rel_infos(RelInfoArr *rel_arr)
00434 {
00435 int relnum;
00436
00437 for (relnum = 0; relnum < rel_arr->nrels; relnum++)
00438 pg_log(PG_VERBOSE, "relname: %s.%s: reloid: %u reltblspace: %s\n",
00439 rel_arr->rels[relnum].nspname, rel_arr->rels[relnum].relname,
00440 rel_arr->rels[relnum].reloid, rel_arr->rels[relnum].tablespace);
00441 }