I wrote: > Assuming that this problem is restricted to initdb, which I think > is true, probably the best fix is to cause the initdb link *only* > to link libpgcommon before libpq. Every other non-backend program > is interested in libpq's encoding IDs if it cares at all.
The more I thought about that the less I liked it. We're trying to get away from link order dependencies, not add more. And the fact that we've had a latent bug for awhile from random-ish changes in link order should reinforce our desire to get out of that business. So I experimented with fixing things so that the versions of these functions exported by libpq have physically different names from those that you'd get from linking to libpgcommon.a or libpgcommon_srv.a. Then, there's certainty about which one a given usage will link to, based on what the #define environment is when the call is compiled. This leads to a pleasingly small patch, at least in the Makefile universe (I've not attempted to sync the meson or MSVC infrastructure with this yet). As a bonus, it should silence those new warnings on AIX. A disadvantage is that this causes an ABI break for backend extensions, so we couldn't consider back-patching it. But I think that's fine given that the problem is only latent in released branches. Thoughts? regards, tom lane
diff --git a/src/bin/initdb/Makefile b/src/bin/initdb/Makefile index d69bd89572..e80e57e457 100644 --- a/src/bin/initdb/Makefile +++ b/src/bin/initdb/Makefile @@ -16,13 +16,12 @@ subdir = src/bin/initdb top_builddir = ../../.. include $(top_builddir)/src/Makefile.global -override CPPFLAGS := -I$(libpq_srcdir) -I$(top_srcdir)/src/timezone $(ICU_CFLAGS) $(CPPFLAGS) - # Note: it's important that we link to encnames.o from libpgcommon, not # from libpq, else we have risks of version skew if we run with a libpq -# shared library from a different PG version. The libpq_pgport macro -# should ensure that that happens. -# +# shared library from a different PG version. Define +# USE_PRIVATE_ENCODING_FUNCS to ensure that that happens. +override CPPFLAGS := -DUSE_PRIVATE_ENCODING_FUNCS -I$(libpq_srcdir) -I$(top_srcdir)/src/timezone $(ICU_CFLAGS) $(CPPFLAGS) + # We need libpq only because fe_utils does. LDFLAGS_INTERNAL += -L$(top_builddir)/src/fe_utils -lpgfeutils $(libpq_pgport) $(ICU_LIBS) diff --git a/src/common/Makefile b/src/common/Makefile index cc5c54dcee..70884be00c 100644 --- a/src/common/Makefile +++ b/src/common/Makefile @@ -140,6 +140,13 @@ libpgcommon.a: $(OBJS_FRONTEND) rm -f $@ $(AR) $(AROPT) $@ $^ +# +# Files in libpgcommon.a should use/export the "xxx_private" versions +# of pg_char_to_encoding() and friends. +# +$(OBJS_FRONTEND): CPPFLAGS += -DUSE_PRIVATE_ENCODING_FUNCS + + # # Shared library versions of object files # diff --git a/src/include/mb/pg_wchar.h b/src/include/mb/pg_wchar.h index 25276b199f..7d2fad91e6 100644 --- a/src/include/mb/pg_wchar.h +++ b/src/include/mb/pg_wchar.h @@ -13,6 +13,8 @@ * included by libpq client programs. In particular, a libpq client * should not assume that the encoding IDs used by the version of libpq * it's linked to match up with the IDs declared here. + * To help prevent mistakes, relevant functions that are exported by + * libpq have a physically different name when being referenced directly. * *------------------------------------------------------------------------- */ @@ -562,6 +564,23 @@ surrogate_pair_to_codepoint(pg_wchar first, pg_wchar second) } +/* + * The functions in this list are exported by libpq, and we need to be sure + * that we know which calls are satisfied by libpq and which are satisfied + * by static linkage to libpgcommon. (This is because we might be using a + * libpq.so that's of a different major version and has different encoding + * IDs from what libpgcommon knows.) The official function names are what + * is actually used in and exported by libpq, while the names exported by + * libpgcommon.a and libpgcommon_srv.a end in "_private". + */ +#if defined(USE_PRIVATE_ENCODING_FUNCS) || !defined(FRONTEND) +#define pg_char_to_encoding pg_char_to_encoding_private +#define pg_encoding_to_char pg_encoding_to_char_private +#define pg_valid_server_encoding pg_valid_server_encoding_private +#define pg_valid_server_encoding_id pg_valid_server_encoding_id_private +#define pg_utf_mblen pg_utf_mblen_private +#endif + /* * These functions are considered part of libpq's exported API and * are also declared in libpq-fe.h.