[PATCH] Support Int64 GUCs
Hi,
Attached is a self-sufficient patch extracted from a larger patchset
[1]: /messages/by-id/CAJ7c6TP9Ce021ebJ=5zOhMjiG3Wqg4hO6Mg0WsccErvAD9vZYA@mail.gmail.com
nearest future. Since there was interest in this particular patch it
deserves being discussed in a separate thread.
Currently we support 32-bit integer values in GUCs, but don't support
64-bit ones. The proposed patch adds this support.
Firstly, it adds DefineCustomInt64Variable() which can be used by the
extension authors.
Secondly, the following core GUCs are made 64-bit:
```
autovacuum_freeze_min_age
autovacuum_freeze_max_age
autovacuum_freeze_table_age
autovacuum_multixact_freeze_min_age
autovacuum_multixact_freeze_max_age
autovacuum_multixact_freeze_table_age
```
I see several open questions with the patch in its current state.
Firstly, I'm not sure if it is beneficial to affect the named GUCs out
of the context of the larger patchset. Perhaps we have better GUCs
that could benefit from being 64-bit? Or should we just leave alone
the core GUCs and focus on providing DefineCustomInt64Variable() ?
Secondly, DefineCustomInt64Variable() is not test-covered. Turned out
it was not even defined (although declared) in the original patch.
This was fixed in the attached version. Maybe one of the test modules
could use it even if it makes little sense for this particular module?
For instance, test/modules/worker_spi/ could use it for
worker_spi.naptime.
Last but not least, large values like 12345678912345 could be
difficult to read. Perhaps we should also support 12_345_678_912_345
syntax? This is not implemented in the attached patch and arguably
could be discussed separately when and if we merge it.
Thoughts?
[1]: /messages/by-id/CAJ7c6TP9Ce021ebJ=5zOhMjiG3Wqg4hO6Mg0WsccErvAD9vZYA@mail.gmail.com
--
Best regards,
Aleksander Alekseev
Attachments:
v1-0001-Support-64-bit-integer-GUCs.patchapplication/octet-stream; name=v1-0001-Support-64-bit-integer-GUCs.patchDownload
From 90c541d47a745a32f8a74529b6c1d9d74c6c0922 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 v1] Support 64-bit integer 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: TODO FIXME
---
src/backend/access/common/reloptions.c | 187 +++++++----
src/backend/utils/misc/guc.c | 418 +++++++++++++++++++++++++
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 ++
src/include/utils/rel.h | 14 +-
8 files changed, 638 insertions(+), 65 deletions(-)
diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
index 49fd35bfc5..62db0d231c 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 :
@@ -1849,17 +1920,17 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind)
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, analyze_threshold)},
{"autovacuum_vacuum_cost_limit", RELOPT_TYPE_INT,
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_cost_limit)},
- {"autovacuum_freeze_min_age", RELOPT_TYPE_INT,
+ {"autovacuum_freeze_min_age", RELOPT_TYPE_INT64,
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, freeze_min_age)},
- {"autovacuum_freeze_max_age", RELOPT_TYPE_INT,
+ {"autovacuum_freeze_max_age", RELOPT_TYPE_INT64,
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, freeze_max_age)},
- {"autovacuum_freeze_table_age", RELOPT_TYPE_INT,
+ {"autovacuum_freeze_table_age", RELOPT_TYPE_INT64,
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, freeze_table_age)},
- {"autovacuum_multixact_freeze_min_age", RELOPT_TYPE_INT,
+ {"autovacuum_multixact_freeze_min_age", RELOPT_TYPE_INT64,
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, multixact_freeze_min_age)},
- {"autovacuum_multixact_freeze_max_age", RELOPT_TYPE_INT,
+ {"autovacuum_multixact_freeze_max_age", RELOPT_TYPE_INT64,
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, multixact_freeze_max_age)},
- {"autovacuum_multixact_freeze_table_age", RELOPT_TYPE_INT,
+ {"autovacuum_multixact_freeze_table_age", RELOPT_TYPE_INT64,
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, multixact_freeze_table_age)},
{"log_autovacuum_min_duration", RELOPT_TYPE_INT,
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, log_min_duration)},
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 13527fc258..2798c04a54 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -262,6 +262,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,
@@ -759,6 +761,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;
@@ -820,6 +826,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;
@@ -848,6 +858,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 */
@@ -936,6 +947,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];
@@ -999,6 +1018,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;
@@ -1426,6 +1457,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
@@ -1461,6 +1493,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;
@@ -1691,6 +1737,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;
@@ -2041,6 +2105,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);
@@ -2424,6 +2500,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)
{
@@ -2946,6 +3040,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
@@ -3192,6 +3351,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;
@@ -3895,6 +4084,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
}
@@ -4337,6 +4616,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);
@@ -4385,6 +4669,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);
@@ -5143,6 +5432,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_int));
+ 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,
@@ -5336,6 +5655,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;
@@ -5468,6 +5795,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;
@@ -5570,6 +5912,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;
@@ -5848,6 +6198,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:
{
/*
@@ -6014,6 +6382,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;
@@ -6227,6 +6603,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;
@@ -6827,6 +7211,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 686309db58..3397808931 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",
@@ -3721,6 +3722,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 df6923c9d5..309c82ebf4 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 840b0fe57f..0a3fe0b54f 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);
@@ -348,6 +350,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) pg_attribute_nonnull(1, 4);
+
extern void DefineCustomRealVariable(const char *name,
const char *short_desc,
const char *long_desc,
@@ -409,6 +424,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[];
diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h
index 8700204953..442a11c329 100644
--- a/src/include/utils/rel.h
+++ b/src/include/utils/rel.h
@@ -312,13 +312,13 @@ typedef struct AutoVacOpts
int vacuum_ins_threshold;
int analyze_threshold;
int vacuum_cost_limit;
- int freeze_min_age;
- int freeze_max_age;
- int freeze_table_age;
- int multixact_freeze_min_age;
- int multixact_freeze_max_age;
- int multixact_freeze_table_age;
- int log_min_duration;
+ int64 freeze_min_age;
+ int64 freeze_max_age;
+ int64 freeze_table_age;
+ int64 multixact_freeze_min_age;
+ int64 multixact_freeze_max_age;
+ int64 multixact_freeze_table_age;
+ int64 log_min_duration;
float8 vacuum_cost_delay;
float8 vacuum_scale_factor;
float8 vacuum_ins_scale_factor;
--
2.46.0
Hi, Alexander!
Thank you for working on this!
On Thu, 12 Sept 2024 at 15:08, Aleksander Alekseev <aleksander@timescale.com>
wrote:
Hi,
Attached is a self-sufficient patch extracted from a larger patchset
[1]. The entire patchset probably will not proceed further in the
nearest future. Since there was interest in this particular patch it
deserves being discussed in a separate thread.Currently we support 32-bit integer values in GUCs, but don't support
64-bit ones. The proposed patch adds this support.Firstly, it adds DefineCustomInt64Variable() which can be used by the
extension authors.Secondly, the following core GUCs are made 64-bit:
```
autovacuum_freeze_min_age
autovacuum_freeze_max_age
autovacuum_freeze_table_age
autovacuum_multixact_freeze_min_age
autovacuum_multixact_freeze_max_age
autovacuum_multixact_freeze_table_age
```I see several open questions with the patch in its current state.
Firstly, I'm not sure if it is beneficial to affect the named GUCs out
of the context of the larger patchset. Perhaps we have better GUCs
that could benefit from being 64-bit? Or should we just leave alone
the core GUCs and focus on providing DefineCustomInt64Variable() ?
I think the direction is good and delivering 64-bit GUCs is very much worth
committing.
The patch itself looks good, but we could need to add locks against
concurrently modifying 64-bit values, which could be non-atomic on older
architectures.
Secondly, DefineCustomInt64Variable() is not test-covered. Turned out
it was not even defined (although declared) in the original patch.
This was fixed in the attached version. Maybe one of the test modules
could use it even if it makes little sense for this particular module?
For instance, test/modules/worker_spi/ could use it for
worker_spi.naptime.Last but not least, large values like 12345678912345 could be
difficult to read. Perhaps we should also support 12_345_678_912_345
syntax? This is not implemented in the attached patch and arguably
could be discussed separately when and if we merge it.
I think 12345678912345 is good enough. Underscore dividers make reading
little bit easier but look weird overall. I can't remember other places
where we output long numbers with dividers.
Regards,
Pavel Borisov
Supabase
Hi Pavel,
I think the direction is good and delivering 64-bit GUCs is very much worth committing.
The patch itself looks good, but we could need to add locks against concurrently modifying 64-bit values, which could be non-atomic on older architectures.
Thanks for the feedback.
I think 12345678912345 is good enough. Underscore dividers make reading little bit easier but look weird overall. I can't remember other places where we output long numbers with dividers.
We already support this in SQL:
psql (18devel)
=# SELECT 123_456;
?column?
----------
123456
--
Best regards,
Aleksander Alekseev
On Thu, Sep 12, 2024 at 02:08:15PM +0300, Aleksander Alekseev wrote:
Secondly, the following core GUCs are made 64-bit:
```
autovacuum_freeze_min_age
autovacuum_freeze_max_age
autovacuum_freeze_table_age
autovacuum_multixact_freeze_min_age
autovacuum_multixact_freeze_max_age
autovacuum_multixact_freeze_table_age
```I see several open questions with the patch in its current state.
Firstly, I'm not sure if it is beneficial to affect the named GUCs out
of the context of the larger patchset. Perhaps we have better GUCs
that could benefit from being 64-bit? Or should we just leave alone
the core GUCs and focus on providing DefineCustomInt64Variable() ?
I don't understand why we would want to make these GUCs 64-bit. All of the
allowed values fit in an int32, so AFAICT this would only serve to mislead
users into thinking they could set these much higher than they can/should.
TBH I'm quite skeptical that this would even be particularly useful for
extension authors. In what cases would a floating point value not suffice?
I'm not totally opposed to the idea of 64-bit GUCs, but I'd like more
information about the motivation.
--
nathan
On Thu, Sep 12, 2024 at 2:29 PM Pavel Borisov <pashkin.elfe@gmail.com> wrote:
Hi, Alexander!
Thank you for working on this!On Thu, 12 Sept 2024 at 15:08, Aleksander Alekseev <aleksander@timescale.com> wrote:
Hi,
Attached is a self-sufficient patch extracted from a larger patchset
[1]. The entire patchset probably will not proceed further in the
nearest future. Since there was interest in this particular patch it
deserves being discussed in a separate thread.Currently we support 32-bit integer values in GUCs, but don't support
64-bit ones. The proposed patch adds this support.Firstly, it adds DefineCustomInt64Variable() which can be used by the
extension authors.Secondly, the following core GUCs are made 64-bit:
```
autovacuum_freeze_min_age
autovacuum_freeze_max_age
autovacuum_freeze_table_age
autovacuum_multixact_freeze_min_age
autovacuum_multixact_freeze_max_age
autovacuum_multixact_freeze_table_age
```I see several open questions with the patch in its current state.
Firstly, I'm not sure if it is beneficial to affect the named GUCs out
of the context of the larger patchset. Perhaps we have better GUCs
that could benefit from being 64-bit? Or should we just leave alone
the core GUCs and focus on providing DefineCustomInt64Variable() ?I think the direction is good and delivering 64-bit GUCs is very much worth committing.
The patch itself looks good, but we could need to add locks against concurrently modifying 64-bit values, which could be non-atomic on older architectures.
GUCs are located in the local memory. No concurrent read/writes of
them are possible. It might happen that SIGHUP comes during
read/write of the GUC variable. But, that's protected the other way:
SignalHandlerForConfigReload() just sets the ConfigReloadPending flag,
which is processed during CHECK_FOR_INTERRUPTS(). So, I don't see a
need to locks here.
------
Regards,
Alexander Korotkov
Supabase
Hi, Aleksander!
Thank you for your work on this subject.
On Thu, Sep 12, 2024 at 2:08 PM Aleksander Alekseev
<aleksander@timescale.com> wrote:
Attached is a self-sufficient patch extracted from a larger patchset
[1]. The entire patchset probably will not proceed further in the
nearest future. Since there was interest in this particular patch it
deserves being discussed in a separate thread.Currently we support 32-bit integer values in GUCs, but don't support
64-bit ones. The proposed patch adds this support.Firstly, it adds DefineCustomInt64Variable() which can be used by the
extension authors.Secondly, the following core GUCs are made 64-bit:
```
autovacuum_freeze_min_age
autovacuum_freeze_max_age
autovacuum_freeze_table_age
autovacuum_multixact_freeze_min_age
autovacuum_multixact_freeze_max_age
autovacuum_multixact_freeze_table_age
```I see several open questions with the patch in its current state.
Firstly, I'm not sure if it is beneficial to affect the named GUCs out
of the context of the larger patchset. Perhaps we have better GUCs
that could benefit from being 64-bit? Or should we just leave alone
the core GUCs and focus on providing DefineCustomInt64Variable() ?
It doesn't look like these *_age GUCs could benefit from being 64-bit,
before 64-bit transaction ids get in. However, I think there are some
better candidates.
autovacuum_vacuum_threshold
autovacuum_vacuum_insert_threshold
autovacuum_analyze_threshold
This GUCs specify number of tuples before vacuum/analyze. That could
be more than 2^31. With large tables of small tuples, I can't even
say this is always impractical to have values greater than 2^31.
Secondly, DefineCustomInt64Variable() is not test-covered. Turned out
it was not even defined (although declared) in the original patch.
This was fixed in the attached version. Maybe one of the test modules
could use it even if it makes little sense for this particular module?
For instance, test/modules/worker_spi/ could use it for
worker_spi.naptime.
I don't think there are good candidates among existing extension GUCs.
I think we could add something for pure testing purposes somewhere in
src/test/modules.
Last but not least, large values like 12345678912345 could be
difficult to read. Perhaps we should also support 12_345_678_912_345
syntax? This is not implemented in the attached patch and arguably
could be discussed separately when and if we merge it.
I also think we're good with 12345678912345 so far.
------
Regards,
Alexander Korotkov
Supabase
Hi, Alexander!
Thank you for your work on this subject.
Thanks for your feedback.
It doesn't look like these *_age GUCs could benefit from being 64-bit,
before 64-bit transaction ids get in. However, I think there are some
better candidates.autovacuum_vacuum_threshold
autovacuum_vacuum_insert_threshold
autovacuum_analyze_thresholdThis GUCs specify number of tuples before vacuum/analyze. That could
be more than 2^31. With large tables of small tuples, I can't even
say this is always impractical to have values greater than 2^31.
Sounds good to me. Fixed.
Secondly, DefineCustomInt64Variable() is not test-covered. Turned out
it was not even defined (although declared) in the original patch.
This was fixed in the attached version. Maybe one of the test modules
could use it even if it makes little sense for this particular module?
For instance, test/modules/worker_spi/ could use it for
worker_spi.naptime.I don't think there are good candidates among existing extension GUCs.
I think we could add something for pure testing purposes somewhere in
src/test/modules.
I found a great candidate in src/test/modules/delay_execution:
```
DefineCustomIntVariable("delay_execution.post_planning_lock_id",
"Sets the advisory lock ID to be
locked/unlocked after planning.",
```
Advisory lock IDs are bigints [1]https://www.postgresql.org/docs/current/functions-admin.html#FUNCTIONS-ADVISORY-LOCKS. I modified the module to use Int64's.
I guess it may also answer Nathan's question.
Last but not least, large values like 12345678912345 could be
difficult to read. Perhaps we should also support 12_345_678_912_345
syntax? This is not implemented in the attached patch and arguably
could be discussed separately when and if we merge it.I also think we're good with 12345678912345 so far.
Fair enough.
PFA the updated patch.
[1]: https://www.postgresql.org/docs/current/functions-admin.html#FUNCTIONS-ADVISORY-LOCKS
--
Best regards,
Aleksander Alekseev
Attachments:
v2-0001-Support-64-bit-integer-GUCs.patchapplication/octet-stream; name=v2-0001-Support-64-bit-integer-GUCs.patchDownload
From 16338797f1cedfae86546e8826385872e8170c1c 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 v2] Support 64-bit integer 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/CAJ7c6TMvPz8q+nC=JoKniy7yxPzQYcCTnNFYmsDP-nnWsAOJ2g@mail.gmail.com
---
src/backend/access/common/reloptions.c | 129 ++++--
src/backend/utils/misc/guc.c | 418 ++++++++++++++++++
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 +
src/include/utils/rel.h | 6 +-
.../modules/delay_execution/delay_execution.c | 28 +-
.../expected/partition-addition.out | 6 +-
.../expected/partition-removal-1.out | 28 +-
.../specs/partition-addition.spec | 6 +-
.../specs/partition-removal-1.spec | 6 +-
13 files changed, 641 insertions(+), 70 deletions(-)
diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
index 49fd35bfc5..b989442942 100644
--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
@@ -222,33 +222,6 @@ static relopt_int intRelOpts[] =
},
SPGIST_DEFAULT_FILLFACTOR, SPGIST_MIN_FILLFACTOR, 100
},
- {
- {
- "autovacuum_vacuum_threshold",
- "Minimum number of tuple updates or deletes prior to vacuum",
- RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
- ShareUpdateExclusiveLock
- },
- -1, 0, INT_MAX
- },
- {
- {
- "autovacuum_vacuum_insert_threshold",
- "Minimum number of tuple inserts prior to vacuum, or -1 to disable insert vacuums",
- RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
- ShareUpdateExclusiveLock
- },
- -2, -1, INT_MAX
- },
- {
- {
- "autovacuum_analyze_threshold",
- "Minimum number of tuple inserts, updates or deletes prior to analyze",
- RELOPT_KIND_HEAP,
- ShareUpdateExclusiveLock
- },
- -1, 0, INT_MAX
- },
{
{
"autovacuum_vacuum_cost_limit",
@@ -380,7 +353,39 @@ static relopt_int intRelOpts[] =
},
-1, 0, 1024
},
+ /* list terminator */
+ {{NULL}}
+};
+static relopt_int64 int64RelOpts[] =
+{
+ {
+ {
+ "autovacuum_vacuum_threshold",
+ "Minimum number of tuple updates or deletes prior to vacuum",
+ RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
+ ShareUpdateExclusiveLock
+ },
+ INT64CONST(-1), INT64CONST(0), PG_INT64_MAX
+ },
+ {
+ {
+ "autovacuum_vacuum_insert_threshold",
+ "Minimum number of tuple inserts prior to vacuum, or -1 to disable insert vacuums",
+ RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
+ ShareUpdateExclusiveLock
+ },
+ INT64CONST(-2), INT64CONST(-1), PG_INT64_MAX
+ },
+ {
+ {
+ "autovacuum_analyze_threshold",
+ "Minimum number of tuple inserts, updates or deletes prior to analyze",
+ RELOPT_KIND_HEAP,
+ ShareUpdateExclusiveLock
+ },
+ INT64CONST(-1), INT64CONST(0), PG_INT64_MAX
+ },
/* list terminator */
{{NULL}}
};
@@ -595,6 +600,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 +648,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 +811,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 +968,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 +1659,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 +1836,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 :
@@ -1841,11 +1910,11 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind)
{"fillfactor", RELOPT_TYPE_INT, offsetof(StdRdOptions, fillfactor)},
{"autovacuum_enabled", RELOPT_TYPE_BOOL,
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, enabled)},
- {"autovacuum_vacuum_threshold", RELOPT_TYPE_INT,
+ {"autovacuum_vacuum_threshold", RELOPT_TYPE_INT64,
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_threshold)},
- {"autovacuum_vacuum_insert_threshold", RELOPT_TYPE_INT,
+ {"autovacuum_vacuum_insert_threshold", RELOPT_TYPE_INT64,
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_ins_threshold)},
- {"autovacuum_analyze_threshold", RELOPT_TYPE_INT,
+ {"autovacuum_analyze_threshold", RELOPT_TYPE_INT64,
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, analyze_threshold)},
{"autovacuum_vacuum_cost_limit", RELOPT_TYPE_INT,
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_cost_limit)},
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 13527fc258..d1e491d22d 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -262,6 +262,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,
@@ -759,6 +761,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;
@@ -820,6 +826,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;
@@ -848,6 +858,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 */
@@ -936,6 +947,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];
@@ -999,6 +1018,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;
@@ -1426,6 +1457,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
@@ -1461,6 +1493,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;
@@ -1691,6 +1737,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;
@@ -2041,6 +2105,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);
@@ -2424,6 +2500,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)
{
@@ -2946,6 +3040,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
@@ -3192,6 +3351,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;
@@ -3895,6 +4084,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
}
@@ -4337,6 +4616,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);
@@ -4385,6 +4669,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);
@@ -5143,6 +5432,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,
@@ -5336,6 +5655,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;
@@ -5468,6 +5795,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;
@@ -5570,6 +5912,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;
@@ -5848,6 +6198,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:
{
/*
@@ -6014,6 +6382,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;
@@ -6227,6 +6603,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;
@@ -6827,6 +7211,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 686309db58..3397808931 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",
@@ -3721,6 +3722,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 df6923c9d5..309c82ebf4 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 840b0fe57f..0a3fe0b54f 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);
@@ -348,6 +350,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) pg_attribute_nonnull(1, 4);
+
extern void DefineCustomRealVariable(const char *name,
const char *short_desc,
const char *long_desc,
@@ -409,6 +424,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[];
diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h
index 8700204953..f89064e274 100644
--- a/src/include/utils/rel.h
+++ b/src/include/utils/rel.h
@@ -308,9 +308,9 @@ typedef struct ForeignKeyCacheInfo
typedef struct AutoVacOpts
{
bool enabled;
- int vacuum_threshold;
- int vacuum_ins_threshold;
- int analyze_threshold;
+ int64 vacuum_threshold;
+ int64 vacuum_ins_threshold;
+ int64 analyze_threshold;
int vacuum_cost_limit;
int freeze_min_age;
int freeze_max_age;
diff --git a/src/test/modules/delay_execution/delay_execution.c b/src/test/modules/delay_execution/delay_execution.c
index 155c8a8d55..62c61d50f8 100644
--- a/src/test/modules/delay_execution/delay_execution.c
+++ b/src/test/modules/delay_execution/delay_execution.c
@@ -31,7 +31,7 @@
PG_MODULE_MAGIC;
/* GUC: advisory lock ID to use. Zero disables the feature. */
-static int post_planning_lock_id = 0;
+static int64 post_planning_lock_id = 0;
/* Save previous planner hook user to be a good citizen */
static planner_hook_type prev_planner_hook = NULL;
@@ -56,9 +56,9 @@ delay_execution_planner(Query *parse, const char *query_string,
if (post_planning_lock_id != 0)
{
DirectFunctionCall1(pg_advisory_lock_int8,
- Int64GetDatum((int64) post_planning_lock_id));
+ Int64GetDatum(post_planning_lock_id));
DirectFunctionCall1(pg_advisory_unlock_int8,
- Int64GetDatum((int64) post_planning_lock_id));
+ Int64GetDatum(post_planning_lock_id));
/*
* Ensure that we notice any pending invalidations, since the advisory
@@ -75,17 +75,17 @@ void
_PG_init(void)
{
/* Set up the GUC to control which lock is used */
- DefineCustomIntVariable("delay_execution.post_planning_lock_id",
- "Sets the advisory lock ID to be locked/unlocked after planning.",
- "Zero disables the delay.",
- &post_planning_lock_id,
- 0,
- 0, INT_MAX,
- PGC_USERSET,
- 0,
- NULL,
- NULL,
- NULL);
+ DefineCustomInt64Variable("delay_execution.post_planning_lock_id",
+ "Sets the advisory lock ID to be locked/unlocked after planning.",
+ "Zero disables the delay.",
+ &post_planning_lock_id,
+ 0,
+ 0, PG_INT64_MAX,
+ PGC_USERSET,
+ 0,
+ NULL,
+ NULL,
+ NULL);
MarkGUCPrefixReserved("delay_execution");
diff --git a/src/test/modules/delay_execution/expected/partition-addition.out b/src/test/modules/delay_execution/expected/partition-addition.out
index 7d6572b2db..57750db160 100644
--- a/src/test/modules/delay_execution/expected/partition-addition.out
+++ b/src/test/modules/delay_execution/expected/partition-addition.out
@@ -1,19 +1,19 @@
Parsed test spec with 2 sessions
starting permutation: s2lock s1exec s2addp s2unlock
-step s2lock: SELECT pg_advisory_lock(12345);
+step s2lock: SELECT pg_advisory_lock(0x1122334455667788);
pg_advisory_lock
----------------
(1 row)
step s1exec: LOAD 'delay_execution';
- SET delay_execution.post_planning_lock_id = 12345;
+ SET delay_execution.post_planning_lock_id = 0x1122334455667788;
SELECT * FROM foo WHERE a <> 1 AND a <> (SELECT 3); <waiting ...>
step s2addp: CREATE TABLE foo2 (LIKE foo);
ALTER TABLE foo ATTACH PARTITION foo2 FOR VALUES IN (2);
INSERT INTO foo VALUES (2, 'ADD2');
-step s2unlock: SELECT pg_advisory_unlock(12345);
+step s2unlock: SELECT pg_advisory_unlock(0x1122334455667788);
pg_advisory_unlock
------------------
t
diff --git a/src/test/modules/delay_execution/expected/partition-removal-1.out b/src/test/modules/delay_execution/expected/partition-removal-1.out
index b81b9995e9..a2e453fdaa 100644
--- a/src/test/modules/delay_execution/expected/partition-removal-1.out
+++ b/src/test/modules/delay_execution/expected/partition-removal-1.out
@@ -1,7 +1,7 @@
Parsed test spec with 3 sessions
starting permutation: s3lock s1b s1exec s2remp s3check s3unlock s3check s1c
-step s3lock: SELECT pg_advisory_lock(12543);
+step s3lock: SELECT pg_advisory_lock(0x7766554433221100);
pg_advisory_lock
----------------
@@ -17,7 +17,7 @@ a|b
3|DEF
(2 rows)
-step s3unlock: SELECT pg_advisory_unlock(12543);
+step s3unlock: SELECT pg_advisory_unlock(0x7766554433221100);
pg_advisory_unlock
------------------
t
@@ -40,7 +40,7 @@ step s1c: COMMIT;
step s2remp: <... completed>
starting permutation: s3lock s1brr s1exec s2remp s3check s3unlock s3check s1c
-step s3lock: SELECT pg_advisory_lock(12543);
+step s3lock: SELECT pg_advisory_lock(0x7766554433221100);
pg_advisory_lock
----------------
@@ -56,7 +56,7 @@ a|b
3|DEF
(2 rows)
-step s3unlock: SELECT pg_advisory_unlock(12543);
+step s3unlock: SELECT pg_advisory_unlock(0x7766554433221100);
pg_advisory_unlock
------------------
t
@@ -79,7 +79,7 @@ step s1c: COMMIT;
step s2remp: <... completed>
starting permutation: s3lock s1b s1exec2 s2remp s3unlock s1c
-step s3lock: SELECT pg_advisory_lock(12543);
+step s3lock: SELECT pg_advisory_lock(0x7766554433221100);
pg_advisory_lock
----------------
@@ -88,7 +88,7 @@ pg_advisory_lock
step s1b: BEGIN;
step s1exec2: SELECT * FROM partrem WHERE a <> (SELECT 2) AND a <> 1; <waiting ...>
step s2remp: ALTER TABLE partrem DETACH PARTITION partrem2 CONCURRENTLY; <waiting ...>
-step s3unlock: SELECT pg_advisory_unlock(12543);
+step s3unlock: SELECT pg_advisory_unlock(0x7766554433221100);
pg_advisory_unlock
------------------
t
@@ -104,7 +104,7 @@ step s1c: COMMIT;
step s2remp: <... completed>
starting permutation: s3lock s1brr s1exec2 s2remp s3unlock s1c
-step s3lock: SELECT pg_advisory_lock(12543);
+step s3lock: SELECT pg_advisory_lock(0x7766554433221100);
pg_advisory_lock
----------------
@@ -113,7 +113,7 @@ pg_advisory_lock
step s1brr: BEGIN ISOLATION LEVEL REPEATABLE READ;
step s1exec2: SELECT * FROM partrem WHERE a <> (SELECT 2) AND a <> 1; <waiting ...>
step s2remp: ALTER TABLE partrem DETACH PARTITION partrem2 CONCURRENTLY; <waiting ...>
-step s3unlock: SELECT pg_advisory_unlock(12543);
+step s3unlock: SELECT pg_advisory_unlock(0x7766554433221100);
pg_advisory_unlock
------------------
t
@@ -129,7 +129,7 @@ step s1c: COMMIT;
step s2remp: <... completed>
starting permutation: s3lock s1brr s1prepare s2remp s1execprep s3unlock s1check s1c s1check s1dealloc
-step s3lock: SELECT pg_advisory_lock(12543);
+step s3lock: SELECT pg_advisory_lock(0x7766554433221100);
pg_advisory_lock
----------------
@@ -139,7 +139,7 @@ step s1brr: BEGIN ISOLATION LEVEL REPEATABLE READ;
step s1prepare: PREPARE ins AS INSERT INTO partrem VALUES ($1, 'GHI');
step s2remp: ALTER TABLE partrem DETACH PARTITION partrem2 CONCURRENTLY; <waiting ...>
step s1execprep: EXECUTE ins(2); <waiting ...>
-step s3unlock: SELECT pg_advisory_unlock(12543);
+step s3unlock: SELECT pg_advisory_unlock(0x7766554433221100);
pg_advisory_unlock
------------------
t
@@ -165,14 +165,14 @@ starting permutation: s1brr s1prepare s2remp s3lock s1execprep s3unlock s1check
step s1brr: BEGIN ISOLATION LEVEL REPEATABLE READ;
step s1prepare: PREPARE ins AS INSERT INTO partrem VALUES ($1, 'GHI');
step s2remp: ALTER TABLE partrem DETACH PARTITION partrem2 CONCURRENTLY; <waiting ...>
-step s3lock: SELECT pg_advisory_lock(12543);
+step s3lock: SELECT pg_advisory_lock(0x7766554433221100);
pg_advisory_lock
----------------
(1 row)
step s1execprep: EXECUTE ins(2); <waiting ...>
-step s3unlock: SELECT pg_advisory_unlock(12543);
+step s3unlock: SELECT pg_advisory_unlock(0x7766554433221100);
pg_advisory_unlock
------------------
t
@@ -201,7 +201,7 @@ a|b
-+-
(0 rows)
-step s3lock: SELECT pg_advisory_lock(12543);
+step s3lock: SELECT pg_advisory_lock(0x7766554433221100);
pg_advisory_lock
----------------
@@ -210,7 +210,7 @@ pg_advisory_lock
step s2remp: ALTER TABLE partrem DETACH PARTITION partrem2 CONCURRENTLY; <waiting ...>
step s1prepare: PREPARE ins AS INSERT INTO partrem VALUES ($1, 'GHI');
step s1execprep: EXECUTE ins(2); <waiting ...>
-step s3unlock: SELECT pg_advisory_unlock(12543);
+step s3unlock: SELECT pg_advisory_unlock(0x7766554433221100);
pg_advisory_unlock
------------------
t
diff --git a/src/test/modules/delay_execution/specs/partition-addition.spec b/src/test/modules/delay_execution/specs/partition-addition.spec
index 99010dfad5..4a68e88cc7 100644
--- a/src/test/modules/delay_execution/specs/partition-addition.spec
+++ b/src/test/modules/delay_execution/specs/partition-addition.spec
@@ -25,12 +25,12 @@ teardown
session "s1"
step "s1exec" { LOAD 'delay_execution';
- SET delay_execution.post_planning_lock_id = 12345;
+ SET delay_execution.post_planning_lock_id = 0x1122334455667788;
SELECT * FROM foo WHERE a <> 1 AND a <> (SELECT 3); }
session "s2"
-step "s2lock" { SELECT pg_advisory_lock(12345); }
-step "s2unlock" { SELECT pg_advisory_unlock(12345); }
+step "s2lock" { SELECT pg_advisory_lock(0x1122334455667788); }
+step "s2unlock" { SELECT pg_advisory_unlock(0x1122334455667788); }
step "s2addp" { CREATE TABLE foo2 (LIKE foo);
ALTER TABLE foo ATTACH PARTITION foo2 FOR VALUES IN (2);
INSERT INTO foo VALUES (2, 'ADD2'); }
diff --git a/src/test/modules/delay_execution/specs/partition-removal-1.spec b/src/test/modules/delay_execution/specs/partition-removal-1.spec
index 5ee2750129..25b40b89a4 100644
--- a/src/test/modules/delay_execution/specs/partition-removal-1.spec
+++ b/src/test/modules/delay_execution/specs/partition-removal-1.spec
@@ -18,7 +18,7 @@ teardown
session "s1"
setup { LOAD 'delay_execution';
- SET delay_execution.post_planning_lock_id = 12543; }
+ SET delay_execution.post_planning_lock_id = 0x7766554433221100; }
step "s1b" { BEGIN; }
step "s1brr" { BEGIN ISOLATION LEVEL REPEATABLE READ; }
step "s1exec" { SELECT * FROM partrem WHERE a <> 1 AND a <> (SELECT 3); }
@@ -33,8 +33,8 @@ session "s2"
step "s2remp" { ALTER TABLE partrem DETACH PARTITION partrem2 CONCURRENTLY; }
session "s3"
-step "s3lock" { SELECT pg_advisory_lock(12543); }
-step "s3unlock" { SELECT pg_advisory_unlock(12543); }
+step "s3lock" { SELECT pg_advisory_lock(0x7766554433221100); }
+step "s3unlock" { SELECT pg_advisory_unlock(0x7766554433221100); }
step "s3check" { SELECT * FROM partrem; }
# The SELECT will be planned with all three partitions shown above,
--
2.46.0
Hi,
PFA the updated patch.
It is worth mentioning that v2 should not be merged as is.
Particularly although it changes the following GUCs:
autovacuum_vacuum_threshold
autovacuum_vacuum_insert_threshold
autovacuum_analyze_threshold
... it doesn't affect the code that uses these GUCs which results in
casting int64s to ints.
I would appreciate a bit more feedback on v2. If the community is fine
with modifying these GUCs I will correct the patch in this respect.
--
Best regards,
Aleksander Alekseev
Hi, Aleksander Alekseev
Thanks for updating the patch.
On Sep 24, 2024, at 17:27, Aleksander Alekseev <aleksander@timescale.com> wrote:
Hi, Alexander!
Thank you for your work on this subject.
Thanks for your feedback.
It doesn't look like these *_age GUCs could benefit from being 64-bit,
before 64-bit transaction ids get in. However, I think there are some
better candidates.autovacuum_vacuum_threshold
autovacuum_vacuum_insert_threshold
autovacuum_analyze_thresholdThis GUCs specify number of tuples before vacuum/analyze. That could
be more than 2^31. With large tables of small tuples, I can't even
say this is always impractical to have values greater than 2^31.Sounds good to me. Fixed.
I found the autovacuum_vacuum_threshold, autovacuum_vacuum_insert_threshold
and autovacuum_analyze_threshold is change to int64 for relation option,
however the GUCs are still integers.
```
postgres=# select * from pg_settings where name = 'autovacuum_vacuum_threshold' \gx
-[ RECORD 1 ]---+------------------------------------------------------------
name | autovacuum_vacuum_threshold
setting | 50
unit |
category | Autovacuum
short_desc | Minimum number of tuple updates or deletes prior to vacuum.
extra_desc |
context | sighup
vartype | integer
source | default
min_val | 0
max_val | 2147483647
enumvals |
boot_val | 50
reset_val | 50
sourcefile |
sourceline |
pending_restart | f
```
Is there something I missed?
Secondly, DefineCustomInt64Variable() is not test-covered. Turned out
it was not even defined (although declared) in the original patch.
This was fixed in the attached version. Maybe one of the test modules
could use it even if it makes little sense for this particular module?
For instance, test/modules/worker_spi/ could use it for
worker_spi.naptime.I don't think there are good candidates among existing extension GUCs.
I think we could add something for pure testing purposes somewhere in
src/test/modules.I found a great candidate in src/test/modules/delay_execution:
```
DefineCustomIntVariable("delay_execution.post_planning_lock_id",
"Sets the advisory lock ID to be
locked/unlocked after planning.",
```Advisory lock IDs are bigints [1]. I modified the module to use Int64's.
I check the delay_execution.post_planning_lock_id parameter, and it’s varitype
is int64, maybe bigint is better, see [1]https://www.postgresql.org/docs/current/datatype-numeric.html.
```
postgres=# select * from pg_settings where name = 'delay_execution.post_planning_lock_id' \gx
-[ RECORD 1 ]---+----------------------------------------------------------------
name | delay_execution.post_planning_lock_id
setting | 0
unit |
category | Customized Options
short_desc | Sets the advisory lock ID to be locked/unlocked after planning.
extra_desc | Zero disables the delay.
context | user
vartype | int64
source | default
min_val | 0
max_val | 9223372036854775807
enumvals |
boot_val | 0
reset_val | 0
sourcefile |
sourceline |
pending_restart | f
```
[1]: https://www.postgresql.org/docs/current/datatype-numeric.html
--
Regrads,
Japin Li
On Tue, Sep 24, 2024 at 12:27:20PM +0300, Aleksander Alekseev wrote:
It doesn't look like these *_age GUCs could benefit from being 64-bit,
before 64-bit transaction ids get in. However, I think there are some
better candidates.autovacuum_vacuum_threshold
autovacuum_vacuum_insert_threshold
autovacuum_analyze_thresholdThis GUCs specify number of tuples before vacuum/analyze. That could
be more than 2^31. With large tables of small tuples, I can't even
say this is always impractical to have values greater than 2^31.[...]
I found a great candidate in src/test/modules/delay_execution:
```
DefineCustomIntVariable("delay_execution.post_planning_lock_id",
"Sets the advisory lock ID to be
locked/unlocked after planning.",
```Advisory lock IDs are bigints [1]. I modified the module to use Int64's.
I guess it may also answer Nathan's question.
Hm. I'm not sure I find any of these to be particularly convincing
examples of why we need int64 GUCs. Yes, the GUCs in question could
potentially be set to higher values, but I've yet to hear of this being a
problem in practice. We might not want to encourage such high values,
either.
--
nathan
Hi,
I found the autovacuum_vacuum_threshold, autovacuum_vacuum_insert_threshold
and autovacuum_analyze_threshold is change to int64 for relation option,
however the GUCs are still integers.```
postgres=# select * from pg_settings where name = 'autovacuum_vacuum_threshold' \gx
-[ RECORD 1 ]---+------------------------------------------------------------
name | autovacuum_vacuum_threshold
setting | 50
unit |
category | Autovacuum
short_desc | Minimum number of tuple updates or deletes prior to vacuum.
extra_desc |
context | sighup
vartype | integer
source | default
min_val | 0
max_val | 2147483647
enumvals |
boot_val | 50
reset_val | 50
sourcefile |
sourceline |
pending_restart | f
```Is there something I missed?
No, you found a bug. The patch didn't change ConfigureNamesInt64[]
thus these GUCs were still treated as int32s.
Here is the corrected patch v3. Thanks!
=# select * from pg_settings where name = 'autovacuum_vacuum_threshold';
-[ RECORD 1 ]---+------------------------------------------------------------
name | autovacuum_vacuum_threshold
setting | 1234605616436508552
unit |
category | Autovacuum
short_desc | Minimum number of tuple updates or deletes prior to vacuum.
extra_desc |
context | sighup
vartype | int64
source | configuration file
min_val | 0
max_val | 9223372036854775807
enumvals |
boot_val | 50
reset_val | 1234605616436508552
sourcefile | /Users/eax/pginstall/data-master/postgresql.conf
sourceline | 664
pending_restart | f
--
Best regards,
Aleksander Alekseev
Attachments:
v3-0001-Support-64-bit-integer-GUCs.patchapplication/octet-stream; name=v3-0001-Support-64-bit-integer-GUCs.patchDownload
From 2d53f9f890c48e0780bc5823e87ba698a5c32909 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 v3] Support 64-bit integer 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>
Reviewed-by: Li Japin <japinli@hotmail.com>
Discussion: https://postgr.es/m/CAJ7c6TMvPz8q+nC=JoKniy7yxPzQYcCTnNFYmsDP-nnWsAOJ2g@mail.gmail.com
---
src/backend/access/common/reloptions.c | 129 ++++--
src/backend/postmaster/autovacuum.c | 6 +-
src/backend/utils/misc/guc.c | 418 ++++++++++++++++++
src/backend/utils/misc/guc_funcs.c | 25 ++
src/backend/utils/misc/guc_tables.c | 64 +--
src/include/access/reloptions.h | 13 +
src/include/postmaster/autovacuum.h | 6 +-
src/include/utils/guc.h | 17 +
src/include/utils/guc_tables.h | 19 +
src/include/utils/rel.h | 6 +-
.../modules/delay_execution/delay_execution.c | 28 +-
.../expected/partition-addition.out | 6 +-
.../expected/partition-removal-1.out | 28 +-
.../specs/partition-addition.spec | 6 +-
.../specs/partition-removal-1.spec | 6 +-
15 files changed, 674 insertions(+), 103 deletions(-)
diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
index 49fd35bfc5..b989442942 100644
--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
@@ -222,33 +222,6 @@ static relopt_int intRelOpts[] =
},
SPGIST_DEFAULT_FILLFACTOR, SPGIST_MIN_FILLFACTOR, 100
},
- {
- {
- "autovacuum_vacuum_threshold",
- "Minimum number of tuple updates or deletes prior to vacuum",
- RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
- ShareUpdateExclusiveLock
- },
- -1, 0, INT_MAX
- },
- {
- {
- "autovacuum_vacuum_insert_threshold",
- "Minimum number of tuple inserts prior to vacuum, or -1 to disable insert vacuums",
- RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
- ShareUpdateExclusiveLock
- },
- -2, -1, INT_MAX
- },
- {
- {
- "autovacuum_analyze_threshold",
- "Minimum number of tuple inserts, updates or deletes prior to analyze",
- RELOPT_KIND_HEAP,
- ShareUpdateExclusiveLock
- },
- -1, 0, INT_MAX
- },
{
{
"autovacuum_vacuum_cost_limit",
@@ -380,7 +353,39 @@ static relopt_int intRelOpts[] =
},
-1, 0, 1024
},
+ /* list terminator */
+ {{NULL}}
+};
+static relopt_int64 int64RelOpts[] =
+{
+ {
+ {
+ "autovacuum_vacuum_threshold",
+ "Minimum number of tuple updates or deletes prior to vacuum",
+ RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
+ ShareUpdateExclusiveLock
+ },
+ INT64CONST(-1), INT64CONST(0), PG_INT64_MAX
+ },
+ {
+ {
+ "autovacuum_vacuum_insert_threshold",
+ "Minimum number of tuple inserts prior to vacuum, or -1 to disable insert vacuums",
+ RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
+ ShareUpdateExclusiveLock
+ },
+ INT64CONST(-2), INT64CONST(-1), PG_INT64_MAX
+ },
+ {
+ {
+ "autovacuum_analyze_threshold",
+ "Minimum number of tuple inserts, updates or deletes prior to analyze",
+ RELOPT_KIND_HEAP,
+ ShareUpdateExclusiveLock
+ },
+ INT64CONST(-1), INT64CONST(0), PG_INT64_MAX
+ },
/* list terminator */
{{NULL}}
};
@@ -595,6 +600,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 +648,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 +811,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 +968,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 +1659,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 +1836,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 :
@@ -1841,11 +1910,11 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind)
{"fillfactor", RELOPT_TYPE_INT, offsetof(StdRdOptions, fillfactor)},
{"autovacuum_enabled", RELOPT_TYPE_BOOL,
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, enabled)},
- {"autovacuum_vacuum_threshold", RELOPT_TYPE_INT,
+ {"autovacuum_vacuum_threshold", RELOPT_TYPE_INT64,
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_threshold)},
- {"autovacuum_vacuum_insert_threshold", RELOPT_TYPE_INT,
+ {"autovacuum_vacuum_insert_threshold", RELOPT_TYPE_INT64,
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_ins_threshold)},
- {"autovacuum_analyze_threshold", RELOPT_TYPE_INT,
+ {"autovacuum_analyze_threshold", RELOPT_TYPE_INT64,
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, analyze_threshold)},
{"autovacuum_vacuum_cost_limit", RELOPT_TYPE_INT,
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_cost_limit)},
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 7d0877c95e..88c39414a6 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -118,11 +118,11 @@ bool autovacuum_start_daemon = false;
int autovacuum_max_workers;
int autovacuum_work_mem = -1;
int autovacuum_naptime;
-int autovacuum_vac_thresh;
+int64 autovacuum_vac_thresh;
double autovacuum_vac_scale;
-int autovacuum_vac_ins_thresh;
+int64 autovacuum_vac_ins_thresh;
double autovacuum_vac_ins_scale;
-int autovacuum_anl_thresh;
+int64 autovacuum_anl_thresh;
double autovacuum_anl_scale;
int autovacuum_freeze_max_age;
int autovacuum_multixact_freeze_max_age;
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 13527fc258..d1e491d22d 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -262,6 +262,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,
@@ -759,6 +761,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;
@@ -820,6 +826,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;
@@ -848,6 +858,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 */
@@ -936,6 +947,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];
@@ -999,6 +1018,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;
@@ -1426,6 +1457,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
@@ -1461,6 +1493,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;
@@ -1691,6 +1737,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;
@@ -2041,6 +2105,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);
@@ -2424,6 +2500,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)
{
@@ -2946,6 +3040,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
@@ -3192,6 +3351,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;
@@ -3895,6 +4084,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
}
@@ -4337,6 +4616,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);
@@ -4385,6 +4669,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);
@@ -5143,6 +5432,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,
@@ -5336,6 +5655,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;
@@ -5468,6 +5795,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;
@@ -5570,6 +5912,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;
@@ -5848,6 +6198,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:
{
/*
@@ -6014,6 +6382,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;
@@ -6227,6 +6603,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;
@@ -6827,6 +7211,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 686309db58..03edd9f95d 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",
@@ -3397,33 +3398,6 @@ struct config_int ConfigureNamesInt[] =
60, 1, INT_MAX / 1000,
NULL, NULL, NULL
},
- {
- {"autovacuum_vacuum_threshold", PGC_SIGHUP, AUTOVACUUM,
- gettext_noop("Minimum number of tuple updates or deletes prior to vacuum."),
- NULL
- },
- &autovacuum_vac_thresh,
- 50, 0, INT_MAX,
- NULL, NULL, NULL
- },
- {
- {"autovacuum_vacuum_insert_threshold", PGC_SIGHUP, AUTOVACUUM,
- gettext_noop("Minimum number of tuple inserts prior to vacuum, or -1 to disable insert vacuums."),
- NULL
- },
- &autovacuum_vac_ins_thresh,
- 1000, -1, INT_MAX,
- NULL, NULL, NULL
- },
- {
- {"autovacuum_analyze_threshold", PGC_SIGHUP, AUTOVACUUM,
- gettext_noop("Minimum number of tuple inserts, updates, or deletes prior to analyze."),
- NULL
- },
- &autovacuum_anl_thresh,
- 50, 0, INT_MAX,
- NULL, NULL, NULL
- },
{
/* see varsup.c for why this is PGC_POSTMASTER not PGC_SIGHUP */
{"autovacuum_freeze_max_age", PGC_POSTMASTER, AUTOVACUUM,
@@ -3721,6 +3695,42 @@ struct config_int ConfigureNamesInt[] =
};
+struct config_int64 ConfigureNamesInt64[] =
+{
+ {
+ {"autovacuum_vacuum_threshold", PGC_SIGHUP, AUTOVACUUM,
+ gettext_noop("Minimum number of tuple updates or deletes prior to vacuum."),
+ NULL
+ },
+ &autovacuum_vac_thresh,
+ INT64CONST(50), INT64CONST(0), PG_INT64_MAX,
+ NULL, NULL, NULL
+ },
+ {
+ {"autovacuum_vacuum_insert_threshold", PGC_SIGHUP, AUTOVACUUM,
+ gettext_noop("Minimum number of tuple inserts prior to vacuum, or -1 to disable insert vacuums."),
+ NULL
+ },
+ &autovacuum_vac_ins_thresh,
+ INT64CONST(1000), INT64CONST(-1), PG_INT64_MAX,
+ NULL, NULL, NULL
+ },
+ {
+ {"autovacuum_analyze_threshold", PGC_SIGHUP, AUTOVACUUM,
+ gettext_noop("Minimum number of tuple inserts, updates, or deletes prior to analyze."),
+ NULL
+ },
+ &autovacuum_anl_thresh,
+ INT64CONST(50), INT64CONST(0), PG_INT64_MAX,
+ NULL, NULL, NULL
+ },
+ /* 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 df6923c9d5..309c82ebf4 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/postmaster/autovacuum.h b/src/include/postmaster/autovacuum.h
index cae1e8b329..15f12ce24f 100644
--- a/src/include/postmaster/autovacuum.h
+++ b/src/include/postmaster/autovacuum.h
@@ -31,11 +31,11 @@ extern PGDLLIMPORT bool autovacuum_start_daemon;
extern PGDLLIMPORT int autovacuum_max_workers;
extern PGDLLIMPORT int autovacuum_work_mem;
extern PGDLLIMPORT int autovacuum_naptime;
-extern PGDLLIMPORT int autovacuum_vac_thresh;
+extern PGDLLIMPORT int64 autovacuum_vac_thresh;
extern PGDLLIMPORT double autovacuum_vac_scale;
-extern PGDLLIMPORT int autovacuum_vac_ins_thresh;
+extern PGDLLIMPORT int64 autovacuum_vac_ins_thresh;
extern PGDLLIMPORT double autovacuum_vac_ins_scale;
-extern PGDLLIMPORT int autovacuum_anl_thresh;
+extern PGDLLIMPORT int64 autovacuum_anl_thresh;
extern PGDLLIMPORT double autovacuum_anl_scale;
extern PGDLLIMPORT int autovacuum_freeze_max_age;
extern PGDLLIMPORT int autovacuum_multixact_freeze_max_age;
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index 840b0fe57f..0a3fe0b54f 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);
@@ -348,6 +350,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) pg_attribute_nonnull(1, 4);
+
extern void DefineCustomRealVariable(const char *name,
const char *short_desc,
const char *long_desc,
@@ -409,6 +424,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[];
diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h
index 8700204953..f89064e274 100644
--- a/src/include/utils/rel.h
+++ b/src/include/utils/rel.h
@@ -308,9 +308,9 @@ typedef struct ForeignKeyCacheInfo
typedef struct AutoVacOpts
{
bool enabled;
- int vacuum_threshold;
- int vacuum_ins_threshold;
- int analyze_threshold;
+ int64 vacuum_threshold;
+ int64 vacuum_ins_threshold;
+ int64 analyze_threshold;
int vacuum_cost_limit;
int freeze_min_age;
int freeze_max_age;
diff --git a/src/test/modules/delay_execution/delay_execution.c b/src/test/modules/delay_execution/delay_execution.c
index 155c8a8d55..62c61d50f8 100644
--- a/src/test/modules/delay_execution/delay_execution.c
+++ b/src/test/modules/delay_execution/delay_execution.c
@@ -31,7 +31,7 @@
PG_MODULE_MAGIC;
/* GUC: advisory lock ID to use. Zero disables the feature. */
-static int post_planning_lock_id = 0;
+static int64 post_planning_lock_id = 0;
/* Save previous planner hook user to be a good citizen */
static planner_hook_type prev_planner_hook = NULL;
@@ -56,9 +56,9 @@ delay_execution_planner(Query *parse, const char *query_string,
if (post_planning_lock_id != 0)
{
DirectFunctionCall1(pg_advisory_lock_int8,
- Int64GetDatum((int64) post_planning_lock_id));
+ Int64GetDatum(post_planning_lock_id));
DirectFunctionCall1(pg_advisory_unlock_int8,
- Int64GetDatum((int64) post_planning_lock_id));
+ Int64GetDatum(post_planning_lock_id));
/*
* Ensure that we notice any pending invalidations, since the advisory
@@ -75,17 +75,17 @@ void
_PG_init(void)
{
/* Set up the GUC to control which lock is used */
- DefineCustomIntVariable("delay_execution.post_planning_lock_id",
- "Sets the advisory lock ID to be locked/unlocked after planning.",
- "Zero disables the delay.",
- &post_planning_lock_id,
- 0,
- 0, INT_MAX,
- PGC_USERSET,
- 0,
- NULL,
- NULL,
- NULL);
+ DefineCustomInt64Variable("delay_execution.post_planning_lock_id",
+ "Sets the advisory lock ID to be locked/unlocked after planning.",
+ "Zero disables the delay.",
+ &post_planning_lock_id,
+ 0,
+ 0, PG_INT64_MAX,
+ PGC_USERSET,
+ 0,
+ NULL,
+ NULL,
+ NULL);
MarkGUCPrefixReserved("delay_execution");
diff --git a/src/test/modules/delay_execution/expected/partition-addition.out b/src/test/modules/delay_execution/expected/partition-addition.out
index 7d6572b2db..57750db160 100644
--- a/src/test/modules/delay_execution/expected/partition-addition.out
+++ b/src/test/modules/delay_execution/expected/partition-addition.out
@@ -1,19 +1,19 @@
Parsed test spec with 2 sessions
starting permutation: s2lock s1exec s2addp s2unlock
-step s2lock: SELECT pg_advisory_lock(12345);
+step s2lock: SELECT pg_advisory_lock(0x1122334455667788);
pg_advisory_lock
----------------
(1 row)
step s1exec: LOAD 'delay_execution';
- SET delay_execution.post_planning_lock_id = 12345;
+ SET delay_execution.post_planning_lock_id = 0x1122334455667788;
SELECT * FROM foo WHERE a <> 1 AND a <> (SELECT 3); <waiting ...>
step s2addp: CREATE TABLE foo2 (LIKE foo);
ALTER TABLE foo ATTACH PARTITION foo2 FOR VALUES IN (2);
INSERT INTO foo VALUES (2, 'ADD2');
-step s2unlock: SELECT pg_advisory_unlock(12345);
+step s2unlock: SELECT pg_advisory_unlock(0x1122334455667788);
pg_advisory_unlock
------------------
t
diff --git a/src/test/modules/delay_execution/expected/partition-removal-1.out b/src/test/modules/delay_execution/expected/partition-removal-1.out
index b81b9995e9..a2e453fdaa 100644
--- a/src/test/modules/delay_execution/expected/partition-removal-1.out
+++ b/src/test/modules/delay_execution/expected/partition-removal-1.out
@@ -1,7 +1,7 @@
Parsed test spec with 3 sessions
starting permutation: s3lock s1b s1exec s2remp s3check s3unlock s3check s1c
-step s3lock: SELECT pg_advisory_lock(12543);
+step s3lock: SELECT pg_advisory_lock(0x7766554433221100);
pg_advisory_lock
----------------
@@ -17,7 +17,7 @@ a|b
3|DEF
(2 rows)
-step s3unlock: SELECT pg_advisory_unlock(12543);
+step s3unlock: SELECT pg_advisory_unlock(0x7766554433221100);
pg_advisory_unlock
------------------
t
@@ -40,7 +40,7 @@ step s1c: COMMIT;
step s2remp: <... completed>
starting permutation: s3lock s1brr s1exec s2remp s3check s3unlock s3check s1c
-step s3lock: SELECT pg_advisory_lock(12543);
+step s3lock: SELECT pg_advisory_lock(0x7766554433221100);
pg_advisory_lock
----------------
@@ -56,7 +56,7 @@ a|b
3|DEF
(2 rows)
-step s3unlock: SELECT pg_advisory_unlock(12543);
+step s3unlock: SELECT pg_advisory_unlock(0x7766554433221100);
pg_advisory_unlock
------------------
t
@@ -79,7 +79,7 @@ step s1c: COMMIT;
step s2remp: <... completed>
starting permutation: s3lock s1b s1exec2 s2remp s3unlock s1c
-step s3lock: SELECT pg_advisory_lock(12543);
+step s3lock: SELECT pg_advisory_lock(0x7766554433221100);
pg_advisory_lock
----------------
@@ -88,7 +88,7 @@ pg_advisory_lock
step s1b: BEGIN;
step s1exec2: SELECT * FROM partrem WHERE a <> (SELECT 2) AND a <> 1; <waiting ...>
step s2remp: ALTER TABLE partrem DETACH PARTITION partrem2 CONCURRENTLY; <waiting ...>
-step s3unlock: SELECT pg_advisory_unlock(12543);
+step s3unlock: SELECT pg_advisory_unlock(0x7766554433221100);
pg_advisory_unlock
------------------
t
@@ -104,7 +104,7 @@ step s1c: COMMIT;
step s2remp: <... completed>
starting permutation: s3lock s1brr s1exec2 s2remp s3unlock s1c
-step s3lock: SELECT pg_advisory_lock(12543);
+step s3lock: SELECT pg_advisory_lock(0x7766554433221100);
pg_advisory_lock
----------------
@@ -113,7 +113,7 @@ pg_advisory_lock
step s1brr: BEGIN ISOLATION LEVEL REPEATABLE READ;
step s1exec2: SELECT * FROM partrem WHERE a <> (SELECT 2) AND a <> 1; <waiting ...>
step s2remp: ALTER TABLE partrem DETACH PARTITION partrem2 CONCURRENTLY; <waiting ...>
-step s3unlock: SELECT pg_advisory_unlock(12543);
+step s3unlock: SELECT pg_advisory_unlock(0x7766554433221100);
pg_advisory_unlock
------------------
t
@@ -129,7 +129,7 @@ step s1c: COMMIT;
step s2remp: <... completed>
starting permutation: s3lock s1brr s1prepare s2remp s1execprep s3unlock s1check s1c s1check s1dealloc
-step s3lock: SELECT pg_advisory_lock(12543);
+step s3lock: SELECT pg_advisory_lock(0x7766554433221100);
pg_advisory_lock
----------------
@@ -139,7 +139,7 @@ step s1brr: BEGIN ISOLATION LEVEL REPEATABLE READ;
step s1prepare: PREPARE ins AS INSERT INTO partrem VALUES ($1, 'GHI');
step s2remp: ALTER TABLE partrem DETACH PARTITION partrem2 CONCURRENTLY; <waiting ...>
step s1execprep: EXECUTE ins(2); <waiting ...>
-step s3unlock: SELECT pg_advisory_unlock(12543);
+step s3unlock: SELECT pg_advisory_unlock(0x7766554433221100);
pg_advisory_unlock
------------------
t
@@ -165,14 +165,14 @@ starting permutation: s1brr s1prepare s2remp s3lock s1execprep s3unlock s1check
step s1brr: BEGIN ISOLATION LEVEL REPEATABLE READ;
step s1prepare: PREPARE ins AS INSERT INTO partrem VALUES ($1, 'GHI');
step s2remp: ALTER TABLE partrem DETACH PARTITION partrem2 CONCURRENTLY; <waiting ...>
-step s3lock: SELECT pg_advisory_lock(12543);
+step s3lock: SELECT pg_advisory_lock(0x7766554433221100);
pg_advisory_lock
----------------
(1 row)
step s1execprep: EXECUTE ins(2); <waiting ...>
-step s3unlock: SELECT pg_advisory_unlock(12543);
+step s3unlock: SELECT pg_advisory_unlock(0x7766554433221100);
pg_advisory_unlock
------------------
t
@@ -201,7 +201,7 @@ a|b
-+-
(0 rows)
-step s3lock: SELECT pg_advisory_lock(12543);
+step s3lock: SELECT pg_advisory_lock(0x7766554433221100);
pg_advisory_lock
----------------
@@ -210,7 +210,7 @@ pg_advisory_lock
step s2remp: ALTER TABLE partrem DETACH PARTITION partrem2 CONCURRENTLY; <waiting ...>
step s1prepare: PREPARE ins AS INSERT INTO partrem VALUES ($1, 'GHI');
step s1execprep: EXECUTE ins(2); <waiting ...>
-step s3unlock: SELECT pg_advisory_unlock(12543);
+step s3unlock: SELECT pg_advisory_unlock(0x7766554433221100);
pg_advisory_unlock
------------------
t
diff --git a/src/test/modules/delay_execution/specs/partition-addition.spec b/src/test/modules/delay_execution/specs/partition-addition.spec
index 99010dfad5..4a68e88cc7 100644
--- a/src/test/modules/delay_execution/specs/partition-addition.spec
+++ b/src/test/modules/delay_execution/specs/partition-addition.spec
@@ -25,12 +25,12 @@ teardown
session "s1"
step "s1exec" { LOAD 'delay_execution';
- SET delay_execution.post_planning_lock_id = 12345;
+ SET delay_execution.post_planning_lock_id = 0x1122334455667788;
SELECT * FROM foo WHERE a <> 1 AND a <> (SELECT 3); }
session "s2"
-step "s2lock" { SELECT pg_advisory_lock(12345); }
-step "s2unlock" { SELECT pg_advisory_unlock(12345); }
+step "s2lock" { SELECT pg_advisory_lock(0x1122334455667788); }
+step "s2unlock" { SELECT pg_advisory_unlock(0x1122334455667788); }
step "s2addp" { CREATE TABLE foo2 (LIKE foo);
ALTER TABLE foo ATTACH PARTITION foo2 FOR VALUES IN (2);
INSERT INTO foo VALUES (2, 'ADD2'); }
diff --git a/src/test/modules/delay_execution/specs/partition-removal-1.spec b/src/test/modules/delay_execution/specs/partition-removal-1.spec
index 5ee2750129..25b40b89a4 100644
--- a/src/test/modules/delay_execution/specs/partition-removal-1.spec
+++ b/src/test/modules/delay_execution/specs/partition-removal-1.spec
@@ -18,7 +18,7 @@ teardown
session "s1"
setup { LOAD 'delay_execution';
- SET delay_execution.post_planning_lock_id = 12543; }
+ SET delay_execution.post_planning_lock_id = 0x7766554433221100; }
step "s1b" { BEGIN; }
step "s1brr" { BEGIN ISOLATION LEVEL REPEATABLE READ; }
step "s1exec" { SELECT * FROM partrem WHERE a <> 1 AND a <> (SELECT 3); }
@@ -33,8 +33,8 @@ session "s2"
step "s2remp" { ALTER TABLE partrem DETACH PARTITION partrem2 CONCURRENTLY; }
session "s3"
-step "s3lock" { SELECT pg_advisory_lock(12543); }
-step "s3unlock" { SELECT pg_advisory_unlock(12543); }
+step "s3lock" { SELECT pg_advisory_lock(0x7766554433221100); }
+step "s3unlock" { SELECT pg_advisory_unlock(0x7766554433221100); }
step "s3check" { SELECT * FROM partrem; }
# The SELECT will be planned with all three partitions shown above,
--
2.46.0
On Sep 25, 2024, at 19:03, Aleksander Alekseev <aleksander@timescale.com> wrote:
Hi,
I found the autovacuum_vacuum_threshold, autovacuum_vacuum_insert_threshold
and autovacuum_analyze_threshold is change to int64 for relation option,
however the GUCs are still integers.
```
postgres=# select * from pg_settings where name = 'autovacuum_vacuum_threshold' \gx
-[ RECORD 1 ]---+------------------------------------------------------------
name | autovacuum_vacuum_threshold
setting | 50
unit |
category | Autovacuum
short_desc | Minimum number of tuple updates or deletes prior to vacuum.
extra_desc |
context | sighup
vartype | integer
source | default
min_val | 0
max_val | 2147483647
enumvals |
boot_val | 50
reset_val | 50
sourcefile |
sourceline |
pending_restart | f
```
Is there something I missed?
No, you found a bug. The patch didn't change ConfigureNamesInt64[]
thus these GUCs were still treated as int32s.
Here is the corrected patch v3. Thanks!
=# select * from pg_settings where name = 'autovacuum_vacuum_threshold';
-[ RECORD 1 ]---+------------------------------------------------------------
name | autovacuum_vacuum_threshold
setting | 1234605616436508552
unit |
category | Autovacuum
short_desc | Minimum number of tuple updates or deletes prior to vacuum.
extra_desc |
context | sighup
vartype | int64
source | configuration file
min_val | 0
max_val | 9223372036854775807
enumvals |
boot_val | 50
reset_val | 1234605616436508552
sourcefile | /Users/eax/pginstall/data-master/postgresql.conf
sourceline | 664
pending_restart | f
Thanks for updating the patch.
After testing the v3 patch, I found it cannot correctly handle the number with underscore.
See:
```
postgres=# alter system set autovacuum_vacuum_threshold to 2_147_483_648;
ERROR: invalid value for parameter "autovacuum_vacuum_threshold": "2_147_483_648"
postgres=# alter system set autovacuum_vacuum_threshold to 2_147_483_647;
ALTER SYSTEM
```
IIRC, the lexer only supports integers but not int64.
--
Best regards,
Japin Li
Hi,
```
postgres=# alter system set autovacuum_vacuum_threshold to 2_147_483_648;
ERROR: invalid value for parameter "autovacuum_vacuum_threshold": "2_147_483_648"
postgres=# alter system set autovacuum_vacuum_threshold to 2_147_483_647;
ALTER SYSTEM
```IIRC, the lexer only supports integers but not int64.
Right. Supporting underscores for GUCs was discussed above but not
implemented in the patch. As Alexander rightly pointed out this is not
a priority and can be discussed separately.
--
Best regards,
Aleksander Alekseev
FWIW, I agree with the upthread opinions that we shouldn't do this
(invent int64 GUCs). I don't think we need the added code bloat
and risk of breaking user code that isn't expecting this new GUC
type. We invented the notion of GUC units in part to ensure that
int32 GUCs could be adapted to handle potentially-large numbers.
And there's always the fallback position of using a float8 GUC
if you really feel you need a wider range.
regards, tom lane
Hi, Tom!
On Wed, Sep 25, 2024 at 6:08 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:
FWIW, I agree with the upthread opinions that we shouldn't do this
(invent int64 GUCs). I don't think we need the added code bloat
and risk of breaking user code that isn't expecting this new GUC
type. We invented the notion of GUC units in part to ensure that
int32 GUCs could be adapted to handle potentially-large numbers.
And there's always the fallback position of using a float8 GUC
if you really feel you need a wider range.
Thank you for your feedback.
Do you think we don't need int64 GUCs just now, when 64-bit
transaction ids are far from committable shape? Or do you think we
don't need int64 GUCs even if we have 64-bit transaction ids? If yes,
what do you think we should use for *_age variables with 64-bit
transaction ids?
------
Regards,
Alexander Korotkov
Supabase
Hi Alexander
I think we need int64 GUCs, due to these parameters(
autovacuum_freeze_table_age, autovacuum_freeze_max_age,When a table age is
greater than any of these parameters an aggressive vacuum will be
performed, When we implementing xid64, is it still necessary to be in the
int range? btw, I have a suggestion to record a warning in the log when the
table age exceeds the int maximum. These default values we can set a
reasonable values ,for example autovacuum_freeze_max_age=4294967295 or
8589934592.
Thanks
Alexander Korotkov <aekorotkov@gmail.com> 于2024年9月26日周四 02:05写道:
Show quoted text
Hi, Tom!
On Wed, Sep 25, 2024 at 6:08 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:
FWIW, I agree with the upthread opinions that we shouldn't do this
(invent int64 GUCs). I don't think we need the added code bloat
and risk of breaking user code that isn't expecting this new GUC
type. We invented the notion of GUC units in part to ensure that
int32 GUCs could be adapted to handle potentially-large numbers.
And there's always the fallback position of using a float8 GUC
if you really feel you need a wider range.Thank you for your feedback.
Do you think we don't need int64 GUCs just now, when 64-bit
transaction ids are far from committable shape? Or do you think we
don't need int64 GUCs even if we have 64-bit transaction ids? If yes,
what do you think we should use for *_age variables with 64-bit
transaction ids?------
Regards,
Alexander Korotkov
Supabase
On Thu, Sep 26, 2024 at 12:30 PM wenhui qiu <qiuwenhuifx@gmail.com> wrote:
I think we need int64 GUCs, due to these parameters( autovacuum_freeze_table_age, autovacuum_freeze_max_age,When a table age is greater than any of these parameters an aggressive vacuum will be performed, When we implementing xid64, is it still necessary to be in the int range? btw, I have a suggestion to record a warning in the log when the table age exceeds the int maximum. These default values we can set a reasonable values ,for example autovacuum_freeze_max_age=4294967295 or 8589934592.
In principle, even with 64-bit transaction ids we could specify *_age
GUCs as int32 with bigger units or as float8. That feels a bit
awkward for me. This is why I queried more about Tom's opinion in
more details: did he propose to wait with int64 GUCs before we have
64-bit transaction ids, or give up about them completely?
Links.
1. /messages/by-id/3649727.1727276882@sss.pgh.pa.us
------
Regards,
Alexander Korotkov
Supabase
Alexander Korotkov <aekorotkov@gmail.com> writes:
Do you think we don't need int64 GUCs just now, when 64-bit
transaction ids are far from committable shape? Or do you think we
don't need int64 GUCs even if we have 64-bit transaction ids? If yes,
what do you think we should use for *_age variables with 64-bit
transaction ids?
I seriously doubt that _age values exceeding INT32_MAX would be
useful, even in the still-extremely-doubtful situation that we
get to true 64-bit XIDs. But if you think we must have that,
we could still use float8 GUCs for them. float8 is exact up
to 2^53 (given IEEE math), and you certainly aren't going to
convince me that anyone needs _age values exceeding that.
For that matter, an imprecise representation of such an age
limit would still be all right wouldn't it?
regards, tom lane
Hi,
I seriously doubt that _age values exceeding INT32_MAX would be
useful, even in the still-extremely-doubtful situation that we
get to true 64-bit XIDs. But if you think we must have that,
we could still use float8 GUCs for them. float8 is exact up
to 2^53 (given IEEE math), and you certainly aren't going to
convince me that anyone needs _age values exceeding that.
For that matter, an imprecise representation of such an age
limit would still be all right wouldn't it?
Considering the recent feedback. I'm marking the corresponding CF
entry as "Rejected".
Thanks to everyone involved!
--
Best regards,
Aleksander Alekseev
Hi hackers!
Upgraded the "Int64 GUC" patch in order to conform to f3f06b13308e3
updates. Rebased and tested upon the current master (3f9b9621766). The
patch is still needed to be up to date as a part of the xid64 solution.
Best regards,
Evgeny Voropaev,
TantorLabs, LLC.
<evorop@gmail.com>
<evgeny.voropaev@tantorlabs.ru>
Hi hackers!
Upgraded the "Int64 GUC" patch in order to conform to f3f06b13308e3
updates. Rebased and tested upon the current master (3f9b9621766). The
patch is still needed to be up to date as a part of the xid64 solution.
Best regards,
Evgeny Voropaev,
TantorLabs, LLC.
<evorop@gmail.com>
<evgeny.voropaev@tantorlabs.ru>
Attachments:
v4-0001-Support-64-bit-integer-GUCs.patchtext/x-patch; charset=UTF-8; name=v4-0001-Support-64-bit-integer-GUCs.patchDownload
From 1ff7cc48d955e02463e6c0ff8a7c0f7673d83f8f Mon Sep 17 00:00:00 2001
From: Evgeny Voropaev <evorop@gmail.com>
Date: Sun, 8 Dec 2024 21:29:31 +0800
Subject: [PATCH v4] Support 64-bit integer 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>
Reviewed-by: Li Japin <japinli@hotmail.com>
Author(rebase onto PG18dev, Dec 8 2024): Evgeny Voropaev <evorop@gmail.com> <evgeny.voropaev@tantorlabs.ru>
Discussion: https://postgr.es/m/CAJ7c6TMvPz8q+nC=JoKniy7yxPzQYcCTnNFYmsDP-nnWsAOJ2g@mail.gmail.com
---
src/backend/access/common/reloptions.c | 129 ++++--
src/backend/postmaster/autovacuum.c | 6 +-
src/backend/utils/misc/guc.c | 418 ++++++++++++++++++
src/backend/utils/misc/guc_funcs.c | 25 ++
src/backend/utils/misc/guc_tables.c | 64 +--
src/include/access/reloptions.h | 13 +
src/include/postmaster/autovacuum.h | 6 +-
src/include/utils/guc.h | 17 +
src/include/utils/guc_tables.h | 19 +
src/include/utils/rel.h | 6 +-
.../modules/delay_execution/delay_execution.c | 28 +-
.../expected/partition-addition.out | 6 +-
.../expected/partition-removal-1.out | 28 +-
.../specs/partition-addition.spec | 6 +-
.../specs/partition-removal-1.spec | 6 +-
15 files changed, 674 insertions(+), 103 deletions(-)
diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
index 49fd35bfc55..b989442942f 100644
--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
@@ -222,33 +222,6 @@ static relopt_int intRelOpts[] =
},
SPGIST_DEFAULT_FILLFACTOR, SPGIST_MIN_FILLFACTOR, 100
},
- {
- {
- "autovacuum_vacuum_threshold",
- "Minimum number of tuple updates or deletes prior to vacuum",
- RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
- ShareUpdateExclusiveLock
- },
- -1, 0, INT_MAX
- },
- {
- {
- "autovacuum_vacuum_insert_threshold",
- "Minimum number of tuple inserts prior to vacuum, or -1 to disable insert vacuums",
- RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
- ShareUpdateExclusiveLock
- },
- -2, -1, INT_MAX
- },
- {
- {
- "autovacuum_analyze_threshold",
- "Minimum number of tuple inserts, updates or deletes prior to analyze",
- RELOPT_KIND_HEAP,
- ShareUpdateExclusiveLock
- },
- -1, 0, INT_MAX
- },
{
{
"autovacuum_vacuum_cost_limit",
@@ -380,7 +353,39 @@ static relopt_int intRelOpts[] =
},
-1, 0, 1024
},
+ /* list terminator */
+ {{NULL}}
+};
+static relopt_int64 int64RelOpts[] =
+{
+ {
+ {
+ "autovacuum_vacuum_threshold",
+ "Minimum number of tuple updates or deletes prior to vacuum",
+ RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
+ ShareUpdateExclusiveLock
+ },
+ INT64CONST(-1), INT64CONST(0), PG_INT64_MAX
+ },
+ {
+ {
+ "autovacuum_vacuum_insert_threshold",
+ "Minimum number of tuple inserts prior to vacuum, or -1 to disable insert vacuums",
+ RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
+ ShareUpdateExclusiveLock
+ },
+ INT64CONST(-2), INT64CONST(-1), PG_INT64_MAX
+ },
+ {
+ {
+ "autovacuum_analyze_threshold",
+ "Minimum number of tuple inserts, updates or deletes prior to analyze",
+ RELOPT_KIND_HEAP,
+ ShareUpdateExclusiveLock
+ },
+ INT64CONST(-1), INT64CONST(0), PG_INT64_MAX
+ },
/* list terminator */
{{NULL}}
};
@@ -595,6 +600,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 +648,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 +811,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 +968,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 +1659,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 +1836,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 :
@@ -1841,11 +1910,11 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind)
{"fillfactor", RELOPT_TYPE_INT, offsetof(StdRdOptions, fillfactor)},
{"autovacuum_enabled", RELOPT_TYPE_BOOL,
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, enabled)},
- {"autovacuum_vacuum_threshold", RELOPT_TYPE_INT,
+ {"autovacuum_vacuum_threshold", RELOPT_TYPE_INT64,
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_threshold)},
- {"autovacuum_vacuum_insert_threshold", RELOPT_TYPE_INT,
+ {"autovacuum_vacuum_insert_threshold", RELOPT_TYPE_INT64,
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_ins_threshold)},
- {"autovacuum_analyze_threshold", RELOPT_TYPE_INT,
+ {"autovacuum_analyze_threshold", RELOPT_TYPE_INT64,
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, analyze_threshold)},
{"autovacuum_vacuum_cost_limit", RELOPT_TYPE_INT,
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_cost_limit)},
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 180bb7e96ed..63c55c13e86 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -118,11 +118,11 @@ bool autovacuum_start_daemon = false;
int autovacuum_max_workers;
int autovacuum_work_mem = -1;
int autovacuum_naptime;
-int autovacuum_vac_thresh;
+int64 autovacuum_vac_thresh;
double autovacuum_vac_scale;
-int autovacuum_vac_ins_thresh;
+int64 autovacuum_vac_ins_thresh;
double autovacuum_vac_ins_scale;
-int autovacuum_anl_thresh;
+int64 autovacuum_anl_thresh;
double autovacuum_anl_scale;
int autovacuum_freeze_max_age;
int autovacuum_multixact_freeze_max_age;
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index c10c0844ab6..fac919a0375 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -263,6 +263,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,
@@ -760,6 +762,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;
@@ -821,6 +827,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;
@@ -849,6 +859,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 */
@@ -937,6 +948,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];
@@ -1000,6 +1019,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;
@@ -1427,6 +1458,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
@@ -1462,6 +1494,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;
@@ -1692,6 +1738,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;
@@ -2042,6 +2106,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);
@@ -2425,6 +2501,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)
{
@@ -2947,6 +3041,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
@@ -3192,6 +3351,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\"",
+ conf->gen.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, conf->gen.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;
@@ -3895,6 +4084,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, 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
}
@@ -4378,6 +4657,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);
@@ -4426,6 +4710,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);
@@ -5184,6 +5473,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,
@@ -5377,6 +5696,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;
@@ -5509,6 +5836,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;
@@ -5611,6 +5953,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;
@@ -5883,6 +6233,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:
{
/*
@@ -6049,6 +6417,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;
@@ -6262,6 +6638,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;
@@ -6862,6 +7246,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 9c9edd3d2f5..d0625d18b3a 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 8cf1afbad20..08626cdaf2c 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",
@@ -3416,33 +3417,6 @@ struct config_int ConfigureNamesInt[] =
60, 1, INT_MAX / 1000,
NULL, NULL, NULL
},
- {
- {"autovacuum_vacuum_threshold", PGC_SIGHUP, AUTOVACUUM,
- gettext_noop("Minimum number of tuple updates or deletes prior to vacuum."),
- NULL
- },
- &autovacuum_vac_thresh,
- 50, 0, INT_MAX,
- NULL, NULL, NULL
- },
- {
- {"autovacuum_vacuum_insert_threshold", PGC_SIGHUP, AUTOVACUUM,
- gettext_noop("Minimum number of tuple inserts prior to vacuum, or -1 to disable insert vacuums."),
- NULL
- },
- &autovacuum_vac_ins_thresh,
- 1000, -1, INT_MAX,
- NULL, NULL, NULL
- },
- {
- {"autovacuum_analyze_threshold", PGC_SIGHUP, AUTOVACUUM,
- gettext_noop("Minimum number of tuple inserts, updates, or deletes prior to analyze."),
- NULL
- },
- &autovacuum_anl_thresh,
- 50, 0, INT_MAX,
- NULL, NULL, NULL
- },
{
/* see varsup.c for why this is PGC_POSTMASTER not PGC_SIGHUP */
{"autovacuum_freeze_max_age", PGC_POSTMASTER, AUTOVACUUM,
@@ -3740,6 +3714,42 @@ struct config_int ConfigureNamesInt[] =
};
+struct config_int64 ConfigureNamesInt64[] =
+{
+ {
+ {"autovacuum_vacuum_threshold", PGC_SIGHUP, AUTOVACUUM,
+ gettext_noop("Minimum number of tuple updates or deletes prior to vacuum."),
+ NULL
+ },
+ &autovacuum_vac_thresh,
+ INT64CONST(50), INT64CONST(0), PG_INT64_MAX,
+ NULL, NULL, NULL
+ },
+ {
+ {"autovacuum_vacuum_insert_threshold", PGC_SIGHUP, AUTOVACUUM,
+ gettext_noop("Minimum number of tuple inserts prior to vacuum, or -1 to disable insert vacuums."),
+ NULL
+ },
+ &autovacuum_vac_ins_thresh,
+ INT64CONST(1000), INT64CONST(-1), PG_INT64_MAX,
+ NULL, NULL, NULL
+ },
+ {
+ {"autovacuum_analyze_threshold", PGC_SIGHUP, AUTOVACUUM,
+ gettext_noop("Minimum number of tuple inserts, updates, or deletes prior to analyze."),
+ NULL
+ },
+ &autovacuum_anl_thresh,
+ INT64CONST(50), INT64CONST(0), PG_INT64_MAX,
+ NULL, NULL, NULL
+ },
+ /* 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 df6923c9d50..309c82ebf4d 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/postmaster/autovacuum.h b/src/include/postmaster/autovacuum.h
index cae1e8b3294..15f12ce24f9 100644
--- a/src/include/postmaster/autovacuum.h
+++ b/src/include/postmaster/autovacuum.h
@@ -31,11 +31,11 @@ extern PGDLLIMPORT bool autovacuum_start_daemon;
extern PGDLLIMPORT int autovacuum_max_workers;
extern PGDLLIMPORT int autovacuum_work_mem;
extern PGDLLIMPORT int autovacuum_naptime;
-extern PGDLLIMPORT int autovacuum_vac_thresh;
+extern PGDLLIMPORT int64 autovacuum_vac_thresh;
extern PGDLLIMPORT double autovacuum_vac_scale;
-extern PGDLLIMPORT int autovacuum_vac_ins_thresh;
+extern PGDLLIMPORT int64 autovacuum_vac_ins_thresh;
extern PGDLLIMPORT double autovacuum_vac_ins_scale;
-extern PGDLLIMPORT int autovacuum_anl_thresh;
+extern PGDLLIMPORT int64 autovacuum_anl_thresh;
extern PGDLLIMPORT double autovacuum_anl_scale;
extern PGDLLIMPORT int autovacuum_freeze_max_age;
extern PGDLLIMPORT int autovacuum_multixact_freeze_max_age;
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index 840b0fe57ff..0a3fe0b54f8 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);
@@ -348,6 +350,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) pg_attribute_nonnull(1, 4);
+
extern void DefineCustomRealVariable(const char *name,
const char *short_desc,
const char *long_desc,
@@ -409,6 +424,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 0c0277c4230..c4dfe0afab3 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[];
diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h
index 87002049538..f89064e2744 100644
--- a/src/include/utils/rel.h
+++ b/src/include/utils/rel.h
@@ -308,9 +308,9 @@ typedef struct ForeignKeyCacheInfo
typedef struct AutoVacOpts
{
bool enabled;
- int vacuum_threshold;
- int vacuum_ins_threshold;
- int analyze_threshold;
+ int64 vacuum_threshold;
+ int64 vacuum_ins_threshold;
+ int64 analyze_threshold;
int vacuum_cost_limit;
int freeze_min_age;
int freeze_max_age;
diff --git a/src/test/modules/delay_execution/delay_execution.c b/src/test/modules/delay_execution/delay_execution.c
index fa4693a3f57..036a9c3e10b 100644
--- a/src/test/modules/delay_execution/delay_execution.c
+++ b/src/test/modules/delay_execution/delay_execution.c
@@ -31,7 +31,7 @@
PG_MODULE_MAGIC;
/* GUC: advisory lock ID to use. Zero disables the feature. */
-static int post_planning_lock_id = 0;
+static int64 post_planning_lock_id = 0;
/* Save previous planner hook user to be a good citizen */
static planner_hook_type prev_planner_hook = NULL;
@@ -56,9 +56,9 @@ delay_execution_planner(Query *parse, const char *query_string,
if (post_planning_lock_id != 0)
{
DirectFunctionCall1(pg_advisory_lock_int8,
- Int64GetDatum((int64) post_planning_lock_id));
+ Int64GetDatum(post_planning_lock_id));
DirectFunctionCall1(pg_advisory_unlock_int8,
- Int64GetDatum((int64) post_planning_lock_id));
+ Int64GetDatum(post_planning_lock_id));
/*
* Ensure that we notice any pending invalidations, since the advisory
@@ -75,17 +75,17 @@ void
_PG_init(void)
{
/* Set up the GUC to control which lock is used */
- DefineCustomIntVariable("delay_execution.post_planning_lock_id",
- "Sets the advisory lock ID to be locked/unlocked after planning.",
- "Zero disables the delay.",
- &post_planning_lock_id,
- 0,
- 0, INT_MAX,
- PGC_USERSET,
- 0,
- NULL,
- NULL,
- NULL);
+ DefineCustomInt64Variable("delay_execution.post_planning_lock_id",
+ "Sets the advisory lock ID to be locked/unlocked after planning.",
+ "Zero disables the delay.",
+ &post_planning_lock_id,
+ 0,
+ 0, PG_INT64_MAX,
+ PGC_USERSET,
+ 0,
+ NULL,
+ NULL,
+ NULL);
MarkGUCPrefixReserved("delay_execution");
diff --git a/src/test/modules/delay_execution/expected/partition-addition.out b/src/test/modules/delay_execution/expected/partition-addition.out
index 7d6572b2db2..57750db1603 100644
--- a/src/test/modules/delay_execution/expected/partition-addition.out
+++ b/src/test/modules/delay_execution/expected/partition-addition.out
@@ -1,19 +1,19 @@
Parsed test spec with 2 sessions
starting permutation: s2lock s1exec s2addp s2unlock
-step s2lock: SELECT pg_advisory_lock(12345);
+step s2lock: SELECT pg_advisory_lock(0x1122334455667788);
pg_advisory_lock
----------------
(1 row)
step s1exec: LOAD 'delay_execution';
- SET delay_execution.post_planning_lock_id = 12345;
+ SET delay_execution.post_planning_lock_id = 0x1122334455667788;
SELECT * FROM foo WHERE a <> 1 AND a <> (SELECT 3); <waiting ...>
step s2addp: CREATE TABLE foo2 (LIKE foo);
ALTER TABLE foo ATTACH PARTITION foo2 FOR VALUES IN (2);
INSERT INTO foo VALUES (2, 'ADD2');
-step s2unlock: SELECT pg_advisory_unlock(12345);
+step s2unlock: SELECT pg_advisory_unlock(0x1122334455667788);
pg_advisory_unlock
------------------
t
diff --git a/src/test/modules/delay_execution/expected/partition-removal-1.out b/src/test/modules/delay_execution/expected/partition-removal-1.out
index b81b9995e9a..a2e453fdaa9 100644
--- a/src/test/modules/delay_execution/expected/partition-removal-1.out
+++ b/src/test/modules/delay_execution/expected/partition-removal-1.out
@@ -1,7 +1,7 @@
Parsed test spec with 3 sessions
starting permutation: s3lock s1b s1exec s2remp s3check s3unlock s3check s1c
-step s3lock: SELECT pg_advisory_lock(12543);
+step s3lock: SELECT pg_advisory_lock(0x7766554433221100);
pg_advisory_lock
----------------
@@ -17,7 +17,7 @@ a|b
3|DEF
(2 rows)
-step s3unlock: SELECT pg_advisory_unlock(12543);
+step s3unlock: SELECT pg_advisory_unlock(0x7766554433221100);
pg_advisory_unlock
------------------
t
@@ -40,7 +40,7 @@ step s1c: COMMIT;
step s2remp: <... completed>
starting permutation: s3lock s1brr s1exec s2remp s3check s3unlock s3check s1c
-step s3lock: SELECT pg_advisory_lock(12543);
+step s3lock: SELECT pg_advisory_lock(0x7766554433221100);
pg_advisory_lock
----------------
@@ -56,7 +56,7 @@ a|b
3|DEF
(2 rows)
-step s3unlock: SELECT pg_advisory_unlock(12543);
+step s3unlock: SELECT pg_advisory_unlock(0x7766554433221100);
pg_advisory_unlock
------------------
t
@@ -79,7 +79,7 @@ step s1c: COMMIT;
step s2remp: <... completed>
starting permutation: s3lock s1b s1exec2 s2remp s3unlock s1c
-step s3lock: SELECT pg_advisory_lock(12543);
+step s3lock: SELECT pg_advisory_lock(0x7766554433221100);
pg_advisory_lock
----------------
@@ -88,7 +88,7 @@ pg_advisory_lock
step s1b: BEGIN;
step s1exec2: SELECT * FROM partrem WHERE a <> (SELECT 2) AND a <> 1; <waiting ...>
step s2remp: ALTER TABLE partrem DETACH PARTITION partrem2 CONCURRENTLY; <waiting ...>
-step s3unlock: SELECT pg_advisory_unlock(12543);
+step s3unlock: SELECT pg_advisory_unlock(0x7766554433221100);
pg_advisory_unlock
------------------
t
@@ -104,7 +104,7 @@ step s1c: COMMIT;
step s2remp: <... completed>
starting permutation: s3lock s1brr s1exec2 s2remp s3unlock s1c
-step s3lock: SELECT pg_advisory_lock(12543);
+step s3lock: SELECT pg_advisory_lock(0x7766554433221100);
pg_advisory_lock
----------------
@@ -113,7 +113,7 @@ pg_advisory_lock
step s1brr: BEGIN ISOLATION LEVEL REPEATABLE READ;
step s1exec2: SELECT * FROM partrem WHERE a <> (SELECT 2) AND a <> 1; <waiting ...>
step s2remp: ALTER TABLE partrem DETACH PARTITION partrem2 CONCURRENTLY; <waiting ...>
-step s3unlock: SELECT pg_advisory_unlock(12543);
+step s3unlock: SELECT pg_advisory_unlock(0x7766554433221100);
pg_advisory_unlock
------------------
t
@@ -129,7 +129,7 @@ step s1c: COMMIT;
step s2remp: <... completed>
starting permutation: s3lock s1brr s1prepare s2remp s1execprep s3unlock s1check s1c s1check s1dealloc
-step s3lock: SELECT pg_advisory_lock(12543);
+step s3lock: SELECT pg_advisory_lock(0x7766554433221100);
pg_advisory_lock
----------------
@@ -139,7 +139,7 @@ step s1brr: BEGIN ISOLATION LEVEL REPEATABLE READ;
step s1prepare: PREPARE ins AS INSERT INTO partrem VALUES ($1, 'GHI');
step s2remp: ALTER TABLE partrem DETACH PARTITION partrem2 CONCURRENTLY; <waiting ...>
step s1execprep: EXECUTE ins(2); <waiting ...>
-step s3unlock: SELECT pg_advisory_unlock(12543);
+step s3unlock: SELECT pg_advisory_unlock(0x7766554433221100);
pg_advisory_unlock
------------------
t
@@ -165,14 +165,14 @@ starting permutation: s1brr s1prepare s2remp s3lock s1execprep s3unlock s1check
step s1brr: BEGIN ISOLATION LEVEL REPEATABLE READ;
step s1prepare: PREPARE ins AS INSERT INTO partrem VALUES ($1, 'GHI');
step s2remp: ALTER TABLE partrem DETACH PARTITION partrem2 CONCURRENTLY; <waiting ...>
-step s3lock: SELECT pg_advisory_lock(12543);
+step s3lock: SELECT pg_advisory_lock(0x7766554433221100);
pg_advisory_lock
----------------
(1 row)
step s1execprep: EXECUTE ins(2); <waiting ...>
-step s3unlock: SELECT pg_advisory_unlock(12543);
+step s3unlock: SELECT pg_advisory_unlock(0x7766554433221100);
pg_advisory_unlock
------------------
t
@@ -201,7 +201,7 @@ a|b
-+-
(0 rows)
-step s3lock: SELECT pg_advisory_lock(12543);
+step s3lock: SELECT pg_advisory_lock(0x7766554433221100);
pg_advisory_lock
----------------
@@ -210,7 +210,7 @@ pg_advisory_lock
step s2remp: ALTER TABLE partrem DETACH PARTITION partrem2 CONCURRENTLY; <waiting ...>
step s1prepare: PREPARE ins AS INSERT INTO partrem VALUES ($1, 'GHI');
step s1execprep: EXECUTE ins(2); <waiting ...>
-step s3unlock: SELECT pg_advisory_unlock(12543);
+step s3unlock: SELECT pg_advisory_unlock(0x7766554433221100);
pg_advisory_unlock
------------------
t
diff --git a/src/test/modules/delay_execution/specs/partition-addition.spec b/src/test/modules/delay_execution/specs/partition-addition.spec
index 99010dfad5c..4a68e88cc74 100644
--- a/src/test/modules/delay_execution/specs/partition-addition.spec
+++ b/src/test/modules/delay_execution/specs/partition-addition.spec
@@ -25,12 +25,12 @@ teardown
session "s1"
step "s1exec" { LOAD 'delay_execution';
- SET delay_execution.post_planning_lock_id = 12345;
+ SET delay_execution.post_planning_lock_id = 0x1122334455667788;
SELECT * FROM foo WHERE a <> 1 AND a <> (SELECT 3); }
session "s2"
-step "s2lock" { SELECT pg_advisory_lock(12345); }
-step "s2unlock" { SELECT pg_advisory_unlock(12345); }
+step "s2lock" { SELECT pg_advisory_lock(0x1122334455667788); }
+step "s2unlock" { SELECT pg_advisory_unlock(0x1122334455667788); }
step "s2addp" { CREATE TABLE foo2 (LIKE foo);
ALTER TABLE foo ATTACH PARTITION foo2 FOR VALUES IN (2);
INSERT INTO foo VALUES (2, 'ADD2'); }
diff --git a/src/test/modules/delay_execution/specs/partition-removal-1.spec b/src/test/modules/delay_execution/specs/partition-removal-1.spec
index 5ee27501294..25b40b89a46 100644
--- a/src/test/modules/delay_execution/specs/partition-removal-1.spec
+++ b/src/test/modules/delay_execution/specs/partition-removal-1.spec
@@ -18,7 +18,7 @@ teardown
session "s1"
setup { LOAD 'delay_execution';
- SET delay_execution.post_planning_lock_id = 12543; }
+ SET delay_execution.post_planning_lock_id = 0x7766554433221100; }
step "s1b" { BEGIN; }
step "s1brr" { BEGIN ISOLATION LEVEL REPEATABLE READ; }
step "s1exec" { SELECT * FROM partrem WHERE a <> 1 AND a <> (SELECT 3); }
@@ -33,8 +33,8 @@ session "s2"
step "s2remp" { ALTER TABLE partrem DETACH PARTITION partrem2 CONCURRENTLY; }
session "s3"
-step "s3lock" { SELECT pg_advisory_lock(12543); }
-step "s3unlock" { SELECT pg_advisory_unlock(12543); }
+step "s3lock" { SELECT pg_advisory_lock(0x7766554433221100); }
+step "s3unlock" { SELECT pg_advisory_unlock(0x7766554433221100); }
step "s3check" { SELECT * FROM partrem; }
# The SELECT will be planned with all three partitions shown above,
--
2.47.1
Hi aleksander
Didn't you mark this patch as rejected last time? Do we still need to
continue this path?
Thanks
On Sun, Dec 8, 2024 at 10:16 PM Evgeny Voropaev <evorop.wiki@gmail.com>
wrote:
Show quoted text
Hi hackers!
Upgraded the "Int64 GUC" patch in order to conform to f3f06b13308e3
updates. Rebased and tested upon the current master (3f9b9621766). The
patch is still needed to be up to date as a part of the xid64 solution.Best regards,
Evgeny Voropaev,
TantorLabs, LLC.
<evorop@gmail.com>
<evgeny.voropaev@tantorlabs.ru>
Hi, Wenhui!
On Tue, 10 Dec 2024 at 17:32, wenhui qiu <qiuwenhuifx@gmail.com> wrote:
Hi aleksander
Didn't you mark this patch as rejected last time? Do we still need to
continue this path?Thanks
On Sun, Dec 8, 2024 at 10:16 PM Evgeny Voropaev <evorop.wiki@gmail.com>
wrote:Hi hackers!
Upgraded the "Int64 GUC" patch in order to conform to f3f06b13308e3
updates. Rebased and tested upon the current master (3f9b9621766). The
patch is still needed to be up to date as a part of the xid64 solution.Best regards,
Evgeny Voropaev,
TantorLabs, LLC.
<evorop@gmail.com>
<evgeny.voropaev@tantorlabs.ru>
I see Aleksander worked on this patch (with many other hackers) and marked
it as rejected. And now Evgeniy, a new developer wants to continue and
rebase this patch and also the patches in another 64-xid thread
disregarding the fact that the patch is rejected. It's not a crime. It's
rejected, true.
Regards,
Pavel Borisov
Pavel Borisov <pashkin.elfe@gmail.com> writes:
I see Aleksander worked on this patch (with many other hackers) and marked
it as rejected. And now Evgeniy, a new developer wants to continue and
rebase this patch and also the patches in another 64-xid thread
disregarding the fact that the patch is rejected. It's not a crime. It's
rejected, true.
No, but it's a waste of time. Just rebasing the patch does nothing to
counter the arguments that made us reject it before.
regards, tom lane
On Tue, 10 Dec 2024 at 19:13, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Pavel Borisov <pashkin.elfe@gmail.com> writes:
I see Aleksander worked on this patch (with many other hackers) and
marked
it as rejected. And now Evgeniy, a new developer wants to continue and
rebase this patch and also the patches in another 64-xid thread
disregarding the fact that the patch is rejected. It's not a crime. It's
rejected, true.No, but it's a waste of time. Just rebasing the patch does nothing to
counter the arguments that made us reject it before.
Tom, I agree! Just wrote this because of probable confusion of names by
Wenhui above.
Regards,
Pavel