From 014264c4054594d92422106ee15ce2891bb1a7ea Mon Sep 17 00:00:00 2001 From: Yura Sokolov Date: Wed, 29 Dec 2021 18:44:34 +0300 Subject: [PATCH v6 1/2] Add 64-bit GUCs for xids Authors: - Alexander Korotkov - Teodor Sigaev - Nikita Glukhov - Konstantin Knizhnik - Maxim Orlov - Pavel Borisov - Yura Sokolov --- src/backend/access/common/reloptions.c | 67 ++++ src/backend/utils/misc/guc.c | 432 +++++++++++++++++++++++++ src/include/access/reloptions.h | 13 + src/include/utils/guc.h | 17 + src/include/utils/guc_tables.h | 18 ++ 5 files changed, 547 insertions(+) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index b5602f53233..3420e47599c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -373,7 +373,12 @@ static relopt_int intRelOpts[] = }, -1, 0, 1024 }, + /* list terminator */ + {{NULL}} +}; +static relopt_int64 int64RelOpts[] = +{ /* list terminator */ {{NULL}} }; @@ -588,6 +593,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, @@ -630,6 +641,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; @@ -785,6 +804,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; @@ -939,6 +961,25 @@ 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, 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 @@ -1613,6 +1654,27 @@ 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 \"" INT64_FORMAT + "\" and \"" INT64_FORMAT "\".", + optint->min, optint->max))); + } + break; case RELOPT_TYPE_REAL: { relopt_real *optreal = (relopt_real *) option->gen; @@ -1768,6 +1830,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 bff949a40bc..8761fe068cf 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -161,6 +161,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, @@ -835,6 +837,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" @@ -941,6 +944,8 @@ static const unit_conversion time_unit_conversion_table[] = {""} /* end of table marker */ }; +static const char *int64_unit_overflow_hint = gettext_noop("Int64 value with units should be positive number < 2^53"); + /* * Contents of GUC tables * @@ -3866,6 +3871,15 @@ static struct config_real ConfigureNamesReal[] = }; +static struct config_int64 ConfigureNamesInt64[] = +{ + /* End-of-list marker */ + { + {NULL, 0, 0, NULL, NULL}, NULL, 0.0, 0.0, 0.0, NULL, NULL, NULL + } +}; + + static struct config_string ConfigureNamesString[] = { { @@ -5187,6 +5201,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; @@ -5248,6 +5266,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; @@ -5276,6 +5298,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 */ @@ -5330,6 +5353,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]; @@ -5370,6 +5401,9 @@ build_guc_variables(void) for (i = 0; ConfigureNamesInt[i].gen.name; i++) guc_vars[num_vars++] = &ConfigureNamesInt[i].gen; + for (i = 0; ConfigureNamesInt64[i].gen.name; i++) + guc_vars[num_vars++] = &ConfigureNamesInt64[i].gen; + for (i = 0; ConfigureNamesReal[i].gen.name; i++) guc_vars[num_vars++] = &ConfigureNamesReal[i].gen; @@ -5795,6 +5829,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 " INT64_FORMAT, + conf->gen.name, 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; @@ -6082,6 +6134,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); @@ -6428,6 +6492,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) { @@ -6956,6 +7038,79 @@ 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; +#ifdef _MSC_VER /* MSVC only */ + val = _strtoi64(value, &endptr, 0); +#elif defined(HAVE_STRTOLL) && SIZEOF_LONG < 8 + val = strtoll(value, &endptr, 0); +#else + val = strtol(value, &endptr, 0); +#endif + + 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 = int64_unit_overflow_hint; + 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 @@ -7197,6 +7352,37 @@ 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(INT64_FORMAT " is outside the valid range for parameter \"%s\" (" + INT64_FORMAT " .. " INT64_FORMAT ")", + newval->int64val, name, + conf->min, 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; @@ -7763,6 +7949,96 @@ set_config_option(const char *name, const char *value, 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)) + free(newextra); + break; + #undef newval } @@ -8178,6 +8454,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), INT64_FORMAT, + *((struct config_int64 *) record)->variable); + return buffer; + case PGC_REAL: snprintf(buffer, sizeof(buffer), "%g", *((struct config_real *) record)->variable); @@ -8225,6 +8506,11 @@ GetConfigOptionResetString(const char *name) ((struct config_int *) record)->reset_val); return buffer; + case PGC_INT64: + snprintf(buffer, sizeof(buffer), INT64_FORMAT, + ((struct config_int64 *) record)->reset_val); + return buffer; + case PGC_REAL: snprintf(buffer, sizeof(buffer), "%g", ((struct config_real *) record)->reset_val); @@ -9253,6 +9539,36 @@ DefineCustomIntVariable(const char *name, define_custom_variable(&var->gen); } +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) +{ + struct config_int64 *var; + + var = (struct config_int64 *) + init_custom_variable(name, short_desc, long_desc, context, flags, + PGC_INT64, sizeof(struct config_int64)); + var->variable = valueAddr; + var->boot_val = bootValue; + var->reset_val = bootValue; + var->min = minValue; + var->max = maxValue; + var->check_hook = check_hook; + var->assign_hook = assign_hook; + var->show_hook = show_hook; + define_custom_variable(&var->gen); +} + void DefineCustomRealVariable(const char *name, const char *short_desc, @@ -9772,6 +10088,31 @@ GetConfigOptionByNum(int varnum, const char **values, bool *noshow) } break; + case PGC_INT64: + { + struct config_int64 *lconf = (struct config_int64 *) conf; + + /* min_val */ + snprintf(buffer, sizeof(buffer), INT64_FORMAT, lconf->min); + values[9] = pstrdup(buffer); + + /* max_val */ + snprintf(buffer, sizeof(buffer), INT64_FORMAT, lconf->max); + values[10] = pstrdup(buffer); + + /* enumvals */ + values[11] = NULL; + + /* boot_val */ + snprintf(buffer, sizeof(buffer), INT64_FORMAT, lconf->boot_val); + values[12] = pstrdup(buffer); + + /* reset_val */ + snprintf(buffer, sizeof(buffer), INT64_FORMAT, lconf->reset_val); + values[13] = pstrdup(buffer); + } + break; + case PGC_REAL: { struct config_real *lconf = (struct config_real *) conf; @@ -10244,6 +10585,21 @@ _ShowOption(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), INT64_FORMAT, + *conf->variable); + val = buffer; + } + } + break; + case PGC_REAL: { struct config_real *conf = (struct config_real *) record; @@ -10346,6 +10702,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, INT64_FORMAT, *conf->variable); + } + break; + case PGC_REAL: { struct config_real *conf = (struct config_real *) gconf; @@ -10617,6 +10981,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. + */ + if (Abs(*conf->variable) < 1000) + valsize = 3 + 1; + else + valsize = 20 + 1; + } + break; + + case PGC_REAL: { /* @@ -10774,6 +11156,14 @@ serialize_variable(char **destptr, Size *maxbytes, } break; + case PGC_INT64: + { + struct config_int64 *conf = (struct config_int64 *) gconf; + + do_serialize(destptr, maxbytes, INT64_FORMAT, *conf->variable); + } + break; + case PGC_REAL: { struct config_real *conf = (struct config_real *) gconf; @@ -10979,6 +11369,14 @@ RestoreGUCState(void *gucstate) { struct config_int *conf = (struct config_int *) gconf; + if (conf->reset_extra && conf->reset_extra != gconf->extra) + 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) free(conf->reset_extra); break; @@ -11553,6 +11951,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\": " INT64_FORMAT, + conf->gen.name, *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/include/access/reloptions.h b/src/include/access/reloptions.h index 7c5fbeb517a..e4068dc0511 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, 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 aa18d304ac0..0618f20841d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -173,12 +173,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); @@ -318,6 +320,19 @@ extern void DefineCustomIntVariable(const char *name, GucIntAssignHook assign_hook, GucShowHook show_hook); +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, @@ -372,6 +387,8 @@ extern void ReportChangedGUCOptions(void); extern void ParseLongOption(const char *string, char **name, char **value); 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 6b40f1eeb8c..d06a0344172 100644 --- a/src/include/utils/guc_tables.h +++ b/src/include/utils/guc_tables.h @@ -23,6 +23,7 @@ enum config_type { PGC_BOOL, PGC_INT, + PGC_INT64, PGC_REAL, PGC_STRING, PGC_ENUM @@ -32,6 +33,7 @@ union config_var_val { bool boolval; int intval; + int64 int64val; double realval; char *stringval; int enumval; @@ -202,6 +204,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; -- 2.24.3 (Apple Git-128)