Remove pg_dump/pg_dumpall support for dumping from pre-9.2 servers.

Per discussion, we'll limit support for old servers to those branches
that can still be built easily on modern platforms, which as of now
is 9.2 and up.  Remove over a thousand lines of code dedicated to
dumping from older server versions.  (As in previous changes of
this sort, we aren't removing pg_restore's ability to read older
archive files ... though it's fair to wonder how that might be
tested nowadays.)  This cleans up some dead code left behind by
commit 989596152.

Discussion: https://postgr.es/m/2923349.1634942313@sss.pgh.pa.us
This commit is contained in:
Tom Lane 2021-12-14 17:09:07 -05:00
parent a2ff18e89f
commit 30e7c175b8
5 changed files with 417 additions and 1761 deletions

View File

@ -398,16 +398,6 @@ PostgreSQL documentation
different worker jobs wouldn't be guaranteed to see the same data in different worker jobs wouldn't be guaranteed to see the same data in
each connection, which could lead to an inconsistent backup. each connection, which could lead to an inconsistent backup.
</para> </para>
<para>
If you want to run a parallel dump of a pre-9.2 server, you need to make sure that the
database content doesn't change from between the time the leader connects to the
database until the last worker job has connected to the database. The easiest way to
do this is to halt any data modifying processes (DDL and DML) accessing the database
before starting the backup. You also need to specify the
<option>--no-synchronized-snapshots</option> parameter when running
<command>pg_dump -j</command> against a pre-9.2 <productname>PostgreSQL</productname>
server.
</para>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -945,9 +935,10 @@ PostgreSQL documentation
<term><option>--no-synchronized-snapshots</option></term> <term><option>--no-synchronized-snapshots</option></term>
<listitem> <listitem>
<para> <para>
This option allows running <command>pg_dump -j</command> against a pre-9.2 This option allows running <command>pg_dump -j</command> against a
server, see the documentation of the <option>-j</option> parameter pre-v10 standby server, at the cost of possibly producing an
for more details. inconsistent dump. See the documentation of the <option>-j</option>
parameter for more details.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -1381,7 +1372,7 @@ CREATE DATABASE foo WITH TEMPLATE template0;
<productname>PostgreSQL</productname> server versions newer than <productname>PostgreSQL</productname> server versions newer than
<application>pg_dump</application>'s version. <application>pg_dump</application> can also <application>pg_dump</application>'s version. <application>pg_dump</application> can also
dump from <productname>PostgreSQL</productname> servers older than its own version. dump from <productname>PostgreSQL</productname> servers older than its own version.
(Currently, servers back to version 8.0 are supported.) (Currently, servers back to version 9.2 are supported.)
However, <application>pg_dump</application> cannot dump from However, <application>pg_dump</application> cannot dump from
<productname>PostgreSQL</productname> servers newer than its own major version; <productname>PostgreSQL</productname> servers newer than its own major version;
it will refuse to even try, rather than risk making an invalid dump. it will refuse to even try, rather than risk making an invalid dump.

View File

