Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 9637bad

Browse files
committed
pg_upgrade: copy locale and encoding information to new cluster.
Previously, pg_upgrade checked that the old and new clusters were compatible, including the locale and encoding. But the new cluster was just created, and only template0 from the new cluster will be preserved (template1 and postgres are both recreated during the upgrade process). Because template0 is not sensitive to locale or encoding, just update the pg_database entry to be the same as template0 from the original cluster. This commit makes it easier to change the default initdb locale or encoding settings without causing needless incompatibilities. Discussion: https://postgr.es/m/d62b2874-729b-d26a-2d0a-0d64f509eca4@enterprisedb.com Reviewed-by: Peter Eisentraut
1 parent 8dff2f2 commit 9637bad

File tree

7 files changed

+192
-183
lines changed

7 files changed

+192
-183
lines changed

src/bin/pg_upgrade/Makefile

+2
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ clean distclean maintainer-clean:
5151
rm -rf delete_old_cluster.sh log/ tmp_check/ \
5252
reindex_hash.sql
5353

54+
export with_icu
55+
5456
check:
5557
$(prove_check)
5658

src/bin/pg_upgrade/check.c

-160
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,6 @@
1616
#include "pg_upgrade.h"
1717

1818
static void check_new_cluster_is_empty(void);
19-
static void check_databases_are_compatible(void);
20-
static void check_locale_and_encoding(DbInfo *olddb, DbInfo *newdb);
21-
static bool equivalent_locale(int category, const char *loca, const char *locb);
2219
static void check_is_install_user(ClusterInfo *cluster);
2320
static void check_proper_datallowconn(ClusterInfo *cluster);
2421
static void check_for_prepared_transactions(ClusterInfo *cluster);
@@ -33,7 +30,6 @@ static void check_for_jsonb_9_4_usage(ClusterInfo *cluster);
3330
static void check_for_pg_role_prefix(ClusterInfo *cluster);
3431
static void check_for_new_tablespace_dir(ClusterInfo *new_cluster);
3532
static void check_for_user_defined_encoding_conversions(ClusterInfo *cluster);
36-
static char *get_canonical_locale_name(int category, const char *locale);
3733

3834

3935
/*
@@ -194,7 +190,6 @@ check_new_cluster(void)
194190
get_db_and_rel_infos(&new_cluster);
195191

196192
check_new_cluster_is_empty();
197-
check_databases_are_compatible();
198193

199194
check_loadable_libraries();
200195

@@ -349,94 +344,6 @@ check_cluster_compatibility(bool live_check)
349344
}
350345

351346

352-
/*
353-
* check_locale_and_encoding()
354-
*
355-
* Check that locale and encoding of a database in the old and new clusters
356-
* are compatible.
357-
*/
358-
static void
359-
check_locale_and_encoding(DbInfo *olddb, DbInfo *newdb)
360-
{
361-
if (olddb->db_encoding != newdb->db_encoding)
362-
pg_fatal("encodings for database \"%s\" do not match: old \"%s\", new \"%s\"",
363-
olddb->db_name,
364-
pg_encoding_to_char(olddb->db_encoding),
365-
pg_encoding_to_char(newdb->db_encoding));
366-
if (!equivalent_locale(LC_COLLATE, olddb->db_collate, newdb->db_collate))
367-
pg_fatal("lc_collate values for database \"%s\" do not match: old \"%s\", new \"%s\"",
368-
olddb->db_name, olddb->db_collate, newdb->db_collate);
369-
if (!equivalent_locale(LC_CTYPE, olddb->db_ctype, newdb->db_ctype))
370-
pg_fatal("lc_ctype values for database \"%s\" do not match: old \"%s\", new \"%s\"",
371-
olddb->db_name, olddb->db_ctype, newdb->db_ctype);
372-
if (olddb->db_collprovider != newdb->db_collprovider)
373-
pg_fatal("locale providers for database \"%s\" do not match: old \"%s\", new \"%s\"",
374-
olddb->db_name,
375-
collprovider_name(olddb->db_collprovider),
376-
collprovider_name(newdb->db_collprovider));
377-
if ((olddb->db_iculocale == NULL && newdb->db_iculocale != NULL) ||
378-
(olddb->db_iculocale != NULL && newdb->db_iculocale == NULL) ||
379-
(olddb->db_iculocale != NULL && newdb->db_iculocale != NULL && strcmp(olddb->db_iculocale, newdb->db_iculocale) != 0))
380-
pg_fatal("ICU locale values for database \"%s\" do not match: old \"%s\", new \"%s\"",
381-
olddb->db_name,
382-
olddb->db_iculocale ? olddb->db_iculocale : "(null)",
383-
newdb->db_iculocale ? newdb->db_iculocale : "(null)");
384-
}
385-
386-
/*
387-
* equivalent_locale()
388-
*
389-
* Best effort locale-name comparison. Return false if we are not 100% sure
390-
* the locales are equivalent.
391-
*
392-
* Note: The encoding parts of the names are ignored. This function is
393-
* currently used to compare locale names stored in pg_database, and
394-
* pg_database contains a separate encoding field. That's compared directly
395-
* in check_locale_and_encoding().
396-
*/
397-
static bool
398-
equivalent_locale(int category, const char *loca, const char *locb)
399-
{
400-
const char *chara;
401-
const char *charb;
402-
char *canona;
403-
char *canonb;
404-
int lena;
405-
int lenb;
406-
407-
/*
408-
* If the names are equal, the locales are equivalent. Checking this first
409-
* avoids calling setlocale() in the common case that the names are equal.
410-
* That's a good thing, if setlocale() is buggy, for example.
411-
*/
412-
if (pg_strcasecmp(loca, locb) == 0)
413-
return true;
414-
415-
/*
416-
* Not identical. Canonicalize both names, remove the encoding parts, and
417-
* try again.
418-
*/
419-
canona = get_canonical_locale_name(category, loca);
420-
chara = strrchr(canona, '.');
421-
lena = chara ? (chara - canona) : strlen(canona);
422-
423-
canonb = get_canonical_locale_name(category, locb);
424-
charb = strrchr(canonb, '.');
425-
lenb = charb ? (charb - canonb) : strlen(canonb);
426-
427-
if (lena == lenb && pg_strncasecmp(canona, canonb, lena) == 0)
428-
{
429-
pg_free(canona);
430-
pg_free(canonb);
431-
return true;
432-
}
433-
434-
pg_free(canona);
435-
pg_free(canonb);
436-
return false;
437-
}
438-
439-
440347
static void
441348
check_new_cluster_is_empty(void)
442349
{
@@ -460,35 +367,6 @@ check_new_cluster_is_empty(void)
460367
}
461368
}
462369

