Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitbbcfee0

Browse files
committed
Fix some more omissions in pg_upgrade's tests for non-upgradable types.
Commits29aeda6 et al closed up some oversights involving not checkingfor non-upgradable types within container types, such as arrays andranges. However, I only looked at version.c, failing to notice thatthere were substantially-equivalent tests in check.c. (The divisionof responsibility between those files is less than clear...)In addition, because genbki.pl does not guarantee that auto-generatedrowtype OIDs will hold still across versions, we need to consider thatthe composite type associated with a system catalog or view isnon-upgradable. It seems unlikely that someone would have a usercolumn declared that way, but if they did, trying to read it in anotherPG version would likely draw "no such pg_type OID" failures, thanksto the type OID embedded in composite Datums.To support the composite and reg*-type cases, extend the recursivequery that does the search to allow any base query that returnsa column of pg_type OIDs, rather than limiting it to exactly onestarting type.As before, back-patch to all supported branches.Discussion:https://postgr.es/m/2798740.1619622555@sss.pgh.pa.us
1 parent896cedc commitbbcfee0

File tree

3 files changed

+133
-149
lines changed

3 files changed

+133
-149
lines changed

‎src/bin/pg_upgrade/check.c

Lines changed: 84 additions & 139 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ static void check_proper_datallowconn(ClusterInfo *cluster);
2323
staticvoidcheck_for_prepared_transactions(ClusterInfo*cluster);
2424
staticvoidcheck_for_isn_and_int8_passing_mismatch(ClusterInfo*cluster);
2525
staticvoidcheck_for_tables_with_oids(ClusterInfo*cluster);
26+
staticvoidcheck_for_composite_data_type_usage(ClusterInfo*cluster);
2627
staticvoidcheck_for_reg_data_type_usage(ClusterInfo*cluster);
2728
staticvoidcheck_for_jsonb_9_4_usage(ClusterInfo*cluster);
2829
staticvoidcheck_for_pg_role_prefix(ClusterInfo*cluster);
@@ -98,6 +99,7 @@ check_and_dump_old_cluster(bool live_check)
9899
check_is_install_user(&old_cluster);
99100
check_proper_datallowconn(&old_cluster);
100101
check_for_prepared_transactions(&old_cluster);
102+
check_for_composite_data_type_usage(&old_cluster);
101103
check_for_reg_data_type_usage(&old_cluster);
102104
check_for_isn_and_int8_passing_mismatch(&old_cluster);
103105

@@ -1000,6 +1002,63 @@ check_for_tables_with_oids(ClusterInfo *cluster)
10001002
}
10011003

10021004

