Skip to content

Commit 4af1cf5

Browse files
leborchukusernamedtreshke
authored
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 2cc5674 commit 4af1cf5

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
@@ -945,6 +946,7 @@ with_rt
945946
with_libcurl
946947
with_apr_config
947948
with_gnu_ld
949+
with_mdblocales
948950
with_ssl
949951
with_openssl
950952
enable_openssl_redirect
@@ -1693,6 +1695,7 @@ Optional Packages:
16931695
--without-libcurl do not use libcurl
16941696
--with-apr-config=PATH path to apr-1-config utility
16951697
--with-gnu-ld assume the C compiler uses GNU ld [default=no]
1698+
--without-mdblocales build without MDB locales
16961699
--with-ssl=LIB use LIB for SSL/TLS support (openssl)
16971700
--with-openssl obsolete spelling of --with-ssl=openssl
16981701

@@ -2909,7 +2912,6 @@ PG_PACKAGE_VERSION=14.4
29092912

29102913

29112914

2912-
29132915
ac_aux_dir=
29142916
for ac_dir in config "$srcdir"/config; do
29152917
if test -f "$ac_dir/install-sh"; then
@@ -12208,6 +12210,38 @@ case $INSTALL in
1220812210
esac
1220912211

1221012212

12213+
#
12214+
# MDB locales
12215+
#
12216+
12217+
12218+
12219+
12220+
# Check whether --with-mdblocales was given.
12221+
if test "${with_mdblocales+set}" = set; then :
12222+
withval=$with_mdblocales;
12223+
case $withval in
12224+
yes)
12225+
12226+
$as_echo "#define USE_MDBLOCALES 1" >>confdefs.h
12227+
12228+
;;
12229+
no)
12230+
:
12231+
;;
12232+
*)
12233+
as_fn_error $? "no argument expected for --with-mdblocales option" "$LINENO" 5
12234+
;;
12235+
esac
12236+
12237+
else
12238+
with_mdblocales=no
12239+
12240+
fi
12241+
12242+
12243+
12244+
1221112245
if test -z "$TAR"; then
1221212246
for ac_prog in tar
1221312247
do
@@ -12844,6 +12878,56 @@ $as_echo "${python_libspec} ${python_additional_libs}" >&6; }
1284412878

1284512879

1284612880

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

1284912933
if test x"$cross_compiling" = x"yes" && test -z "$with_system_tzdata"; then
@@ -17065,6 +17149,17 @@ fi
1706517149

1706617150
done
1706717151

17152+
fi
17153+
17154+
if test "$with_mdblocales" = yes; then
17155+
ac_fn_c_check_header_mongrel "$LINENO" "mdblocales.h" "ac_cv_header_mdblocales_h" "$ac_includes_default"
17156+
if test "x$ac_cv_header_mdblocales_h" = xyes; then :
17157+
17158+
else
17159+
as_fn_error $? "mdblocales header not found." "$LINENO" 5
17160+
fi
17161+
17162+
1706817163
fi
1706917164

1707017165
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)