On Sat, Mar 20, 2021 at 06:20:39PM -0500, Justin Pryzby wrote: > Rebased on HEAD. > 0005 forgot to update compression_1.out. > Included changes to ./configure.ac and some other patches, but not Tomas's, > since it'll make CFBOT get mad as soon as that's pushed.
Rebased again. Renamed "t" to a badcompresstbl to avoid name conflicts. Polish the enum GUC patch some. I noticed that TOAST_INVALID_COMPRESSION_ID was unused ... but then I found a use for it.
>From edc0e6ab248600c6d33dd681359554550c88a679 Mon Sep 17 00:00:00 2001 From: Justin Pryzby <pryz...@telsasoft.com> Date: Fri, 19 Mar 2021 19:12:53 -0500 Subject: [PATCH v3 01/12] Add docs for default_toast_compression.. bbe0a81db69bd10bd166907c3701492a29aca294 --- doc/src/sgml/config.sgml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index ee4925d6d9..5cb851a5eb 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -8151,6 +8151,29 @@ COPY postgres_log FROM '/full/path/to/logfile.csv' WITH csv; </listitem> </varlistentry> + <varlistentry id="guc-default-toast-compression" xreflabel="default_toast_compression"> + <term><varname>default_toast_compression</varname> (<type>string</type>) + <indexterm> + <primary><varname>default_toast_compression</varname> configuration parameter</primary> + </indexterm> + </term> + <listitem> + <para> + This parameter specifies the default compression method to use + when compressing data in <acronym>TOAST</acronym> tables. + It applies only to variable-width data types. + It may be overriden by compression clauses in the + <command>CREATE</command> command, or changed after the relation is + created by <command>ALTER TABLE ... SET COMPRESSION</command>. + + The supported compression methods are <literal>pglz</literal> and + (if configured at the time <productname>PostgreSQL</productname> was + built) <literal>lz4</literal>. + The default is <literal>pglz</literal>. + </para> + </listitem> + </varlistentry> + <varlistentry id="guc-temp-tablespaces" xreflabel="temp_tablespaces"> <term><varname>temp_tablespaces</varname> (<type>string</type>) <indexterm> -- 2.17.0
>From 02a9038381bdfe577aa32b67bcd231acd61f2c20 Mon Sep 17 00:00:00 2001 From: Justin Pryzby <pryz...@telsasoft.com> Date: Fri, 19 Mar 2021 21:52:28 -0500 Subject: [PATCH v3 02/12] doc: pg_dump --no-toast-compression --- doc/src/sgml/ref/pg_dump.sgml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/doc/src/sgml/ref/pg_dump.sgml b/doc/src/sgml/ref/pg_dump.sgml index bcbb7a25fb..989b8e2381 100644 --- a/doc/src/sgml/ref/pg_dump.sgml +++ b/doc/src/sgml/ref/pg_dump.sgml @@ -931,6 +931,18 @@ PostgreSQL documentation </listitem> </varlistentry> + <varlistentry> + <term><option>--no-toast-compression</option></term> + <listitem> + <para> + Do not output commands to set <acronym>TOAST</acronym> compression + methods. + With this option, all objects will be created using whichever + compression method is the default during restore. + </para> + </listitem> + </varlistentry> + <varlistentry> <term><option>--no-unlogged-table-data</option></term> <listitem> -- 2.17.0
>From 7e9b4b3c6f12abaf7531ef5109e084dc188e7dda Mon Sep 17 00:00:00 2001 From: Justin Pryzby <pryz...@telsasoft.com> Date: Fri, 19 Mar 2021 20:23:40 -0500 Subject: [PATCH v3 03/12] Compression method is an char not an OID --- src/backend/commands/tablecmds.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 877c08814e..22f3c5efc0 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -7847,6 +7847,7 @@ SetIndexStorageProperties(Relation rel, Relation attrelation, index_close(indrel, lockmode); } } + /* * ALTER TABLE ALTER COLUMN SET STORAGE * @@ -15070,7 +15071,7 @@ ATExecSetCompression(AlteredTableInfo *tab, AttrNumber attnum; char *compression; char typstorage; - Oid cmoid; + char cmethod; ObjectAddress address; Assert(IsA(newValue, String)); @@ -15104,10 +15105,10 @@ ATExecSetCompression(AlteredTableInfo *tab, format_type_be(atttableform->atttypid)))); /* get the attribute compression method. */ - cmoid = GetAttributeCompression(atttableform, compression); + cmethod = GetAttributeCompression(atttableform, compression); /* update pg_attribute entry */ - atttableform->attcompression = cmoid; + atttableform->attcompression = cmethod; CatalogTupleUpdate(attrel, &tuple->t_self, tuple); InvokeObjectPostAlterHook(RelationRelationId, @@ -15118,7 +15119,7 @@ ATExecSetCompression(AlteredTableInfo *tab, * Apply the change to indexes as well (only for simple index columns, * matching behavior of index.c ConstructTupleDescriptor()). */ - SetIndexStorageProperties(rel, attrel, attnum, cmoid, '\0', lockmode); + SetIndexStorageProperties(rel, attrel, attnum, cmethod, '\0', lockmode); heap_freetuple(tuple); -- 2.17.0
>From 2262c8ffb041e8a7452bda724c676b6118895f4b Mon Sep 17 00:00:00 2001 From: Justin Pryzby <pryz...@telsasoft.com> Date: Fri, 19 Mar 2021 20:07:31 -0500 Subject: [PATCH v3 04/12] Remove duplicative macro --- src/include/access/toast_compression.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/include/access/toast_compression.h b/src/include/access/toast_compression.h index 5c9220c171..44b73bd57c 100644 --- a/src/include/access/toast_compression.h +++ b/src/include/access/toast_compression.h @@ -50,8 +50,6 @@ typedef enum ToastCompressionId errdetail("This functionality requires the server to be built with lz4 support."), \ errhint("You need to rebuild PostgreSQL using --with-lz4."))) -#define IsValidCompression(cm) ((cm) != InvalidCompressionMethod) - #define IsStorageCompressible(storage) ((storage) != TYPSTORAGE_PLAIN && \ (storage) != TYPSTORAGE_EXTERNAL) -- 2.17.0
>From 2deb4e72773a0d0fe9cff73527b3464329b8763f Mon Sep 17 00:00:00 2001 From: Justin Pryzby <pryz...@telsasoft.com> Date: Fri, 19 Mar 2021 20:19:55 -0500 Subject: [PATCH v3 05/12] Error on invalid compression in CREATE and ALTER --- src/backend/commands/tablecmds.c | 10 +++++++--- src/test/regress/expected/compression.out | 6 ++++++ src/test/regress/expected/compression_1.out | 6 ++++++ src/test/regress/sql/compression.sql | 5 +++++ 4 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 22f3c5efc0..54fea31e43 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -17863,9 +17863,13 @@ GetAttributeCompression(Form_pg_attribute att, char *compression) /* fallback to default compression if it's not specified */ if (compression == NULL) - cmethod = GetDefaultToastCompression(); - else - cmethod = CompressionNameToMethod(compression); + return GetDefaultToastCompression(); + + cmethod = CompressionNameToMethod(compression); + if (!CompressionMethodIsValid(cmethod)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("invalid compression method \"%s\"", compression))); return cmethod; } diff --git a/src/test/regress/expected/compression.out b/src/test/regress/expected/compression.out index 18ac5f05bb..c2f2e0e230 100644 --- a/src/test/regress/expected/compression.out +++ b/src/test/regress/expected/compression.out @@ -347,4 +347,10 @@ SELECT length(f1) FROM cmmove3; 10040 (2 rows) +CREATE TABLE badcompresstbl (a text COMPRESSION I_Do_Not_Exist_Compression); -- fails +ERROR: invalid compression method "i_do_not_exist_compression" +CREATE TABLE badcompresstbl (a text); +ALTER TABLE badcompresstbl ALTER a SET COMPRESSION I_Do_Not_Exist_Compression; -- fails +ERROR: invalid compression method "i_do_not_exist_compression" +DROP TABLE badcompresstbl; \set HIDE_TOAST_COMPRESSION true diff --git a/src/test/regress/expected/compression_1.out b/src/test/regress/expected/compression_1.out index c4a2cea4cd..6626f8e927 100644 --- a/src/test/regress/expected/compression_1.out +++ b/src/test/regress/expected/compression_1.out @@ -340,4 +340,10 @@ SELECT length(f1) FROM cmmove3; 10000 (1 row) +CREATE TABLE badcompresstbl (a text COMPRESSION I_Do_Not_Exist_Compression); -- fails +ERROR: invalid compression method "i_do_not_exist_compression" +CREATE TABLE badcompresstbl (a text); +ALTER TABLE badcompresstbl ALTER a SET COMPRESSION I_Do_Not_Exist_Compression; -- fails +ERROR: invalid compression method "i_do_not_exist_compression" +DROP TABLE badcompresstbl; \set HIDE_TOAST_COMPRESSION true diff --git a/src/test/regress/sql/compression.sql b/src/test/regress/sql/compression.sql index e23669cc94..5e178be04a 100644 --- a/src/test/regress/sql/compression.sql +++ b/src/test/regress/sql/compression.sql @@ -137,4 +137,9 @@ SELECT length(f1) FROM cmmove1; SELECT length(f1) FROM cmmove2; SELECT length(f1) FROM cmmove3; +CREATE TABLE badcompresstbl (a text COMPRESSION I_Do_Not_Exist_Compression); -- fails +CREATE TABLE badcompresstbl (a text); +ALTER TABLE badcompresstbl ALTER a SET COMPRESSION I_Do_Not_Exist_Compression; -- fails +DROP TABLE badcompresstbl; + \set HIDE_TOAST_COMPRESSION true -- 2.17.0
>From 005ae4b7668a31dd4a7ab1c25ce3af3420346d2f Mon Sep 17 00:00:00 2001 From: Justin Pryzby <pryz...@telsasoft.com> Date: Fri, 19 Mar 2021 19:39:10 -0500 Subject: [PATCH v3 06/12] WIP: Change default_toast_compression GUC to an enum.. ..since the final version of the TOAST lz4 patch doesn't require catalog access --- src/backend/access/common/toast_compression.c | 57 ++++--------------- src/backend/utils/misc/guc.c | 23 ++++---- src/include/access/toast_compression.h | 11 ++-- src/test/regress/expected/compression.out | 4 +- src/test/regress/expected/compression_1.out | 9 ++- 5 files changed, 33 insertions(+), 71 deletions(-) diff --git a/src/backend/access/common/toast_compression.c b/src/backend/access/common/toast_compression.c index 00af1740cf..aa28772159 100644 --- a/src/backend/access/common/toast_compression.c +++ b/src/backend/access/common/toast_compression.c @@ -23,8 +23,16 @@ #include "fmgr.h" #include "utils/builtins.h" -/* Compile-time default */ -char *default_toast_compression = DEFAULT_TOAST_COMPRESSION; +/* GUC */ +int default_toast_compression = TOAST_PGLZ_COMPRESSION_ID; + +const struct config_enum_entry default_toast_compression_options[] = { + {"pglz", TOAST_PGLZ_COMPRESSION_ID, false}, +#ifdef USE_LZ4 + {"lz4", TOAST_LZ4_COMPRESSION_ID, false}, +#endif + {NULL, 0, false} +}; /* * Compress a varlena using PGLZ. @@ -269,48 +277,3 @@ toast_get_compression_id(struct varlena *attr) return cmid; } - -/* - * Validate a new value for the default_toast_compression GUC. - */ -bool -check_default_toast_compression(char **newval, void **extra, GucSource source) -{ - if (**newval == '\0') - { - GUC_check_errdetail("%s cannot be empty.", - "default_toast_compression"); - return false; - } - - if (strlen(*newval) >= NAMEDATALEN) - { - GUC_check_errdetail("%s is too long (maximum %d characters).", - "default_toast_compression", NAMEDATALEN - 1); - return false; - } - - if (!CompressionMethodIsValid(CompressionNameToMethod(*newval))) - { - /* - * When source == PGC_S_TEST, don't throw a hard error for a - * nonexistent compression method, only a NOTICE. See comments in - * guc.h. - */ - if (source == PGC_S_TEST) - { - ereport(NOTICE, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("compression method \"%s\" does not exist", - *newval))); - } - else - { - GUC_check_errdetail("Compression method \"%s\" does not exist.", - *newval); - return false; - } - } - - return true; -} diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 4272cf4821..5480d3d088 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -518,6 +518,7 @@ extern const struct config_enum_entry archive_mode_options[]; extern const struct config_enum_entry recovery_target_action_options[]; extern const struct config_enum_entry sync_method_options[]; extern const struct config_enum_entry dynamic_shared_memory_options[]; +extern const struct config_enum_entry default_toast_compression_options[]; /* * GUC option variables that are exported from this module @@ -3953,17 +3954,6 @@ static struct config_string ConfigureNamesString[] = check_default_table_access_method, NULL, NULL }, - { - {"default_toast_compression", PGC_USERSET, CLIENT_CONN_STATEMENT, - gettext_noop("Sets the default compression for new columns."), - NULL, - GUC_IS_NAME - }, - &default_toast_compression, - DEFAULT_TOAST_COMPRESSION, - check_default_toast_compression, NULL, NULL - }, - { {"default_tablespace", PGC_USERSET, CLIENT_CONN_STATEMENT, gettext_noop("Sets the default tablespace to create tables and indexes in."), @@ -4605,6 +4595,17 @@ static struct config_enum ConfigureNamesEnum[] = NULL, NULL, NULL }, + { + {"default_toast_compression", PGC_USERSET, CLIENT_CONN_STATEMENT, + gettext_noop("Sets the default compression for new columns."), + NULL, + GUC_IS_NAME + }, + &default_toast_compression, + TOAST_PGLZ_COMPRESSION_ID, + default_toast_compression_options, NULL, NULL + }, + { {"default_transaction_isolation", PGC_USERSET, CLIENT_CONN_STATEMENT, gettext_noop("Sets the transaction isolation level of each new transaction."), diff --git a/src/include/access/toast_compression.h b/src/include/access/toast_compression.h index 44b73bd57c..c5cea08ccd 100644 --- a/src/include/access/toast_compression.h +++ b/src/include/access/toast_compression.h @@ -16,10 +16,8 @@ #include "utils/guc.h" /* GUCs */ -extern char *default_toast_compression; - -/* default compression method if not specified. */ -#define DEFAULT_TOAST_COMPRESSION "pglz" +extern int default_toast_compression; +extern const struct config_enum_entry default_toast_compression_options[]; /* * Built-in compression method-id. The toast compression header will store @@ -78,7 +76,7 @@ GetCompressionMethodName(char method) * in the built-in methods then return InvalidCompressionMethod. */ static inline char -CompressionNameToMethod(char *compression) +CompressionNameToMethod(const char *compression) { if (strcmp(compression, "pglz") == 0) return TOAST_PGLZ_COMPRESSION; @@ -101,7 +99,8 @@ CompressionNameToMethod(char *compression) static inline char GetDefaultToastCompression(void) { - return CompressionNameToMethod(default_toast_compression); + Assert(default_toast_compression < TOAST_INVALID_COMPRESSION_ID); + return CompressionNameToMethod(default_toast_compression_options[default_toast_compression].name); } /* pglz compression/decompression routines */ diff --git a/src/test/regress/expected/compression.out b/src/test/regress/expected/compression.out index c2f2e0e230..566a1877ea 100644 --- a/src/test/regress/expected/compression.out +++ b/src/test/regress/expected/compression.out @@ -234,10 +234,10 @@ DETAIL: pglz versus lz4 -- test default_toast_compression GUC SET default_toast_compression = ''; ERROR: invalid value for parameter "default_toast_compression": "" -DETAIL: default_toast_compression cannot be empty. +HINT: Available values: pglz, lz4. SET default_toast_compression = 'I do not exist compression'; ERROR: invalid value for parameter "default_toast_compression": "I do not exist compression" -DETAIL: Compression method "I do not exist compression" does not exist. +HINT: Available values: pglz, lz4. SET default_toast_compression = 'lz4'; DROP TABLE cmdata2; CREATE TABLE cmdata2 (f1 text); diff --git a/src/test/regress/expected/compression_1.out b/src/test/regress/expected/compression_1.out index 6626f8e927..3990933415 100644 --- a/src/test/regress/expected/compression_1.out +++ b/src/test/regress/expected/compression_1.out @@ -227,14 +227,13 @@ DETAIL: pglz versus lz4 -- test default_toast_compression GUC SET default_toast_compression = ''; ERROR: invalid value for parameter "default_toast_compression": "" -DETAIL: default_toast_compression cannot be empty. +HINT: Available values: pglz. SET default_toast_compression = 'I do not exist compression'; ERROR: invalid value for parameter "default_toast_compression": "I do not exist compression" -DETAIL: Compression method "I do not exist compression" does not exist. +HINT: Available values: pglz. SET default_toast_compression = 'lz4'; -ERROR: unsupported LZ4 compression method -DETAIL: This functionality requires the server to be built with lz4 support. -HINT: You need to rebuild PostgreSQL using --with-lz4. +ERROR: invalid value for parameter "default_toast_compression": "lz4" +HINT: Available values: pglz. DROP TABLE cmdata2; CREATE TABLE cmdata2 (f1 text); \d+ cmdata2 -- 2.17.0
>From fc2b846ed482f5407278a171da3ce3c847425a00 Mon Sep 17 00:00:00 2001 From: Justin Pryzby <pryz...@telsasoft.com> Date: Sat, 20 Mar 2021 16:13:44 -0500 Subject: [PATCH v3 08/12] Commentary about slicing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit My language, per gripe from Álvaro Herrera: | I updated the coverage script to use --with-lz4; results are updated. | While eyeballing the results I noticed this bit in | lz4_decompress_datum_slice(): | | + /* slice decompression not supported prior to 1.8.3 */ | + if (LZ4_versionNumber() < 10803) | + return lz4_decompress_datum(value); | | which I read as returning the complete decompressed datum if slice | decompression is not supported. I thought that was a bug, but looking | at the caller I realize that this isn't really a problem, since it's | detoast_attr_slice's responsibility to slice the result further -- no | bug, it's just wasteful. I suggest to add comments to this effect, | perhaps as the attached (feel free to reword, I think mine is awkward.) --- src/backend/access/common/detoast.c | 3 +++ src/backend/access/common/toast_compression.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/backend/access/common/detoast.c b/src/backend/access/common/detoast.c index bed50e8603..519fe8c6a6 100644 --- a/src/backend/access/common/detoast.c +++ b/src/backend/access/common/detoast.c @@ -498,6 +498,9 @@ toast_decompress_datum(struct varlena *attr) * Decompress the front of a compressed version of a varlena datum. * offset handling happens in detoast_attr_slice. * Here we just decompress a slice from the front. + * + * If slice decompression is not supported, the full datum is decompressed, and + * then sliced by detoast_attr_slice. */ static struct varlena * toast_decompress_datum_slice(struct varlena *attr, int32 slicelength) diff --git a/src/backend/access/common/toast_compression.c b/src/backend/access/common/toast_compression.c index aa28772159..9107d16445 100644 --- a/src/backend/access/common/toast_compression.c +++ b/src/backend/access/common/toast_compression.c @@ -213,6 +213,9 @@ lz4_decompress_datum(const struct varlena *value) /* * Decompress part of a varlena that was compressed using LZ4. + * + * If slice decompression is not supported, the full datum is decompressed, and + * then sliced by detoast_attr_slice. */ struct varlena * lz4_decompress_datum_slice(const struct varlena *value, int32 slicelength) -- 2.17.0