463-
/*
464-
* Check that every database that already exists in the new cluster is
465-
* compatible with the corresponding database in the old one.
466-
*/
467-
static void
468-
check_databases_are_compatible(void)
469-
{
470-
int newdbnum;
471-
int olddbnum;
472-
DbInfo *newdbinfo;
473-
DbInfo *olddbinfo;
474-
475-
for (newdbnum = 0; newdbnum < new_cluster.dbarr.ndbs; newdbnum++)
476-
{
477-
newdbinfo = &new_cluster.dbarr.dbs[newdbnum];
478-
479-
/* Find the corresponding database in the old cluster */
480-
for (olddbnum = 0; olddbnum < old_cluster.dbarr.ndbs; olddbnum++)
481-
{
482-
olddbinfo = &old_cluster.dbarr.dbs[olddbnum];
483-
if (strcmp(newdbinfo->db_name, olddbinfo->db_name) == 0)
484-
{
485-
check_locale_and_encoding(olddbinfo, newdbinfo);
486-
break;
487-
}
488-
}
489-
}
490-
}
491-
492370
/*
493371
* A previous run of pg_upgrade might have failed and the new cluster
494372
* directory recreated, but they might have forgotten to remove
@@ -1524,41 +1402,3 @@ check_for_user_defined_encoding_conversions(ClusterInfo *cluster)
15241402
else
15251403
check_ok();
15261404
}
1527-
1528-
1529-
/*
1530-
* get_canonical_locale_name
1531-
*
1532-
* Send the locale name to the system, and hope we get back a canonical
1533-
* version. This should match the backend's check_locale() function.
1534-
*/
1535-
static char *
1536-
get_canonical_locale_name(int category, const char *locale)
1537-
{
1538-
char *save;
1539-
char *res;
1540-
1541-
/* get the current setting, so we can restore it. */
1542-
save = setlocale(category, NULL);
1543-
if (!save)
1544-
pg_fatal("failed to get the current locale");
1545-
1546-
/* 'save' may be pointing at a modifiable scratch variable, so copy it. */
1547-
save = pg_strdup(save);
1548-
1549-
/* set the locale with setlocale, to see if it accepts it. */
1550-
res = setlocale(category, locale);
1551-
1552-
if (!res)
1553-
pg_fatal("failed to get system locale name for \"%s\"", locale);
1554-
1555-
res = pg_strdup(res);
1556-
1557-
/* restore old value. */
1558-
if (!setlocale(category, save))
1559-
pg_fatal("failed to restore old locale \"%s\"", save);
1560-
1561-
pg_free(save);
1562-
1563-
return res;
1564-
}

src/bin/pg_upgrade/info.c

+51-18
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ static void create_rel_filename_map(const char *old_data, const char *new_data,
2020
static void report_unmatched_relation(const RelInfo *rel, const DbInfo *db,
2121
bool is_new_db);
2222
static void free_db_and_rel_infos(DbInfoArr *db_arr);
23+
static void get_template0_info(ClusterInfo *cluster);
2324
static void get_db_infos(ClusterInfo *cluster);
2425
static void get_rel_infos(ClusterInfo *cluster, DbInfo *dbinfo);
2526
static void free_rel_infos(RelInfoArr *rel_arr);
@@ -278,6 +279,7 @@ get_db_and_rel_infos(ClusterInfo *cluster)
278279
if (cluster->dbarr.dbs != NULL)
279280
free_db_and_rel_infos(&cluster->dbarr);
280281

282+
get_template0_info(cluster);
281283
get_db_infos(cluster);
282284

283285
for (dbnum = 0; dbnum < cluster->dbarr.ndbs; dbnum++)
@@ -293,6 +295,55 @@ get_db_and_rel_infos(ClusterInfo *cluster)
293295
}
294296

