#define FLEX_SCANNER
#define YY_FLEX_MAJOR_VERSION 2
#define YY_FLEX_MINOR_VERSION 5
-#define YY_FLEX_SUBMINOR_VERSION 37
+#define YY_FLEX_SUBMINOR_VERSION 35
#if YY_FLEX_SUBMINOR_VERSION > 0
#define FLEX_BETA
#endif
typedef uint16_t flex_uint16_t;
typedef int32_t flex_int32_t;
typedef uint32_t flex_uint32_t;
+typedef uint64_t flex_uint64_t;
#else
typedef signed char flex_int8_t;
typedef short int flex_int16_t;
typedef unsigned char flex_uint8_t;
typedef unsigned short int flex_uint16_t;
typedef unsigned int flex_uint32_t;
+#endif /* ! C99 */
/* Limits of integral types. */
#ifndef INT8_MIN
#define UINT32_MAX (4294967295U)
#endif
-#endif /* ! C99 */
-
#endif /* ! FLEXINT_H */
#ifdef __cplusplus
/* Begin user sect3 */
-#define yywrap() 1
+#define yywrap(n) 1
#define YY_SKIP_YYWRAP
typedef unsigned char YY_CHAR;
*/
#define YY_DO_BEFORE_ACTION \
(yytext_ptr) = yy_bp; \
- yyleng = (size_t) (yy_cp - yy_bp); \
+ yyleng = (yy_size_t) (yy_cp - yy_bp); \
(yy_hold_char) = *yy_cp; \
*yy_cp = '\0'; \
(yy_c_buf_p) = yy_cp;
flex_int32_t yy_verify;
flex_int32_t yy_nxt;
};
-static yyconst flex_int16_t yy_accept[38] =
+static yyconst flex_int16_t yy_accept[40] =
{ 0,
0, 0, 12, 10, 2, 1, 10, 10, 10, 8,
7, 7, 9, 4, 2, 0, 3, 0, 5, 0,
- 8, 7, 7, 8, 0, 0, 6, 4, 4, 0,
- 5, 0, 0, 8, 7, 6, 0
+ 8, 7, 7, 8, 0, 7, 7, 6, 4, 4,
+ 0, 5, 0, 0, 8, 7, 7, 6, 0
} ;
static yyconst flex_int32_t yy_ec[256] =
14, 13, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 18,
- 15, 15, 1, 1, 1, 1, 1, 15, 15, 15,
- 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
- 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
- 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
- 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
- 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
- 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
- 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
-
- 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
- 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
- 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
- 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
- 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
- 15, 15, 15, 15, 15
+ 15, 15, 1, 1, 1, 1, 1, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19
} ;
-static yyconst flex_int32_t yy_meta[19] =
+static yyconst flex_int32_t yy_meta[20] =
{ 0,
1, 1, 2, 1, 1, 1, 3, 3, 3, 4,
- 4, 1, 5, 4, 3, 1, 3, 3
+ 4, 1, 5, 6, 5, 1, 3, 5, 3
} ;
-static yyconst flex_int16_t yy_base[45] =
+static yyconst flex_int16_t yy_base[47] =
{ 0,
- 0, 0, 61, 86, 58, 86, 55, 14, 23, 43,
- 10, 46, 86, 28, 47, 40, 86, 16, 86, 22,
- 28, 0, 0, 0, 40, 0, 24, 45, 0, 24,
- 39, 43, 12, 14, 0, 22, 86, 62, 67, 22,
- 70, 75, 77, 80
+ 0, 0, 66, 115, 59, 115, 57, 15, 24, 40,
+ 28, 35, 115, 40, 50, 48, 115, 17, 115, 21,
+ 36, 0, 12, 0, 52, 0, 54, 8, 66, 0,
+ 24, 39, 40, 13, 17, 0, 0, 4, 115, 83,
+ 89, 92, 96, 102, 104, 108
} ;
-static yyconst flex_int16_t yy_def[45] =
+static yyconst flex_int16_t yy_def[47] =
{ 0,
- 37, 1, 37, 37, 37, 37, 38, 39, 37, 40,
- 9, 9, 37, 41, 37, 38, 37, 39, 37, 42,
- 40, 11, 12, 21, 37, 43, 44, 41, 28, 39,
- 39, 42, 37, 37, 43, 44, 0, 37, 37, 37,
- 37, 37, 37, 37
+ 39, 1, 39, 39, 39, 39, 40, 41, 39, 42,
+ 39, 11, 39, 43, 39, 40, 39, 41, 39, 44,
+ 42, 11, 11, 21, 39, 45, 39, 46, 43, 29,
+ 41, 41, 44, 39, 39, 27, 27, 46, 0, 39,
+ 39, 39, 39, 39, 39, 39
} ;
-static yyconst flex_int16_t yy_nxt[105] =
+static yyconst flex_int16_t yy_nxt[135] =
{ 0,
4, 5, 6, 7, 8, 9, 9, 10, 4, 11,
- 12, 13, 14, 14, 14, 4, 14, 14, 19, 23,
- 19, 34, 34, 34, 34, 24, 31, 26, 19, 20,
- 21, 20, 22, 23, 27, 27, 27, 32, 36, 20,
- 36, 25, 17, 19, 29, 33, 33, 31, 15, 34,
- 34, 27, 27, 27, 20, 23, 25, 17, 32, 15,
- 37, 29, 16, 16, 16, 16, 16, 18, 37, 18,
- 18, 18, 28, 28, 28, 30, 37, 30, 30, 30,
- 35, 35, 27, 27, 27, 3, 37, 37, 37, 37,
- 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
-
- 37, 37, 37, 37
+ 12, 13, 14, 14, 14, 4, 14, 14, 14, 19,
+ 38, 19, 35, 35, 38, 32, 35, 35, 19, 26,
+ 20, 21, 20, 22, 23, 21, 33, 23, 23, 20,
+ 26, 26, 26, 19, 32, 27, 28, 28, 28, 25,
+ 17, 15, 26, 25, 20, 33, 30, 34, 34, 17,
+ 15, 35, 35, 36, 36, 39, 37, 37, 26, 39,
+ 39, 26, 28, 28, 28, 39, 39, 39, 39, 39,
+ 39, 39, 30, 16, 16, 16, 16, 16, 16, 18,
+ 39, 18, 18, 18, 18, 24, 39, 24, 29, 29,
+
+ 29, 29, 31, 39, 31, 31, 31, 31, 26, 26,
+ 28, 28, 28, 28, 3, 39, 39, 39, 39, 39,
+ 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
+ 39, 39, 39, 39
} ;
-static yyconst flex_int16_t yy_chk[105] =
+static yyconst flex_int16_t yy_chk[135] =
{ 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 8, 11,
- 18, 33, 33, 34, 34, 40, 20, 11, 30, 8,
- 9, 18, 9, 9, 14, 14, 14, 20, 36, 30,
- 27, 21, 16, 31, 14, 25, 25, 32, 15, 25,
- 25, 28, 28, 28, 31, 12, 10, 7, 32, 5,
- 3, 28, 38, 38, 38, 38, 38, 39, 0, 39,
- 39, 39, 41, 41, 41, 42, 0, 42, 42, 42,
- 43, 43, 44, 44, 44, 37, 37, 37, 37, 37,
- 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
-
- 37, 37, 37, 37
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 8,
+ 38, 18, 34, 34, 28, 20, 35, 35, 31, 23,
+ 8, 9, 18, 9, 9, 11, 20, 11, 11, 31,
+ 11, 11, 11, 32, 33, 11, 14, 14, 14, 21,
+ 16, 15, 12, 10, 32, 33, 14, 25, 25, 7,
+ 5, 25, 25, 27, 27, 3, 27, 27, 27, 0,
+ 0, 27, 29, 29, 29, 0, 0, 0, 0, 0,
+ 0, 0, 29, 40, 40, 40, 40, 40, 40, 41,
+ 0, 41, 41, 41, 41, 42, 0, 42, 43, 43,
+
+ 43, 43, 44, 0, 44, 44, 44, 44, 45, 45,
+ 46, 46, 46, 46, 39, 39, 39, 39, 39, 39,
+ 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
+ 39, 39, 39, 39
} ;
static yy_state_type yy_last_accepting_state;
ConfigVariable **head_p, ConfigVariable **tail_p);
#define YY_NO_INPUT 1
-#line 550 "config/pool_config.c"
+#line 556 "config/pool_config.c"
#define INITIAL 0
/* This used to be an fputs(), but since the string might contain NUL's,
* we now use fwrite().
*/
-#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0)
+#define ECHO fwrite( yytext, yyleng, 1, yyout )
#endif
/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
{ \
int c = '*'; \
- size_t n; \
+ yy_size_t n; \
for ( n = 0; n < max_size && \
(c = getc( yyin )) != EOF && c != '\n'; ++n ) \
buf[n] = (char) c; \
register char *yy_cp, *yy_bp;
register int yy_act;
-#line 89 "pool_config.l"
+#line 90 "pool_config.l"
-#line 733 "config/pool_config.c"
+#line 739 "config/pool_config.c"
if ( !(yy_init) )
{
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
{
yy_current_state = (int) yy_def[yy_current_state];
- if ( yy_current_state >= 38 )
+ if ( yy_current_state >= 40 )
yy_c = yy_meta[(unsigned int) yy_c];
}
yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
++yy_cp;
}
- while ( yy_current_state != 37 );
+ while ( yy_current_state != 39 );
yy_cp = (yy_last_accepting_cpos);
yy_current_state = (yy_last_accepting_state);
case 1:
/* rule 1 can match eol */
YY_RULE_SETUP
-#line 91 "pool_config.l"
+#line 92 "pool_config.l"
Lineno++; return POOL_EOL;
YY_BREAK
case 2:
YY_RULE_SETUP
-#line 92 "pool_config.l"
+#line 93 "pool_config.l"
/* eat whitespace */
YY_BREAK
case 3:
(yy_c_buf_p) = yy_cp -= 1;
YY_DO_BEFORE_ACTION; /* set up yytext again */
YY_RULE_SETUP
-#line 93 "pool_config.l"
+#line 94 "pool_config.l"
/* eat comment */
YY_BREAK
case 4:
YY_RULE_SETUP
-#line 95 "pool_config.l"
+#line 96 "pool_config.l"
return POOL_KEY;
YY_BREAK
case 5:
YY_RULE_SETUP
-#line 96 "pool_config.l"
+#line 97 "pool_config.l"
return POOL_STRING;
YY_BREAK
case 6:
YY_RULE_SETUP
-#line 97 "pool_config.l"
+#line 98 "pool_config.l"
return POOL_UNQUOTED_STRING;
YY_BREAK
case 7:
YY_RULE_SETUP
-#line 98 "pool_config.l"
+#line 99 "pool_config.l"
return POOL_INTEGER;
YY_BREAK
case 8:
YY_RULE_SETUP
-#line 99 "pool_config.l"
+#line 100 "pool_config.l"
return POOL_REAL;
YY_BREAK
case 9:
YY_RULE_SETUP
-#line 100 "pool_config.l"
+#line 101 "pool_config.l"
return POOL_EQUALS;
YY_BREAK
case 10:
YY_RULE_SETUP
-#line 102 "pool_config.l"
+#line 103 "pool_config.l"
return POOL_PARSE_ERROR;
YY_BREAK
case 11:
YY_RULE_SETUP
-#line 104 "pool_config.l"
+#line 105 "pool_config.l"
ECHO;
YY_BREAK
-#line 871 "config/pool_config.c"
+#line 877 "config/pool_config.c"
case YY_STATE_EOF(INITIAL):
yyterminate();
{ /* Not enough room in the buffer - grow it. */
/* just a shorter name for the current buffer */
- YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE;
+ YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
int yy_c_buf_p_offset =
(int) ((yy_c_buf_p) - b->yy_ch_buf);
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
{
yy_current_state = (int) yy_def[yy_current_state];
- if ( yy_current_state >= 38 )
+ if ( yy_current_state >= 40 )
yy_c = yy_meta[(unsigned int) yy_c];
}
yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
{
yy_current_state = (int) yy_def[yy_current_state];
- if ( yy_current_state >= 38 )
+ if ( yy_current_state >= 40 )
yy_c = yy_meta[(unsigned int) yy_c];
}
yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
- yy_is_jam = (yy_current_state == 37);
+ yy_is_jam = (yy_current_state == 39);
- return yy_is_jam ? 0 : yy_current_state;
+ return yy_is_jam ? 0 : yy_current_state;
}
#ifndef YY_NO_INPUT
case EOB_ACT_END_OF_FILE:
{
if ( yywrap( ) )
- return EOF;
+ return 0;
if ( ! (yy_did_buffer_switch_on_eof) )
YY_NEW_FILE;
/** Setup the input buffer state to scan the given bytes. The next call to yylex() will
* scan from a @e copy of @a bytes.
- * @param yybytes the byte buffer to scan
- * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
+ * @param bytes the byte buffer to scan
+ * @param len the number of bytes in the buffer pointed to by @a bytes.
*
* @return the newly allocated buffer state object.
*/
{
YY_BUFFER_STATE b;
char *buf;
- yy_size_t n;
- yy_size_t i;
+ yy_size_t n, i;
/* Get memory for full buffer, including space for trailing EOB's. */
n = _yybytes_len + 2;
#define YYTABLES_NAME "yytables"
-#line 104 "pool_config.l"
+#line 105 "pool_config.l"
* pgpool: a language independent connection pool server for PostgreSQL
* written by Tatsuo Ishii
*
- * Copyright (c) 2003-2019 PgPool Global Development Group
+ * Copyright (c) 2003-2020 PgPool Global Development Group
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby
#include <ctype.h>
#include <unistd.h>
#include <limits.h>
+#include <math.h>
#include "pool.h"
#include "pool_config.h"
static struct config_generic *get_index_free_record_if_any(struct config_generic *record);
+static bool parse_int(const char *value, int64 *result, int flags, const char **hintmsg, int64 MaxVal);
+static bool convert_to_base_unit(double value, const char *unit,
+ int base_unit, double *base_value);
#ifndef POOL_PRIVATE
+
+static void convert_int_from_base_unit(int64 base_value, int base_unit,
+ int64 *value, const char **unit);
+
+
/* These functions are used to provide Hints for enum type config parameters and
* to output the vslues of the parameters.
* These functuons are not available for tools since they use the stringInfo that is
{NULL, 0, false}
};
+/* From PostgreSQL's guc.c */
+/*
+ * Unit conversion tables.
+ *
+ * There are two tables, one for memory units, and another for time units.
+ * For each supported conversion from one unit to another, we have an entry
+ * in the table.
+ *
+ * To keep things simple, and to avoid possible roundoff error,
+ * conversions are never chained. There needs to be a direct conversion
+ * between all units (of the same type).
+ *
+ * The conversions for each base unit must be kept in order from greatest to
+ * smallest human-friendly unit; convert_xxx_from_base_unit() rely on that.
+ * (The order of the base-unit groups does not matter.)
+ */
+#define MAX_UNIT_LEN 3 /* length of longest recognized unit string */
+
+typedef struct
+{
+ char unit[MAX_UNIT_LEN + 1]; /* unit, as a string, like "kB" or
+ * "min" */
+ int base_unit; /* GUC_UNIT_XXX */
+ double multiplier; /* Factor for converting unit -> base_unit */
+} unit_conversion;
+
+static const char *memory_units_hint = "Valid units for this parameter are \"B\", \"kB\", \"MB\", \"GB\", and \"TB\".";
+
+static const unit_conversion memory_unit_conversion_table[] =
+{
+ {"TB", GUC_UNIT_BYTE, 1024.0 * 1024.0 * 1024.0 * 1024.0},
+ {"GB", GUC_UNIT_BYTE, 1024.0 * 1024.0 * 1024.0},
+ {"MB", GUC_UNIT_BYTE, 1024.0 * 1024.0},
+ {"kB", GUC_UNIT_BYTE, 1024.0},
+ {"B", GUC_UNIT_BYTE, 1.0},
+
+ {"TB", GUC_UNIT_KB, 1024.0 * 1024.0 * 1024.0},
+ {"GB", GUC_UNIT_KB, 1024.0 * 1024.0},
+ {"MB", GUC_UNIT_KB, 1024.0},
+ {"kB", GUC_UNIT_KB, 1.0},
+ {"B", GUC_UNIT_KB, 1.0 / 1024.0},
+
+ {"TB", GUC_UNIT_MB, 1024.0 * 1024.0},
+ {"GB", GUC_UNIT_MB, 1024.0},
+ {"MB", GUC_UNIT_MB, 1.0},
+ {"kB", GUC_UNIT_MB, 1.0 / 1024.0},
+ {"B", GUC_UNIT_MB, 1.0 / (1024.0 * 1024.0)},
+
+ {""} /* end of table marker */
+};
+
+static const char *time_units_hint = "Valid units for this parameter are \"us\", \"ms\", \"s\", \"min\", \"h\", and \"d\".";
+
+static const unit_conversion time_unit_conversion_table[] =
+{
+ {"d", GUC_UNIT_MS, 1000 * 60 * 60 * 24},
+ {"h", GUC_UNIT_MS, 1000 * 60 * 60},
+ {"min", GUC_UNIT_MS, 1000 * 60},
+ {"s", GUC_UNIT_MS, 1000},
+ {"ms", GUC_UNIT_MS, 1},
+ {"us", GUC_UNIT_MS, 1.0 / 1000},
+
+ {"d", GUC_UNIT_S, 60 * 60 * 24},
+ {"h", GUC_UNIT_S, 60 * 60},
+ {"min", GUC_UNIT_S, 60},
+ {"s", GUC_UNIT_S, 1},
+ {"ms", GUC_UNIT_S, 1.0 / 1000},
+ {"us", GUC_UNIT_S, 1.0 / (1000 * 1000)},
+
+ {"d", GUC_UNIT_MIN, 60 * 24},
+ {"h", GUC_UNIT_MIN, 60},
+ {"min", GUC_UNIT_MIN, 1},
+ {"s", GUC_UNIT_MIN, 1.0 / 60},
+ {"ms", GUC_UNIT_MIN, 1.0 / (1000 * 60)},
+ {"us", GUC_UNIT_MIN, 1.0 / (1000 * 1000 * 60)},
+
+ {""} /* end of table marker */
+};
static struct config_bool ConfigureNamesBool[] =
{
{
{
{
{"delay_threshold", CFGCXT_RELOAD, STREAMING_REPLICATION_CONFIG,
- "standby delay threshold.",
- CONFIG_VAR_TYPE_LONG, false, 0
+ "standby delay threshold in bytes.",
+ CONFIG_VAR_TYPE_LONG, false, GUC_UNIT_BYTE
},
&g_pool_config.delay_threshold,
0,
{
{"relcache_expire", CFGCXT_INIT, CACHE_CONFIG,
"Relation cache expiration time in seconds.",
- CONFIG_VAR_TYPE_LONG, false, 0
+ CONFIG_VAR_TYPE_LONG, false, GUC_UNIT_S
},
&g_pool_config.relcache_expire,
0,
{
{"memqcache_total_size", CFGCXT_INIT, CACHE_CONFIG,
"Total memory size in bytes for storing memory cache.",
- CONFIG_VAR_TYPE_LONG, false, 0
+ CONFIG_VAR_TYPE_LONG, false, GUC_UNIT_BYTE
},
&g_pool_config.memqcache_total_size,
(int64) 67108864,
{
{"health_check_timeout", CFGCXT_RELOAD, HEALTH_CHECK_CONFIG,
"Backend node health check timeout value in seconds.",
- CONFIG_VAR_TYPE_INT_ARRAY, true, 0, MAX_NUM_BACKENDS
+ CONFIG_VAR_TYPE_INT_ARRAY, true, GUC_UNIT_S, MAX_NUM_BACKENDS
},
NULL,
20,
{
{"health_check_period", CFGCXT_RELOAD, HEALTH_CHECK_CONFIG,
"Time interval in seconds between the health checks.",
- CONFIG_VAR_TYPE_INT_ARRAY, true, 0, MAX_NUM_BACKENDS
+ CONFIG_VAR_TYPE_INT_ARRAY, true, GUC_UNIT_S, MAX_NUM_BACKENDS
},
NULL,
0,
{
{"health_check_retry_delay", CFGCXT_RELOAD, HEALTH_CHECK_CONFIG,
"The amount of time in seconds to wait between failed health check retries.",
- CONFIG_VAR_TYPE_INT_ARRAY, true, 0, MAX_NUM_BACKENDS
+ CONFIG_VAR_TYPE_INT_ARRAY, true, GUC_UNIT_S, MAX_NUM_BACKENDS
},
NULL,
1,
{
{"connect_timeout", CFGCXT_RELOAD, HEALTH_CHECK_CONFIG,
"Timeout in milliseconds before giving up connecting to backend.",
- CONFIG_VAR_TYPE_INT_ARRAY, true, 0, MAX_NUM_BACKENDS
+ CONFIG_VAR_TYPE_INT_ARRAY, true, GUC_UNIT_MS, MAX_NUM_BACKENDS
},
NULL,
10000,
{
{"child_life_time", CFGCXT_INIT, CONNECTION_POOL_CONFIG,
"pgpool-II child process life time in seconds.",
- CONFIG_VAR_TYPE_INT, false, 0
+ CONFIG_VAR_TYPE_INT, false, GUC_UNIT_S
},
&g_pool_config.child_life_time,
300,
{
{"client_idle_limit", CFGCXT_SESSION, CONNECTION_POOL_CONFIG,
"idle time in seconds to disconnects a client.",
- CONFIG_VAR_TYPE_INT, false, 0
+ CONFIG_VAR_TYPE_INT, false, GUC_UNIT_S
},
&g_pool_config.client_idle_limit,
0,
{
{"connection_life_time", CFGCXT_INIT, CONNECTION_POOL_CONFIG,
"Cached connections expiration time in seconds.",
- CONFIG_VAR_TYPE_INT, false, 0
+ CONFIG_VAR_TYPE_INT, false, GUC_UNIT_S
},
&g_pool_config.connection_life_time,
0,
{
{"authentication_timeout", CFGCXT_INIT, CONNECTION_CONFIG,
"Time out value in seconds for client authentication.",
- CONFIG_VAR_TYPE_INT, false, 0
+ CONFIG_VAR_TYPE_INT, false, GUC_UNIT_S
},
&g_pool_config.authentication_timeout,
0,
{
{"sr_check_period", CFGCXT_RELOAD, STREAMING_REPLICATION_CONFIG,
"Time interval in seconds between the streaming replication delay checks.",
- CONFIG_VAR_TYPE_INT, false, 0
+ CONFIG_VAR_TYPE_INT, false, GUC_UNIT_S
},
&g_pool_config.sr_check_period,
0,
{
{"recovery_timeout", CFGCXT_RELOAD, RECOVERY_CONFIG,
"Maximum time in seconds to wait for the recovering PostgreSQL node.",
- CONFIG_VAR_TYPE_INT, false, 0
+ CONFIG_VAR_TYPE_INT, false, GUC_UNIT_S
},
&g_pool_config.recovery_timeout,
90,
{
{"client_idle_limit_in_recovery", CFGCXT_SESSION, RECOVERY_CONFIG,
"Time limit is seconds for the child connection, before it is terminated during the 2nd stage recovery.",
- CONFIG_VAR_TYPE_INT, false, 0
+ CONFIG_VAR_TYPE_INT, false, GUC_UNIT_S
},
&g_pool_config.client_idle_limit_in_recovery,
0,
{
{"search_primary_node_timeout", CFGCXT_RELOAD, FAILOVER_CONFIG,
"Max time in seconds to search for primary node after failover.",
- CONFIG_VAR_TYPE_INT, false, 0
+ CONFIG_VAR_TYPE_INT, false, GUC_UNIT_S
},
&g_pool_config.search_primary_node_timeout,
300,
{
{"wd_interval", CFGCXT_INIT, WATCHDOG_CONFIG,
"Time interval in seconds between life check.",
- CONFIG_VAR_TYPE_INT, false, 0
+ CONFIG_VAR_TYPE_INT, false, GUC_UNIT_S
},
&g_pool_config.wd_interval,
10,
{
{"wd_heartbeat_keepalive", CFGCXT_INIT, WATCHDOG_CONFIG,
"Time interval in seconds between sending the heartbeat siganl.",
- CONFIG_VAR_TYPE_INT, false, 0
+ CONFIG_VAR_TYPE_INT, false, GUC_UNIT_S
},
&g_pool_config.wd_heartbeat_keepalive,
2,
{
{"wd_heartbeat_deadtime", CFGCXT_INIT, WATCHDOG_CONFIG,
"Deadtime interval in seconds for heartbeat siganl.",
- CONFIG_VAR_TYPE_INT, false, 0
+ CONFIG_VAR_TYPE_INT, false, GUC_UNIT_S
},
&g_pool_config.wd_heartbeat_deadtime,
30,
{
{"memqcache_expire", CFGCXT_INIT, CACHE_CONFIG,
"Memory cache entry life time specified in seconds.",
- CONFIG_VAR_TYPE_INT, false, 0
+ CONFIG_VAR_TYPE_INT, false, GUC_UNIT_S
},
&g_pool_config.memqcache_expire,
0,
{
{"memqcache_maxcache", CFGCXT_INIT, CACHE_CONFIG,
"Maximum SELECT result size in bytes.",
- CONFIG_VAR_TYPE_INT, false, 0
+ CONFIG_VAR_TYPE_INT, false, GUC_UNIT_BYTE
},
&g_pool_config.memqcache_maxcache,
409600,
{
{"memqcache_cache_block_size", CFGCXT_INIT, CACHE_CONFIG,
"Cache block size in bytes.",
- CONFIG_VAR_TYPE_INT, false, 0
+ CONFIG_VAR_TYPE_INT, false, GUC_UNIT_BYTE
},
&g_pool_config.memqcache_cache_block_size,
1048576,
{
{"auto_failback_interval", CFGCXT_RELOAD, FAILOVER_CONFIG,
"min interval of executing auto_failback in seconds",
- CONFIG_VAR_TYPE_INT, false, 0
+ CONFIG_VAR_TYPE_INT, false, GUC_UNIT_S
},
&g_pool_config.auto_failback_interval,
60,
if (value != NULL)
{
- newval = atoi(value);
+ int64 newval64;
+ const char *hintmsg;
+
+ if (!parse_int(value, &newval64,
+ conf->gen.flags, &hintmsg, INT_MAX))
+ {
+ ereport(elevel,
+ (errmsg("invalid value for parameter \"%s\": \"%s\"",
+ name, value),
+ hintmsg ? errhint("%s", _(hintmsg)) : 0));
+ return false;
+ }
+ newval = (int)newval64;
}
else if (source == PGC_S_DEFAULT)
{
if (value != NULL)
{
- newval = atoi(value);
+ int64 newval64;
+ const char *hintmsg;
+
+ if (!parse_int(value, &newval64,
+ conf->gen.flags, &hintmsg, INT_MAX))
+ {
+ ereport(elevel,
+ (errmsg("invalid value for parameter \"%s\": \"%s\"",
+ name, value),
+ hintmsg ? errhint("%s", _(hintmsg)) : 0));
+ return false;
+ }
+ newval = (int)newval64;
}
else if (source == PGC_S_DEFAULT)
{
if (value != NULL)
{
- newval = pool_atoi64(value);
+ const char *hintmsg;
+
+ if (!parse_int(value, &newval,
+ conf->gen.flags, &hintmsg, conf->max))
+ {
+ ereport(elevel,
+ (errmsg("invalid value for parameter \"%s\": \"%s\"",
+ name, value),
+ hintmsg ? errhint("%s", _(hintmsg)) : 0));
+ return false;
+ }
}
else if (source == PGC_S_DEFAULT)
{
return ret;
}
+/*
+ * Try to parse value as an integer. The accepted formats are the
+ * usual decimal, octal, or hexadecimal formats, as well as floating-point
+ * formats (which will be rounded to integer after any units conversion).
+ * Optionally, the value can be followed by a unit name if "flags" indicates
+ * a unit is allowed.
+ *
+ * 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.
+ */
+static bool
+parse_int(const char *value, int64 *result, int flags, const char **hintmsg, int64 MaxVal)
+{
+ /*
+ * We assume here that double is wide enough to represent any integer
+ * value with adequate precision.
+ */
+ double val;
+ char *endptr;
+
+ /* To suppress compiler warnings, always set output params */
+ if (result)
+ *result = 0;
+ if (hintmsg)
+ *hintmsg = NULL;
+
+ /*
+ * Try to parse as an integer (allowing octal or hex input). If the
+ * conversion stops at a decimal point or 'e', or overflows, re-parse as
+ * float. This should work fine as long as we have no unit names starting
+ * with 'e'. If we ever do, the test could be extended to check for a
+ * sign or digit after 'e', but for now that's unnecessary.
+ */
+ errno = 0;
+ val = strtol(value, &endptr, 0);
+ if (*endptr == '.' || *endptr == 'e' || *endptr == 'E' ||
+ errno == ERANGE)
+ {
+ errno = 0;
+ val = strtod(value, &endptr);
+ }
+
+ if (endptr == value || errno == ERANGE)
+ return false; /* no HINT for these cases */
+
+ /* reject NaN (infinities will fail range check below) */
+ if (isnan(val))
+ return false; /* treat same as syntax error; no HINT */
+
+
+ /* allow whitespace between number and unit */
+ while (isspace((unsigned char) *endptr))
+ endptr++;
+
+ /* Handle possible unit */
+ if (*endptr != '\0')
+ {
+ if ((flags & GUC_UNIT) == 0)
+ {
+ return false; /* this setting does not accept a unit */
+ }
+ if (!convert_to_base_unit(val,
+ endptr, (flags & GUC_UNIT),
+ &val))
+ {
+ /* invalid unit, or garbage after the unit; set hint and fail. */
+ if (hintmsg)
+ {
+ if (flags & GUC_UNIT_MEMORY)
+ *hintmsg = memory_units_hint;
+ else
+ *hintmsg = time_units_hint;
+ }
+ return false;
+ }
+ }
+
+ /* Round to int, then check for overflow */
+ val = rint(val);
+
+ if (val > MaxVal || val < INT_MIN)
+ {
+ if (hintmsg)
+ *hintmsg = "Value exceeds allowed range.";
+ return false;
+ }
+
+ if (result)
+ *result = (int64) val;
+ return true;
+}
+/*
+ * Convert a value from one of the human-friendly units ("kB", "min" etc.)
+ * to the given base unit. 'value' and 'unit' are the input value and unit
+ * to convert from (there can be trailing spaces in the unit string).
+ * The converted value is stored in *base_value.
+ * It's caller's responsibility to round off the converted value as necessary
+ * and check for out-of-range.
+ *
+ * Returns true on success, false if the input unit is not recognized.
+ */
+
+static bool
+convert_to_base_unit(double value, const char *unit,
+ int base_unit, double *base_value)
+{
+ char unitstr[MAX_UNIT_LEN + 1];
+ int unitlen;
+ const unit_conversion *table;
+ int i;
+
+ /* extract unit string to compare to table entries */
+ unitlen = 0;
+ while (*unit != '\0' && !isspace((unsigned char) *unit) &&
+ unitlen < MAX_UNIT_LEN)
+ unitstr[unitlen++] = *(unit++);
+ unitstr[unitlen] = '\0';
+ /* allow whitespace after unit */
+ while (isspace((unsigned char) *unit))
+ unit++;
+ if (*unit != '\0')
+ return false; /* unit too long, or garbage after it */
+
+ /* now search the appropriate table */
+ if (base_unit & GUC_UNIT_MEMORY)
+ table = memory_unit_conversion_table;
+ else
+ table = time_unit_conversion_table;
+
+ for (i = 0; *table[i].unit; i++)
+ {
+ if (base_unit == table[i].base_unit &&
+ strcmp(unitstr, table[i].unit) == 0)
+ {
+ double cvalue = value * table[i].multiplier;
+
+ /*
+ * If the user gave a fractional value such as "30.1GB", round it
+ * off to the nearest multiple of the next smaller unit, if there
+ * is one.
+ */
+ if (*table[i + 1].unit &&
+ base_unit == table[i + 1].base_unit)
+ cvalue = rint(cvalue / table[i + 1].multiplier) *
+ table[i + 1].multiplier;
+
+ *base_value = cvalue;
+ return true;
+ }
+ }
+ return false;
+}
#ifndef POOL_PRIVATE
+/*
+ * Convert an integer value in some base unit to a human-friendly unit.
+ *
+ * The output unit is chosen so that it's the greatest unit that can represent
+ * the value without loss. For example, if the base unit is GUC_UNIT_KB, 1024
+ * is converted to 1 MB, but 1025 is represented as 1025 kB.
+ */
+static void
+convert_int_from_base_unit(int64 base_value, int base_unit,
+ int64 *value, const char **unit)
+{
+ const unit_conversion *table;
+ int i;
+
+ *unit = NULL;
+
+ if (base_unit & GUC_UNIT_MEMORY)
+ table = memory_unit_conversion_table;
+ else
+ table = time_unit_conversion_table;
+
+ for (i = 0; *table[i].unit; i++)
+ {
+ if (base_unit == table[i].base_unit)
+ {
+ /*
+ * Accept the first conversion that divides the value evenly. We
+ * assume that the conversions for each base unit are ordered from
+ * greatest unit to the smallest!
+ */
+ if (table[i].multiplier <= 1.0 ||
+ base_value % (int64) table[i].multiplier == 0)
+ {
+ *value = (int64) rint(base_value / table[i].multiplier);
+ *unit = table[i].unit;
+ break;
+ }
+ }
+ }
+
+ Assert(*unit != NULL);
+}
+
/*
* Lookup the name for an enum option with the selected value.
* The returned string is a pointer to static data and not
val = (*conf->show_hook) ();
else
{
- int result = *conf->variable;
- snprintf(buffer, sizeof(buffer), "%d",
- result);
+ /*
+ * Use int64 arithmetic to avoid overflows in units
+ * conversion.
+ */
+ int64 result = (int64) *conf->variable;
+ const char *unit;
+
+ if (result > 0 && (record->flags & GUC_UNIT))
+ convert_int_from_base_unit(result,
+ record->flags & GUC_UNIT,
+ &result, &unit);
+ else
+ unit = "";
+
+ snprintf(buffer, sizeof(buffer), INT64_FORMAT "%s",
+ result, unit);
val = buffer;
}
}
else
{
int64 result = (int64) *conf->variable;
+ const char *unit;
+
+ if (result > 0 && (record->flags & GUC_UNIT))
+ convert_int_from_base_unit(result,
+ record->flags & GUC_UNIT,
+ &result, &unit);
+ else
+ unit = "";
- snprintf(buffer, sizeof(buffer), INT64_FORMAT,
- result);
+ snprintf(buffer, sizeof(buffer), INT64_FORMAT "%s",
+ result, unit);
val = buffer;
}
}