Skip to content

Commit 1aafe7a

Browse files
leborchukusernamedtreshke
committed
Movable DataBase Locales for Cloudberry (#1363)
* Movable DataBase Locales for Cloudberry We inherited this issue from PostgreSQL. PostgreSQL uses glibc to sort strings. In version glibc=2.28, collations broke down badly (in general, there are no guarantees when updating glibc). Changing collations breaks indexes. Similarly, a cluster with different collations also behaves unpredictably. What and when something has changed in glibc can be found on https://github.com/ardentperf/glibc-unicode-sorting Also there is special postgresql-wiki https://wiki.postgresql.org/wiki/Locale_data_changes And you tube video https://www.youtube.com/watch?v=0E6O-V8Jato In short, the issue can be seen through the use of bash: ( echo "1-1"; echo "11" ) | LC_COLLATE=en_US.UTF-8 sort gives the different results in ubunru 18.04 and 22.04. There is no way to solve the problem other than by not changing the symbol order. We freeze symbol order and use it instead of glibc. Here the solution https://github.com/postgredients/mdb-locales. In this PR I have added PostgreSQL patch that replaces all glibc locale-related calls with a calls to an external libary. It activates using new configure parameter --with-mdblocales, which is off by default. Using custom locales needs libmdblocales1 package and mdb-locales package with symbol table. Build needs libmdblocales-dev package with headers. Fixing the symbol order is necessary for OS upgrade. For example Ubuntu 22.04 EOL is April 2027, Rocky 8 Active Support ended May 2024, and Security support ends in 2029. We use Movable DataBase Locales in Greenplum 6 and all our PostgreSQL installations (starting with PostgreSQL 12). This patch is adopted patch version from our internal PostgreSQL 14 fork. * mdb_admin role This patch introcudes new pseudo-pre-defined role "mdb_admin". Introduces 2 new function: extern bool mdb_admin_allow_bypass_owner_checks(Oid userId, Oid ownerId); extern void check_mdb_admin_is_member_of_role(Oid member, Oid role); To check mdb admin belongship and role-to-role ownership transfer correctness. Our mdb_admin ACL model is the following: * Any roles user or/and roles can be granted with mdb_admin * mdb_admin memeber can tranfser ownershup of relations, namespaces and functions to other roles, if target role in neither: superuser, pg_read_server_files, pg_write_server_files nor pg_execute_server_program. * mdb_superuser role This patch introcudes new pseudo-pre-defined role "mdb_superuser". Role is capable of: GRANT/REVOKE any set of priviledges to/from any object in database. Has power of pg_database_owner in any database, including: DROP any object in database (except system catalog and stuff) Role is NOT capable of: Create database, role, extension or alter other roles with such priviledges. Transfer ownership to /pass has_priv of roles: PG_READ_ALL_DATA PG_WRITE_ALL_DATA PG_EXECUTE_SERVER_PROGRAM PG_READ_SERVER_FILES PG_WRITE_SERVER_FILES PG_DATABASE_OWNER Allow mdb_superuser to alter objects and grant ACl to objects, owner by pg_database_owner. Also, when acl check, allow mdb_supersuer use pg_database_owner role power to pass check * Extend multixact SLRU The issue here is the same as for the PG, good detail description I found in Nikolay blog post https://v2.postgres.ai/blog/20210831-postgresql-subtransactions-considered-harmful See also the history of original PG patches in https://commitfest.postgresql.org/patch/2627/ We could get all those fixes after rebasing to PG18, but for now, we need to adjust SLRU structure sizes. --------- Co-authored-by: usernamedt <usernamedt@yandex-team.com> Co-authored-by: reshke <reshkekirill@gmail.com>
1 parent a558ff1 commit 1aafe7a

56 files changed

Lines changed: 1466 additions & 114 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

configure

Lines changed: 96 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -698,6 +698,7 @@ BISON
698698
MKDIR_P
699699
LN_S
700700
TAR
701+
USE_MDBLOCALES
701702
install_bin
702703
INSTALL_DATA
703704
INSTALL_SCRIPT
@@ -946,6 +947,7 @@ with_rt
946947
with_libcurl
947948
with_apr_config
948949
with_gnu_ld
950+
with_mdblocales
949951
with_ssl
950952
with_openssl
951953
enable_openssl_redirect
@@ -1705,6 +1707,7 @@ Optional Packages:
17051707
--without-libcurl do not use libcurl
17061708
--with-apr-config=PATH path to apr-1-config utility
17071709
--with-gnu-ld assume the C compiler uses GNU ld [default=no]
1710+
--without-mdblocales build without MDB locales
17081711
--with-ssl=LIB use LIB for SSL/TLS support (openssl)
17091712
--with-openssl obsolete spelling of --with-ssl=openssl
17101713

@@ -2921,7 +2924,6 @@ PG_PACKAGE_VERSION=14.4
29212924

29222925

29232926

2924-
29252927
ac_aux_dir=
29262928
for ac_dir in config "$srcdir"/config; do
29272929
if test -f "$ac_dir/install-sh"; then
@@ -12220,6 +12222,38 @@ case $INSTALL in
1222012222
esac
1222112223

1222212224

12225+
#
12226+
# MDB locales
12227+
#
12228+
12229+
12230+
12231+
12232+
# Check whether --with-mdblocales was given.
12233+
if test "${with_mdblocales+set}" = set; then :
12234+
withval=$with_mdblocales;
12235+
case $withval in
12236+
yes)
12237+
12238+
$as_echo "#define USE_MDBLOCALES 1" >>confdefs.h
12239+
12240+
;;
12241+
no)
12242+
:
12243+
;;
12244+
*)
12245+
as_fn_error $? "no argument expected for --with-mdblocales option" "$LINENO" 5
12246+
;;
12247+
esac
12248+
12249+
else
12250+
with_mdblocales=no
12251+
12252+
fi
12253+
12254+
12255+
12256+
1222312257
if test -z "$TAR"; then
1222412258
for ac_prog in tar
1222512259
do
@@ -12856,6 +12890,56 @@ $as_echo "${python_libspec} ${python_additional_libs}" >&6; }
1285612890