295297

298+
/*
299+
* Get information about template0, which will be copied from the old cluster
300+
* to the new cluster.
301+
*/
302+
static void
303+
get_template0_info(ClusterInfo *cluster)
304+
{
305+
PGconn *conn = connectToServer(cluster, "template1");
306+
DbLocaleInfo *locale;
307+
PGresult *dbres;
308+
int i_datencoding;
309+
int i_datlocprovider;
310+
int i_datcollate;
311+
int i_datctype;
312+
int i_daticulocale;
313+
314+
dbres = executeQueryOrDie(conn,
315+
"SELECT encoding, datlocprovider, "
316+
" datcollate, datctype, daticulocale "
317+
"FROM pg_catalog.pg_database "
318+
"WHERE datname='template0'");
319+
320+
if (PQntuples(dbres) != 1)
321+
pg_fatal("template0 not found");
322+
323+
locale = pg_malloc(sizeof(DbLocaleInfo));
324+
325+
i_datencoding = PQfnumber(dbres, "encoding");
326+
i_datlocprovider = PQfnumber(dbres, "datlocprovider");
327+
i_datcollate = PQfnumber(dbres, "datcollate");
328+
i_datctype = PQfnumber(dbres, "datctype");
329+
i_daticulocale = PQfnumber(dbres, "daticulocale");
330+
331+
locale->db_encoding = atoi(PQgetvalue(dbres, 0, i_datencoding));
332+
locale->db_collprovider = PQgetvalue(dbres, 0, i_datlocprovider)[0];
333+
locale->db_collate = pg_strdup(PQgetvalue(dbres, 0, i_datcollate));
334+
locale->db_ctype = pg_strdup(PQgetvalue(dbres, 0, i_datctype));
335+
if (PQgetisnull(dbres, 0, i_daticulocale))
336+
locale->db_iculocale = NULL;
337+
else
338+
locale->db_iculocale = pg_strdup(PQgetvalue(dbres, 0, i_daticulocale));
339+
340+
cluster->template0 = locale;
341+
342+
PQclear(dbres);
343+
PQfinish(conn);
344+
}
345+
346+
296347
/*
297348
* get_db_infos()
298349
*
@@ -309,11 +360,6 @@ get_db_infos(ClusterInfo *cluster)
309360
DbInfo *dbinfos;
310361
int i_datname,
311362
i_oid,
312-
i_encoding,
313-
i_datcollate,
314-
i_datctype,
315-
i_datlocprovider,
316-
i_daticulocale,
317363
i_spclocation;
318364
char query[QUERY_ALLOC];
319365

@@ -337,11 +383,6 @@ get_db_infos(ClusterInfo *cluster)
337383

338384
i_oid = PQfnumber(res, "oid");
339385
i_datname = PQfnumber(res, "datname");
340-
i_encoding = PQfnumber(res, "encoding");
341-
i_datcollate = PQfnumber(res, "datcollate");
342-
i_datctype = PQfnumber(res, "datctype");
343-
i_datlocprovider = PQfnumber(res, "datlocprovider");
344-
i_daticulocale = PQfnumber(res, "daticulocale");
345386
i_spclocation = PQfnumber(res, "spclocation");
346387

347388
ntups = PQntuples(res);
@@ -351,14 +392,6 @@ get_db_infos(ClusterInfo *cluster)
351392
{
352393
dbinfos[tupnum].db_oid = atooid(PQgetvalue(res, tupnum, i_oid));
353394
dbinfos[tupnum].db_name = pg_strdup(PQgetvalue(res, tupnum, i_datname));
354-
dbinfos[tupnum].db_encoding = atoi(PQgetvalue(res, tupnum, i_encoding));
355-
dbinfos[tupnum].db_collate = pg_strdup(PQgetvalue(res, tupnum, i_datcollate));
356-
dbinfos[tupnum].db_ctype = pg_strdup(PQgetvalue(res, tupnum, i_datctype));
357-
dbinfos[tupnum].db_collprovider = PQgetvalue(res, tupnum, i_datlocprovider)[0];
358-
if (PQgetisnull(res, tupnum, i_daticulocale))
359-
dbinfos[tupnum].db_iculocale = NULL;
360-
else
361-
dbinfos[tupnum].db_iculocale = pg_strdup(PQgetvalue(res, tupnum, i_daticulocale));
362395
snprintf(dbinfos[tupnum].db_tablespace, sizeof(dbinfos[tupnum].db_tablespace), "%s",
363396
PQgetvalue(res, tupnum, i_spclocation));
364397
}

src/bin/pg_upgrade/meson.build

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ tests += {
3838
'sd': meson.current_source_dir(),
3939
'bd': meson.current_build_dir(),
4040
'tap': {
41+
'env': {'with_icu': icu.found() ? 'yes' : 'no'},
4142
'tests': [
4243
't/001_basic.pl',
4344
't/002_pg_upgrade.pl',

0 commit comments

Comments
 (0)