From fbb691c006290a7379c6cb0d3c7be3e53b0d052e Mon Sep 17 00:00:00 2001 From: Maxim Orlov Date: Fri, 11 Mar 2022 11:34:26 +0300 Subject: [PATCH v48 7/8] Use 64-bit GUCs Authors: - Alexander Korotkov - Teodor Sigaev - Nikita Glukhov - Maxim Orlov - Pavel Borisov - Yura Sokolov Reviewed-by: Aleksander Alekseev 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 | 69 +++++ src/backend/utils/misc/guc.c | 365 +++++++++++++++++++++++++ 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, 518 insertions(+) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 6458a9c276..b0993f37d4 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -382,7 +382,12 @@ static relopt_int intRelOpts[] = }, -1, 0, 1024 }, + /* list terminator */ + {{NULL}} +}; +static relopt_int64 int64RelOpts[] = +{ /* list terminator */ {{NULL}} }; @@ -597,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, @@ -639,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; @@ -794,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; @@ -948,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 @@ -1619,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; @@ -1774,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 6f21752b84..eb67cf207e 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -255,6 +255,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, @@ -752,6 +754,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; @@ -813,6 +819,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; @@ -841,6 +851,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 */ @@ -992,6 +1003,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; @@ -1552,6 +1575,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; @@ -1903,6 +1944,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); @@ -2273,6 +2326,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) { @@ -2795,6 +2866,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 @@ -3036,6 +3172,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; @@ -3691,6 +3857,96 @@ set_config_option_ext(const char *name, const char *value, 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)) + free(newextra); + break; + #undef newval } @@ -4118,6 +4374,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); @@ -4165,6 +4426,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); @@ -5096,6 +5362,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; @@ -5221,6 +5495,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; @@ -5323,6 +5612,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; @@ -5600,6 +5897,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: { /* @@ -5766,6 +6081,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; @@ -5983,6 +6306,14 @@ RestoreGUCState(void *gucstate) 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) + free(conf->reset_extra); + break; + } case PGC_REAL: { struct config_real *conf = (struct config_real *) gconf; @@ -6548,6 +6879,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 108b3bd129..6811c62338 100644 --- a/src/backend/utils/misc/guc_funcs.c +++ b/src/backend/utils/misc/guc_funcs.c @@ -668,6 +668,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 05ab087934..8869eb4112 100644 --- a/src/backend/utils/misc/guc_tables.c +++ b/src/backend/utils/misc/guc_tables.c @@ -727,6 +727,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" @@ -3412,6 +3413,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 21bde78ed0..b8a8eb84e7 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 b3aaff9665..d7c4105a84 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -176,12 +176,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); @@ -316,6 +318,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, @@ -376,6 +391,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 51f7f09fde..cd91ef69eb 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; @@ -224,6 +226,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; @@ -278,6 +296,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.37.0 (Apple Git-136)