1285712891

1285812892

12893+
fi
12894+
12895+
if test "$with_mdblocales" = yes; then
12896+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for mdb_setlocale in -lmdblocales" >&5
12897+
$as_echo_n "checking for mdb_setlocale in -lmdblocales... " >&6; }
12898+
if ${ac_cv_lib_mdblocales_mdb_setlocale+:} false; then :
12899+
$as_echo_n "(cached) " >&6
12900+
else
12901+
ac_check_lib_save_LIBS=$LIBS
12902+
LIBS="-lmdblocales $LIBS"
12903+
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
12904+
/* end confdefs.h. */
12905+
12906+
/* Override any GCC internal prototype to avoid an error.
12907+
Use char because int might match the return type of a GCC
12908+
builtin and then its argument prototype would still apply. */
12909+
#ifdef __cplusplus
12910+
extern "C"
12911+
#endif
12912+
char mdb_setlocale ();
12913+
int
12914+
main ()
12915+
{
12916+
return mdb_setlocale ();
12917+
;
12918+
return 0;
12919+
}
12920+
_ACEOF
12921+
if ac_fn_c_try_link "$LINENO"; then :
12922+
ac_cv_lib_mdblocales_mdb_setlocale=yes
12923+
else
12924+
ac_cv_lib_mdblocales_mdb_setlocale=no
12925+
fi
12926+
rm -f core conftest.err conftest.$ac_objext \
12927+
conftest$ac_exeext conftest.$ac_ext
12928+
LIBS=$ac_check_lib_save_LIBS
12929+
fi
12930+
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_mdblocales_mdb_setlocale" >&5
12931+
$as_echo "$ac_cv_lib_mdblocales_mdb_setlocale" >&6; }
12932+
if test "x$ac_cv_lib_mdblocales_mdb_setlocale" = xyes; then :
12933+
cat >>confdefs.h <<_ACEOF
12934+
#define HAVE_LIBMDBLOCALES 1
12935+
_ACEOF
12936+
12937+
LIBS="-lmdblocales $LIBS"
12938+
12939+
else
12940+
as_fn_error $? "mdblocales library not found" "$LINENO" 5
12941+
fi
12942+
1285912943
fi
1286012944