@ -227,10 +227,6 @@ buildACLCommands(const char *name, const char *subname, const char *nspname,
appendPQExpBuffer(firstsql, "%s FROM ", name); appendPQExpBuffer(firstsql, "%s FROM ", name);
if (grantee->len == 0) if (grantee->len == 0)
appendPQExpBufferStr(firstsql, "PUBLIC;\n"); appendPQExpBufferStr(firstsql, "PUBLIC;\n");
else if (strncmp(grantee->data, "group ",
strlen("group ")) == 0)
appendPQExpBuffer(firstsql, "GROUP %s;\n",
fmtId(grantee->data + strlen("group ")));
else else
appendPQExpBuffer(firstsql, "%s;\n", appendPQExpBuffer(firstsql, "%s;\n",
fmtId(grantee->data)); fmtId(grantee->data));
@ -247,14 +243,9 @@ buildACLCommands(const char *name, const char *subname, const char *nspname,
* public privileges are added in new versions: the REVOKE ALL will revoke * public privileges are added in new versions: the REVOKE ALL will revoke
* them, leading to behavior different from what the old version had, * them, leading to behavior different from what the old version had,
* which is generally not what's wanted. So add back default privs if the * which is generally not what's wanted. So add back default privs if the
* source database is too old to have had that particular priv. * source database is too old to have had that particular priv. (As of
* right now, no such cases exist in supported versions.)
*/ */
if (remoteVersion < 80200 && strcmp(type, "DATABASE") == 0)
{
/* database CONNECT priv didn't exist before 8.2 */
appendPQExpBuffer(firstsql, "%sGRANT CONNECT ON %s %s TO PUBLIC;\n",
prefix, type, name);
}
/* /*
* Scan individual ACL items to be granted. * Scan individual ACL items to be granted.
@ -306,10 +297,6 @@ buildACLCommands(const char *name, const char *subname, const char *nspname,
appendPQExpBuffer(thissql, "%s TO ", name); appendPQExpBuffer(thissql, "%s TO ", name);
if (grantee->len == 0) if (grantee->len == 0)
appendPQExpBufferStr(thissql, "PUBLIC;\n"); appendPQExpBufferStr(thissql, "PUBLIC;\n");
else if (strncmp(grantee->data, "group ",
strlen("group ")) == 0)
appendPQExpBuffer(thissql, "GROUP %s;\n",
fmtId(grantee->data + strlen("group ")));
else else
appendPQExpBuffer(thissql, "%s;\n", fmtId(grantee->data)); appendPQExpBuffer(thissql, "%s;\n", fmtId(grantee->data));
} }
@ -322,10 +309,6 @@ buildACLCommands(const char *name, const char *subname, const char *nspname,
appendPQExpBuffer(thissql, "%s TO ", name); appendPQExpBuffer(thissql, "%s TO ", name);
if (grantee->len == 0) if (grantee->len == 0)
appendPQExpBufferStr(thissql, "PUBLIC"); appendPQExpBufferStr(thissql, "PUBLIC");
else if (strncmp(grantee->data, "group ",
strlen("group ")) == 0)
appendPQExpBuffer(thissql, "GROUP %s",
fmtId(grantee->data + strlen("group ")));
else else
appendPQExpBufferStr(thissql, fmtId(grantee->data)); appendPQExpBufferStr(thissql, fmtId(grantee->data));
appendPQExpBufferStr(thissql, " WITH GRANT OPTION;\n"); appendPQExpBufferStr(thissql, " WITH GRANT OPTION;\n");
@ -420,16 +403,12 @@ buildDefaultACLCommands(const char *type, const char *nspname,
/* /*
* This will parse an aclitem string, having the general form * This will parse an aclitem string, having the general form
* username=privilegecodes/grantor * username=privilegecodes/grantor
* or
* group groupname=privilegecodes/grantor
* (the "group" case occurs only with servers before 8.1).
* *
* Returns true on success, false on parse error. On success, the components * Returns true on success, false on parse error. On success, the components
* of the string are returned in the PQExpBuffer parameters. * of the string are returned in the PQExpBuffer parameters.
* *
* The returned grantee string will be the dequoted username or groupname * The returned grantee string will be the dequoted username, or an empty
* (preceded with "group " in the latter case). Note that a grant to PUBLIC * string in the case of a grant to PUBLIC. The returned grantor is the
* is represented by an empty grantee string. The returned grantor is the
* dequoted grantor name. Privilege characters are translated to GRANT/REVOKE * dequoted grantor name. Privilege characters are translated to GRANT/REVOKE
* comma-separated privileges lists. If "privswgo" is non-NULL, the result is * comma-separated privileges lists. If "privswgo" is non-NULL, the result is
* separate lists for privileges with grant option ("privswgo") and without * separate lists for privileges with grant option ("privswgo") and without
@ -522,8 +501,7 @@ do { \
{ {
CONVERT_PRIV('d', "DELETE"); CONVERT_PRIV('d', "DELETE");
CONVERT_PRIV('t', "TRIGGER"); CONVERT_PRIV('t', "TRIGGER");
if (remoteVersion >= 80400) CONVERT_PRIV('D', "TRUNCATE");
CONVERT_PRIV('D', "TRUNCATE");
} }
} }

View File

@ -904,13 +904,10 @@ restore_toc_entry(ArchiveHandle *AH, TocEntry *te, bool is_parallel)
StartTransaction(&AH->public); StartTransaction(&AH->public);
/* /*
* If the server version is >= 8.4, make sure we issue * Issue TRUNCATE with ONLY so that child tables are
* TRUNCATE with ONLY so that child tables are not * not wiped.
* wiped.
*/ */
ahprintf(AH, "TRUNCATE TABLE %s%s;\n\n", ahprintf(AH, "TRUNCATE TABLE ONLY %s;\n\n",
(PQserverVersion(AH->connection) >= 80400 ?
"ONLY " : ""),
fmtQualifiedId(te->namespace, te->tag)); fmtQualifiedId(te->namespace, te->tag));
} }