1005+
/*
1006+
* check_for_composite_data_type_usage()
1007+
*Check for system-defined composite types used in user tables.
1008+
*
1009+
*The OIDs of rowtypes of system catalogs and information_schema views
1010+
*can change across major versions; unlike user-defined types, we have
1011+
*no mechanism for forcing them to be the same in the new cluster.
1012+
*Hence, if any user table uses one, that's problematic for pg_upgrade.
1013+
*/
1014+
staticvoid
1015+
check_for_composite_data_type_usage(ClusterInfo*cluster)
1016+
{
1017+
boolfound;
1018+
OidfirstUserOid;
1019+
charoutput_path[MAXPGPATH];
1020+
char*base_query;
1021+
1022+
prep_status("Checking for system-defined composite types in user tables");
1023+
1024+
snprintf(output_path,sizeof(output_path),"tables_using_composite.txt");
1025+
1026+
/*
1027+
* Look for composite types that were made during initdb *or* belong to
1028+
* information_schema; that's important in case information_schema was
1029+
* dropped and reloaded.
1030+
*
1031+
* The cutoff OID here should match the source cluster's value of
1032+
* FirstNormalObjectId. We hardcode it rather than using that C #define
1033+
* because, if that #define is ever changed, our own version's value is
1034+
* NOT what to use. Eventually we may need a test on the source cluster's
1035+
* version to select the correct value.
1036+
*/
1037+
firstUserOid=16384;
1038+
1039+
base_query=psprintf("SELECT t.oid FROM pg_catalog.pg_type t "
1040+
"LEFT JOIN pg_catalog.pg_namespace n ON t.typnamespace = n.oid "
1041+
" WHERE typtype = 'c' AND (t.oid < %u OR nspname = 'information_schema')",
1042+
firstUserOid);
1043+
1044+
found=check_for_data_types_usage(cluster,base_query,output_path);
1045+
1046+
free(base_query);
1047+
1048+
if (found)
1049+
{
1050+
pg_log(PG_REPORT,"fatal\n");
1051+
pg_fatal("Your installation contains system-defined composite type(s) in user tables.\n"
1052+
"These type OIDs are not stable across PostgreSQL versions,\n"
1053+
"so this cluster cannot currently be upgraded. You can\n"
1054+
"drop the problem columns and restart the upgrade.\n"
1055+
"A list of the problem columns is in the file:\n"
1056+
" %s\n\n",output_path);
1057+
}
1058+
else
1059+
check_ok();
1060+
}
1061+
10031062
/*
10041063
* check_for_reg_data_type_usage()
10051064
*pg_upgrade only preserves these system values:
@@ -1014,88 +1073,36 @@ check_for_tables_with_oids(ClusterInfo *cluster)
10141073
staticvoid
10151074
check_for_reg_data_type_usage(ClusterInfo*cluster)
10161075
{
1017-
intdbnum;
1018-
FILE*script=NULL;
1019-
boolfound= false;
1076+
boolfound;
10201077
charoutput_path[MAXPGPATH];
10211078

10221079
prep_status("Checking for reg* data types in user tables");
10231080

10241081
snprintf(output_path,sizeof(output_path),"tables_using_reg.txt");
10251082

1026-
for (dbnum=0;dbnum<cluster->dbarr.ndbs;dbnum++)
1027-
{
1028-
PGresult*res;
1029-
booldb_used= false;
1030-
intntups;
1031-
introwno;
1032-
inti_nspname,
1033-
i_relname,
1034-
i_attname;
1035-
DbInfo*active_db=&cluster->dbarr.dbs[dbnum];
1036-
PGconn*conn=connectToServer(cluster,active_db->db_name);
1037-
1038-
/*
1039-
* While several relkinds don't store any data, e.g. views, they can
1040-
* be used to define data types of other columns, so we check all
1041-
* relkinds.
1042-
*/
1043-
res=executeQueryOrDie(conn,
1044-
"SELECT n.nspname, c.relname, a.attname "
1045-
"FROMpg_catalog.pg_class c, "
1046-
"pg_catalog.pg_namespace n, "
1047-
"pg_catalog.pg_attribute a, "
1048-
"pg_catalog.pg_type t "
1049-
"WHEREc.oid = a.attrelid AND "
1050-
"NOT a.attisdropped AND "
1051-
" a.atttypid = t.oid AND "
1052-
" t.typnamespace = "
1053-
" (SELECT oid FROM pg_namespace "
1054-
" WHERE nspname = 'pg_catalog') AND"
1055-
"t.typname IN ( "
1056-
/* regclass.oid is preserved, so 'regclass' is OK */
1057-
" 'regcollation', "
1058-
" 'regconfig', "
1059-
" 'regdictionary', "
1060-
" 'regnamespace', "
1061-
" 'regoper', "
1062-
" 'regoperator', "
1063-
" 'regproc', "
1064-
" 'regprocedure' "
1065-
/* regrole.oid is preserved, so 'regrole' is OK */
1066-
/* regtype.oid is preserved, so 'regtype' is OK */
1067-
") AND "
1068-
"c.relnamespace = n.oid AND "
1069-
"n.nspname NOT IN ('pg_catalog', 'information_schema')");
1070-
1071-
ntups=PQntuples(res);
1072-
i_nspname=PQfnumber(res,"nspname");
1073-
i_relname=PQfnumber(res,"relname");
1074-
i_attname=PQfnumber(res,"attname");
1075-
for (rowno=0;rowno<ntups;rowno++)
1076-
{
1077-
found= true;
1078-
if (script==NULL&& (script=fopen_priv(output_path,"w"))==NULL)
1079-
pg_fatal("could not open file \"%s\": %s\n",
1080-
output_path,strerror(errno));
1081-
if (!db_used)
1082-
{
1083-
fprintf(script,"In database: %s\n",active_db->db_name);
1084-
db_used= true;
1085-
}
1086-
fprintf(script," %s.%s.%s\n",
1087-
PQgetvalue(res,rowno,i_nspname),
1088-
PQgetvalue(res,rowno,i_relname),
1089-
PQgetvalue(res,rowno,i_attname));
1090-
}
1091-
1092-
PQclear(res);
1093-
1094-
PQfinish(conn);
1095-
}
1096-
1097-
if (script)
1098-
fclose(script);
1083+
/*
1084+
* Note: older servers will not have all of these reg* types, so we have
1085+
* to write the query like this rather than depending on casts to regtype.
1086+
*/
1087+
found=check_for_data_types_usage(cluster,
1088+
"SELECT oid FROM pg_catalog.pg_type t "
1089+
"WHERE t.typnamespace = "
1090+
" (SELECT oid FROM pg_catalog.pg_namespace "
1091+
" WHERE nspname = 'pg_catalog') "
1092+
" AND t.typname IN ( "
1093+
/* pg_class.oid is preserved, so 'regclass' is OK */
1094+
" 'regcollation', "
1095+
" 'regconfig', "
1096+
" 'regdictionary', "
1097+
" 'regnamespace', "
1098+
" 'regoper', "
1099+
" 'regoperator', "
1100+
" 'regproc', "
1101+
" 'regprocedure' "
1102+
/* pg_authid.oid is preserved, so 'regrole' is OK */
1103+
/* pg_type.oid is (mostly) preserved, so 'regtype' is OK */
1104+
" )",
1105+
output_path);
10991106