1286112945
if test x"$cross_compiling" = x"yes" && test -z "$with_system_tzdata"; then
@@ -17077,6 +17161,17 @@ fi
1707717161

1707817162
done
1707917163

17164+
fi
17165+
17166+
if test "$with_mdblocales" = yes; then
17167+
ac_fn_c_check_header_mongrel "$LINENO" "mdblocales.h" "ac_cv_header_mdblocales_h" "$ac_includes_default"
17168+
if test "x$ac_cv_header_mdblocales_h" = xyes; then :
17169+
17170+
else
17171+
as_fn_error $? "mdblocales header not found." "$LINENO" 5
17172+
fi
17173+
17174+
1708017175
fi
1708117176

1708217177
if test "$with_gssapi" = yes ; then

configure.ac

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1462,6 +1462,14 @@ case $INSTALL in
14621462
esac
14631463
AC_SUBST(install_bin)
14641464

1465+
#
1466+
# MDB locales
1467+
#
1468+
1469+
PGAC_ARG_BOOL(with, mdblocales, yes, [build without MDB locales],
1470+
[AC_DEFINE([USE_MDBLOCALES], 1, [Define to 1 to build with MDB locales. (--with-mdblocales)])])
1471+
AC_SUBST(USE_MDBLOCALES)
1472+
14651473
PGAC_PATH_PROGS(TAR, tar)
14661474
AC_PROG_LN_S
14671475
AC_PROG_MKDIR_P
@@ -1620,6 +1628,11 @@ failure. It is possible the compiler isn't looking in the proper directory.
16201628
Use --without-zlib to disable zlib support.])])
16211629
fi
16221630

1631+
if test "$with_mdblocales" = yes; then
1632+
AC_CHECK_LIB(mdblocales, mdb_setlocale, [],
1633+
[AC_MSG_ERROR([mdblocales library not found])])
1634+
fi
1635+
16231636
if test "$enable_external_fts" = yes; then
16241637
AC_CHECK_LIB(jansson, jansson_version_str, [],
16251638
[AC_MSG_ERROR([jansson library not found or version is too old, version must >= 2.13])])
@@ -1999,6 +2012,10 @@ if test "$with_lz4" = yes; then
19992012
AC_CHECK_HEADERS(lz4.h, [], [AC_MSG_ERROR([lz4.h header file is required for LZ4])])
20002013
fi
20012014

2015+
if test "$with_mdblocales" = yes; then
2016+
AC_CHECK_HEADER(mdblocales.h, [], [AC_MSG_ERROR([mdblocales header not found.])])
2017+
fi
2018+
20022019
if test "$with_gssapi" = yes ; then
20032020
AC_CHECK_HEADERS(gssapi/gssapi.h, [],
20042021
[AC_CHECK_HEADERS(gssapi.h, [], [AC_MSG_ERROR([gssapi.h header file is required for GSSAPI])])])

contrib/pax_storage/src/cpp/storage/oper/pax_oper.cc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
*-------------------------------------------------------------------------
2626
*/
2727

28+
#include "common/mdb_locale.h"
2829
#include "storage/oper/pax_oper.h"
2930

3031
#include "comm/cbdb_wrappers.h"
@@ -588,9 +589,9 @@ static inline bool LocaleIsC(Oid collation) {
588589
return (bool)result;
589590
}
590591

591-
localeptr = setlocale(LC_COLLATE, NULL);
592+
localeptr = SETLOCALE(LC_COLLATE, NULL);
592593
CBDB_CHECK(localeptr, cbdb::CException::ExType::kExTypeCError,
593-
fmt("Invalid locale, fail to `setlocale`, errno: %d", errno));
594+
fmt("Invalid locale, fail to `SETLOCALE`, errno: %d", errno));
594595

