diff --git a/src/backend/utils/fmgr/dfmgr.c b/src/backend/utils/fmgr/dfmgr.c index f41035d33c..6f70813a6d 100644 --- a/src/backend/utils/fmgr/dfmgr.c +++ b/src/backend/utils/fmgr/dfmgr.c @@ -300,14 +300,22 @@ incompatible_module_error(const char *libname, * block might not even have the fields we expect. */ if (magic_data.version != module_magic_data->version) + { + char library_version[32]; + + if (module_magic_data->version >= 1000) + snprintf(library_version, sizeof(library_version), "%d", + module_magic_data->version / 100); + else + snprintf(library_version, sizeof(library_version), "%d.%d", + module_magic_data->version / 100, + module_magic_data->version % 100); ereport(ERROR, (errmsg("incompatible library \"%s\": version mismatch", libname), - errdetail("Server is version %d.%d, library is version %d.%d.", - magic_data.version / 100, - magic_data.version % 100, - module_magic_data->version / 100, - module_magic_data->version % 100))); + errdetail("Server is version %d, library is version %s.", + magic_data.version / 100, library_version))); + } /* * Otherwise, spell out which fields don't agree. diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c index 9c0af4e848..4aaf657cce 100644 --- a/src/bin/psql/command.c +++ b/src/bin/psql/command.c @@ -635,8 +635,11 @@ exec_command(const char *cmd, if (pset.sversion < 80400) { - psql_error("The server (version %d.%d) does not support editing function source.\n", - pset.sversion / 10000, (pset.sversion / 100) % 100); + char sverbuf[32]; + + psql_error("The server (version %s) does not support editing function source.\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); status = PSQL_CMD_ERROR; } else if (!query_buf) @@ -731,8 +734,11 @@ exec_command(const char *cmd, if (pset.sversion < 70400) { - psql_error("The server (version %d.%d) does not support editing view definitions.\n", - pset.sversion / 10000, (pset.sversion / 100) % 100); + char sverbuf[32]; + + psql_error("The server (version %s) does not support editing view definitions.\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); status = PSQL_CMD_ERROR; } else if (!query_buf) @@ -1362,8 +1368,11 @@ exec_command(const char *cmd, OT_WHOLE_LINE, NULL, true); if (pset.sversion < 80400) { - psql_error("The server (version %d.%d) does not support showing function source.\n", - pset.sversion / 10000, (pset.sversion / 100) % 100); + char sverbuf[32]; + + psql_error("The server (version %s) does not support showing function source.\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); status = PSQL_CMD_ERROR; } else if (!func) @@ -1441,8 +1450,11 @@ exec_command(const char *cmd, OT_WHOLE_LINE, NULL, true); if (pset.sversion < 70400) { - psql_error("The server (version %d.%d) does not support showing view definitions.\n", - pset.sversion / 10000, (pset.sversion / 100) % 100); + char sverbuf[32]; + + psql_error("The server (version %s) does not support showing view definitions.\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); status = PSQL_CMD_ERROR; } else if (!view) @@ -2014,22 +2026,21 @@ connection_warnings(bool in_startup) if (!pset.quiet && !pset.notty) { int client_ver = PG_VERSION_NUM; + char cverbuf[32]; + char sverbuf[32]; if (pset.sversion != client_ver) { const char *server_version; - char server_ver_str[16]; /* Try to get full text form, might include "devel" etc */ server_version = PQparameterStatus(pset.db, "server_version"); + /* Otherwise fall back on pset.sversion */ if (!server_version) { - snprintf(server_ver_str, sizeof(server_ver_str), - "%d.%d.%d", - pset.sversion / 10000, - (pset.sversion / 100) % 100, - pset.sversion % 100); - server_version = server_ver_str; + formatPGVersionNumber(pset.sversion, true, + sverbuf, sizeof(sverbuf)); + server_version = sverbuf; } printf(_("%s (%s, server %s)\n"), @@ -2040,10 +2051,13 @@ connection_warnings(bool in_startup) printf("%s (%s)\n", pset.progname, PG_VERSION); if (pset.sversion / 100 > client_ver / 100) - printf(_("WARNING: %s major version %d.%d, server major version %d.%d.\n" + printf(_("WARNING: %s major version %s, server major version %s.\n" " Some psql features might not work.\n"), - pset.progname, client_ver / 10000, (client_ver / 100) % 100, - pset.sversion / 10000, (pset.sversion / 100) % 100); + pset.progname, + formatPGVersionNumber(client_ver, false, + cverbuf, sizeof(cverbuf)), + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); #ifdef WIN32 checkWin32Codepage(); diff --git a/src/bin/psql/common.c b/src/bin/psql/common.c index 2450b9c3f8..7399950284 100644 --- a/src/bin/psql/common.c +++ b/src/bin/psql/common.c @@ -18,6 +18,7 @@ #include #endif +#include "fe_utils/string_utils.h" #include "portability/instr_time.h" #include "settings.h" @@ -1202,8 +1203,11 @@ SendQuery(const char *query) { if (on_error_rollback_warning == false && pset.sversion < 80000) { - psql_error("The server (version %d.%d) does not support savepoints for ON_ERROR_ROLLBACK.\n", - pset.sversion / 10000, (pset.sversion / 100) % 100); + char sverbuf[32]; + + psql_error("The server (version %s) does not support savepoints for ON_ERROR_ROLLBACK.\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); on_error_rollback_warning = true; } else diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c index 27be10215b..6275a688c7 100644 --- a/src/bin/psql/describe.c +++ b/src/bin/psql/describe.c @@ -142,8 +142,11 @@ describeAccessMethods(const char *pattern, bool verbose) if (pset.sversion < 90600) { - psql_error("The server (version %d.%d) does not support access methods.\n", - pset.sversion / 10000, (pset.sversion / 100) % 100); + char sverbuf[32]; + + psql_error("The server (version %s) does not support access methods.\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); return true; } @@ -205,8 +208,11 @@ describeTablespaces(const char *pattern, bool verbose) if (pset.sversion < 80000) { - psql_error("The server (version %d.%d) does not support tablespaces.\n", - pset.sversion / 10000, (pset.sversion / 100) % 100); + char sverbuf[32]; + + psql_error("The server (version %s) does not support tablespaces.\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); return true; } @@ -311,8 +317,11 @@ describeFunctions(const char *functypes, const char *pattern, bool verbose, bool if (showWindow && pset.sversion < 80400) { - psql_error("\\df does not take a \"w\" option with server version %d.%d\n", - pset.sversion / 10000, (pset.sversion / 100) % 100); + char sverbuf[32]; + + psql_error("\\df does not take a \"w\" option with server version %s\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); return true; } @@ -962,8 +971,11 @@ listDefaultACLs(const char *pattern) if (pset.sversion < 90000) { - psql_error("The server (version %d.%d) does not support altering default privileges.\n", - pset.sversion / 10000, (pset.sversion / 100) % 100); + char sverbuf[32]; + + psql_error("The server (version %s) does not support altering default privileges.\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); return true; } @@ -3548,8 +3560,11 @@ listCollations(const char *pattern, bool verbose, bool showSystem) if (pset.sversion < 90100) { - psql_error("The server (version %d.%d) does not support collations.\n", - pset.sversion / 10000, (pset.sversion / 100) % 100); + char sverbuf[32]; + + psql_error("The server (version %s) does not support collations.\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); return true; } @@ -3680,8 +3695,11 @@ listTSParsers(const char *pattern, bool verbose) if (pset.sversion < 80300) { - psql_error("The server (version %d.%d) does not support full text search.\n", - pset.sversion / 10000, (pset.sversion / 100) % 100); + char sverbuf[32]; + + psql_error("The server (version %s) does not support full text search.\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); return true; } @@ -3915,8 +3933,11 @@ listTSDictionaries(const char *pattern, bool verbose) if (pset.sversion < 80300) { - psql_error("The server (version %d.%d) does not support full text search.\n", - pset.sversion / 10000, (pset.sversion / 100) % 100); + char sverbuf[32]; + + psql_error("The server (version %s) does not support full text search.\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); return true; } @@ -3983,8 +4004,11 @@ listTSTemplates(const char *pattern, bool verbose) if (pset.sversion < 80300) { - psql_error("The server (version %d.%d) does not support full text search.\n", - pset.sversion / 10000, (pset.sversion / 100) % 100); + char sverbuf[32]; + + psql_error("The server (version %s) does not support full text search.\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); return true; } @@ -4051,8 +4075,11 @@ listTSConfigs(const char *pattern, bool verbose) if (pset.sversion < 80300) { - psql_error("The server (version %d.%d) does not support full text search.\n", - pset.sversion / 10000, (pset.sversion / 100) % 100); + char sverbuf[32]; + + psql_error("The server (version %s) does not support full text search.\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); return true; } @@ -4249,8 +4276,11 @@ listForeignDataWrappers(const char *pattern, bool verbose) if (pset.sversion < 80400) { - psql_error("The server (version %d.%d) does not support foreign-data wrappers.\n", - pset.sversion / 10000, (pset.sversion / 100) % 100); + char sverbuf[32]; + + psql_error("The server (version %s) does not support foreign-data wrappers.\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); return true; } @@ -4329,8 +4359,11 @@ listForeignServers(const char *pattern, bool verbose) if (pset.sversion < 80400) { - psql_error("The server (version %d.%d) does not support foreign servers.\n", - pset.sversion / 10000, (pset.sversion / 100) % 100); + char sverbuf[32]; + + psql_error("The server (version %s) does not support foreign servers.\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); return true; } @@ -4408,8 +4441,11 @@ listUserMappings(const char *pattern, bool verbose) if (pset.sversion < 80400) { - psql_error("The server (version %d.%d) does not support user mappings.\n", - pset.sversion / 10000, (pset.sversion / 100) % 100); + char sverbuf[32]; + + psql_error("The server (version %s) does not support user mappings.\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); return true; } @@ -4466,8 +4502,11 @@ listForeignTables(const char *pattern, bool verbose) if (pset.sversion < 90100) { - psql_error("The server (version %d.%d) does not support foreign tables.\n", - pset.sversion / 10000, (pset.sversion / 100) % 100); + char sverbuf[32]; + + psql_error("The server (version %s) does not support foreign tables.\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); return true; } @@ -4541,8 +4580,11 @@ listExtensions(const char *pattern) if (pset.sversion < 90100) { - psql_error("The server (version %d.%d) does not support extensions.\n", - pset.sversion / 10000, (pset.sversion / 100) % 100); + char sverbuf[32]; + + psql_error("The server (version %s) does not support extensions.\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); return true; } @@ -4595,8 +4637,11 @@ listExtensionContents(const char *pattern) if (pset.sversion < 90100) { - psql_error("The server (version %d.%d) does not support extensions.\n", - pset.sversion / 10000, (pset.sversion / 100) % 100); + char sverbuf[32]; + + psql_error("The server (version %s) does not support extensions.\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); return true; } diff --git a/src/fe_utils/string_utils.c b/src/fe_utils/string_utils.c index f986dbcf39..2c566b1ad7 100644 --- a/src/fe_utils/string_utils.c +++ b/src/fe_utils/string_utils.c @@ -168,6 +168,44 @@ fmtQualifiedId(int remoteVersion, const char *schema, const char *id) } +/* + * Format a Postgres version number (in the PG_VERSION_NUM integer format + * returned by PQserverVersion()) as a string. This exists mainly to + * encapsulate knowledge about two-part vs. three-part version numbers. + * + * For re-entrancy, caller must supply the buffer the string is put in. + * Recommended size of the buffer is 32 bytes. + * + * Returns address of 'buf', as a notational convenience. + */ +char * +formatPGVersionNumber(int version_number, bool include_minor, + char *buf, size_t buflen) +{ + if (version_number >= 100000) + { + /* New two-part style */ + if (include_minor) + snprintf(buf, buflen, "%d.%d", version_number / 10000, + version_number % 10000); + else + snprintf(buf, buflen, "%d", version_number / 10000); + } + else + { + /* Old three-part style */ + if (include_minor) + snprintf(buf, buflen, "%d.%d.%d", version_number / 10000, + (version_number / 100) % 100, + version_number % 100); + else + snprintf(buf, buflen, "%d.%d", version_number / 10000, + (version_number / 100) % 100); + } + return buf; +} + + /* * Convert a string value to an SQL string literal and append it to * the given buffer. We assume the specified client_encoding and diff --git a/src/include/fe_utils/string_utils.h b/src/include/fe_utils/string_utils.h index 7bbed360a3..452ffc0771 100644 --- a/src/include/fe_utils/string_utils.h +++ b/src/include/fe_utils/string_utils.h @@ -30,6 +30,9 @@ extern const char *fmtId(const char *identifier); extern const char *fmtQualifiedId(int remoteVersion, const char *schema, const char *id); +extern char *formatPGVersionNumber(int version_number, bool include_minor, + char *buf, size_t buflen); + extern void appendStringLiteral(PQExpBuffer buf, const char *str, int encoding, bool std_strings); extern void appendStringLiteralConn(PQExpBuffer buf, const char *str,