File diff suppressed because it is too large Load Diff

View File

@ -36,7 +36,6 @@ static void help(void);
static void dropRoles(PGconn *conn); static void dropRoles(PGconn *conn);
static void dumpRoles(PGconn *conn); static void dumpRoles(PGconn *conn);
static void dumpRoleMembership(PGconn *conn); static void dumpRoleMembership(PGconn *conn);
static void dumpGroups(PGconn *conn);
static void dropTablespaces(PGconn *conn); static void dropTablespaces(PGconn *conn);
static void dumpTablespaces(PGconn *conn); static void dumpTablespaces(PGconn *conn);
static void dropDBs(PGconn *conn); static void dropDBs(PGconn *conn);
@ -440,8 +439,7 @@ main(int argc, char *argv[])
/* /*
* If there was a database specified on the command line, use that, * If there was a database specified on the command line, use that,
* otherwise try to connect to database "postgres", and failing that * otherwise try to connect to database "postgres", and failing that
* "template1". "postgres" is the preferred choice for 8.1 and later * "template1".
* servers, but it usually will not exist on older ones.
*/ */
if (pgdb) if (pgdb)
{ {
@ -517,7 +515,7 @@ main(int argc, char *argv[])
std_strings = "off"; std_strings = "off";
/* Set the role if requested */ /* Set the role if requested */
if (use_role && server_version >= 80100) if (use_role)
{ {
PQExpBuffer query = createPQExpBuffer(); PQExpBuffer query = createPQExpBuffer();
@ -527,7 +525,7 @@ main(int argc, char *argv[])
} }
/* Force quoting of all identifiers if requested. */ /* Force quoting of all identifiers if requested. */
if (quote_all_identifiers && server_version >= 90100) if (quote_all_identifiers)
executeCommand(conn, "SET quote_all_identifiers = true"); executeCommand(conn, "SET quote_all_identifiers = true");
fprintf(OPF, "--\n-- PostgreSQL database cluster dump\n--\n\n"); fprintf(OPF, "--\n-- PostgreSQL database cluster dump\n--\n\n");
@ -581,11 +579,8 @@ main(int argc, char *argv[])
/* Dump roles (users) */ /* Dump roles (users) */
dumpRoles(conn); dumpRoles(conn);
/* Dump role memberships --- need different method for pre-8.1 */ /* Dump role memberships */
if (server_version >= 80100) dumpRoleMembership(conn);
dumpRoleMembership(conn);
else
dumpGroups(conn);
} }
/* Dump tablespaces */ /* Dump tablespaces */
@ -698,19 +693,11 @@ dropRoles(PGconn *conn)
"FROM %s " "FROM %s "
"WHERE rolname !~ '^pg_' " "WHERE rolname !~ '^pg_' "
"ORDER BY 1", role_catalog); "ORDER BY 1", role_catalog);
else if (server_version >= 80100) else
printfPQExpBuffer(buf, printfPQExpBuffer(buf,
"SELECT rolname " "SELECT rolname "
"FROM %s " "FROM %s "
"ORDER BY 1", role_catalog); "ORDER BY 1", role_catalog);
else
printfPQExpBuffer(buf,
"SELECT usename as rolname "
"FROM pg_shadow "
"UNION "
"SELECT groname as rolname "
"FROM pg_group "
"ORDER BY 1");
res = executeQuery(conn, buf->data); res = executeQuery(conn, buf->data);
@ -782,7 +769,7 @@ dumpRoles(PGconn *conn)
"rolname = current_user AS is_current_user " "rolname = current_user AS is_current_user "
"FROM %s " "FROM %s "
"ORDER BY 2", role_catalog, role_catalog); "ORDER BY 2", role_catalog, role_catalog);
else if (server_version >= 90100) else
printfPQExpBuffer(buf, printfPQExpBuffer(buf,
"SELECT oid, rolname, rolsuper, rolinherit, " "SELECT oid, rolname, rolsuper, rolinherit, "
"rolcreaterole, rolcreatedb, " "rolcreaterole, rolcreatedb, "
@ -793,62 +780,6 @@ dumpRoles(PGconn *conn)
"rolname = current_user AS is_current_user " "rolname = current_user AS is_current_user "
"FROM %s " "FROM %s "
"ORDER BY 2", role_catalog, role_catalog); "ORDER BY 2", role_catalog, role_catalog);
else if (server_version >= 80200)
printfPQExpBuffer(buf,
"SELECT oid, rolname, rolsuper, rolinherit, "
"rolcreaterole, rolcreatedb, "
"rolcanlogin, rolconnlimit, rolpassword, "
"rolvaliduntil, false as rolreplication, "
"false as rolbypassrls, "
"pg_catalog.shobj_description(oid, '%s') as rolcomment, "
"rolname = current_user AS is_current_user "
"FROM %s "
"ORDER BY 2", role_catalog, role_catalog);
else if (server_version >= 80100)
printfPQExpBuffer(buf,
"SELECT oid, rolname, rolsuper, rolinherit, "
"rolcreaterole, rolcreatedb, "
"rolcanlogin, rolconnlimit, rolpassword, "
"rolvaliduntil, false as rolreplication, "
"false as rolbypassrls, "
"null as rolcomment, "
"rolname = current_user AS is_current_user "
"FROM %s "
"ORDER BY 2", role_catalog);
else
printfPQExpBuffer(buf,
"SELECT 0 as oid, usename as rolname, "
"usesuper as rolsuper, "
"true as rolinherit, "
"usesuper as rolcreaterole, "
"usecreatedb as rolcreatedb, "
"true as rolcanlogin, "
"-1 as rolconnlimit, "
"passwd as rolpassword, "
"valuntil as rolvaliduntil, "
"false as rolreplication, "
"false as rolbypassrls, "
"null as rolcomment, "
"usename = current_user AS is_current_user "
"FROM pg_shadow "
"UNION ALL "
"SELECT 0 as oid, groname as rolname, "
"false as rolsuper, "
"true as rolinherit, "
"false as rolcreaterole, "
"false as rolcreatedb, "
"false as rolcanlogin, "
"-1 as rolconnlimit, "
"null::text as rolpassword, "
"null::timestamptz as rolvaliduntil, "
"false as rolreplication, "
"false as rolbypassrls, "
"null as rolcomment, "
"false AS is_current_user "
"FROM pg_group "
"WHERE NOT EXISTS (SELECT 1 FROM pg_shadow "
" WHERE usename = groname) "
"ORDER BY 2");
res = executeQuery(conn, buf->data); res = executeQuery(conn, buf->data);
@ -967,7 +898,7 @@ dumpRoles(PGconn *conn)
appendPQExpBufferStr(buf, ";\n"); appendPQExpBufferStr(buf, ";\n");
} }
if (!no_security_labels && server_version >= 90200) if (!no_security_labels)
buildShSecLabels(conn, "pg_authid", auth_oid, buildShSecLabels(conn, "pg_authid", auth_oid,
"ROLE", rolename, "ROLE", rolename,
buf); buf);
@ -980,6 +911,9 @@ dumpRoles(PGconn *conn)
* We do it this way because config settings for roles could mention the * We do it this way because config settings for roles could mention the
* names of other roles. * names of other roles.
*/ */
if (PQntuples(res) > 0)
fprintf(OPF, "\n--\n-- User Configurations\n--\n");
for (i = 0; i < PQntuples(res); i++) for (i = 0; i < PQntuples(res); i++)
dumpUserConfig(conn, PQgetvalue(res, i, i_rolname)); dumpUserConfig(conn, PQgetvalue(res, i, i_rolname));
@ -992,7 +926,7 @@ dumpRoles(PGconn *conn)
/* /*
* Dump role memberships. This code is used for 8.1 and later servers. * Dump role memberships.
* *
* Note: we expect dumpRoles already created all the roles, but there is * Note: we expect dumpRoles already created all the roles, but there is
* no membership yet. * no membership yet.
@ -1049,75 +983,6 @@ dumpRoleMembership(PGconn *conn)
fprintf(OPF, "\n\n"); fprintf(OPF, "\n\n");
} }
/*
* Dump group memberships from a pre-8.1 server. It's annoying that we
* can't share any useful amount of code with the post-8.1 case, but
* the catalog representations are too different.
*
* Note: we expect dumpRoles already created all the roles, but there is
* no membership yet.
*/
static void
dumpGroups(PGconn *conn)
{
PQExpBuffer buf = createPQExpBuffer();
PGresult *res;
int i;
res = executeQuery(conn,
"SELECT groname, grolist FROM pg_group ORDER BY 1");
if (PQntuples(res) > 0)
fprintf(OPF, "--\n-- Role memberships\n--\n\n");
for (i = 0; i < PQntuples(res); i++)
{
char *groname = PQgetvalue(res, i, 0);
char *grolist = PQgetvalue(res, i, 1);
PGresult *res2;
int j;
/*
* Array representation is {1,2,3} ... convert to (1,2,3)
*/
if (strlen(grolist) < 3)
continue;
grolist = pg_strdup(grolist);
grolist[0] = '(';
grolist[strlen(grolist) - 1] = ')';
printfPQExpBuffer(buf,
"SELECT usename FROM pg_shadow "
"WHERE usesysid IN %s ORDER BY 1",
grolist);
free(grolist);
res2 = executeQuery(conn, buf->data);
for (j = 0; j < PQntuples(res2); j++)
{
char *usename = PQgetvalue(res2, j, 0);
/*
* Don't try to grant a role to itself; can happen if old
* installation has identically named user and group.
*/
if (strcmp(groname, usename) == 0)
continue;
fprintf(OPF, "GRANT %s", fmtId(groname));
fprintf(OPF, " TO %s;\n", fmtId(usename));
}
PQclear(res2);
}
PQclear(res);
destroyPQExpBuffer(buf);
fprintf(OPF, "\n\n");
}
/* /*
* Drop tablespaces. * Drop tablespaces.
@ -1167,41 +1032,15 @@ dumpTablespaces(PGconn *conn)
* Get all tablespaces except built-in ones (which we assume are named * Get all tablespaces except built-in ones (which we assume are named
* pg_xxx) * pg_xxx)
*/ */
if (server_version >= 90200) res = executeQuery(conn, "SELECT oid, spcname, "
res = executeQuery(conn, "SELECT oid, spcname, " "pg_catalog.pg_get_userbyid(spcowner) AS spcowner, "
"pg_catalog.pg_get_userbyid(spcowner) AS spcowner, " "pg_catalog.pg_tablespace_location(oid), "
"pg_catalog.pg_tablespace_location(oid), " "spcacl, acldefault('t', spcowner) AS acldefault, "
"spcacl, acldefault('t', spcowner) AS acldefault, " "array_to_string(spcoptions, ', '),"
"array_to_string(spcoptions, ', ')," "pg_catalog.shobj_description(oid, 'pg_tablespace') "
"pg_catalog.shobj_description(oid, 'pg_tablespace') " "FROM pg_catalog.pg_tablespace "
"FROM pg_catalog.pg_tablespace " "WHERE spcname !~ '^pg_' "
"WHERE spcname !~ '^pg_' " "ORDER BY 1");
"ORDER BY 1");
else if (server_version >= 90000)
res = executeQuery(conn, "SELECT oid, spcname, "
"pg_catalog.pg_get_userbyid(spcowner) AS spcowner, "
"spclocation, spcacl, NULL AS acldefault, "
"array_to_string(spcoptions, ', '),"
"pg_catalog.shobj_description(oid, 'pg_tablespace') "
"FROM pg_catalog.pg_tablespace "
"WHERE spcname !~ '^pg_' "
"ORDER BY 1");
else if (server_version >= 80200)
res = executeQuery(conn, "SELECT oid, spcname, "
"pg_catalog.pg_get_userbyid(spcowner) AS spcowner, "
"spclocation, spcacl, NULL AS acldefault, null, "
"pg_catalog.shobj_description(oid, 'pg_tablespace') "
"FROM pg_catalog.pg_tablespace "
"WHERE spcname !~ '^pg_' "
"ORDER BY 1");
else
res = executeQuery(conn, "SELECT oid, spcname, "
"pg_catalog.pg_get_userbyid(spcowner) AS spcowner, "
"spclocation, spcacl, NULL AS acldefault, "
"null, null "
"FROM pg_catalog.pg_tablespace "
"WHERE spcname !~ '^pg_' "
"ORDER BY 1");
if (PQntuples(res) > 0) if (PQntuples(res) > 0)
fprintf(OPF, "--\n-- Tablespaces\n--\n\n"); fprintf(OPF, "--\n-- Tablespaces\n--\n\n");
@ -1253,7 +1092,7 @@ dumpTablespaces(PGconn *conn)
appendPQExpBufferStr(buf, ";\n"); appendPQExpBufferStr(buf, ";\n");
} }
if (!no_security_labels && server_version >= 90200) if (!no_security_labels)
buildShSecLabels(conn, "pg_tablespace", spcoid, buildShSecLabels(conn, "pg_tablespace", spcoid,
"TABLESPACE", spcname, "TABLESPACE", spcname,
buf); buf);
@ -1323,52 +1162,31 @@ static void
dumpUserConfig(PGconn *conn, const char *username) dumpUserConfig(PGconn *conn, const char *username)
{ {
PQExpBuffer buf = createPQExpBuffer(); PQExpBuffer buf = createPQExpBuffer();
int count = 1; PGresult *res;
bool first = true;
for (;;) printfPQExpBuffer(buf, "SELECT unnest(setconfig) FROM pg_db_role_setting "
"WHERE setdatabase = 0 AND setrole = "
"(SELECT oid FROM %s WHERE rolname = ",
role_catalog);
appendStringLiteralConn(buf, username, conn);
appendPQExpBufferChar(buf, ')');
res = executeQuery(conn, buf->data);
if (PQntuples(res) > 0)
fprintf(OPF, "\n--\n-- User Config \"%s\"\n--\n\n", username);
for (int i = 0; i < PQntuples(res); i++)
{ {
PGresult *res; resetPQExpBuffer(buf);
makeAlterConfigCommand(conn, PQgetvalue(res, i, 0),
if (server_version >= 90000) "ROLE", username, NULL, NULL,
printfPQExpBuffer(buf, "SELECT setconfig[%d] FROM pg_db_role_setting WHERE " buf);
"setdatabase = 0 AND setrole = " fprintf(OPF, "%s", buf->data);
"(SELECT oid FROM %s WHERE rolname = ", count, role_catalog);
else if (server_version >= 80100)
printfPQExpBuffer(buf, "SELECT rolconfig[%d] FROM %s WHERE rolname = ", count, role_catalog);
else
printfPQExpBuffer(buf, "SELECT useconfig[%d] FROM pg_shadow WHERE usename = ", count);
appendStringLiteralConn(buf, username, conn);
if (server_version >= 90000)
appendPQExpBufferChar(buf, ')');
res = executeQuery(conn, buf->data);
if (PQntuples(res) == 1 &&
!PQgetisnull(res, 0, 0))
{
/* comment at section start, only if needed */
if (first)
{
fprintf(OPF, "--\n-- User Configurations\n--\n\n");
first = false;
}
fprintf(OPF, "--\n-- User Config \"%s\"\n--\n\n", username);
resetPQExpBuffer(buf);
makeAlterConfigCommand(conn, PQgetvalue(res, 0, 0),
"ROLE", username, NULL, NULL,
buf);
fprintf(OPF, "%s", buf->data);
PQclear(res);
count++;
}
else
{
PQclear(res);
break;
}
} }
PQclear(res);
destroyPQExpBuffer(buf); destroyPQExpBuffer(buf);
} }
@ -1775,11 +1593,11 @@ connectDatabase(const char *dbname, const char *connection_string,
my_version = PG_VERSION_NUM; my_version = PG_VERSION_NUM;
/* /*
* We allow the server to be back to 8.4, and up to any minor release of * We allow the server to be back to 9.2, and up to any minor release of
* our own major version. (See also version check in pg_dump.c.) * our own major version. (See also version check in pg_dump.c.)
*/ */
if (my_version != server_version if (my_version != server_version
&& (server_version < 80400 || && (server_version < 90200 ||
(server_version / 100) > (my_version / 100))) (server_version / 100) > (my_version / 100)))
{ {
pg_log_error("server version: %s; %s version: %s", pg_log_error("server version: %s; %s version: %s",