mirror of
https://github.com/postgres/postgres.git
synced 2025-04-22 23:02:54 +03:00
Store GUC data in a memory context, instead of using malloc().
The only real argument for using malloc directly was that we needed the ability to not throw error on OOM; but mcxt.c grew that feature awhile ago. Keeping the data in a memory context improves accountability and debuggability --- for example, without this it's almost impossible to detect memory leaks in the GUC code with anything less costly than valgrind. Moreover, the next patch in this series will add a hash table for GUC lookup, and it'd be pretty silly to be using palloc-dependent hash facilities alongside malloc'd storage of the underlying data. This is a bit invasive though, in particular causing an API break for GUC check hooks that want to modify the GUC's value or use an "extra" data structure. They must now use guc_malloc() and guc_free() instead of malloc() and free(). Failure to change affected code will result in assertion failures or worse; but thanks to recent effort in the mcxt infrastructure, it shouldn't be too hard to diagnose such oversights (at least in assert-enabled builds). One note is that this changes ParseLongOption() to return short-lived palloc'd not malloc'd data. There wasn't any caller for which the previous definition was better. Discussion: https://postgr.es/m/2982579.1662416866@sss.pgh.pa.us
This commit is contained in:
parent
9c911ec065
commit
407b50f2d4
@ -287,8 +287,8 @@ BootstrapModeMain(int argc, char *argv[], bool check_only)
|
|||||||
}
|
}
|
||||||
|
|
||||||
SetConfigOption(name, value, PGC_POSTMASTER, PGC_S_ARGV);
|
SetConfigOption(name, value, PGC_POSTMASTER, PGC_S_ARGV);
|
||||||
free(name);
|
pfree(name);
|
||||||
free(value);
|
pfree(value);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -1290,8 +1290,8 @@ check_temp_tablespaces(char **newval, void **extra, GucSource source)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Now prepare an "extra" struct for assign_temp_tablespaces */
|
/* Now prepare an "extra" struct for assign_temp_tablespaces */
|
||||||
myextra = malloc(offsetof(temp_tablespaces_extra, tblSpcs) +
|
myextra = guc_malloc(LOG, offsetof(temp_tablespaces_extra, tblSpcs) +
|
||||||
numSpcs * sizeof(Oid));
|
numSpcs * sizeof(Oid));
|
||||||
if (!myextra)
|
if (!myextra)
|
||||||
return false;
|
return false;
|
||||||
myextra->numSpcs = numSpcs;
|
myextra->numSpcs = numSpcs;
|
||||||
|
@ -148,7 +148,7 @@ check_datestyle(char **newval, void **extra, GucSource source)
|
|||||||
char *subval;
|
char *subval;
|
||||||
void *subextra = NULL;
|
void *subextra = NULL;
|
||||||
|
|
||||||
subval = strdup(GetConfigOptionResetString("datestyle"));
|
subval = guc_strdup(LOG, GetConfigOptionResetString("datestyle"));
|
||||||
if (!subval)
|
if (!subval)
|
||||||
{
|
{
|
||||||
ok = false;
|
ok = false;
|
||||||
@ -156,7 +156,7 @@ check_datestyle(char **newval, void **extra, GucSource source)
|
|||||||
}
|
}
|
||||||
if (!check_datestyle(&subval, &subextra, source))
|
if (!check_datestyle(&subval, &subextra, source))
|
||||||
{
|
{
|
||||||
free(subval);
|
guc_free(subval);
|
||||||
ok = false;
|
ok = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -165,8 +165,8 @@ check_datestyle(char **newval, void **extra, GucSource source)
|
|||||||
newDateStyle = myextra[0];
|
newDateStyle = myextra[0];
|
||||||
if (!have_order)
|
if (!have_order)
|
||||||
newDateOrder = myextra[1];
|
newDateOrder = myextra[1];
|
||||||
free(subval);
|
guc_free(subval);
|
||||||
free(subextra);
|
guc_free(subextra);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -187,9 +187,9 @@ check_datestyle(char **newval, void **extra, GucSource source)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Prepare the canonical string to return. GUC wants it malloc'd.
|
* Prepare the canonical string to return. GUC wants it guc_malloc'd.
|
||||||
*/
|
*/
|
||||||
result = (char *) malloc(32);
|
result = (char *) guc_malloc(LOG, 32);
|
||||||
if (!result)
|
if (!result)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -221,13 +221,13 @@ check_datestyle(char **newval, void **extra, GucSource source)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
free(*newval);
|
guc_free(*newval);
|
||||||
*newval = result;
|
*newval = result;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set up the "extra" struct actually used by assign_datestyle.
|
* Set up the "extra" struct actually used by assign_datestyle.
|
||||||
*/
|
*/
|
||||||
myextra = (int *) malloc(2 * sizeof(int));
|
myextra = (int *) guc_malloc(LOG, 2 * sizeof(int));
|
||||||
if (!myextra)
|
if (!myextra)
|
||||||
return false;
|
return false;
|
||||||
myextra[0] = newDateStyle;
|
myextra[0] = newDateStyle;
|
||||||
@ -366,7 +366,7 @@ check_timezone(char **newval, void **extra, GucSource source)
|
|||||||
/*
|
/*
|
||||||
* Pass back data for assign_timezone to use
|
* Pass back data for assign_timezone to use
|
||||||
*/
|
*/
|
||||||
*extra = malloc(sizeof(pg_tz *));
|
*extra = guc_malloc(LOG, sizeof(pg_tz *));
|
||||||
if (!*extra)
|
if (!*extra)
|
||||||
return false;
|
return false;
|
||||||
*((pg_tz **) *extra) = new_tz;
|
*((pg_tz **) *extra) = new_tz;
|
||||||
@ -439,7 +439,7 @@ check_log_timezone(char **newval, void **extra, GucSource source)
|
|||||||
/*
|
/*
|
||||||
* Pass back data for assign_log_timezone to use
|
* Pass back data for assign_log_timezone to use
|
||||||
*/
|
*/
|
||||||
*extra = malloc(sizeof(pg_tz *));
|
*extra = guc_malloc(LOG, sizeof(pg_tz *));
|
||||||
if (!*extra)
|
if (!*extra)
|
||||||
return false;
|
return false;
|
||||||
*((pg_tz **) *extra) = new_tz;
|
*((pg_tz **) *extra) = new_tz;
|
||||||
@ -500,7 +500,7 @@ check_timezone_abbreviations(char **newval, void **extra, GucSource source)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* OK, load the file and produce a malloc'd TimeZoneAbbrevTable */
|
/* OK, load the file and produce a guc_malloc'd TimeZoneAbbrevTable */
|
||||||
*extra = load_tzoffsets(*newval);
|
*extra = load_tzoffsets(*newval);
|
||||||
|
|
||||||
/* tzparser.c returns NULL on failure, reporting via GUC_check_errmsg */
|
/* tzparser.c returns NULL on failure, reporting via GUC_check_errmsg */
|
||||||
@ -647,7 +647,7 @@ check_transaction_deferrable(bool *newval, void **extra, GucSource source)
|
|||||||
bool
|
bool
|
||||||
check_random_seed(double *newval, void **extra, GucSource source)
|
check_random_seed(double *newval, void **extra, GucSource source)
|
||||||
{
|
{
|
||||||
*extra = malloc(sizeof(int));
|
*extra = guc_malloc(LOG, sizeof(int));
|
||||||
if (!*extra)
|
if (!*extra)
|
||||||
return false;
|
return false;
|
||||||
/* Arm the assign only if source of value is an interactive SET */
|
/* Arm the assign only if source of value is an interactive SET */
|
||||||
@ -735,8 +735,8 @@ check_client_encoding(char **newval, void **extra, GucSource source)
|
|||||||
if (strcmp(*newval, canonical_name) != 0 &&
|
if (strcmp(*newval, canonical_name) != 0 &&
|
||||||
strcmp(*newval, "UNICODE") != 0)
|
strcmp(*newval, "UNICODE") != 0)
|
||||||
{
|
{
|
||||||
free(*newval);
|
guc_free(*newval);
|
||||||
*newval = strdup(canonical_name);
|
*newval = guc_strdup(LOG, canonical_name);
|
||||||
if (!*newval)
|
if (!*newval)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -744,7 +744,7 @@ check_client_encoding(char **newval, void **extra, GucSource source)
|
|||||||
/*
|
/*
|
||||||
* Save the encoding's ID in *extra, for use by assign_client_encoding.
|
* Save the encoding's ID in *extra, for use by assign_client_encoding.
|
||||||
*/
|
*/
|
||||||
*extra = malloc(sizeof(int));
|
*extra = guc_malloc(LOG, sizeof(int));
|
||||||
if (!*extra)
|
if (!*extra)
|
||||||
return false;
|
return false;
|
||||||
*((int *) *extra) = encoding;
|
*((int *) *extra) = encoding;
|
||||||
@ -847,7 +847,7 @@ check_session_authorization(char **newval, void **extra, GucSource source)
|
|||||||
ReleaseSysCache(roleTup);
|
ReleaseSysCache(roleTup);
|
||||||
|
|
||||||
/* Set up "extra" struct for assign_session_authorization to use */
|
/* Set up "extra" struct for assign_session_authorization to use */
|
||||||
myextra = (role_auth_extra *) malloc(sizeof(role_auth_extra));
|
myextra = (role_auth_extra *) guc_malloc(LOG, sizeof(role_auth_extra));
|
||||||
if (!myextra)
|
if (!myextra)
|
||||||
return false;
|
return false;
|
||||||
myextra->roleid = roleid;
|
myextra->roleid = roleid;
|
||||||
@ -957,7 +957,7 @@ check_role(char **newval, void **extra, GucSource source)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Set up "extra" struct for assign_role to use */
|
/* Set up "extra" struct for assign_role to use */
|
||||||
myextra = (role_auth_extra *) malloc(sizeof(role_auth_extra));
|
myextra = (role_auth_extra *) guc_malloc(LOG, sizeof(role_auth_extra));
|
||||||
if (!myextra)
|
if (!myextra)
|
||||||
return false;
|
return false;
|
||||||
myextra->roleid = roleid;
|
myextra->roleid = roleid;
|
||||||
|
@ -849,8 +849,8 @@ PostmasterMain(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
SetConfigOption(name, value, PGC_POSTMASTER, PGC_S_ARGV);
|
SetConfigOption(name, value, PGC_POSTMASTER, PGC_S_ARGV);
|
||||||
free(name);
|
pfree(name);
|
||||||
free(value);
|
pfree(value);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1054,9 +1054,9 @@ check_synchronous_standby_names(char **newval, void **extra, GucSource source)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* GUC extra value must be malloc'd, not palloc'd */
|
/* GUC extra value must be guc_malloc'd, not palloc'd */
|
||||||
pconf = (SyncRepConfigData *)
|
pconf = (SyncRepConfigData *)
|
||||||
malloc(syncrep_parse_result->config_size);
|
guc_malloc(LOG, syncrep_parse_result->config_size);
|
||||||
if (pconf == NULL)
|
if (pconf == NULL)
|
||||||
return false;
|
return false;
|
||||||
memcpy(pconf, syncrep_parse_result, syncrep_parse_result->config_size);
|
memcpy(pconf, syncrep_parse_result, syncrep_parse_result->config_size);
|
||||||
|
@ -3871,8 +3871,8 @@ process_postgres_switches(int argc, char *argv[], GucContext ctx,
|
|||||||
optarg)));
|
optarg)));
|
||||||
}
|
}
|
||||||
SetConfigOption(name, value, ctx, gucsource);
|
SetConfigOption(name, value, ctx, gucsource);
|
||||||
free(name);
|
pfree(name);
|
||||||
free(value);
|
pfree(value);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
#include "utils/date.h"
|
#include "utils/date.h"
|
||||||
#include "utils/datetime.h"
|
#include "utils/datetime.h"
|
||||||
|
#include "utils/guc.h"
|
||||||
#include "utils/memutils.h"
|
#include "utils/memutils.h"
|
||||||
#include "utils/tzparser.h"
|
#include "utils/tzparser.h"
|
||||||
|
|
||||||
@ -4782,8 +4783,8 @@ TemporalSimplify(int32 max_precis, Node *node)
|
|||||||
* to create the final array of timezone tokens. The argument array
|
* to create the final array of timezone tokens. The argument array
|
||||||
* is already sorted in name order.
|
* is already sorted in name order.
|
||||||
*
|
*
|
||||||
* The result is a TimeZoneAbbrevTable (which must be a single malloc'd chunk)
|
* The result is a TimeZoneAbbrevTable (which must be a single guc_malloc'd
|
||||||
* or NULL on malloc failure. No other error conditions are defined.
|
* chunk) or NULL on alloc failure. No other error conditions are defined.
|
||||||
*/
|
*/
|
||||||
TimeZoneAbbrevTable *
|
TimeZoneAbbrevTable *
|
||||||
ConvertTimeZoneAbbrevs(struct tzEntry *abbrevs, int n)
|
ConvertTimeZoneAbbrevs(struct tzEntry *abbrevs, int n)
|
||||||
@ -4812,7 +4813,7 @@ ConvertTimeZoneAbbrevs(struct tzEntry *abbrevs, int n)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Alloc the result ... */
|
/* Alloc the result ... */
|
||||||
tbl = malloc(tbl_size);
|
tbl = guc_malloc(LOG, tbl_size);
|
||||||
if (!tbl)
|
if (!tbl)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
6
src/backend/utils/cache/ts_cache.c
vendored
6
src/backend/utils/cache/ts_cache.c
vendored
@ -633,9 +633,9 @@ check_default_text_search_config(char **newval, void **extra, GucSource source)
|
|||||||
|
|
||||||
ReleaseSysCache(tuple);
|
ReleaseSysCache(tuple);
|
||||||
|
|
||||||
/* GUC wants it malloc'd not palloc'd */
|
/* GUC wants it guc_malloc'd not palloc'd */
|
||||||
free(*newval);
|
guc_free(*newval);
|
||||||
*newval = strdup(buf);
|
*newval = guc_strdup(LOG, buf);
|
||||||
pfree(buf);
|
pfree(buf);
|
||||||
if (!*newval)
|
if (!*newval)
|
||||||
return false;
|
return false;
|
||||||
|
@ -51,13 +51,13 @@ out-of-memory.
|
|||||||
This might be used for example to canonicalize the spelling of a string
|
This might be used for example to canonicalize the spelling of a string
|
||||||
value, round off a buffer size to the nearest supported value, or replace
|
value, round off a buffer size to the nearest supported value, or replace
|
||||||
a special value such as "-1" with a computed default value. If the
|
a special value such as "-1" with a computed default value. If the
|
||||||
function wishes to replace a string value, it must malloc (not palloc)
|
function wishes to replace a string value, it must guc_malloc (not palloc)
|
||||||
the replacement value, and be sure to free() the previous value.
|
the replacement value, and be sure to guc_free() the previous value.
|
||||||
|
|
||||||
* Derived information, such as the role OID represented by a user name,
|
* Derived information, such as the role OID represented by a user name,
|
||||||
can be stored for use by the assign hook. To do this, malloc (not palloc)
|
can be stored for use by the assign hook. To do this, guc_malloc (not palloc)
|
||||||
storage space for the information, and return its address at *extra.
|
storage space for the information, and return its address at *extra.
|
||||||
guc.c will automatically free() this space when the associated GUC setting
|
guc.c will automatically guc_free() this space when the associated GUC setting
|
||||||
is no longer of interest. *extra is initialized to NULL before call, so
|
is no longer of interest. *extra is initialized to NULL before call, so
|
||||||
it can be ignored if not needed.
|
it can be ignored if not needed.
|
||||||
|
|
||||||
@ -255,10 +255,9 @@ maintained by GUC.
|
|||||||
GUC Memory Handling
|
GUC Memory Handling
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
String variable values are allocated with malloc/strdup, not with the
|
String variable values are allocated with guc_malloc or guc_strdup,
|
||||||
palloc/pstrdup mechanisms. We would need to keep them in a permanent
|
which ensure that the values are kept in a long-lived context, and provide
|
||||||
context anyway, and malloc gives us more control over handling
|
more control over handling out-of-memory failures than bare palloc.
|
||||||
out-of-memory failures.
|
|
||||||
|
|
||||||
We allow a string variable's actual value, reset_val, boot_val, and stacked
|
We allow a string variable's actual value, reset_val, boot_val, and stacked
|
||||||
values to point at the same storage. This makes it slightly harder to free
|
values to point at the same storage. This makes it slightly harder to free
|
||||||
|
@ -188,6 +188,9 @@ static const char *const map_old_guc_names[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* Memory context holding all GUC-related data */
|
||||||
|
static MemoryContext GUCMemoryContext;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Actual lookup of variables is done through this single, sorted array.
|
* Actual lookup of variables is done through this single, sorted array.
|
||||||
*/
|
*/
|
||||||
@ -595,19 +598,22 @@ bail_out:
|
|||||||
return head;
|
return head;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Some infrastructure for checking malloc/strdup/realloc calls
|
* Some infrastructure for GUC-related memory allocation
|
||||||
|
*
|
||||||
|
* These functions are generally modeled on libc's malloc/realloc/etc,
|
||||||
|
* but any OOM issue is reported at the specified elevel.
|
||||||
|
* (Thus, control returns only if that's less than ERROR.)
|
||||||
*/
|
*/
|
||||||
void *
|
void *
|
||||||
guc_malloc(int elevel, size_t size)
|
guc_malloc(int elevel, size_t size)
|
||||||
{
|
{
|
||||||
void *data;
|
void *data;
|
||||||
|
|
||||||
/* Avoid unportable behavior of malloc(0) */
|
data = MemoryContextAllocExtended(GUCMemoryContext, size,
|
||||||
if (size == 0)
|
MCXT_ALLOC_NO_OOM);
|
||||||
size = 1;
|
if (unlikely(data == NULL))
|
||||||
data = malloc(size);
|
|
||||||
if (data == NULL)
|
|
||||||
ereport(elevel,
|
ereport(elevel,
|
||||||
(errcode(ERRCODE_OUT_OF_MEMORY),
|
(errcode(ERRCODE_OUT_OF_MEMORY),
|
||||||
errmsg("out of memory")));
|
errmsg("out of memory")));
|
||||||
@ -619,11 +625,20 @@ guc_realloc(int elevel, void *old, size_t size)
|
|||||||
{
|
{
|
||||||
void *data;
|
void *data;
|
||||||
|
|
||||||
/* Avoid unportable behavior of realloc(NULL, 0) */
|
if (old != NULL)
|
||||||
if (old == NULL && size == 0)
|
{
|
||||||
size = 1;
|
/* This is to help catch old code that malloc's GUC data. */
|
||||||
data = realloc(old, size);
|
Assert(GetMemoryChunkContext(old) == GUCMemoryContext);
|
||||||
if (data == NULL)
|
data = repalloc_extended(old, size,
|
||||||
|
MCXT_ALLOC_NO_OOM);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Like realloc(3), but not like repalloc(), we allow old == NULL. */
|
||||||
|
data = MemoryContextAllocExtended(GUCMemoryContext, size,
|
||||||
|
MCXT_ALLOC_NO_OOM);
|
||||||
|
}
|
||||||
|
if (unlikely(data == NULL))
|
||||||
ereport(elevel,
|
ereport(elevel,
|
||||||
(errcode(ERRCODE_OUT_OF_MEMORY),
|
(errcode(ERRCODE_OUT_OF_MEMORY),
|
||||||
errmsg("out of memory")));
|
errmsg("out of memory")));
|
||||||
@ -634,15 +649,29 @@ char *
|
|||||||
guc_strdup(int elevel, const char *src)
|
guc_strdup(int elevel, const char *src)
|
||||||
{
|
{
|
||||||
char *data;
|
char *data;
|
||||||
|
size_t len = strlen(src) + 1;
|
||||||
|
|
||||||
data = strdup(src);
|
data = guc_malloc(elevel, len);
|
||||||
if (data == NULL)
|
if (likely(data != NULL))
|
||||||
ereport(elevel,
|
memcpy(data, src, len);
|
||||||
(errcode(ERRCODE_OUT_OF_MEMORY),
|
|
||||||
errmsg("out of memory")));
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
guc_free(void *ptr)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Historically, GUC-related code has relied heavily on the ability to do
|
||||||
|
* free(NULL), so we allow that here even though pfree() doesn't.
|
||||||
|
*/
|
||||||
|
if (ptr != NULL)
|
||||||
|
{
|
||||||
|
/* This is to help catch old code that malloc's GUC data. */
|
||||||
|
Assert(GetMemoryChunkContext(ptr) == GUCMemoryContext);
|
||||||
|
pfree(ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Detect whether strval is referenced anywhere in a GUC string item
|
* Detect whether strval is referenced anywhere in a GUC string item
|
||||||
@ -680,7 +709,7 @@ set_string_field(struct config_string *conf, char **field, char *newval)
|
|||||||
|
|
||||||
/* Free old value if it's not NULL and isn't referenced anymore */
|
/* Free old value if it's not NULL and isn't referenced anymore */
|
||||||
if (oldval && !string_field_used(conf, oldval))
|
if (oldval && !string_field_used(conf, oldval))
|
||||||
free(oldval);
|
guc_free(oldval);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -741,7 +770,7 @@ set_extra_field(struct config_generic *gconf, void **field, void *newval)
|
|||||||
|
|
||||||
/* Free old value if it's not NULL and isn't referenced anymore */
|
/* Free old value if it's not NULL and isn't referenced anymore */
|
||||||
if (oldval && !extra_field_used(gconf, oldval))
|
if (oldval && !extra_field_used(gconf, oldval))
|
||||||
free(oldval);
|
guc_free(oldval);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -749,7 +778,7 @@ set_extra_field(struct config_generic *gconf, void **field, void *newval)
|
|||||||
* The "extra" field associated with the active value is copied, too.
|
* The "extra" field associated with the active value is copied, too.
|
||||||
*
|
*
|
||||||
* NB: be sure stringval and extra fields of a new stack entry are
|
* NB: be sure stringval and extra fields of a new stack entry are
|
||||||
* initialized to NULL before this is used, else we'll try to free() them.
|
* initialized to NULL before this is used, else we'll try to guc_free() them.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
set_stack_value(struct config_generic *gconf, config_var_value *val)
|
set_stack_value(struct config_generic *gconf, config_var_value *val)
|
||||||
@ -817,9 +846,9 @@ get_guc_variables(void)
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Build the sorted array. This is split out so that it could be
|
* Build the sorted array. This is split out so that help_config.c can
|
||||||
* re-executed after startup (e.g., we could allow loadable modules to
|
* extract all the variables without running all of InitializeGUCOptions.
|
||||||
* add vars, and then we'd need to re-sort).
|
* It's not meant for use anyplace else.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
build_guc_variables(void)
|
build_guc_variables(void)
|
||||||
@ -829,6 +858,17 @@ build_guc_variables(void)
|
|||||||
struct config_generic **guc_vars;
|
struct config_generic **guc_vars;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create the memory context that will hold all GUC-related data.
|
||||||
|
*/
|
||||||
|
Assert(GUCMemoryContext == NULL);
|
||||||
|
GUCMemoryContext = AllocSetContextCreate(TopMemoryContext,
|
||||||
|
"GUCMemoryContext",
|
||||||
|
ALLOCSET_DEFAULT_SIZES);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Count all the built-in variables, and set their vartypes correctly.
|
||||||
|
*/
|
||||||
for (i = 0; ConfigureNamesBool[i].gen.name; i++)
|
for (i = 0; ConfigureNamesBool[i].gen.name; i++)
|
||||||
{
|
{
|
||||||
struct config_bool *conf = &ConfigureNamesBool[i];
|
struct config_bool *conf = &ConfigureNamesBool[i];
|
||||||
@ -895,7 +935,7 @@ build_guc_variables(void)
|
|||||||
for (i = 0; ConfigureNamesEnum[i].gen.name; i++)
|
for (i = 0; ConfigureNamesEnum[i].gen.name; i++)
|
||||||
guc_vars[num_vars++] = &ConfigureNamesEnum[i].gen;
|
guc_vars[num_vars++] = &ConfigureNamesEnum[i].gen;
|
||||||
|
|
||||||
free(guc_variables);
|
guc_free(guc_variables);
|
||||||
guc_variables = guc_vars;
|
guc_variables = guc_vars;
|
||||||
num_guc_variables = num_vars;
|
num_guc_variables = num_vars;
|
||||||
size_guc_variables = size_vars;
|
size_guc_variables = size_vars;
|
||||||
@ -1001,7 +1041,7 @@ add_placeholder_variable(const char *name, int elevel)
|
|||||||
gen->name = guc_strdup(elevel, name);
|
gen->name = guc_strdup(elevel, name);
|
||||||
if (gen->name == NULL)
|
if (gen->name == NULL)
|
||||||
{
|
{
|
||||||
free(var);
|
guc_free(var);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1020,8 +1060,8 @@ add_placeholder_variable(const char *name, int elevel)
|
|||||||
|
|
||||||
if (!add_guc_variable((struct config_generic *) var, elevel))
|
if (!add_guc_variable((struct config_generic *) var, elevel))
|
||||||
{
|
{
|
||||||
free(unconstify(char *, gen->name));
|
guc_free(unconstify(char *, gen->name));
|
||||||
free(var);
|
guc_free(var);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1255,7 +1295,7 @@ InitializeGUCOptions(void)
|
|||||||
pg_timezone_initialize();
|
pg_timezone_initialize();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Build sorted array of all GUC variables.
|
* Create GUCMemoryContext and build sorted array of all GUC variables.
|
||||||
*/
|
*/
|
||||||
build_guc_variables();
|
build_guc_variables();
|
||||||
|
|
||||||
@ -1482,6 +1522,7 @@ SelectConfigFiles(const char *userDoption, const char *progname)
|
|||||||
{
|
{
|
||||||
char *configdir;
|
char *configdir;
|
||||||
char *fname;
|
char *fname;
|
||||||
|
bool fname_is_malloced;
|
||||||
struct stat stat_buf;
|
struct stat stat_buf;
|
||||||
struct config_string *data_directory_rec;
|
struct config_string *data_directory_rec;
|
||||||
|
|
||||||
@ -1509,12 +1550,16 @@ SelectConfigFiles(const char *userDoption, const char *progname)
|
|||||||
* the same way by future backends.
|
* the same way by future backends.
|
||||||
*/
|
*/
|
||||||
if (ConfigFileName)
|
if (ConfigFileName)
|
||||||
|
{
|
||||||
fname = make_absolute_path(ConfigFileName);
|
fname = make_absolute_path(ConfigFileName);
|
||||||
|
fname_is_malloced = true;
|
||||||
|
}
|
||||||
else if (configdir)
|
else if (configdir)
|
||||||
{
|
{
|
||||||
fname = guc_malloc(FATAL,
|
fname = guc_malloc(FATAL,
|
||||||
strlen(configdir) + strlen(CONFIG_FILENAME) + 2);
|
strlen(configdir) + strlen(CONFIG_FILENAME) + 2);
|
||||||
sprintf(fname, "%s/%s", configdir, CONFIG_FILENAME);
|
sprintf(fname, "%s/%s", configdir, CONFIG_FILENAME);
|
||||||
|
fname_is_malloced = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1530,7 +1575,11 @@ SelectConfigFiles(const char *userDoption, const char *progname)
|
|||||||
* it can't be overridden later.
|
* it can't be overridden later.
|
||||||
*/
|
*/
|
||||||
SetConfigOption("config_file", fname, PGC_POSTMASTER, PGC_S_OVERRIDE);
|
SetConfigOption("config_file", fname, PGC_POSTMASTER, PGC_S_OVERRIDE);
|
||||||
free(fname);
|
|
||||||
|
if (fname_is_malloced)
|
||||||
|
free(fname);
|
||||||
|
else
|
||||||
|
guc_free(fname);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now read the config file for the first time.
|
* Now read the config file for the first time.
|
||||||
@ -1604,12 +1653,16 @@ SelectConfigFiles(const char *userDoption, const char *progname)
|
|||||||
* Figure out where pg_hba.conf is, and make sure the path is absolute.
|
* Figure out where pg_hba.conf is, and make sure the path is absolute.
|
||||||
*/
|
*/
|
||||||
if (HbaFileName)
|
if (HbaFileName)
|
||||||
|
{
|
||||||
fname = make_absolute_path(HbaFileName);
|
fname = make_absolute_path(HbaFileName);
|
||||||
|
fname_is_malloced = true;
|
||||||
|
}
|
||||||
else if (configdir)
|
else if (configdir)
|
||||||
{
|
{
|
||||||
fname = guc_malloc(FATAL,
|
fname = guc_malloc(FATAL,
|
||||||
strlen(configdir) + strlen(HBA_FILENAME) + 2);
|
strlen(configdir) + strlen(HBA_FILENAME) + 2);
|
||||||
sprintf(fname, "%s/%s", configdir, HBA_FILENAME);
|
sprintf(fname, "%s/%s", configdir, HBA_FILENAME);
|
||||||
|
fname_is_malloced = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1621,18 +1674,26 @@ SelectConfigFiles(const char *userDoption, const char *progname)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
SetConfigOption("hba_file", fname, PGC_POSTMASTER, PGC_S_OVERRIDE);
|
SetConfigOption("hba_file", fname, PGC_POSTMASTER, PGC_S_OVERRIDE);
|
||||||
free(fname);
|
|
||||||
|
if (fname_is_malloced)
|
||||||
|
free(fname);
|
||||||
|
else
|
||||||
|
guc_free(fname);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Likewise for pg_ident.conf.
|
* Likewise for pg_ident.conf.
|
||||||
*/
|
*/
|
||||||
if (IdentFileName)
|
if (IdentFileName)
|
||||||
|
{
|
||||||
fname = make_absolute_path(IdentFileName);
|
fname = make_absolute_path(IdentFileName);
|
||||||
|
fname_is_malloced = true;
|
||||||
|
}
|
||||||
else if (configdir)
|
else if (configdir)
|
||||||
{
|
{
|
||||||
fname = guc_malloc(FATAL,
|
fname = guc_malloc(FATAL,
|
||||||
strlen(configdir) + strlen(IDENT_FILENAME) + 2);
|
strlen(configdir) + strlen(IDENT_FILENAME) + 2);
|
||||||
sprintf(fname, "%s/%s", configdir, IDENT_FILENAME);
|
sprintf(fname, "%s/%s", configdir, IDENT_FILENAME);
|
||||||
|
fname_is_malloced = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1644,7 +1705,11 @@ SelectConfigFiles(const char *userDoption, const char *progname)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
SetConfigOption("ident_file", fname, PGC_POSTMASTER, PGC_S_OVERRIDE);
|
SetConfigOption("ident_file", fname, PGC_POSTMASTER, PGC_S_OVERRIDE);
|
||||||
free(fname);
|
|
||||||
|
if (fname_is_malloced)
|
||||||
|
free(fname);
|
||||||
|
else
|
||||||
|
guc_free(fname);
|
||||||
|
|
||||||
free(configdir);
|
free(configdir);
|
||||||
|
|
||||||
@ -2289,12 +2354,12 @@ ReportGUCOption(struct config_generic *record)
|
|||||||
pq_endmessage(&msgbuf);
|
pq_endmessage(&msgbuf);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We need a long-lifespan copy. If strdup() fails due to OOM, we'll
|
* We need a long-lifespan copy. If guc_strdup() fails due to OOM,
|
||||||
* set last_reported to NULL and thereby possibly make a duplicate
|
* we'll set last_reported to NULL and thereby possibly make a
|
||||||
* report later.
|
* duplicate report later.
|
||||||
*/
|
*/
|
||||||
free(record->last_reported);
|
guc_free(record->last_reported);
|
||||||
record->last_reported = strdup(val);
|
record->last_reported = guc_strdup(LOG, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
pfree(val);
|
pfree(val);
|
||||||
@ -2893,7 +2958,7 @@ parse_and_validate_value(struct config_generic *record,
|
|||||||
if (!call_string_check_hook(conf, &newval->stringval, newextra,
|
if (!call_string_check_hook(conf, &newval->stringval, newextra,
|
||||||
source, elevel))
|
source, elevel))
|
||||||
{
|
{
|
||||||
free(newval->stringval);
|
guc_free(newval->stringval);
|
||||||
newval->stringval = NULL;
|
newval->stringval = NULL;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -3328,7 +3393,7 @@ set_config_option_ext(const char *name, const char *value,
|
|||||||
{
|
{
|
||||||
/* Release newextra, unless it's reset_extra */
|
/* Release newextra, unless it's reset_extra */
|
||||||
if (newextra && !extra_field_used(&conf->gen, newextra))
|
if (newextra && !extra_field_used(&conf->gen, newextra))
|
||||||
free(newextra);
|
guc_free(newextra);
|
||||||
|
|
||||||
if (*conf->variable != newval)
|
if (*conf->variable != newval)
|
||||||
{
|
{
|
||||||
@ -3387,7 +3452,7 @@ set_config_option_ext(const char *name, const char *value,
|
|||||||
|
|
||||||
/* Perhaps we didn't install newextra anywhere */
|
/* Perhaps we didn't install newextra anywhere */
|
||||||
if (newextra && !extra_field_used(&conf->gen, newextra))
|
if (newextra && !extra_field_used(&conf->gen, newextra))
|
||||||
free(newextra);
|
guc_free(newextra);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#undef newval
|
#undef newval
|
||||||
@ -3426,7 +3491,7 @@ set_config_option_ext(const char *name, const char *value,
|
|||||||
{
|
{
|
||||||
/* Release newextra, unless it's reset_extra */
|
/* Release newextra, unless it's reset_extra */
|
||||||
if (newextra && !extra_field_used(&conf->gen, newextra))
|
if (newextra && !extra_field_used(&conf->gen, newextra))
|
||||||
free(newextra);
|
guc_free(newextra);
|
||||||
|
|
||||||
if (*conf->variable != newval)
|
if (*conf->variable != newval)
|
||||||
{
|
{
|
||||||
@ -3485,7 +3550,7 @@ set_config_option_ext(const char *name, const char *value,
|
|||||||
|
|
||||||
/* Perhaps we didn't install newextra anywhere */
|
/* Perhaps we didn't install newextra anywhere */
|
||||||
if (newextra && !extra_field_used(&conf->gen, newextra))
|
if (newextra && !extra_field_used(&conf->gen, newextra))
|
||||||
free(newextra);
|
guc_free(newextra);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#undef newval
|
#undef newval
|
||||||
@ -3524,7 +3589,7 @@ set_config_option_ext(const char *name, const char *value,
|
|||||||
{
|
{
|
||||||
/* Release newextra, unless it's reset_extra */
|
/* Release newextra, unless it's reset_extra */
|
||||||
if (newextra && !extra_field_used(&conf->gen, newextra))
|
if (newextra && !extra_field_used(&conf->gen, newextra))
|
||||||
free(newextra);
|
guc_free(newextra);
|
||||||
|
|
||||||
if (*conf->variable != newval)
|
if (*conf->variable != newval)
|
||||||
{
|
{
|
||||||
@ -3583,7 +3648,7 @@ set_config_option_ext(const char *name, const char *value,
|
|||||||
|
|
||||||
/* Perhaps we didn't install newextra anywhere */
|
/* Perhaps we didn't install newextra anywhere */
|
||||||
if (newextra && !extra_field_used(&conf->gen, newextra))
|
if (newextra && !extra_field_used(&conf->gen, newextra))
|
||||||
free(newextra);
|
guc_free(newextra);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#undef newval
|
#undef newval
|
||||||
@ -3617,7 +3682,7 @@ set_config_option_ext(const char *name, const char *value,
|
|||||||
if (!call_string_check_hook(conf, &newval, &newextra,
|
if (!call_string_check_hook(conf, &newval, &newextra,
|
||||||
source, elevel))
|
source, elevel))
|
||||||
{
|
{
|
||||||
free(newval);
|
guc_free(newval);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3645,10 +3710,10 @@ set_config_option_ext(const char *name, const char *value,
|
|||||||
|
|
||||||
/* Release newval, unless it's reset_val */
|
/* Release newval, unless it's reset_val */
|
||||||
if (newval && !string_field_used(conf, newval))
|
if (newval && !string_field_used(conf, newval))
|
||||||
free(newval);
|
guc_free(newval);
|
||||||
/* Release newextra, unless it's reset_extra */
|
/* Release newextra, unless it's reset_extra */
|
||||||
if (newextra && !extra_field_used(&conf->gen, newextra))
|
if (newextra && !extra_field_used(&conf->gen, newextra))
|
||||||
free(newextra);
|
guc_free(newextra);
|
||||||
|
|
||||||
if (newval_different)
|
if (newval_different)
|
||||||
{
|
{
|
||||||
@ -3709,10 +3774,10 @@ set_config_option_ext(const char *name, const char *value,
|
|||||||
|
|
||||||
/* Perhaps we didn't install newval anywhere */
|
/* Perhaps we didn't install newval anywhere */
|
||||||
if (newval && !string_field_used(conf, newval))
|
if (newval && !string_field_used(conf, newval))
|
||||||
free(newval);
|
guc_free(newval);
|
||||||
/* Perhaps we didn't install newextra anywhere */
|
/* Perhaps we didn't install newextra anywhere */
|
||||||
if (newextra && !extra_field_used(&conf->gen, newextra))
|
if (newextra && !extra_field_used(&conf->gen, newextra))
|
||||||
free(newextra);
|
guc_free(newextra);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#undef newval
|
#undef newval
|
||||||
@ -3751,7 +3816,7 @@ set_config_option_ext(const char *name, const char *value,
|
|||||||
{
|
{
|
||||||
/* Release newextra, unless it's reset_extra */
|
/* Release newextra, unless it's reset_extra */
|
||||||
if (newextra && !extra_field_used(&conf->gen, newextra))
|
if (newextra && !extra_field_used(&conf->gen, newextra))
|
||||||
free(newextra);
|
guc_free(newextra);
|
||||||
|
|
||||||
if (*conf->variable != newval)
|
if (*conf->variable != newval)
|
||||||
{
|
{
|
||||||
@ -3810,7 +3875,7 @@ set_config_option_ext(const char *name, const char *value,
|
|||||||
|
|
||||||
/* Perhaps we didn't install newextra anywhere */
|
/* Perhaps we didn't install newextra anywhere */
|
||||||
if (newextra && !extra_field_used(&conf->gen, newextra))
|
if (newextra && !extra_field_used(&conf->gen, newextra))
|
||||||
free(newextra);
|
guc_free(newextra);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#undef newval
|
#undef newval
|
||||||
@ -3848,7 +3913,7 @@ set_config_sourcefile(const char *name, char *sourcefile, int sourceline)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
sourcefile = guc_strdup(elevel, sourcefile);
|
sourcefile = guc_strdup(elevel, sourcefile);
|
||||||
free(record->sourcefile);
|
guc_free(record->sourcefile);
|
||||||
record->sourcefile = sourcefile;
|
record->sourcefile = sourcefile;
|
||||||
record->sourceline = sourceline;
|
record->sourceline = sourceline;
|
||||||
}
|
}
|
||||||
@ -4239,8 +4304,8 @@ AlterSystemSetConfigFile(AlterSystemStmt *altersysstmt)
|
|||||||
name, value)));
|
name, value)));
|
||||||
|
|
||||||
if (record->vartype == PGC_STRING && newval.stringval != NULL)
|
if (record->vartype == PGC_STRING && newval.stringval != NULL)
|
||||||
free(newval.stringval);
|
guc_free(newval.stringval);
|
||||||
free(newextra);
|
guc_free(newextra);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We must also reject values containing newlines, because the
|
* We must also reject values containing newlines, because the
|
||||||
@ -4535,7 +4600,7 @@ define_custom_variable(struct config_generic *variable)
|
|||||||
set_string_field(pHolder, pHolder->variable, NULL);
|
set_string_field(pHolder, pHolder->variable, NULL);
|
||||||
set_string_field(pHolder, &pHolder->reset_val, NULL);
|
set_string_field(pHolder, &pHolder->reset_val, NULL);
|
||||||
|
|
||||||
free(pHolder);
|
guc_free(pHolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -4814,7 +4879,7 @@ MarkGUCPrefixReserved(const char *className)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* And remember the name so we can prevent future mistakes. */
|
/* And remember the name so we can prevent future mistakes. */
|
||||||
oldcontext = MemoryContextSwitchTo(TopMemoryContext);
|
oldcontext = MemoryContextSwitchTo(GUCMemoryContext);
|
||||||
reserved_class_prefix = lappend(reserved_class_prefix, pstrdup(className));
|
reserved_class_prefix = lappend(reserved_class_prefix, pstrdup(className));
|
||||||
MemoryContextSwitchTo(oldcontext);
|
MemoryContextSwitchTo(oldcontext);
|
||||||
}
|
}
|
||||||
@ -5287,9 +5352,9 @@ read_nondefault_variables(void)
|
|||||||
if (varsourcefile[0])
|
if (varsourcefile[0])
|
||||||
set_config_sourcefile(varname, varsourcefile, varsourceline);
|
set_config_sourcefile(varname, varsourcefile, varsourceline);
|
||||||
|
|
||||||
free(varname);
|
guc_free(varname);
|
||||||
free(varvalue);
|
guc_free(varvalue);
|
||||||
free(varsourcefile);
|
guc_free(varsourcefile);
|
||||||
}
|
}
|
||||||
|
|
||||||
FreeFile(fp);
|
FreeFile(fp);
|
||||||
@ -5731,9 +5796,9 @@ RestoreGUCState(void *gucstate)
|
|||||||
* pointers.
|
* pointers.
|
||||||
*/
|
*/
|
||||||
Assert(gconf->stack == NULL);
|
Assert(gconf->stack == NULL);
|
||||||
free(gconf->extra);
|
guc_free(gconf->extra);
|
||||||
free(gconf->last_reported);
|
guc_free(gconf->last_reported);
|
||||||
free(gconf->sourcefile);
|
guc_free(gconf->sourcefile);
|
||||||
switch (gconf->vartype)
|
switch (gconf->vartype)
|
||||||
{
|
{
|
||||||
case PGC_BOOL:
|
case PGC_BOOL:
|
||||||
@ -5741,7 +5806,7 @@ RestoreGUCState(void *gucstate)
|
|||||||
struct config_bool *conf = (struct config_bool *) gconf;
|
struct config_bool *conf = (struct config_bool *) gconf;
|
||||||
|
|
||||||
if (conf->reset_extra && conf->reset_extra != gconf->extra)
|
if (conf->reset_extra && conf->reset_extra != gconf->extra)
|
||||||
free(conf->reset_extra);
|
guc_free(conf->reset_extra);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PGC_INT:
|
case PGC_INT:
|
||||||
@ -5749,7 +5814,7 @@ RestoreGUCState(void *gucstate)
|
|||||||
struct config_int *conf = (struct config_int *) gconf;
|
struct config_int *conf = (struct config_int *) gconf;
|
||||||
|
|
||||||
if (conf->reset_extra && conf->reset_extra != gconf->extra)
|
if (conf->reset_extra && conf->reset_extra != gconf->extra)
|
||||||
free(conf->reset_extra);
|
guc_free(conf->reset_extra);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PGC_REAL:
|
case PGC_REAL:
|
||||||
@ -5757,18 +5822,18 @@ RestoreGUCState(void *gucstate)
|
|||||||
struct config_real *conf = (struct config_real *) gconf;
|
struct config_real *conf = (struct config_real *) gconf;
|
||||||
|
|
||||||
if (conf->reset_extra && conf->reset_extra != gconf->extra)
|
if (conf->reset_extra && conf->reset_extra != gconf->extra)
|
||||||
free(conf->reset_extra);
|
guc_free(conf->reset_extra);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PGC_STRING:
|
case PGC_STRING:
|
||||||
{
|
{
|
||||||
struct config_string *conf = (struct config_string *) gconf;
|
struct config_string *conf = (struct config_string *) gconf;
|
||||||
|
|
||||||
free(*conf->variable);
|
guc_free(*conf->variable);
|
||||||
if (conf->reset_val && conf->reset_val != *conf->variable)
|
if (conf->reset_val && conf->reset_val != *conf->variable)
|
||||||
free(conf->reset_val);
|
guc_free(conf->reset_val);
|
||||||
if (conf->reset_extra && conf->reset_extra != gconf->extra)
|
if (conf->reset_extra && conf->reset_extra != gconf->extra)
|
||||||
free(conf->reset_extra);
|
guc_free(conf->reset_extra);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PGC_ENUM:
|
case PGC_ENUM:
|
||||||
@ -5776,7 +5841,7 @@ RestoreGUCState(void *gucstate)
|
|||||||
struct config_enum *conf = (struct config_enum *) gconf;
|
struct config_enum *conf = (struct config_enum *) gconf;
|
||||||
|
|
||||||
if (conf->reset_extra && conf->reset_extra != gconf->extra)
|
if (conf->reset_extra && conf->reset_extra != gconf->extra)
|
||||||
free(conf->reset_extra);
|
guc_free(conf->reset_extra);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -5838,7 +5903,7 @@ RestoreGUCState(void *gucstate)
|
|||||||
/*
|
/*
|
||||||
* A little "long argument" simulation, although not quite GNU
|
* A little "long argument" simulation, although not quite GNU
|
||||||
* compliant. Takes a string of the form "some-option=some value" and
|
* compliant. Takes a string of the form "some-option=some value" and
|
||||||
* returns name = "some_option" and value = "some value" in malloc'ed
|
* returns name = "some_option" and value = "some value" in palloc'ed
|
||||||
* storage. Note that '-' is converted to '_' in the option name. If
|
* storage. Note that '-' is converted to '_' in the option name. If
|
||||||
* there is no '=' in the input string then value will be NULL.
|
* there is no '=' in the input string then value will be NULL.
|
||||||
*/
|
*/
|
||||||
@ -5856,15 +5921,15 @@ ParseLongOption(const char *string, char **name, char **value)
|
|||||||
|
|
||||||
if (string[equal_pos] == '=')
|
if (string[equal_pos] == '=')
|
||||||
{
|
{
|
||||||
*name = guc_malloc(FATAL, equal_pos + 1);
|
*name = palloc(equal_pos + 1);
|
||||||
strlcpy(*name, string, equal_pos + 1);
|
strlcpy(*name, string, equal_pos + 1);
|
||||||
|
|
||||||
*value = guc_strdup(FATAL, &string[equal_pos + 1]);
|
*value = pstrdup(&string[equal_pos + 1]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* no equal sign in string */
|
/* no equal sign in string */
|
||||||
*name = guc_strdup(FATAL, string);
|
*name = pstrdup(string);
|
||||||
*value = NULL;
|
*value = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5898,8 +5963,6 @@ ProcessGUCArray(ArrayType *array,
|
|||||||
char *s;
|
char *s;
|
||||||
char *name;
|
char *name;
|
||||||
char *value;
|
char *value;
|
||||||
char *namecopy;
|
|
||||||
char *valuecopy;
|
|
||||||
|
|
||||||
d = array_ref(array, 1, &i,
|
d = array_ref(array, 1, &i,
|
||||||
-1 /* varlenarray */ ,
|
-1 /* varlenarray */ ,
|
||||||
@ -5920,22 +5983,16 @@ ProcessGUCArray(ArrayType *array,
|
|||||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||||
errmsg("could not parse setting for parameter \"%s\"",
|
errmsg("could not parse setting for parameter \"%s\"",
|
||||||
name)));
|
name)));
|
||||||
free(name);
|
pfree(name);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* free malloc'd strings immediately to avoid leak upon error */
|
(void) set_config_option(name, value,
|
||||||
namecopy = pstrdup(name);
|
|
||||||
free(name);
|
|
||||||
valuecopy = pstrdup(value);
|
|
||||||
free(value);
|
|
||||||
|
|
||||||
(void) set_config_option(namecopy, valuecopy,
|
|
||||||
context, source,
|
context, source,
|
||||||
action, true, 0, false);
|
action, true, 0, false);
|
||||||
|
|
||||||
pfree(namecopy);
|
pfree(name);
|
||||||
pfree(valuecopy);
|
pfree(value);
|
||||||
pfree(s);
|
pfree(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -6399,7 +6456,7 @@ call_string_check_hook(struct config_string *conf, char **newval, void **extra,
|
|||||||
}
|
}
|
||||||
PG_CATCH();
|
PG_CATCH();
|
||||||
{
|
{
|
||||||
free(*newval);
|
guc_free(*newval);
|
||||||
PG_RE_THROW();
|
PG_RE_THROW();
|
||||||
}
|
}
|
||||||
PG_END_TRY();
|
PG_END_TRY();
|
||||||
|
@ -439,7 +439,7 @@ ParseTzFile(const char *filename, int depth,
|
|||||||
* load_tzoffsets --- read and parse the specified timezone offset file
|
* load_tzoffsets --- read and parse the specified timezone offset file
|
||||||
*
|
*
|
||||||
* On success, return a filled-in TimeZoneAbbrevTable, which must have been
|
* On success, return a filled-in TimeZoneAbbrevTable, which must have been
|
||||||
* malloc'd not palloc'd. On failure, return NULL, using GUC_check_errmsg
|
* guc_malloc'd not palloc'd. On failure, return NULL, using GUC_check_errmsg
|
||||||
* and friends to give details of the problem.
|
* and friends to give details of the problem.
|
||||||
*/
|
*/
|
||||||
TimeZoneAbbrevTable *
|
TimeZoneAbbrevTable *
|
||||||
|
@ -401,6 +401,7 @@ extern ArrayType *GUCArrayReset(ArrayType *array);
|
|||||||
extern void *guc_malloc(int elevel, size_t size);
|
extern void *guc_malloc(int elevel, size_t size);
|
||||||
extern pg_nodiscard void *guc_realloc(int elevel, void *old, size_t size);
|
extern pg_nodiscard void *guc_realloc(int elevel, void *old, size_t size);
|
||||||
extern char *guc_strdup(int elevel, const char *src);
|
extern char *guc_strdup(int elevel, const char *src);
|
||||||
|
extern void guc_free(void *ptr);
|
||||||
|
|
||||||
#ifdef EXEC_BACKEND
|
#ifdef EXEC_BACKEND
|
||||||
extern void write_nondefault_variables(GucContext context);
|
extern void write_nondefault_variables(GucContext context);
|
||||||
|
@ -114,7 +114,7 @@ plpgsql_extra_checks_check_hook(char **newvalue, void **extra, GucSource source)
|
|||||||
list_free(elemlist);
|
list_free(elemlist);
|
||||||
}
|
}
|
||||||
|
|
||||||
myextra = (int *) malloc(sizeof(int));
|
myextra = (int *) guc_malloc(LOG, sizeof(int));
|
||||||
if (!myextra)
|
if (!myextra)
|
||||||
return false;
|
return false;
|
||||||
*myextra = extrachecks;
|
*myextra = extrachecks;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user