v53-0004-Use-64-bit-GUCs.patch
application/octet-stream
Filename: v53-0004-Use-64-bit-GUCs.patch
Type: application/octet-stream
Part: 2
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: format-patch
Series: patch v53-0004
Subject: Use 64-bit GUCs
| File | + | − |
|---|---|---|
| src/backend/access/common/reloptions.c | 123 | 52 |
| src/backend/utils/misc/guc.c | 388 | 0 |
| src/backend/utils/misc/guc_funcs.c | 25 | 0 |
| src/backend/utils/misc/guc_tables.c | 10 | 0 |
| src/include/access/reloptions.h | 13 | 0 |
| src/include/utils/guc.h | 17 | 0 |
| src/include/utils/guc_tables.h | 19 | 0 |
From e7ff6828a8421a81a591e151159b140540260b80 Mon Sep 17 00:00:00 2001
From: Maxim Orlov <m.orlov@postgrespro.ru>
Date: Fri, 11 Mar 2022 11:34:26 +0300
Subject: [PATCH v53 4/5] Use 64-bit GUCs
Author: Alexander Korotkov <aekorotkov@gmail.com>
Author: Teodor Sigaev <teodor@sigaev.ru>
Author: Nikita Glukhov <n.gluhov@postgrespro.ru>
Author: Maxim Orlov <orlovmg@gmail.com>
Author: Pavel Borisov <pashkin.elfe@gmail.com>
Author: Yura Sokolov <y.sokolov@postgrespro.ru> <funny.falcon@gmail.com>
Author: Aleksander Alekseev <aleksander@timescale.com>
Discussion: https://postgr.es/m/CACG%3DezZe1NQSCnfHOr78AtAZxJZeCvxrts0ygrxYwe%3DpyyjVWA%40mail.gmail.com
Discussion: https://postgr.es/m/CAJ7c6TPDOYBYrnCAeyndkBktO0WG2xSdYduTF0nxq%2BvfkmTF5Q%40mail.gmail.com
---
src/backend/access/common/reloptions.c | 175 +++++++----
src/backend/utils/misc/guc.c | 388 +++++++++++++++++++++++++
src/backend/utils/misc/guc_funcs.c | 25 ++
src/backend/utils/misc/guc_tables.c | 10 +
src/include/access/reloptions.h | 13 +
src/include/utils/guc.h | 17 ++
src/include/utils/guc_tables.h | 19 ++
7 files changed, 595 insertions(+), 52 deletions(-)
diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
index d6eb5d8559..22c9a62f62 100644
--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
@@ -258,58 +258,6 @@ static relopt_int intRelOpts[] =
},
-1, 1, 10000
},
- {
- {
- "autovacuum_freeze_min_age",
- "Minimum age at which VACUUM should freeze a table row, for autovacuum",
- RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
- ShareUpdateExclusiveLock
- },
- -1, 0, 1000000000
- },
- {
- {
- "autovacuum_multixact_freeze_min_age",
- "Minimum multixact age at which VACUUM should freeze a row multixact's, for autovacuum",
- RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
- ShareUpdateExclusiveLock
- },
- -1, 0, 1000000000
- },
- {
- {
- "autovacuum_freeze_max_age",
- "Age at which to autovacuum a table to prevent transaction ID wraparound",
- RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
- ShareUpdateExclusiveLock
- },
- -1, 100000, 2000000000
- },
- {
- {
- "autovacuum_multixact_freeze_max_age",
- "Multixact age at which to autovacuum a table to prevent multixact wraparound",
- RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
- ShareUpdateExclusiveLock
- },
- -1, 10000, 2000000000
- },
- {
- {
- "autovacuum_freeze_table_age",
- "Age at which VACUUM should perform a full table sweep to freeze row versions",
- RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
- ShareUpdateExclusiveLock
- }, -1, 0, 2000000000
- },
- {
- {
- "autovacuum_multixact_freeze_table_age",
- "Age of multixact at which VACUUM should perform a full table sweep to freeze row versions",
- RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
- ShareUpdateExclusiveLock
- }, -1, 0, 2000000000
- },
{
{
"log_autovacuum_min_duration",
@@ -380,7 +328,66 @@ static relopt_int intRelOpts[] =
},
-1, 0, 1024
},
+ /* list terminator */
+ {{NULL}}
+};
+static relopt_int64 int64RelOpts[] =
+{
+ {
+ {
+ "autovacuum_freeze_min_age",
+ "Minimum age at which VACUUM should freeze a table row, for autovacuum",
+ RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
+ ShareUpdateExclusiveLock
+ },
+ INT64CONST(-1), INT64CONST(0), INT64CONST(1000000000)
+ },
+ {
+ {
+ "autovacuum_multixact_freeze_min_age",
+ "Minimum multixact age at which VACUUM should freeze a row multixact's, for autovacuum",
+ RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
+ ShareUpdateExclusiveLock
+ },
+ INT64CONST(-1), INT64CONST(0), INT64CONST(1000000000)
+ },
+ {
+ {
+ "autovacuum_freeze_max_age",
+ "Age at which to autovacuum a table to prevent transaction ID wraparound",
+ RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
+ ShareUpdateExclusiveLock
+ },
+ INT64CONST(-1), INT64CONST(100000), INT64CONST(2000000000)
+ },
+ {
+ {
+ "autovacuum_multixact_freeze_max_age",
+ "Multixact age at which to autovacuum a table to prevent multixact wraparound",
+ RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
+ ShareUpdateExclusiveLock
+ },
+ INT64CONST(-1), INT64CONST(10000), INT64CONST(2000000000)
+ },
+ {
+ {
+ "autovacuum_freeze_table_age",
+ "Age at which VACUUM should perform a full table sweep to freeze row versions",
+ RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
+ ShareUpdateExclusiveLock
+ },
+ INT64CONST(-1), INT64CONST(0), INT64CONST(2000000000)
+ },
+ {
+ {
+ "autovacuum_multixact_freeze_table_age",
+ "Age of multixact at which VACUUM should perform a full table sweep to freeze row versions",
+ RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
+ ShareUpdateExclusiveLock
+ },
+ INT64CONST(-1), INT64CONST(0), INT64CONST(2000000000)
+ },
/* list terminator */
{{NULL}}
};
@@ -595,6 +602,12 @@ initialize_reloptions(void)
intRelOpts[i].gen.lockmode));
j++;
}
+ for (i = 0; int64RelOpts[i].gen.name; i++)
+ {
+ Assert(DoLockModesConflict(int64RelOpts[i].gen.lockmode,
+ int64RelOpts[i].gen.lockmode));
+ j++;
+ }
for (i = 0; realRelOpts[i].gen.name; i++)
{
Assert(DoLockModesConflict(realRelOpts[i].gen.lockmode,
@@ -637,6 +650,14 @@ initialize_reloptions(void)
j++;
}
+ for (i = 0; int64RelOpts[i].gen.name; i++)
+ {
+ relOpts[j] = &int64RelOpts[i].gen;
+ relOpts[j]->type = RELOPT_TYPE_INT64;
+ relOpts[j]->namelen = strlen(relOpts[j]->name);
+ j++;
+ }
+
for (i = 0; realRelOpts[i].gen.name; i++)
{
relOpts[j] = &realRelOpts[i].gen;
@@ -792,6 +813,9 @@ allocate_reloption(bits32 kinds, int type, const char *name, const char *desc,
case RELOPT_TYPE_INT:
size = sizeof(relopt_int);
break;
+ case RELOPT_TYPE_INT64:
+ size = sizeof(relopt_int64);
+ break;
case RELOPT_TYPE_REAL:
size = sizeof(relopt_real);
break;
@@ -946,6 +970,26 @@ init_real_reloption(bits32 kinds, const char *name, const char *desc,
return newoption;
}
+/*
+ * add_int64_reloption
+ * Add a new 64-bit integer reloption
+ */
+void
+add_int64_reloption(bits32 kinds, const char *name, char *desc,
+ int64 default_val, int64 min_val, int64 max_val,
+ LOCKMODE lockmode)
+{
+ relopt_int64 *newoption;
+
+ newoption = (relopt_int64 *) allocate_reloption(kinds, RELOPT_TYPE_INT64,
+ name, desc, lockmode);
+ newoption->default_val = default_val;
+ newoption->min = min_val;
+ newoption->max = max_val;
+
+ add_reloption((relopt_gen *) newoption);
+}
+
/*
* add_real_reloption
* Add a new float reloption
@@ -1617,6 +1661,28 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len,
optint->min, optint->max)));
}
break;
+ case RELOPT_TYPE_INT64:
+ {
+ relopt_int64 *optint = (relopt_int64 *) option->gen;
+
+ parsed = parse_int64(value, &option->values.int64_val, 0, NULL);
+ if (validate && !parsed)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("invalid value for 64-bit integer option \"%s\": %s",
+ option->gen->name, value)));
+ if (validate && (option->values.int64_val < optint->min ||
+ option->values.int64_val > optint->max))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("value %s out of bounds for option \"%s\"",
+ value, option->gen->name),
+ errdetail("Valid values are between \"%lld"
+ "\" and \"%lld\".",
+ (long long ) optint->min,
+ (long long) optint->max)));
+ }
+ break;
case RELOPT_TYPE_REAL:
{
relopt_real *optreal = (relopt_real *) option->gen;
@@ -1772,6 +1838,11 @@ fillRelOptions(void *rdopts, Size basesize,
options[i].values.int_val :
((relopt_int *) options[i].gen)->default_val;
break;
+ case RELOPT_TYPE_INT64:
+ *(int64 *) itempos = options[i].isset ?
+ options[i].values.int64_val :
+ ((relopt_int64 *) options[i].gen)->default_val;
+ break;
case RELOPT_TYPE_REAL:
*(double *) itempos = options[i].isset ?
options[i].values.real_val :
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 547cecde24..24b74015c7 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -265,6 +265,8 @@ static bool call_bool_check_hook(struct config_bool *conf, bool *newval,
void **extra, GucSource source, int elevel);
static bool call_int_check_hook(struct config_int *conf, int *newval,
void **extra, GucSource source, int elevel);
+static bool call_int64_check_hook(struct config_int64 *conf, int64 *newval,
+ void **extra, GucSource source, int elevel);
static bool call_real_check_hook(struct config_real *conf, double *newval,
void **extra, GucSource source, int elevel);
static bool call_string_check_hook(struct config_string *conf, char **newval,
@@ -762,6 +764,10 @@ extra_field_used(struct config_generic *gconf, void *extra)
if (extra == ((struct config_int *) gconf)->reset_extra)
return true;
break;
+ case PGC_INT64:
+ if (extra == ((struct config_int64 *) gconf)->reset_extra)
+ return true;
+ break;
case PGC_REAL:
if (extra == ((struct config_real *) gconf)->reset_extra)
return true;
@@ -823,6 +829,10 @@ set_stack_value(struct config_generic *gconf, config_var_value *val)
val->val.intval =
*((struct config_int *) gconf)->variable;
break;
+ case PGC_INT64:
+ val->val.int64val =
+ *((struct config_int64 *) gconf)->variable;
+ break;
case PGC_REAL:
val->val.realval =
*((struct config_real *) gconf)->variable;
@@ -851,6 +861,7 @@ discard_stack_value(struct config_generic *gconf, config_var_value *val)
{
case PGC_BOOL:
case PGC_INT:
+ case PGC_INT64:
case PGC_REAL:
case PGC_ENUM:
/* no need to do anything */
@@ -939,6 +950,14 @@ build_guc_variables(void)
num_vars++;
}
+ for (i = 0; ConfigureNamesInt64[i].gen.name; i++)
+ {
+ struct config_int64 *conf = &ConfigureNamesInt64[i];
+
+ conf->gen.vartype = PGC_INT64;
+ num_vars++;
+ }
+
for (i = 0; ConfigureNamesReal[i].gen.name; i++)
{
struct config_real *conf = &ConfigureNamesReal[i];
@@ -1002,6 +1021,18 @@ build_guc_variables(void)
hentry->gucvar = gucvar;
}
+ for (i = 0; ConfigureNamesInt64[i].gen.name; i++)
+ {
+ struct config_generic *gucvar = &ConfigureNamesInt64[i].gen;
+
+ hentry = (GUCHashEntry *) hash_search(guc_hashtab,
+ &gucvar->name,
+ HASH_ENTER,
+ &found);
+ Assert(!found);
+ hentry->gucvar = gucvar;
+ }
+
for (i = 0; ConfigureNamesReal[i].gen.name; i++)
{
struct config_generic *gucvar = &ConfigureNamesReal[i].gen;
@@ -1429,6 +1460,7 @@ check_GUC_name_for_parameter_acl(const char *name)
* The following validation rules apply for the values:
* bool - can be false, otherwise must be same as the boot_val
* int - can be 0, otherwise must be same as the boot_val
+ * int64 - can be 0, otherwise must be same as the boot_val
* real - can be 0.0, otherwise must be same as the boot_val
* string - can be NULL, otherwise must be strcmp equal to the boot_val
* enum - must be same as the boot_val
@@ -1464,6 +1496,20 @@ check_GUC_init(struct config_generic *gconf)
}
break;
}
+ case PGC_INT64:
+ {
+ struct config_int64 *conf = (struct config_int64 *) gconf;
+
+ if (*conf->variable != 0 && *conf->variable != conf->boot_val)
+ {
+ elog(LOG, "GUC (PGC_INT64) %s, boot_val=%lld, C-var=%lld",
+ conf->gen.name,
+ (long long) conf->boot_val,
+ (long long) *conf->variable);
+ return false;
+ }
+ break;
+ }
case PGC_REAL:
{
struct config_real *conf = (struct config_real *) gconf;
@@ -1694,6 +1740,24 @@ InitializeOneGUCOption(struct config_generic *gconf)
conf->gen.extra = conf->reset_extra = extra;
break;
}
+ case PGC_INT64:
+ {
+ struct config_int64 *conf = (struct config_int64 *) gconf;
+ int64 newval = conf->boot_val;
+ void *extra = NULL;
+
+ Assert(newval >= conf->min);
+ Assert(newval <= conf->max);
+ if (!call_int64_check_hook(conf, &newval, &extra,
+ PGC_S_DEFAULT, LOG))
+ elog(FATAL, "failed to initialize %s to %lld",
+ conf->gen.name, (long long) newval);
+ if (conf->assign_hook)
+ (*conf->assign_hook) (newval, extra);
+ *conf->variable = conf->reset_val = newval;
+ conf->gen.extra = conf->reset_extra = extra;
+ break;
+ }
case PGC_REAL:
{
struct config_real *conf = (struct config_real *) gconf;
@@ -2044,6 +2108,18 @@ ResetAllOptions(void)
{
struct config_int *conf = (struct config_int *) gconf;
+ if (conf->assign_hook)
+ conf->assign_hook(conf->reset_val,
+ conf->reset_extra);
+ *conf->variable = conf->reset_val;
+ set_extra_field(&conf->gen, &conf->gen.extra,
+ conf->reset_extra);
+ break;
+ }
+ case PGC_INT64:
+ {
+ struct config_int64 *conf = (struct config_int64 *) gconf;
+
if (conf->assign_hook)
conf->assign_hook(conf->reset_val,
conf->reset_extra);
@@ -2427,6 +2503,24 @@ AtEOXact_GUC(bool isCommit, int nestLevel)
int newval = newvalue.val.intval;
void *newextra = newvalue.extra;
+ if (*conf->variable != newval ||
+ conf->gen.extra != newextra)
+ {
+ if (conf->assign_hook)
+ conf->assign_hook(newval, newextra);
+ *conf->variable = newval;
+ set_extra_field(&conf->gen, &conf->gen.extra,
+ newextra);
+ changed = true;
+ }
+ break;
+ }
+ case PGC_INT64:
+ {
+ struct config_int64 *conf = (struct config_int64 *) gconf;
+ int64 newval = newvalue.val.int64val;
+ void *newextra = newvalue.extra;
+
if (*conf->variable != newval ||
conf->gen.extra != newextra)
{
@@ -2949,6 +3043,71 @@ parse_int(const char *value, int *result, int flags, const char **hintmsg)
return true;
}
+/*
+ * Try to parse value as an 64-bit integer. The accepted format is
+ * decimal number.
+ *
+ * If the string parses okay, return true, else false.
+ * If okay and result is not NULL, return the value in *result.
+ * If not okay and hintmsg is not NULL, *hintmsg is set to a suitable
+ * HINT message, or NULL if no hint provided.
+ */
+bool
+parse_int64(const char *value, int64 *result, int flags, const char **hintmsg)
+{
+ int64 val;
+ char *endptr;
+
+ /* To suppress compiler warnings, always set output params */
+ if (result)
+ *result = 0;
+ if (hintmsg)
+ *hintmsg = NULL;
+
+ /* We assume here that int64 is at least as wide as long */
+ errno = 0;
+ val = strtoi64(value, &endptr, 0);
+
+ if (endptr == value)
+ return false; /* no HINT for integer syntax error */
+
+ if (errno == ERANGE)
+ {
+ if (hintmsg)
+ *hintmsg = gettext_noop("Value exceeds 64-bit integer range.");
+ return false;
+ }
+
+ /*
+ * got double format and/or units. For now we attempts parse it as double
+ * and throw error on 53bit overflow
+ */
+ if (*endptr != '\0')
+ {
+ double dval;
+ bool ok;
+
+ ok = parse_real(value, &dval, flags, hintmsg);
+ if (!ok)
+ return false;
+
+ dval = rint(val);
+
+ if (fabs(dval) >= (double) ((uint64) 1 << 53))
+ {
+ *hintmsg = gettext_noop("Int64 value with units should be positive number < 2^53");
+ return false;
+ }
+
+ val = (int64) dval;
+ }
+
+
+ if (result)
+ *result = val;
+ return true;
+}
+
/*
* Try to parse value as a floating point number in the usual format.
* Optionally, the value can be followed by a unit name if "flags" indicates
@@ -3195,6 +3354,36 @@ parse_and_validate_value(struct config_generic *record,
return false;
}
break;
+ case PGC_INT64:
+ {
+ struct config_int64 *conf = (struct config_int64 *) record;
+ const char *hintmsg;
+
+ if (!parse_int64(value, &newval->int64val, conf->gen.flags, &hintmsg))
+ {
+ ereport(elevel,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("invalid value for parameter \"%s\": \"%s\"",
+ name, value),
+ hintmsg ? errhint("%s", _(hintmsg)) : 0));
+ return false;
+ }
+
+ if (newval->int64val < conf->min || newval->int64val > conf->max)
+ {
+ ereport(elevel,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("%lld is outside the valid range for parameter \"%s\" (%lld .. %lld)",
+ (long long) newval->int64val, name,
+ (long long) conf->min, (long long) conf->max)));
+ return false;
+ }
+
+ if (!call_int64_check_hook(conf, &newval->int64val, newextra,
+ source, elevel))
+ return false;
+ }
+ break;
case PGC_REAL:
{
struct config_real *conf = (struct config_real *) record;
@@ -3889,6 +4078,96 @@ set_config_with_handle(const char *name, config_handle *handle,
guc_free(newextra);
break;
+#undef newval
+ }
+
+ case PGC_INT64:
+ {
+ struct config_int64 *conf = (struct config_int64 *) record;
+
+#define newval (newval_union.int64val)
+
+ if (value)
+ {
+ if (!parse_and_validate_value(record, name, value,
+ source, elevel,
+ &newval_union, &newextra))
+ return 0;
+ }
+ else if (source == PGC_S_DEFAULT)
+ {
+ newval = conf->boot_val;
+ if (!call_int64_check_hook(conf, &newval, &newextra,
+ source, elevel))
+ return 0;
+ }
+ else
+ {
+ newval = conf->reset_val;
+ newextra = conf->reset_extra;
+ source = conf->gen.reset_source;
+ context = conf->gen.reset_scontext;
+ }
+
+ if (prohibitValueChange)
+ {
+ if (*conf->variable != newval)
+ {
+ record->status |= GUC_PENDING_RESTART;
+ ereport(elevel,
+ (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM),
+ errmsg("parameter \"%s\" cannot be changed without restarting the server",
+ name)));
+ return 0;
+ }
+ record->status &= ~GUC_PENDING_RESTART;
+ return -1;
+ }
+
+ if (changeVal)
+ {
+ /* Save old value to support transaction abort */
+ if (!makeDefault)
+ push_old_value(&conf->gen, action);
+
+ if (conf->assign_hook)
+ (*conf->assign_hook) (newval, newextra);
+ *conf->variable = newval;
+ set_extra_field(&conf->gen, &conf->gen.extra,
+ newextra);
+ conf->gen.source = source;
+ conf->gen.scontext = context;
+ }
+ if (makeDefault)
+ {
+ GucStack *stack;
+
+ if (conf->gen.reset_source <= source)
+ {
+ conf->reset_val = newval;
+ set_extra_field(&conf->gen, &conf->reset_extra,
+ newextra);
+ conf->gen.reset_source = source;
+ conf->gen.reset_scontext = context;
+ }
+ for (stack = conf->gen.stack; stack; stack = stack->prev)
+ {
+ if (stack->source <= source)
+ {
+ stack->prior.val.intval = newval;
+ set_extra_field(&conf->gen, &stack->prior.extra,
+ newextra);
+ stack->source = source;
+ stack->scontext = context;
+ }
+ }
+ }
+
+ /* Perhaps we didn't install newextra anywhere */
+ if (newextra && !extra_field_used(&conf->gen, newextra))
+ guc_free(newextra);
+ break;
+
#undef newval
}
@@ -4331,6 +4610,11 @@ GetConfigOption(const char *name, bool missing_ok, bool restrict_privileged)
*((struct config_int *) record)->variable);
return buffer;
+ case PGC_INT64:
+ snprintf(buffer, sizeof(buffer), "%lld",
+ (long long) *((struct config_int64 *) record)->variable);
+ return buffer;
+
case PGC_REAL:
snprintf(buffer, sizeof(buffer), "%g",
*((struct config_real *) record)->variable);
@@ -4379,6 +4663,11 @@ GetConfigOptionResetString(const char *name)
((struct config_int *) record)->reset_val);
return buffer;
+ case PGC_INT64:
+ snprintf(buffer, sizeof(buffer), "%lld",
+ (long long) ((struct config_int64 *) record)->reset_val);
+ return buffer;
+
case PGC_REAL:
snprintf(buffer, sizeof(buffer), "%g",
((struct config_real *) record)->reset_val);
@@ -5330,6 +5619,14 @@ get_explain_guc_options(int *num)
}
break;
+ case PGC_INT64:
+ {
+ struct config_int64 *lconf = (struct config_int64 *) conf;
+
+ modified = (lconf->boot_val != *(lconf->variable));
+ }
+ break;
+
case PGC_REAL:
{
struct config_real *lconf = (struct config_real *) conf;
@@ -5462,6 +5759,21 @@ ShowGUCOption(struct config_generic *record, bool use_units)
}
break;
+ case PGC_INT64:
+ {
+ struct config_int64 *conf = (struct config_int64 *) record;
+
+ if (conf->show_hook)
+ val = (*conf->show_hook) ();
+ else
+ {
+ snprintf(buffer, sizeof(buffer), "%lld",
+ (long long) *conf->variable);
+ val = buffer;
+ }
+ }
+ break;
+
case PGC_REAL:
{
struct config_real *conf = (struct config_real *) record;
@@ -5564,6 +5876,14 @@ write_one_nondefault_variable(FILE *fp, struct config_generic *gconf)
}
break;
+ case PGC_INT64:
+ {
+ struct config_int64 *conf = (struct config_int64 *) gconf;
+
+ fprintf(fp, "%lld", (long long) *conf->variable);
+ }
+ break;
+
case PGC_REAL:
{
struct config_real *conf = (struct config_real *) gconf;
@@ -5842,6 +6162,24 @@ estimate_variable_size(struct config_generic *gconf)
}
break;
+ case PGC_INT64:
+ {
+ struct config_int64 *conf = (struct config_int64 *) gconf;
+
+ /*
+ * Instead of getting the exact display length, use max
+ * length. Also reduce the max length for typical ranges of
+ * small values. Maximum value is 2^63, i.e. 20 chars.
+ * Include one byte for sign.
+ */
+#define ABS(x) ((x) >= 0 ? (x) : -(x))
+ if (ABS(*conf->variable) < 1000)
+ valsize = 3 + 1;
+ else
+ valsize = 20 + 1;
+ }
+ break;
+
case PGC_REAL:
{
/*
@@ -6008,6 +6346,14 @@ serialize_variable(char **destptr, Size *maxbytes,
}
break;
+ case PGC_INT64:
+ {
+ struct config_int64 *conf = (struct config_int64 *) gconf;
+
+ do_serialize(destptr, maxbytes, "%lld", (long long) *conf->variable);
+ }
+ break;
+
case PGC_REAL:
{
struct config_real *conf = (struct config_real *) gconf;
@@ -6221,6 +6567,14 @@ RestoreGUCState(void *gucstate)
{
struct config_int *conf = (struct config_int *) gconf;
+ if (conf->reset_extra && conf->reset_extra != gconf->extra)
+ guc_free(conf->reset_extra);
+ break;
+ }
+ case PGC_INT64:
+ {
+ struct config_int64 *conf = (struct config_int64 *) gconf;
+
if (conf->reset_extra && conf->reset_extra != gconf->extra)
guc_free(conf->reset_extra);
break;
@@ -6821,6 +7175,40 @@ call_int_check_hook(struct config_int *conf, int *newval, void **extra,
return true;
}
+static bool
+call_int64_check_hook(struct config_int64 *conf, int64 *newval, void **extra,
+ GucSource source, int elevel)
+{
+ /* Quick success if no hook */
+ if (!conf->check_hook)
+ return true;
+
+ /* Reset variables that might be set by hook */
+ GUC_check_errcode_value = ERRCODE_INVALID_PARAMETER_VALUE;
+ GUC_check_errmsg_string = NULL;
+ GUC_check_errdetail_string = NULL;
+ GUC_check_errhint_string = NULL;
+
+ if (!(*conf->check_hook) (newval, extra, source))
+ {
+ ereport(elevel,
+ (errcode(GUC_check_errcode_value),
+ GUC_check_errmsg_string ?
+ errmsg_internal("%s", GUC_check_errmsg_string) :
+ errmsg("invalid value for parameter \"%s\": %lld",
+ conf->gen.name, (long long) *newval),
+ GUC_check_errdetail_string ?
+ errdetail_internal("%s", GUC_check_errdetail_string) : 0,
+ GUC_check_errhint_string ?
+ errhint("%s", GUC_check_errhint_string) : 0));
+ /* Flush any strings created in ErrorContext */
+ FlushErrorState();
+ return false;
+ }
+
+ return true;
+}
+
static bool
call_real_check_hook(struct config_real *conf, double *newval, void **extra,
GucSource source, int elevel)
diff --git a/src/backend/utils/misc/guc_funcs.c b/src/backend/utils/misc/guc_funcs.c
index 9c9edd3d2f..d0625d18b3 100644
--- a/src/backend/utils/misc/guc_funcs.c
+++ b/src/backend/utils/misc/guc_funcs.c
@@ -673,6 +673,31 @@ GetConfigOptionValues(struct config_generic *conf, const char **values)
}
break;
+ case PGC_INT64:
+ {
+ struct config_int64 *lconf = (struct config_int64 *) conf;
+
+ /* min_val */
+ snprintf(buffer, sizeof(buffer), "%lld", (long long) lconf->min);
+ values[9] = pstrdup(buffer);
+
+ /* max_val */
+ snprintf(buffer, sizeof(buffer), "%lld", (long long) lconf->max);
+ values[10] = pstrdup(buffer);
+
+ /* enumvals */
+ values[11] = NULL;
+
+ /* boot_val */
+ snprintf(buffer, sizeof(buffer), "%lld", (long long) lconf->boot_val);
+ values[12] = pstrdup(buffer);
+
+ /* reset_val */
+ snprintf(buffer, sizeof(buffer), "%lld", (long long) lconf->reset_val);
+ values[13] = pstrdup(buffer);
+ }
+ break;
+
case PGC_REAL:
{
struct config_real *lconf = (struct config_real *) conf;
diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c
index 46c258be28..635b72213a 100644
--- a/src/backend/utils/misc/guc_tables.c
+++ b/src/backend/utils/misc/guc_tables.c
@@ -731,6 +731,7 @@ const char *const config_type_names[] =
{
[PGC_BOOL] = "bool",
[PGC_INT] = "integer",
+ [PGC_INT64] = "int64",
[PGC_REAL] = "real",
[PGC_STRING] = "string",
[PGC_ENUM] = "enum",
@@ -3654,6 +3655,15 @@ struct config_int ConfigureNamesInt[] =
};
+struct config_int64 ConfigureNamesInt64[] =
+{
+ /* End-of-list marker */
+ {
+ {NULL, 0, 0, NULL, NULL}, NULL, 0, 0, 0, NULL, NULL, NULL
+ }
+};
+
+
struct config_real ConfigureNamesReal[] =
{
{
diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h
index 81829b8270..1c175a941f 100644
--- a/src/include/access/reloptions.h
+++ b/src/include/access/reloptions.h
@@ -30,6 +30,7 @@ typedef enum relopt_type
{
RELOPT_TYPE_BOOL,
RELOPT_TYPE_INT,
+ RELOPT_TYPE_INT64,
RELOPT_TYPE_REAL,
RELOPT_TYPE_ENUM,
RELOPT_TYPE_STRING,
@@ -81,6 +82,7 @@ typedef struct relopt_value
{
bool bool_val;
int int_val;
+ int64 int64_val;
double real_val;
int enum_val;
char *string_val; /* allocated separately */
@@ -102,6 +104,14 @@ typedef struct relopt_int
int max;
} relopt_int;
+typedef struct relopt_int64
+{
+ relopt_gen gen;
+ int64 default_val;
+ int64 min;
+ int64 max;
+} relopt_int64;
+
typedef struct relopt_real
{
relopt_gen gen;
@@ -185,6 +195,9 @@ extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc,
extern void add_int_reloption(bits32 kinds, const char *name, const char *desc,
int default_val, int min_val, int max_val,
LOCKMODE lockmode);
+extern void add_int64_reloption(bits32 kinds, const char *name, char *desc,
+ int64 default_val, int64 min_val, int64 max_val,
+ LOCKMODE lockmode);
extern void add_real_reloption(bits32 kinds, const char *name, const char *desc,
double default_val, double min_val, double max_val,
LOCKMODE lockmode);
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index ff506bf48d..9cbaddca32 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -178,12 +178,14 @@ struct config_enum_entry
*/
typedef bool (*GucBoolCheckHook) (bool *newval, void **extra, GucSource source);
typedef bool (*GucIntCheckHook) (int *newval, void **extra, GucSource source);
+typedef bool (*GucInt64CheckHook) (int64 *newval, void **extra, GucSource source);
typedef bool (*GucRealCheckHook) (double *newval, void **extra, GucSource source);
typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource source);
typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source);
typedef void (*GucBoolAssignHook) (bool newval, void *extra);
typedef void (*GucIntAssignHook) (int newval, void *extra);
+typedef void (*GucInt64AssignHook) (int64 newval, void *extra);
typedef void (*GucRealAssignHook) (double newval, void *extra);
typedef void (*GucStringAssignHook) (const char *newval, void *extra);
typedef void (*GucEnumAssignHook) (int newval, void *extra);
@@ -319,6 +321,19 @@ extern void DefineCustomIntVariable(const char *name,
GucIntAssignHook assign_hook,
GucShowHook show_hook) pg_attribute_nonnull(1, 4);
+extern void DefineCustomInt64Variable(const char *name,
+ const char *short_desc,
+ const char *long_desc,
+ int64 *valueAddr,
+ int64 bootValue,
+ int64 minValue,
+ int64 maxValue,
+ GucContext context,
+ int flags,
+ GucInt64CheckHook check_hook,
+ GucInt64AssignHook assign_hook,
+ GucShowHook show_hook);
+
extern void DefineCustomRealVariable(const char *name,
const char *short_desc,
const char *long_desc,
@@ -380,6 +395,8 @@ extern void ParseLongOption(const char *string, char **name, char **value);
extern const char *get_config_unit_name(int flags);
extern bool parse_int(const char *value, int *result, int flags,
const char **hintmsg);
+extern bool parse_int64(const char *value, int64 *result, int flags,
+ const char **hintmsg);
extern bool parse_real(const char *value, double *result, int flags,
const char **hintmsg);
extern int set_config_option(const char *name, const char *value,
diff --git a/src/include/utils/guc_tables.h b/src/include/utils/guc_tables.h
index 0c0277c423..c4dfe0afab 100644
--- a/src/include/utils/guc_tables.h
+++ b/src/include/utils/guc_tables.h
@@ -24,6 +24,7 @@ enum config_type
{
PGC_BOOL,
PGC_INT,
+ PGC_INT64,
PGC_REAL,
PGC_STRING,
PGC_ENUM,
@@ -33,6 +34,7 @@ union config_var_val
{
bool boolval;
int intval;
+ int64 int64val;
double realval;
char *stringval;
int enumval;
@@ -225,6 +227,22 @@ struct config_int
void *reset_extra;
};
+struct config_int64
+{
+ struct config_generic gen;
+ /* constant fields, must be set correctly in initial value: */
+ int64 *variable;
+ int64 boot_val;
+ int64 min;
+ int64 max;
+ GucInt64CheckHook check_hook;
+ GucInt64AssignHook assign_hook;
+ GucShowHook show_hook;
+ /* variable fields, initialized at runtime: */
+ int64 reset_val;
+ void *reset_extra;
+};
+
struct config_real
{
struct config_generic gen;
@@ -289,6 +307,7 @@ extern PGDLLIMPORT const char *const GucSource_Names[];
/* data arrays defining all the built-in GUC variables */
extern PGDLLIMPORT struct config_bool ConfigureNamesBool[];
extern PGDLLIMPORT struct config_int ConfigureNamesInt[];
+extern PGDLLIMPORT struct config_int64 ConfigureNamesInt64[];
extern PGDLLIMPORT struct config_real ConfigureNamesReal[];
extern PGDLLIMPORT struct config_string ConfigureNamesString[];
extern PGDLLIMPORT struct config_enum ConfigureNamesEnum[];
--
2.45.2