595596
if (strcmp(localeptr, "C") == 0 || // cut line
596597
strcmp(localeptr, "POSIX") == 0) {

contrib/pax_storage/src/test/regress/expected/create_function_3.out

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,10 +166,10 @@ SET SESSION AUTHORIZATION regress_unpriv_user;
166166
SET search_path TO temp_func_test, public;
167167
ALTER FUNCTION functest_E_1(int) NOT LEAKPROOF;
168168
ALTER FUNCTION functest_E_2(int) LEAKPROOF;
169-
ERROR: only superuser can define a leakproof function
169+
ERROR: only superuser or mdb_admin can define a leakproof function
170170
CREATE FUNCTION functest_E_3(int) RETURNS bool LANGUAGE 'sql'
171171
LEAKPROOF AS 'SELECT $1 < 200'; -- fail
172-
ERROR: only superuser can define a leakproof function
172+
ERROR: only superuser or mdb_admin can define a leakproof function
173173
RESET SESSION AUTHORIZATION;
174174
--
175175
-- CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT

contrib/pax_storage/src/test/regress/expected/create_function_3_optimizer.out

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,10 +166,10 @@ SET SESSION AUTHORIZATION regress_unpriv_user;
166166
SET search_path TO temp_func_test, public;
167167
ALTER FUNCTION functest_E_1(int) NOT LEAKPROOF;
168168
ALTER FUNCTION functest_E_2(int) LEAKPROOF;
169-
ERROR: only superuser can define a leakproof function
169+
ERROR: only superuser or mdb_admin can define a leakproof function
170170
CREATE FUNCTION functest_E_3(int) RETURNS bool LANGUAGE 'sql'
171171
LEAKPROOF AS 'SELECT $1 < 200'; -- fail
172-
ERROR: only superuser can define a leakproof function
172+
ERROR: only superuser or mdb_admin can define a leakproof function
173173
RESET SESSION AUTHORIZATION;
174174
--
175175
-- CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT

devops/build/automation/cloudberry/scripts/configure-cloudberry.sh

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,12 @@
6262
# --enable-cassert
6363
# --enable-debug-extensions
6464
#
65+
# ENABLE_MDBLOCALES - Enable custom locales (true/false, defaults to
66+
# false)
67+
#
68+
# When true, add option:
69+
# --with-mdblocales
70+
#
6571
# Prerequisites:
6672
# - System dependencies must be installed:
6773
# * xerces-c development files
@@ -138,6 +144,11 @@ if [ "${ENABLE_DEBUG:-false}" = "true" ]; then
138144
--enable-debug-extensions"
139145
fi
140146

147+
CONFIGURE_MDBLOCALES_OPTS="--without-mdblocales"
148+
if [ "${ENABLE_MDBLOCALES:-false}" = "true" ]; then
149+
CONFIGURE_MDBLOCALES_OPTS="--with-mdblocales"
150+
fi
151+
141152
# Configure build
142153
log_section "Configure"
143154
execute_cmd ./configure --prefix=${BUILD_DESTINATION} \
@@ -164,6 +175,7 @@ execute_cmd ./configure --prefix=${BUILD_DESTINATION} \
164175
--with-ssl=openssl \
165176
--with-openssl \
166177
--with-uuid=e2fs \
178+
${CONFIGURE_MDBLOCALES_OPTS} \
167179
--with-includes=/usr/local/xerces-c/include \
168180
--with-libraries=${BUILD_DESTINATION}/lib || exit 4
169181
log_section_end "Configure"

gpcontrib/orafce/others.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
#include "utils/uuid.h"
4646
#include "orafce.h"
4747
#include "builtins.h"
48+
#include "common/mdb_locale.h"
4849

4950
/*
5051
* Source code for nlssort is taken from postgresql-nls-string
@@ -322,7 +323,7 @@ _nls_run_strxfrm(text *string, text *locale)
322323
*/
323324
if (!lc_collate_cache)
324325
{
325-
if ((lc_collate_cache = setlocale(LC_COLLATE, NULL)))
326+
if ((lc_collate_cache = SETLOCALE(LC_COLLATE, NULL)))
326327
/* Make a copy of the locale name string. */
327328
#ifdef _MSC_VER
328329
lc_collate_cache = _strdup(lc_collate_cache);
@@ -364,7 +365,7 @@ _nls_run_strxfrm(text *string, text *locale)
364365
* If setlocale failed, we know the default stayed the same,
365366
* co we can safely elog.
366367
*/
367-
if (!setlocale(LC_COLLATE, locale_str))
368+
if (!SETLOCALE(LC_COLLATE, locale_str))
368369
elog(ERROR, "failed to set the requested LC_COLLATE value [%s]", locale_str);
369370

370371
changed_locale = true;
@@ -409,7 +410,7 @@ _nls_run_strxfrm(text *string, text *locale)
409410
/*
410411
* Set original locale
411412
*/
412-
if (!setlocale(LC_COLLATE, lc_collate_cache))
413+
if (!SETLOCALE(LC_COLLATE, lc_collate_cache))
413414
elog(FATAL, "failed to set back the default LC_COLLATE value [%s]", lc_collate_cache);
414415
}
415416

@@ -422,7 +423,7 @@ _nls_run_strxfrm(text *string, text *locale)
422423
/*
423424
* Set original locale
424425
*/
425-
if (!setlocale(LC_COLLATE, lc_collate_cache))
426+
if (!SETLOCALE(LC_COLLATE, lc_collate_cache))
426427
elog(FATAL, "failed to set back the default LC_COLLATE value [%s]", lc_collate_cache);
427428
pfree(locale_str);
428429
}

