* guc_memory.cpp
*
* Support for grand unified configuration schema, including SET
* command, configuration file, and command line options.
* See src/backend/utils/misc/README for more information.
*
*
* Copyright (c) 2000-2012, PostgreSQL Global Development Group
* Portions Copyright (c) 2010-2012 Postgres-XC Development Group
* Written by Peter Eisentraut <peter_e@gmx.net>.
*
* IDENTIFICATION
* src/backend/utils/misc/guc/guc_memory.cpp
*
* --------------------------------------------------------------------
*/
#include "postgres.h"
#include "knl/knl_variable.h"
#include <float.h>
#include <math.h>
#include <limits.h>
#include "utils/elog.h"
#ifdef HAVE_SYSLOG
#include <syslog.h>
#endif
#include "access/cbmparsexlog.h"
#include "access/gin.h"
#include "access/gtm.h"
#include "pgxc/pgxc.h"
#include "access/transam.h"
#include "access/twophase.h"
#include "access/xact.h"
#include "access/xlog.h"
#ifdef ENABLE_BBOX
#include "gs_bbox.h"
#endif
#include "catalog/namespace.h"
#include "catalog/pgxc_group.h"
#include "catalog/storage_gtt.h"
#include "commands/async.h"
#include "commands/prepare.h"
#include "commands/vacuum.h"
#include "commands/variable.h"
#include "commands/tablespace.h"
#include "commands/trigger.h"
#include "funcapi.h"
#include "instruments/instr_statement.h"
#include "job/job_scheduler.h"
#include "libpq/auth.h"
#include "libpq/be-fsstubs.h"
#include "libpq/libpq.h"
#include "libpq/pqformat.h"
#include "miscadmin.h"
#include "opfusion/opfusion.h"
#include "optimizer/cost.h"
#include "optimizer/geqo.h"
#include "optimizer/nodegroups.h"
#include "optimizer/paths.h"
#include "optimizer/planmain.h"
#include "optimizer/prep.h"
#include "optimizer/gtmfree.h"
#include "parser/parse_expr.h"
#include "parser/parse_oper.h"
#include "parser/parse_type.h"
#include "parser/parser.h"
#include "parser/scansup.h"
#include "pgstat.h"
#include "pgxc/route.h"
#include "workload/workload.h"
#include "pgaudit.h"
#include "instruments/instr_unique_sql.h"
#include "commands/tablecmds.h"
#include "nodes/nodes.h"
#include "optimizer/pgxcship.h"
#include "pgxc/execRemote.h"
#include "pgxc/locator.h"
#include "optimizer/pgxcplan.h"
#include "pgxc/poolmgr.h"
#include "pgxc/nodemgr.h"
#include "utils/lsyscache.h"
#include "access/multi_redo_settings.h"
#include "catalog/pg_authid.h"
#include "commands/user.h"
#include "commands/user.h"
#include "flock.h"
#include "gaussdb_version.h"
#include "libcomm/libcomm.h"
#include "libpq/libpq-be.h"
#include "libpq/md5.h"
#include "libpq/sha2.h"
#include "optimizer/planner.h"
#include "optimizer/streamplan.h"
#include "postmaster/alarmchecker.h"
#include "postmaster/autovacuum.h"
#include "postmaster/bgwriter.h"
#include "postmaster/pagewriter.h"
#include "postmaster/postmaster.h"
#include "postmaster/syslogger.h"
#include "postmaster/twophasecleaner.h"
#include "postmaster/walwriter.h"
#include "replication/dataqueue.h"
#include "replication/datareceiver.h"
#include "replication/reorderbuffer.h"
#include "replication/replicainternal.h"
#include "replication/slot.h"
#include "replication/syncrep.h"
#include "replication/walreceiver.h"
#include "replication/walsender.h"
#include "storage/buf/bufmgr.h"
#include "storage/cucache_mgr.h"
#include "storage/smgr/fd.h"
#include "storage/predicate.h"
#include "storage/procarray.h"
#include "storage/standby.h"
#include "storage/remote_adapter.h"
#include "tcop/tcopprot.h"
#include "threadpool/threadpool.h"
#include "tsearch/ts_cache.h"
#include "utils/acl.h"
#include "utils/anls_opt.h"
#include "utils/atomic.h"
#include "utils/be_module.h"
#include "utils/builtins.h"
#include "utils/bytea.h"
#include "utils/distribute_test.h"
#include "utils/guc_tables.h"
#include "utils/memtrack.h"
#include "utils/memutils.h"
#include "utils/pg_locale.h"
#include "utils/plancache.h"
#include "utils/portal.h"
#include "utils/ps_status.h"
#include "utils/rel_gs.h"
#include "utils/rel.h"
#include "utils/snapmgr.h"
#include "utils/syscache.h"
#include "access/heapam.h"
#include "utils/tzparser.h"
#include "utils/xml.h"
#include "workload/cpwlm.h"
#include "workload/workload.h"
#include "utils/guc_memory.h"
#include "utils/mem_snapshot.h"
static bool check_memory_detail_tracking(char** newval, void** extra, GucSource source);
static void assign_memory_detail_tracking(const char* newval, void* extra);
static const char* show_memory_detail_tracking(void);
static const char* show_enable_memory_limit(void);
static bool check_syscache_threshold_gpc(int* newval, void** extra, GucSource source);
static bool check_max_borrow_memory(int* newval, void** extra, GucSource source);
static bool check_uncontrolled_memory_context(char** newval, void** extra, GucSource source);
static void assign_uncontrolled_memory_context(const char* newval, void* extra);
static const char* show_uncontrolled_memory_context(void);
void free_memory_context_list(memory_context_list* head_node);
memory_context_list* split_string_into_list(const char* source);
static void InitMemoryConfigureNamesBool();
static void InitMemoryConfigureNamesInt();
static void InitMemoryConfigureNamesInt64();
static void InitMemoryConfigureNamesReal();
static void InitMemoryConfigureNamesString();
static void InitMemoryConfigureNamesEnum();
static const struct config_enum_entry memory_tracking_option[] = {
{"none", MEMORY_TRACKING_NONE, false},
{"peak", MEMORY_TRACKING_PEAKMEMORY, false},
{"normal", MEMORY_TRACKING_NORMAL, false},
{"executor", MEMORY_TRACKING_EXECUTOR, false},
{"fullexec", MEMORY_TRACKING_FULLEXEC, false},
{NULL, 0, false}
};
static const struct config_enum_entry memory_trace_level[] = {
{"none", MEMORY_TRACE_NONE, false},
{"level1", MEMORY_TRACE_LEVEL1, false},
{"level2", MEMORY_TRACE_LEVEL2, false},
{NULL, 0, false}
};
* Contents of GUC tables
*
* See src/backend/utils/misc/README for design notes.
*
* TO ADD AN OPTION AS FOLLOWS.
*
* 1. Declare a global variable of type bool, int, double, or char*
* and make use of it.
*
* 2. Decide at what times it's safe to set the option. See guc.h for
* details.
*
* 3. Decide on a name, a default value, upper and lower bounds (if
* applicable), etc.
*
* 4. Add a record below.
*
* 5. Add it to src/backend/utils/misc/postgresql_single.conf.sample or
* src/backend/utils/misc/postgresql_distribute.conf.sample or both,
* if appropriate.
*
* 6. Don't forget to document the option (at least in config.sgml).
*
* 7. If it's a new GUC_LIST option you must edit pg_dumpall.c to ensure
* it is not single quoted at dump time.
*/
void InitMemoryConfigureNames()
{
InitMemoryConfigureNamesBool();
InitMemoryConfigureNamesInt();
InitMemoryConfigureNamesInt64();
InitMemoryConfigureNamesReal();
InitMemoryConfigureNamesString();
InitMemoryConfigureNamesEnum();
return;
}
static void InitMemoryConfigureNamesBool()
{
struct config_bool localConfigureNamesBool[] = {
{{"memorypool_enable",
PGC_POSTMASTER,
NODE_ALL,
RESOURCES_MEM,
gettext_noop("Using memory pool."),
NULL},
&g_instance.attr.attr_memory.memorypool_enable,
false,
NULL,
NULL,
NULL},
{{"enable_memory_limit",
PGC_POSTMASTER,
NODE_ALL,
RESOURCES_MEM,
gettext_noop("Using memory protect feature."),
NULL},
&g_instance.attr.attr_memory.enable_memory_limit,
true,
NULL,
NULL,
show_enable_memory_limit},
{{"enable_memory_context_control",
PGC_SIGHUP,
NODE_ALL,
RESOURCES_MEM,
gettext_noop("check the max space size of memory context."),
NULL},
&u_sess->attr.attr_memory.enable_memory_context_control,
false,
NULL,
NULL,
NULL},
{{"disable_memory_protect",
PGC_USERSET,
NODE_ALL,
RESOURCES_MEM,
gettext_noop("disable memory protect for query execution."),
NULL},
&u_sess->attr.attr_memory.disable_memory_protect,
false,
NULL,
NULL,
NULL},
{{"disable_memory_stats",
PGC_POSTMASTER,
NODE_ALL,
RESOURCES_MEM,
gettext_noop("disable memory stats for query execution."),
NULL},
&g_instance.attr.attr_memory.disable_memory_stats,
false,
NULL,
NULL,
NULL},
#ifdef MEMORY_CONTEXT_CHECKING
{{"enable_memory_context_check_debug",
PGC_POSTMASTER,
NODE_ALL,
RESOURCES_MEM,
gettext_noop("check the memory context info on debug mode."),
NULL},
&g_instance.attr.attr_memory.enable_memory_context_check_debug,
false,
NULL,
NULL,
NULL},
#endif
{{"enable_borrow_memory",
PGC_POSTMASTER,
NODE_ALL,
RESOURCES_MEM,
gettext_noop("enable borrow memory for HTAP and operators."),
NULL},
&g_instance.attr.attr_memory.enable_borrow_memory,
false,
NULL,
NULL,
NULL},
{{NULL,
(GucContext)0,
(GucNodeType)0,
(config_group)0,
NULL,
NULL},
NULL,
false,
NULL,
NULL,
NULL}
};
Size bytes = sizeof(localConfigureNamesBool);
u_sess->utils_cxt.ConfigureNamesBool[GUC_ATTR_MEMORY] =
(struct config_bool*)MemoryContextAlloc(SESS_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_CBB), bytes);
errno_t rc = memcpy_s(u_sess->utils_cxt.ConfigureNamesBool[GUC_ATTR_MEMORY], bytes, localConfigureNamesBool, bytes);
securec_check_ss(rc, "\0", "\0");
}
static void InitMemoryConfigureNamesInt()
{
struct config_int localConfigureNamesInt[] = {
{{"memorypool_size",
PGC_POSTMASTER,
NODE_ALL,
RESOURCES_MEM,
gettext_noop("Sets the number of memory pool used by the server."),
NULL,
GUC_UNIT_KB},
&g_instance.attr.attr_memory.memorypool_size,
1024 * 512,
128 * 1024,
INT_MAX / 2,
NULL,
NULL,
NULL},
{{"max_process_memory",
PGC_POSTMASTER,
NODE_ALL,
RESOURCES_MEM,
gettext_noop("Sets the maximum number of memory used by the process."),
NULL,
GUC_UNIT_KB},
&g_instance.attr.attr_memory.max_process_memory,
12 * 1024 * 1024,
2 * 1024 * 1024,
INT_MAX,
NULL,
NULL,
NULL},
{{"local_syscache_threshold",
PGC_SIGHUP,
NODE_ALL,
RESOURCES_MEM,
gettext_noop("Sets the maximum threshold for cleaning cache."),
NULL,
GUC_UNIT_KB},
&u_sess->attr.attr_memory.local_syscache_threshold,
256 * 1024,
1 * 1024,
512 * 1024,
check_syscache_threshold_gpc,
NULL,
NULL},
{{"global_syscache_threshold",
PGC_SIGHUP,
NODE_ALL,
RESOURCES_MEM,
gettext_noop("Sets the maximum threshold for cleaning global syscache."),
NULL,
GUC_UNIT_KB},
&g_instance.attr.attr_memory.global_syscache_threshold,
160 * 1024,
16 * 1024,
1024 * 1024 * 1024,
NULL,
NULL,
NULL},
{{"work_mem",
PGC_USERSET,
NODE_ALL,
RESOURCES_MEM,
gettext_noop("Sets the maximum memory to be used for query workspaces."),
gettext_noop("This much memory can be used by each internal "
"sort operation and hash table before switching to "
"temporary disk files."),
GUC_UNIT_KB},
&u_sess->attr.attr_memory.work_mem,
64 * 1024,
64,
MAX_KILOBYTES,
NULL,
NULL,
NULL},
{{"maintenance_work_mem",
PGC_USERSET,
NODE_ALL,
RESOURCES_MEM,
gettext_noop("Sets the maximum memory to be used for maintenance operations."),
gettext_noop("This includes operations such as VACUUM and CREATE INDEX."),
GUC_UNIT_KB},
&u_sess->attr.attr_memory.maintenance_work_mem,
16384,
1024,
MAX_KILOBYTES,
NULL,
NULL,
NULL},
{{"borrow_work_mem",
PGC_USERSET,
NODE_ALL,
RESOURCES_MEM,
gettext_noop("Sets the maximum borrow memory to be used for query workspaces."),
NULL,
GUC_UNIT_KB},
&u_sess->attr.attr_memory.borrow_work_mem,
0,
0,
INT_MAX,
NULL,
NULL,
NULL},
{{"max_borrow_memory",
PGC_POSTMASTER,
NODE_ALL,
RESOURCES_MEM,
gettext_noop("Sets the maximum number of rack memory can be borrowed by the process."),
NULL,
GUC_UNIT_KB},
&g_instance.attr.attr_memory.max_borrow_memory,
0,
0,
INT_MAX,
check_max_borrow_memory,
NULL,
NULL},
#ifdef ENABLE_HTAP
{{"max_imcs_cache",
PGC_POSTMASTER,
NODE_ALL,
RESOURCES_MEM,
gettext_noop("Sets the maximum size of imcs memory used by the process."),
NULL,
GUC_UNIT_KB},
&g_instance.attr.attr_memory.max_imcs_cache,
100 * 1024,
100 * 1024,
INT_MAX,
NULL,
NULL,
NULL},
{{"htap_borrow_mem_percent",
PGC_POSTMASTER,
NODE_ALL,
RESOURCES_MEM,
gettext_noop("Sets the maximum percentage of imcs memory occupied by borrow memory."),
NULL},
&g_instance.attr.attr_memory.htap_borrow_mem_percent,
50,
0,
100,
NULL,
NULL,
NULL},
#endif
{{NULL,
(GucContext)0,
(GucNodeType)0,
(config_group)0,
NULL,
NULL},
NULL,
0,
0,
0,
NULL,
NULL,
NULL}
};
Size bytes = sizeof(localConfigureNamesInt);
u_sess->utils_cxt.ConfigureNamesInt[GUC_ATTR_MEMORY] =
(struct config_int*)MemoryContextAlloc(SESS_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_CBB), bytes);
errno_t rc = memcpy_s(u_sess->utils_cxt.ConfigureNamesInt[GUC_ATTR_MEMORY], bytes,
localConfigureNamesInt, bytes);
securec_check_ss(rc, "\0", "\0");
}
static void InitMemoryConfigureNamesReal()
{
struct config_real localConfigureNamesReal[] = {
{{NULL,
(GucContext)0,
(GucNodeType)0,
(config_group)0,
NULL,
NULL},
NULL,
0.0,
0.0,
0.0,
NULL,
NULL,
NULL}
};
Size bytes = sizeof(localConfigureNamesReal);
u_sess->utils_cxt.ConfigureNamesReal[GUC_ATTR_MEMORY] =
(struct config_real*)MemoryContextAlloc(SESS_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_CBB), bytes);
errno_t rc = memcpy_s(u_sess->utils_cxt.ConfigureNamesReal[GUC_ATTR_MEMORY], bytes,
localConfigureNamesReal, bytes);
securec_check_ss(rc, "\0", "\0");
}
static void InitMemoryConfigureNamesInt64()
{
struct config_int64 localConfigureNamesInt64[] = {
{{NULL,
(GucContext)0,
(GucNodeType)0,
(config_group)0,
NULL,
NULL},
NULL,
0,
0,
0,
NULL,
NULL,
NULL}
};
Size bytes = sizeof(localConfigureNamesInt64);
u_sess->utils_cxt.ConfigureNamesInt64[GUC_ATTR_MEMORY] =
(struct config_int64*)MemoryContextAlloc(SESS_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_CBB), bytes);
errno_t rc = memcpy_s(u_sess->utils_cxt.ConfigureNamesInt64[GUC_ATTR_MEMORY], bytes,
localConfigureNamesInt64, bytes);
securec_check_ss(rc, "\0", "\0");
}
static void InitMemoryConfigureNamesString()
{
struct config_string localConfigureNamesString[] = {
{{"memory_detail_tracking",
PGC_USERSET,
NODE_ALL,
RESOURCES_MEM,
gettext_noop("Sets the operator name and peak size for triggering the memory logging in that time."),
NULL,
GUC_IS_NAME | GUC_REPORT | GUC_NOT_IN_SAMPLE},
&u_sess->attr.attr_memory.memory_detail_tracking,
"",
check_memory_detail_tracking,
assign_memory_detail_tracking,
show_memory_detail_tracking},
{{"uncontrolled_memory_context",
PGC_USERSET,
NODE_ALL,
RESOURCES_MEM,
gettext_noop("Sets the white list of MemoryContext allocation."),
NULL},
&u_sess->attr.attr_memory.uncontrolled_memory_context,
"",
check_uncontrolled_memory_context,
assign_uncontrolled_memory_context,
show_uncontrolled_memory_context},
{{"resilience_memory_reject_percent",
PGC_SIGHUP,
NODE_ALL,
RESOURCES_MEM,
gettext_noop("Sets the memory percent."),
NULL,
GUC_LIST_INPUT},
&u_sess->attr.attr_memory.memory_reset_percent_item,
"0,0",
CheckMemoryResetPercent,
AssignMemoryResetPercent,
NULL},
{{NULL,
(GucContext)0,
(GucNodeType)0,
(config_group)0,
NULL,
NULL},
NULL,
NULL,
NULL,
NULL,
NULL}
};
Size bytes = sizeof(localConfigureNamesString);
u_sess->utils_cxt.ConfigureNamesString[GUC_ATTR_MEMORY] =
(struct config_string*)MemoryContextAlloc(SESS_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_CBB), bytes);
errno_t rc = memcpy_s(u_sess->utils_cxt.ConfigureNamesString[GUC_ATTR_MEMORY], bytes,
localConfigureNamesString, bytes);
securec_check_ss(rc, "\0", "\0");
}
static void InitMemoryConfigureNamesEnum()
{
struct config_enum localConfigureNamesEnum[] = {
{{"memory_tracking_mode",
PGC_USERSET,
NODE_ALL,
RESOURCES_MEM,
gettext_noop("Choose which style to track the memory usage."),
NULL},
&u_sess->attr.attr_memory.memory_tracking_mode,
MEMORY_TRACKING_NONE,
memory_tracking_option,
NULL,
NULL,
NULL},
{{"memory_trace_level",
PGC_SIGHUP,
NODE_ALL,
RESOURCES_MEM,
gettext_noop("Sets the used memory level for memory snapshot."),
NULL},
&u_sess->attr.attr_memory.memory_trace_level,
MEMORY_TRACE_LEVEL1,
memory_trace_level,
NULL,
NULL,
NULL},
{{NULL,
(GucContext)0,
(GucNodeType)0,
(config_group)0,
NULL,
NULL},
NULL,
0,
NULL,
NULL,
NULL,
NULL}
};
Size bytes = sizeof(localConfigureNamesEnum);
u_sess->utils_cxt.ConfigureNamesEnum[GUC_ATTR_MEMORY] =
(struct config_enum*)MemoryContextAlloc(SESS_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_CBB), bytes);
errno_t rc = memcpy_s(u_sess->utils_cxt.ConfigureNamesEnum[GUC_ATTR_MEMORY], bytes,
localConfigureNamesEnum, bytes);
securec_check_ss(rc, "\0", "\0");
}
* description: to verify if the input value is correct.
* arguments:
* newval: the input string for checking
* extra: the extra information
* source: the GUC Source information
* return value: ture of false
*
* Notes that: this GUC is only used on DEBUG version;
* the format should be input as "seqnum:plannodeid".
*
*/
static bool check_memory_detail_tracking(char** newval, void** extra, GucSource source)
{
#ifdef MEMORY_CONTEXT_CHECKING
char *p, *q;
for (p = *newval; *p; p++) {
if (*p < 32 || *p > 126)
*p = '?';
}
p = *newval;
if (p && *p != '\0' && (NULL == (q = strchr(p, ':')) || (isdigit(*(q + 1)) == 0)))
return false;
return true;
#else
#ifndef FASTCHECK
char* p = *newval;
if (p && *p != '\0')
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("unsupported to set memory_detail_tracking value under release version.")));
#endif
return true;
#endif
}
* description: to parse the GUC value and assign to the global variable
* arguments: standard GUC arguments
*/
static void assign_memory_detail_tracking(const char* newval, void* extra)
{
#ifdef MEMORY_CONTEXT_CHECKING
MemoryTrackingParseGUC(newval);
#endif
}
* description: to show the information
* arguments: standard GUC arguments
*/
static const char* show_memory_detail_tracking(void)
{
char* buf = t_thrd.buf_cxt.show_memory_detail_tracking_buf;
#ifdef MEMORY_CONTEXT_CHECKING
int size = sizeof(t_thrd.buf_cxt.show_memory_detail_tracking_buf);
errno_t rc = snprintf_s(buf,
size,
size - 1,
"Memory Context Sequent Count: %d, Plan Nodeid: %d",
t_thrd.utils_cxt.memory_track_sequent_count,
t_thrd.utils_cxt.memory_track_plan_nodeid);
securec_check_ss(rc, "\0", "\0");
#endif
return buf;
}
static const char* show_enable_memory_limit(void)
{
char* buf = t_thrd.buf_cxt.show_enable_memory_limit_buf;
int size = sizeof(t_thrd.buf_cxt.show_enable_memory_limit_buf);
int rcs;
if (t_thrd.utils_cxt.gs_mp_inited) {
rcs = snprintf_s(buf, size, size - 1, "%s", "on");
securec_check_ss(rcs, "\0", "\0");
} else {
rcs = snprintf_s(buf, size, size - 1, "%s", "off");
securec_check_ss(rcs, "\0", "\0");
}
return buf;
}
static bool check_syscache_threshold_gpc(int* newval, void** extra, GucSource source)
{
at least 16MB if gpc is on. */
if (g_instance.attr.attr_common.enable_global_plancache && *newval < 16 * 1024) {
ereport(WARNING, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("cannot set local_syscache_threshold to %dMB in case gpc is on but not valid.",
*newval / 1024)));
return false;
}
return true;
}
static bool check_max_borrow_memory(int* newval, void** extra, GucSource source)
{
constexpr int minRackAllocSizeKb = MIN_RACK_ALLOC_SIZE / 1024;
if (*newval % minRackAllocSizeKb == 0) {
return true;
}
ereport(WARNING, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("max_borrow_memory must be a integer multiple of 128MB.")));
return false;
}
void free_memory_context_list(memory_context_list* head_node)
{
memory_context_list* last = NULL;
while (head_node != NULL) {
last = head_node;
head_node = head_node->next;
pfree(last);
last = NULL;
}
}
* And these substrings will be appended to a memory_context_list.
* Referenced by GUC uncontrolled_memory_context.
*/
memory_context_list* split_string_into_list(const char* source)
{
errno_t rc = EOK;
int string_length = strlen(source) + 1;
int first_ch_length = 0;
char* str = static_cast<char*>(MemoryContextAlloc(SESS_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_CBB), string_length));
rc = strcpy_s(str, string_length, source);
securec_check_errno(rc, pfree(str), NULL);
memory_context_list* head_node = static_cast<memory_context_list*>(MemoryContextAlloc(
SESS_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_CBB), sizeof(memory_context_list)));
memory_context_list* current_node = head_node;
current_node->next = NULL;
current_node->value = NULL;
char* first_ch = str;
size_t len = 0;
for (int i = 0; i < string_length; i++, len++) {
if (str[i] == ',' || str[i] == '\0') {
if (NULL != current_node->value) {
current_node->next = static_cast<memory_context_list*>(MemoryContextAlloc(
SESS_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_CBB), sizeof(memory_context_list)));
current_node = current_node->next;
current_node->next = NULL;
current_node->value = NULL;
}
first_ch[len] = '\0';
first_ch_length = strlen(first_ch) + 1;
current_node->value = static_cast<char*>(MemoryContextAlloc(
SESS_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_CBB), first_ch_length));
rc = strcpy_s(current_node->value, first_ch_length, first_ch);
securec_check_errno(rc, pfree(str); free_memory_context_list(head_node), NULL);
* 'i++' and 'first_ch += len + 1' means skipping '\0'
*/
first_ch += len + 1;
i++;
len = 0;
}
}
return head_node;
}
static bool check_uncontrolled_memory_context(char** newval, void** extra, GucSource source)
{
for (char* p = *newval; *p; p++) {
if (*p < 32 || *p > 126) {
ereport(ERROR,
(errcode(ERRCODE_UNTRANSLATABLE_CHARACTER), errmsg("The text entered contains illegal characters!")));
return false;
}
}
return true;
}
static void assign_uncontrolled_memory_context(const char* newval, void* extra)
{
if (u_sess->utils_cxt.memory_context_limited_white_list) {
free_memory_context_list(u_sess->utils_cxt.memory_context_limited_white_list);
u_sess->utils_cxt.memory_context_limited_white_list = NULL;
}
u_sess->utils_cxt.memory_context_limited_white_list = split_string_into_list(newval);
}
static const char* show_uncontrolled_memory_context(void)
{
const size_t length = 1024;
char* buff = static_cast<char*>(MemoryContextAllocZero(SESS_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_CBB), length));
errno_t rc = EOK;
size_t len;
rc = strcpy_s(buff, length, "MemoryContext white list:\n");
securec_check_errno(rc, buff[length - 1] = '\0', buff);
for (memory_context_list* iter = u_sess->utils_cxt.memory_context_limited_white_list; iter && iter->value;
iter = iter->next) {
rc = strcat_s(buff, length, iter->value);
securec_check_errno(rc, buff[length - 1] = '\0', buff);
len = strlen(buff);
if (len < (length - 1)) {
buff[len] = '\n';
buff[len + 1] = '\0';
}
}
return buff;
}