14
14
#include "pg_upgrade.h"
15
15
16
16
17
- static void set_locale_and_encoding (ClusterInfo * cluster );
18
17
static void check_new_cluster_is_empty (void );
19
- static void check_locale_and_encoding (ControlData * oldctrl ,
20
- ControlData * newctrl );
21
- static bool equivalent_locale (const char * loca , const char * locb );
22
- static bool equivalent_encoding (const char * chara , const char * charb );
18
+ static void check_databases_are_compatible (void );
19
+ static void check_locale_and_encoding (DbInfo * olddb , DbInfo * newdb );
20
+ static bool equivalent_locale (int category , const char * loca , const char * locb );
23
21
static void check_is_install_user (ClusterInfo * cluster );
24
22
static void check_for_prepared_transactions (ClusterInfo * cluster );
25
23
static void check_for_isn_and_int8_passing_mismatch (ClusterInfo * cluster );
@@ -81,8 +79,6 @@ check_and_dump_old_cluster(bool live_check)
81
79
if (!live_check )
82
80
start_postmaster (& old_cluster , true);
83
81
84
- set_locale_and_encoding (& old_cluster );
85
-
86
82
get_pg_database_relfilenode (& old_cluster );
87
83
88
84
/* Extract a list of databases and tables from the old cluster */
@@ -127,13 +123,10 @@ check_and_dump_old_cluster(bool live_check)
127
123
void
128
124
check_new_cluster (void )
129
125
{
130
- set_locale_and_encoding (& new_cluster );
131
-
132
- check_locale_and_encoding (& old_cluster .controldata , & new_cluster .controldata );
133
-
134
126
get_db_and_rel_infos (& new_cluster );
135
127
136
128
check_new_cluster_is_empty ();
129
+ check_databases_are_compatible ();
137
130
138
131
check_loadable_libraries ();
139
132
@@ -278,156 +271,73 @@ check_cluster_compatibility(bool live_check)
278
271
}
279
272
280
273
281
- /*
282
- * set_locale_and_encoding()
283
- *
284
- * query the database to get the template0 locale
285
- */
286
- static void
287
- set_locale_and_encoding (ClusterInfo * cluster )
288
- {
289
- ControlData * ctrl = & cluster -> controldata ;
290
- PGconn * conn ;
291
- PGresult * res ;
292
- int i_encoding ;
293
- int cluster_version = cluster -> major_version ;
294
-
295
- conn = connectToServer (cluster , "template1" );
296
-
297
- /* for pg < 80400, we got the values from pg_controldata */
298
- if (cluster_version >= 80400 )
299
- {
300
- int i_datcollate ;
301
- int i_datctype ;
302
-
303
- res = executeQueryOrDie (conn ,
304
- "SELECT datcollate, datctype "
305
- "FROM pg_catalog.pg_database "
306
- "WHERE datname = 'template0' " );
307
- assert (PQntuples (res ) == 1 );
308
-
309
- i_datcollate = PQfnumber (res , "datcollate" );
310
- i_datctype = PQfnumber (res , "datctype" );
311
-
312
- if (GET_MAJOR_VERSION (cluster -> major_version ) < 902 )
313
- {
314
- /*
315
- * Pre-9.2 did not canonicalize the supplied locale names to match
316
- * what the system returns, while 9.2+ does, so convert pre-9.2 to
317
- * match.
318
- */
319
- ctrl -> lc_collate = get_canonical_locale_name (LC_COLLATE ,
320
- pg_strdup (PQgetvalue (res , 0 , i_datcollate )));
321
- ctrl -> lc_ctype = get_canonical_locale_name (LC_CTYPE ,
322
- pg_strdup (PQgetvalue (res , 0 , i_datctype )));
323
- }
324
- else
325
- {
326
- ctrl -> lc_collate = pg_strdup (PQgetvalue (res , 0 , i_datcollate ));
327
- ctrl -> lc_ctype = pg_strdup (PQgetvalue (res , 0 , i_datctype ));
328
- }
329
-
330
- PQclear (res );
331
- }
332
-
333
- res = executeQueryOrDie (conn ,
334
- "SELECT pg_catalog.pg_encoding_to_char(encoding) "
335
- "FROM pg_catalog.pg_database "
336
- "WHERE datname = 'template0' " );
337
- assert (PQntuples (res ) == 1 );
338
-
339
- i_encoding = PQfnumber (res , "pg_encoding_to_char" );
340
- ctrl -> encoding = pg_strdup (PQgetvalue (res , 0 , i_encoding ));
341
-
342
- PQclear (res );
343
-
344
- PQfinish (conn );
345
- }
346
-
347
-
348
274
/*
349
275
* check_locale_and_encoding()
350
276
*
351
- * Check that old and new locale and encoding match. Even though the backend
352
- * tries to canonicalize stored locale names, the platform often doesn't
353
- * cooperate, so it's entirely possible that one DB thinks its locale is
354
- * "en_US.UTF-8" while the other says "en_US.utf8". Try to be forgiving.
277
+ * Check that locale and encoding of a database in the old and new clusters
278
+ * are compatible.
355
279
*/
356
280
static void
357
- check_locale_and_encoding (ControlData * oldctrl ,
358
- ControlData * newctrl )
281
+ check_locale_and_encoding (DbInfo * olddb , DbInfo * newdb )
359
282
{
360
- if (!equivalent_locale (oldctrl -> lc_collate , newctrl -> lc_collate ))
361
- pg_fatal ("lc_collate cluster values do not match: old \"%s\", new \"%s\"\n" ,
362
- oldctrl -> lc_collate , newctrl -> lc_collate );
363
- if (!equivalent_locale (oldctrl -> lc_ctype , newctrl -> lc_ctype ))
364
- pg_fatal ("lc_ctype cluster values do not match: old \"%s\", new \"%s\"\n" ,
365
- oldctrl -> lc_ctype , newctrl -> lc_ctype );
366
- if (!equivalent_encoding (oldctrl -> encoding , newctrl -> encoding ))
367
- pg_fatal ("encoding cluster values do not match: old \"%s\", new \"%s\"\n" ,
368
- oldctrl -> encoding , newctrl -> encoding );
283
+ if (olddb -> db_encoding != newdb -> db_encoding )
284
+ pg_fatal ("encodings for database \"%s\" do not match: old \"%s\", new \"%s\"\n" ,
285
+ olddb -> db_name ,
286
+ pg_encoding_to_char (olddb -> db_encoding ),
287
+ pg_encoding_to_char (newdb -> db_encoding ));
288
+ if (!equivalent_locale (LC_COLLATE , olddb -> db_collate , newdb -> db_collate ))
289
+ pg_fatal ("lc_collate values for database \"%s\" do not match: old \"%s\", new \"%s\"\n" ,
290
+ olddb -> db_name , olddb -> db_collate , newdb -> db_collate );
291
+ if (!equivalent_locale (LC_CTYPE , olddb -> db_ctype , newdb -> db_ctype ))
292
+ pg_fatal ("lc_ctype values for database \"%s\" do not match: old \"%s\", new \"%s\"\n" ,
293
+ olddb -> db_name , olddb -> db_ctype , newdb -> db_ctype );
369
294
}
370
295
371
296
/*
372
297
* equivalent_locale()
373
298
*
374
299
* Best effort locale-name comparison. Return false if we are not 100% sure
375
300
* the locales are equivalent.
301
+ *
302
+ * Note: The encoding parts of the names are ignored. This function is
303
+ * currently used to compare locale names stored in pg_database, and
304
+ * pg_database contains a separate encoding field. That's compared directly
305
+ * in check_locale_and_encoding().
376
306
*/
377
307
static bool
378
- equivalent_locale (const char * loca , const char * locb )
308
+ equivalent_locale (int category , const char * loca , const char * locb )
379
309
{
380
310
const char * chara = strrchr (loca , '.' );
381
311
const char * charb = strrchr (locb , '.' );
382
- int lencmp ;
383
-
384
- /* If they don't both contain an encoding part, just do strcasecmp(). */
385
- if (!chara || !charb )
386
- return (pg_strcasecmp (loca , locb ) == 0 );
312
+ char * canona ;
313
+ char * canonb ;
314
+ int lena ;
315
+ int lenb ;
387
316
388
317
/*
389
- * Compare the encoding parts. Windows tends to use code page numbers for
390
- * the encoding part, which equivalent_encoding() won't like, so accept if
391
- * the strings are case-insensitive equal; otherwise use
392
- * equivalent_encoding() to compare.
318
+ * If the names are equal, the locales are equivalent. Checking this
319
+ * first avoids calling setlocale() in the common case that the names
320
+ * are equal. That's a good thing, if setlocale() is buggy, for example.
393
321
*/
394
- if (pg_strcasecmp (chara + 1 , charb + 1 ) != 0 &&
395
- !equivalent_encoding (chara + 1 , charb + 1 ))
396
- return false;
322
+ if (pg_strcasecmp (loca , locb ) == 0 )
323
+ return true;
397
324
398
325
/*
399
- * OK, compare the locale identifiers (e.g. en_US part of en_US.utf8).
400
- *
401
- * It's tempting to ignore non-alphanumeric chars here, but for now it's
402
- * not clear that that's necessary; just do case-insensitive comparison.
326
+ * Not identical. Canonicalize both names, remove the encoding parts,
327
+ * and try again.
403
328
*/
404
- lencmp = chara - loca ;
405
- if ( lencmp != charb - locb )
406
- return false ;
329
+ canona = get_canonical_locale_name ( category , loca ) ;
330
+ chara = strrchr ( canona , '.' );
331
+ lena = chara ? ( chara - canona ) : strlen ( canona ) ;
407
332
408
- return (pg_strncasecmp (loca , locb , lencmp ) == 0 );
409
- }
333
+ canonb = get_canonical_locale_name (category , locb );
334
+ charb = strrchr (canonb , '.' );
335
+ lenb = charb ? (charb - canonb ) : strlen (canonb );
410
336
411
- /*
412
- * equivalent_encoding()
413
- *
414
- * Best effort encoding-name comparison. Return true only if the encodings
415
- * are valid server-side encodings and known equivalent.
416
- *
417
- * Because the lookup in pg_valid_server_encoding() does case folding and
418
- * ignores non-alphanumeric characters, this will recognize many popular
419
- * variant spellings as equivalent, eg "utf8" and "UTF-8" will match.
420
- */
421
- static bool
422
- equivalent_encoding (const char * chara , const char * charb )
423
- {
424
- int enca = pg_valid_server_encoding (chara );
425
- int encb = pg_valid_server_encoding (charb );
337
+ if (lena == lenb && pg_strncasecmp (canona , canonb , lena ) == 0 )
338
+ return true;
426
339
427
- if (enca < 0 || encb < 0 )
428
- return false;
429
-
430
- return (enca == encb );
340
+ return false;
431
341
}
432
342
433
343
@@ -450,7 +360,35 @@ check_new_cluster_is_empty(void)
450
360
new_cluster .dbarr .dbs [dbnum ].db_name );
451
361
}
452
362
}
363
+ }
364
+
365
+ /*
366
+ * Check that every database that already exists in the new cluster is
367
+ * compatible with the corresponding database in the old one.
368
+ */
369
+ static void
370
+ check_databases_are_compatible (void )
371
+ {
372
+ int newdbnum ;
373
+ int olddbnum ;
374
+ DbInfo * newdbinfo ;
375
+ DbInfo * olddbinfo ;
453
376
377
+ for (newdbnum = 0 ; newdbnum < new_cluster .dbarr .ndbs ; newdbnum ++ )
378
+ {
379
+ newdbinfo = & new_cluster .dbarr .dbs [newdbnum ];
380
+
381
+ /* Find the corresponding database in the old cluster */
382
+ for (olddbnum = 0 ; olddbnum < old_cluster .dbarr .ndbs ; olddbnum ++ )
383
+ {
384
+ olddbinfo = & old_cluster .dbarr .dbs [olddbnum ];
385
+ if (strcmp (newdbinfo -> db_name , olddbinfo -> db_name ) == 0 )
386
+ {
387
+ check_locale_and_encoding (olddbinfo , newdbinfo );
388
+ break ;
389
+ }
390
+ }
391
+ }
454
392
}
455
393
456
394
0 commit comments