src/backend/catalog/namespace.c

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2971,7 +2971,6 @@ LookupExplicitNamespace(const char *nspname, bool missing_ok)
29712971
{
29722972
Oid namespaceId;
29732973
AclResult aclresult;
2974-
29752974
/* check for pg_temp alias */
29762975
if (strcmp(nspname, "pg_temp") == 0)
29772976
{
@@ -2989,7 +2988,24 @@ LookupExplicitNamespace(const char *nspname, bool missing_ok)
29892988
if (missing_ok && !OidIsValid(namespaceId))
29902989
return InvalidOid;
29912990

2992-
aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_USAGE);
2991+
HeapTuple tuple;
2992+
Oid ownerId;
2993+
2994+
tuple = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(namespaceId));
2995+
if (!HeapTupleIsValid(tuple))
2996+
ereport(ERROR,
2997+
(errcode(ERRCODE_UNDEFINED_SCHEMA),
2998+
errmsg("schema with OID %u does not exist", namespaceId)));
2999+
3000+
ownerId = ((Form_pg_namespace) GETSTRUCT(tuple))->nspowner;
3001+
3002+
ReleaseSysCache(tuple);
3003+
3004+
if (!mdb_admin_allow_bypass_owner_checks(GetUserId(), ownerId)) {
3005+
aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_USAGE);
3006+
} else {
3007+
aclresult = ACLCHECK_OK;
3008+
}
29933009
if (aclresult != ACLCHECK_OK)
29943010
aclcheck_error(aclresult, OBJECT_SCHEMA,
29953011
nspname);

src/backend/commands/alter.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1085,7 +1085,8 @@ AlterObjectOwner_internal(Relation rel, Oid objectId, Oid new_ownerId)
10851085
if (!superuser())
10861086
{
10871087
/* must be owner */
1088-
if (!has_privs_of_role(GetUserId(), old_ownerId))
1088+
if (!has_privs_of_role(GetUserId(), old_ownerId)
1089+
&& !mdb_admin_allow_bypass_owner_checks(GetUserId(), old_ownerId))
10891090
{
10901091
char *objname;
10911092
char namebuf[NAMEDATALEN];
@@ -1105,14 +1106,13 @@ AlterObjectOwner_internal(Relation rel, Oid objectId, Oid new_ownerId)
11051106
aclcheck_error(ACLCHECK_NOT_OWNER, get_object_type(classId, objectId),
11061107
objname);
11071108
}
1108-
/* Must be able to become new owner */
1109-
check_is_member_of_role(GetUserId(), new_ownerId);
1109+
1110+
check_mdb_admin_is_member_of_role(GetUserId(), new_ownerId);
11101111

11111112
/* New owner must have CREATE privilege on namespace */
11121113
if (OidIsValid(namespaceId))
11131114
{
11141115
AclResult aclresult;
1115-
11161116
aclresult = pg_namespace_aclcheck(namespaceId, new_ownerId,
11171117
ACL_CREATE);
11181118
if (aclresult != ACLCHECK_OK)

0 commit comments

Comments
 (0)