1/*-------------------------------------------------------------------------
5 * Shared code for compression methods and specifications.
7 * A compression specification specifies the parameters that should be used
8 * when performing compression with a specific algorithm. The simplest
9 * possible compression specification is an integer, which sets the
12 * Otherwise, a compression specification is a comma-separated list of items,
13 * each having the form keyword or keyword=value.
15 * Currently, the supported keywords are "level", "long", and "workers".
17 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
20 * src/common/compression.c
21 *-------------------------------------------------------------------------
45 * Look up a compression algorithm by name. Returns true and sets *algorithm
46 * if the name is recognized. Otherwise returns false.
51 if (strcmp(
name,
"none") == 0)
53 else if (strcmp(
name,
"gzip") == 0)
55 else if (strcmp(
name,
"lz4") == 0)
57 else if (strcmp(
name,
"zstd") == 0)
65 * Get the human-readable name corresponding to a particular compression
81 /* no default, to provoke compiler warnings if values are added */
84 return "???";
/* placate compiler */
88 * Parse a compression specification for a specified algorithm.
90 * See the file header comments for a brief description of what a compression
91 * specification is expected to look like.
93 * On return, all fields of the result object will be initialized.
94 * In particular, result->parse_error will be NULL if no errors occurred
95 * during parsing, and will otherwise contain an appropriate error message.
96 * The caller may free this error message string using pfree, if desired.
97 * Note, however, even if there's no parse error, the string might not make
98 * sense: e.g. for gzip, level=12 is not sensible, but it does parse OK.
100 * The compression level is assigned by default if not directly specified
101 * by the specification.
103 * Use validate_compress_specification() to find out whether a compression
104 * specification is semantically sensible.
111 char *bare_level_endp;
113 /* Initial setup of result object. */
119 * Assign a default level depending on the compression method. This may
129 result->
level = 0;
/* fast compression mode */
132 psprintf(
_(
"this build does not support compression with %s"),
138 result->
level = ZSTD_CLEVEL_DEFAULT;
141 psprintf(
_(
"this build does not support compression with %s"),
147 result->
level = Z_DEFAULT_COMPRESSION;
150 psprintf(
_(
"this build does not support compression with %s"),
156 /* If there is no specification, we're done already. */
157 if (specification == NULL)
160 /* As a special case, the specification can be a bare integer. */
161 bare_level = strtol(specification, &bare_level_endp, 10);
162 if (specification != bare_level_endp && *bare_level_endp ==
'0円')
164 result->
level = bare_level;
168 /* Look for comma-separated keyword or keyword=value entries. */
181 /* Figure start, end, and length of next keyword and any value. */
182 kwstart = kwend = specification;
183 while (*kwend !=
'0円' && *kwend !=
',' && *kwend !=
'=')
185 kwlen = kwend - kwstart;
188 vstart = vend = NULL;
194 vstart = vend = kwend + 1;
195 while (*vend !=
'0円' && *vend !=
',')
197 vlen = vend - vstart;
201 /* Reject empty keyword. */
205 pstrdup(
_(
"found empty string where a compression option was expected"));
209 /* Extract keyword and value as separate C strings. */
210 keyword =
palloc(kwlen + 1);
211 memcpy(keyword, kwstart, kwlen);
212 keyword[kwlen] =
'0円';
218 memcpy(
value, vstart, vlen);
222 /* Handle whatever keyword we found. */
223 if (strcmp(keyword,
"level") == 0)
228 * No need to set a flag in "options", there is a default level
229 * set at least thanks to the logic above.
232 else if (strcmp(keyword,
"workers") == 0)
237 else if (strcmp(keyword,
"long") == 0)
244 psprintf(
_(
"unrecognized compression option: \"%s\""), keyword);
246 /* Release memory, just to be tidy. */
252 * If we got an error or have reached the end of the string, stop.
254 * If there is no value, then the end of the keyword might have been
255 * the end of the string. If there is a value, then the end of the
256 * keyword cannot have been the end of the string, but the end of the
257 * value might have been.
260 (vend == NULL ? *kwend ==
'0円' : *vend ==
'0円'))
263 /* Advance to next entry and loop around. */
264 specification = vend == NULL ? kwend + 1 : vend + 1;
269 * Parse 'value' as an integer and return the result.
271 * If parsing fails, set result->parse_error to an appropriate message
283 psprintf(
_(
"compression option \"%s\" requires a value"),
288 ivalue = strtol(
value, &ivalue_endp, 10);
289 if (ivalue_endp ==
value || *ivalue_endp !=
'0円')
292 psprintf(
_(
"value for compression option \"%s\" must be an integer"),
300 * Parse 'value' as a boolean and return the result.
302 * If parsing fails, set result->parse_error to an appropriate message
303 * and return -1. The caller must check result->parse_error to determine if
304 * the call was successful.
306 * Valid values are: yes, no, on, off, 1, 0.
308 * Inspired by ParseVariableBool().
331 psprintf(
_(
"value for compression option \"%s\" must be a Boolean value"),
337 * Returns NULL if the compression specification string was syntactically
338 * valid and semantically sensible. Otherwise, returns an error message.
340 * Does not test whether this build of PostgreSQL supports the requested
341 * compression method.
348 int default_level = 0;
350 /* If it didn't even parse OK, it's definitely no good. */
355 * Check that the algorithm expects a compression level and it is within
356 * the legal range for the algorithm.
363 default_level = Z_DEFAULT_COMPRESSION;
368 default_level = 0;
/* fast mode */
372 max_level = ZSTD_maxCLevel();
373 min_level = ZSTD_minCLevel();
374 default_level = ZSTD_CLEVEL_DEFAULT;
378 if (spec->
level != 0)
379 return psprintf(
_(
"compression algorithm \"%s\" does not accept a compression level"),
384 if ((spec->
level < min_level || spec->
level > max_level) &&
385 spec->
level != default_level)
386 return psprintf(
_(
"compression algorithm \"%s\" expects a compression level between %d and %d (default at %d)"),
388 min_level, max_level, default_level);
391 * Of the compression algorithms that we currently support, only zstd
392 * allows parallel workers.
397 return psprintf(
_(
"compression algorithm \"%s\" does not accept a worker count"),
402 * Of the compression algorithms that we currently support, only zstd
403 * supports long-distance mode.
408 return psprintf(
_(
"compression algorithm \"%s\" does not support long-distance mode"),
418 * Basic parsing of a value specified through a command-line option, commonly
421 * The parsing consists of a METHOD:DETAIL string fed later to
422 * parse_compress_specification(). This only extracts METHOD and DETAIL.
423 * If only an integer is found, the method is implied by the value specified.
433 * Check whether the compression specification consists of a bare integer.
435 * For backward-compatibility, assume "none" if the integer found is zero
436 * and "gzip" otherwise.
438 result = strtol(
option, &endp, 10);
455 * Check whether there is a compression detail following the algorithm
458 sep = strchr(
option,
':');
static bool expect_boolean_value(char *keyword, char *value, pg_compress_specification *result)
const char * get_compress_algorithm_name(pg_compress_algorithm algorithm)
char * validate_compress_specification(pg_compress_specification *spec)
bool parse_compress_algorithm(char *name, pg_compress_algorithm *algorithm)
static int expect_integer_value(char *keyword, char *value, pg_compress_specification *result)
void parse_compress_specification(pg_compress_algorithm algorithm, char *specification, pg_compress_specification *result)
#define PG_COMPRESSION_OPTION_WORKERS
#define PG_COMPRESSION_OPTION_LONG_DISTANCE
void parse_compress_options(const char *option, char **algorithm, char **detail)
Assert(PointerIsAligned(start, uint64))
char * pstrdup(const char *in)
void pfree(void *pointer)
int pg_strcasecmp(const char *s1, const char *s2)
char * psprintf(const char *fmt,...)
pg_compress_algorithm algorithm