11001107
if (found)
11011108
{
@@ -1120,75 +1127,13 @@ check_for_reg_data_type_usage(ClusterInfo *cluster)
11201127
staticvoid
11211128
check_for_jsonb_9_4_usage(ClusterInfo*cluster)
11221129
{
1123-
intdbnum;
1124-
FILE*script=NULL;
1125-
boolfound= false;
11261130
charoutput_path[MAXPGPATH];
11271131

11281132
prep_status("Checking for incompatible \"jsonb\" data type");
11291133

11301134
snprintf(output_path,sizeof(output_path),"tables_using_jsonb.txt");
11311135

1132-
for (dbnum=0;dbnum<cluster->dbarr.ndbs;dbnum++)
1133-
{
1134-
PGresult*res;
1135-
booldb_used= false;
1136-
intntups;
1137-
introwno;
1138-
inti_nspname,
1139-
i_relname,
1140-
i_attname;
1141-
DbInfo*active_db=&cluster->dbarr.dbs[dbnum];
1142-
PGconn*conn=connectToServer(cluster,active_db->db_name);
1143-
1144-
/*
1145-
* While several relkinds don't store any data, e.g. views, they can
1146-
* be used to define data types of other columns, so we check all
1147-
* relkinds.
1148-
*/
1149-
res=executeQueryOrDie(conn,
1150-
"SELECT n.nspname, c.relname, a.attname "
1151-
"FROMpg_catalog.pg_class c, "
1152-
"pg_catalog.pg_namespace n, "
1153-
"pg_catalog.pg_attribute a "
1154-
"WHEREc.oid = a.attrelid AND "
1155-
"NOT a.attisdropped AND "
1156-
"a.atttypid = 'pg_catalog.jsonb'::pg_catalog.regtype AND "
1157-
"c.relnamespace = n.oid AND "
1158-
/* exclude possible orphaned temp tables */
1159-
"n.nspname !~ '^pg_temp_' AND "
1160-
"n.nspname NOT IN ('pg_catalog', 'information_schema')");
1161-
1162-
ntups=PQntuples(res);
1163-
i_nspname=PQfnumber(res,"nspname");
1164-
i_relname=PQfnumber(res,"relname");
1165-
i_attname=PQfnumber(res,"attname");
1166-
for (rowno=0;rowno<ntups;rowno++)
1167-
{
1168-
found= true;
1169-
if (script==NULL&& (script=fopen_priv(output_path,"w"))==NULL)
1170-
pg_fatal("could not open file \"%s\": %s\n",
1171-
output_path,strerror(errno));
1172-
if (!db_used)
1173-
{
1174-
fprintf(script,"In database: %s\n",active_db->db_name);
1175-
db_used= true;
1176-
}
1177-
fprintf(script," %s.%s.%s\n",
1178-
PQgetvalue(res,rowno,i_nspname),
1179-
PQgetvalue(res,rowno,i_relname),
1180-
PQgetvalue(res,rowno,i_attname));
1181-
}
1182-
1183-
PQclear(res);
1184-
1185-
PQfinish(conn);
1186-
}
1187-
1188-
if (script)
1189-
fclose(script);
1190-
1191-
if (found)
1136+
if (check_for_data_type_usage(cluster,"pg_catalog.jsonb",output_path))
11921137
{
11931138
pg_log(PG_REPORT,"fatal\n");
11941139
pg_fatal("Your installation contains the \"jsonb\" data type in user tables.\n"

‎src/bin/pg_upgrade/pg_upgrade.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,12 @@ voidpg_putenv(const char *var, const char *val);
442442

443443
/* version.c */
444444

445+
boolcheck_for_data_types_usage(ClusterInfo*cluster,
446+
constchar*base_query,
447+
constchar*output_path);
448+
boolcheck_for_data_type_usage(ClusterInfo*cluster,
449+
constchar*typename,
450+
constchar*output_path);
445451
voidnew_9_0_populate_pg_largeobject_metadata(ClusterInfo*cluster,
446452
boolcheck_mode);
447453
voidold_9_3_check_for_line_data_type_usage(ClusterInfo*cluster);

‎src/bin/pg_upgrade/version.c

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -97,17 +97,22 @@ new_9_0_populate_pg_largeobject_metadata(ClusterInfo *cluster, bool check_mode)
9797

9898

9999
/*
100-
*check_for_data_type_usage
101-
*Detect whether there are any stored columns depending onthegiven type
100+
*check_for_data_types_usage()
101+
*Detect whether there are any stored columns depending on given type(s)
102102
*
103103
* If so, write a report to the given file name, and return true.
104104
*
105-
* We check for the type in tables, matviews, and indexes, but not views;
105+
* base_query should be a SELECT yielding a single column named "oid",
106+
* containing the pg_type OIDs of one or more types that are known to have
107+
* inconsistent on-disk representations across server versions.
108+
*
109+
* We check for the type(s) in tables, matviews, and indexes, but not views;
106110
* there's no storage involved in a view.
107111
*/
108-
staticbool
109-
check_for_data_type_usage(ClusterInfo*cluster,constchar*typename,
110-
char*output_path)
112+
bool
113+
check_for_data_types_usage(ClusterInfo*cluster,
114+
constchar*base_query,
115+
constchar*output_path)
111116
{
112117
boolfound= false;
113118
FILE*script=NULL;
@@ -127,16 +132,16 @@ check_for_data_type_usage(ClusterInfo *cluster, const char *typename,
127132
i_attname;
128133

129134
/*
130-
* The type of interest might be wrapped in a domain, array,
135+
* The type(s) of interest might be wrapped in a domain, array,
131136
* composite, or range, and these container types can be nested (to
132137
* varying extents depending on server version, but that's not of
133138
* concern here). To handle all these cases we need a recursive CTE.
134139
*/
135140
initPQExpBuffer(&querybuf);
136141
appendPQExpBuffer(&querybuf,
137142
"WITH RECURSIVE oids AS ( "
138-
/*the targettype itself */
139-
"SELECT '%s'::pg_catalog.regtype AS oid "
143+
/*start with thetype(s) returned by base_query */
144+
"%s "
140145
"UNION ALL "
141146
"SELECT * FROM ( "
142147
/* inner WITH because we can only reference the CTE once */
@@ -154,7 +159,7 @@ check_for_data_type_usage(ClusterInfo *cluster, const char *typename,
154159
" c.oid = a.attrelid AND "
155160
" NOT a.attisdropped AND "
156161
" a.atttypid = x.oid ",
157-
typename);
162+
base_query);
158163

159164
/* Ranges were introduced in 9.2 */
160165
if (GET_MAJOR_VERSION(cluster->major_version) >=902)
@@ -222,6 +227,34 @@ check_for_data_type_usage(ClusterInfo *cluster, const char *typename,
222227
returnfound;
223228
}
224229

230+
/*
231+
* check_for_data_type_usage()
232+
*Detect whether there are any stored columns depending on the given type
233+
*
234+
* If so, write a report to the given file name, and return true.
235+
*
236+
* typename should be a fully qualified type name. This is just a
237+
* trivial wrapper around check_for_data_types_usage() to convert a
238+
* type name into a base query.
239+
*/
240+
bool
241+
check_for_data_type_usage(ClusterInfo*cluster,
242+
constchar*typename,
243+
constchar*output_path)
244+
{
245+
boolfound;
246+
char*base_query;
247+
248+
base_query=psprintf("SELECT '%s'::pg_catalog.regtype AS oid",
249+
typename);
250+
251+
found=check_for_data_types_usage(cluster,base_query,output_path);
252+
253+
free(base_query);
254+
255+
returnfound;
256+
}
257+
225258

226259
/*
227260
* old_9_3_check_for_line_data_type_usage()

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp