diff --git a/.unreleased/pr_7126 b/.unreleased/pr_7126 new file mode 100644 index 00000000000..1854e0368fe --- /dev/null +++ b/.unreleased/pr_7126 @@ -0,0 +1 @@ +Implements: #7126 Add functions to show compression info diff --git a/sql/pre_install/types.functions.sql b/sql/pre_install/types.functions.sql index 03c20f50c01..ced40c02d24 100644 --- a/sql/pre_install/types.functions.sql +++ b/sql/pre_install/types.functions.sql @@ -34,6 +34,11 @@ CREATE OR REPLACE FUNCTION _timescaledb_functions.compressed_data_recv(internal) AS '@MODULE_PATHNAME@', 'ts_compressed_data_recv' LANGUAGE C IMMUTABLE STRICT; +CREATE OR REPLACE FUNCTION _timescaledb_functions.compressed_data_info(_timescaledb_internal.compressed_data) + RETURNS TABLE (algorithm name, has_nulls bool) + LANGUAGE C STRICT IMMUTABLE + AS '@MODULE_PATHNAME@', 'ts_compressed_data_info'; + CREATE OR REPLACE FUNCTION _timescaledb_functions.dimension_info_in(cstring) RETURNS _timescaledb_internal.dimension_info LANGUAGE C STRICT IMMUTABLE diff --git a/sql/updates/latest-dev.sql b/sql/updates/latest-dev.sql index 42f8bf0d737..af19e697810 100644 --- a/sql/updates/latest-dev.sql +++ b/sql/updates/latest-dev.sql @@ -65,3 +65,8 @@ SELECT pg_catalog.pg_extension_config_dump(pg_get_serial_sequence('_timescaledb_ GRANT SELECT ON _timescaledb_catalog.chunk_column_stats TO PUBLIC; GRANT SELECT ON _timescaledb_catalog.chunk_column_stats_id_seq TO PUBLIC; + +CREATE FUNCTION _timescaledb_functions.compressed_data_info(_timescaledb_internal.compressed_data) + RETURNS TABLE (algorithm name, has_nulls bool) + LANGUAGE C STRICT IMMUTABLE + AS '@MODULE_PATHNAME@', 'ts_compressed_data_info'; diff --git a/sql/updates/reverse-dev.sql b/sql/updates/reverse-dev.sql index 4096ae8198e..a2dd9b7f7b8 100644 --- a/sql/updates/reverse-dev.sql +++ b/sql/updates/reverse-dev.sql @@ -5,3 +5,4 @@ DROP FUNCTION IF EXISTS @extschema@.disable_column_stats(REGCLASS, NAME, BOOLEAN ALTER EXTENSION timescaledb DROP TABLE _timescaledb_catalog.chunk_column_stats; ALTER EXTENSION timescaledb DROP SEQUENCE _timescaledb_catalog.chunk_column_stats_id_seq; DROP TABLE IF EXISTS _timescaledb_catalog.chunk_column_stats; +DROP FUNCTION _timescaledb_functions.compressed_data_info(_timescaledb_internal.compressed_data); diff --git a/src/cross_module_fn.c b/src/cross_module_fn.c index c4de2340734..886f58aa5de 100644 --- a/src/cross_module_fn.c +++ b/src/cross_module_fn.c @@ -66,6 +66,7 @@ CROSSMODULE_WRAPPER(compressed_data_send); CROSSMODULE_WRAPPER(compressed_data_recv); CROSSMODULE_WRAPPER(compressed_data_in); CROSSMODULE_WRAPPER(compressed_data_out); +CROSSMODULE_WRAPPER(compressed_data_info); CROSSMODULE_WRAPPER(deltadelta_compressor_append); CROSSMODULE_WRAPPER(deltadelta_compressor_finish); CROSSMODULE_WRAPPER(gorilla_compressor_append); diff --git a/src/cross_module_fn.h b/src/cross_module_fn.h index f5ff3faed4c..08548d4cf7f 100644 --- a/src/cross_module_fn.h +++ b/src/cross_module_fn.h @@ -118,6 +118,7 @@ typedef struct CrossModuleFunctions PGFunction compressed_data_recv; PGFunction compressed_data_in; PGFunction compressed_data_out; + PGFunction compressed_data_info; bool (*process_compress_table)(AlterTableCmd *cmd, Hypertable *ht, WithClauseResult *with_clause_options); void (*process_altertable_cmd)(Hypertable *ht, const AlterTableCmd *cmd); diff --git a/tsl/src/compression/algorithms/array.c b/tsl/src/compression/algorithms/array.c index 69852d6e114..ef3216274cc 100644 --- a/tsl/src/compression/algorithms/array.c +++ b/tsl/src/compression/algorithms/array.c @@ -40,6 +40,13 @@ typedef struct ArrayCompressed uint64 alignment_sentinel[FLEXIBLE_ARRAY_MEMBER]; } ArrayCompressed; +bool +array_compressed_has_nulls(const CompressedDataHeader *header) +{ + const ArrayCompressed *ac = (const ArrayCompressed *) header; + return ac->has_nulls; +} + static void pg_attribute_unused() assertions(void) { diff --git a/tsl/src/compression/algorithms/array.h b/tsl/src/compression/algorithms/array.h index d2cdec905f2..7381d059603 100644 --- a/tsl/src/compression/algorithms/array.h +++ b/tsl/src/compression/algorithms/array.h @@ -26,6 +26,7 @@ typedef struct ArrayDecompressionIterator ArrayDecompressionIterator; extern const Compressor array_compressor; +extern bool array_compressed_has_nulls(const CompressedDataHeader *header); extern Compressor *array_compressor_for_type(Oid element_type); extern ArrayCompressor *array_compressor_alloc(Oid type_to_compress); extern void array_compressor_append_null(ArrayCompressor *compressor); diff --git a/tsl/src/compression/algorithms/deltadelta.c b/tsl/src/compression/algorithms/deltadelta.c index d44b305b712..48e3b00b893 100644 --- a/tsl/src/compression/algorithms/deltadelta.c +++ b/tsl/src/compression/algorithms/deltadelta.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -76,6 +77,13 @@ typedef struct ExtendedCompressor DeltaDeltaCompressor *internal; } ExtendedCompressor; +bool +deltadelta_compressed_has_nulls(const CompressedDataHeader *header) +{ + const DeltaDeltaCompressed *ddc = (const DeltaDeltaCompressed *) header; + return ddc->has_nulls; +} + static void deltadelta_compressor_append_bool(Compressor *compressor, Datum val) { diff --git a/tsl/src/compression/algorithms/deltadelta.h b/tsl/src/compression/algorithms/deltadelta.h index c9983cbbda9..6495691188f 100644 --- a/tsl/src/compression/algorithms/deltadelta.h +++ b/tsl/src/compression/algorithms/deltadelta.h @@ -27,6 +27,7 @@ typedef struct DeltaDeltaCompressor DeltaDeltaCompressor; typedef struct DeltaDeltaCompressed DeltaDeltaCompressed; typedef struct DeltaDeltaDecompressionIterator DeltaDeltaDecompressionIterator; +extern bool deltadelta_compressed_has_nulls(const CompressedDataHeader *header); extern Compressor *delta_delta_compressor_for_type(Oid element_type); extern DeltaDeltaCompressor *delta_delta_compressor_alloc(void); extern void delta_delta_compressor_append_null(DeltaDeltaCompressor *compressor); diff --git a/tsl/src/compression/algorithms/dictionary.c b/tsl/src/compression/algorithms/dictionary.c index c7cf51d981f..c13bc828b49 100644 --- a/tsl/src/compression/algorithms/dictionary.c +++ b/tsl/src/compression/algorithms/dictionary.c @@ -48,6 +48,13 @@ typedef struct DictionaryCompressed uint64 alignment_sentinel[FLEXIBLE_ARRAY_MEMBER]; } DictionaryCompressed; +bool +dictionary_compressed_has_nulls(const CompressedDataHeader *header) +{ + const DictionaryCompressed *dc = (const DictionaryCompressed *) header; + return dc->has_nulls; +} + static void pg_attribute_unused() assertions(void) { diff --git a/tsl/src/compression/algorithms/dictionary.h b/tsl/src/compression/algorithms/dictionary.h index 9f946f0e724..c17b3dd7101 100644 --- a/tsl/src/compression/algorithms/dictionary.h +++ b/tsl/src/compression/algorithms/dictionary.h @@ -23,6 +23,7 @@ typedef struct DictionaryCompressor DictionaryCompressor; typedef struct DictionaryCompressed DictionaryCompressed; typedef struct DictionaryDecompressionIterator DictionaryDecompressionIterator; +extern bool dictionary_compressed_has_nulls(const CompressedDataHeader *header); extern Compressor *dictionary_compressor_for_type(Oid element_type); extern DictionaryCompressor *dictionary_compressor_alloc(Oid type_to_compress); extern void dictionary_compressor_append_null(DictionaryCompressor *compressor); diff --git a/tsl/src/compression/algorithms/gorilla.c b/tsl/src/compression/algorithms/gorilla.c index bcc7a543fbf..4ea934c85dd 100644 --- a/tsl/src/compression/algorithms/gorilla.c +++ b/tsl/src/compression/algorithms/gorilla.c @@ -62,6 +62,13 @@ typedef struct CompressedGorillaData Simple8bRleSerialized *nulls; /* NULL if no nulls */ } CompressedGorillaData; +bool +gorilla_compressed_has_nulls(const CompressedDataHeader *header) +{ + const GorillaCompressed *gc = (const GorillaCompressed *) header; + return gc->has_nulls; +} + static void pg_attribute_unused() assertions(void) { diff --git a/tsl/src/compression/algorithms/gorilla.h b/tsl/src/compression/algorithms/gorilla.h index 67689501ec8..800d74d78a2 100644 --- a/tsl/src/compression/algorithms/gorilla.h +++ b/tsl/src/compression/algorithms/gorilla.h @@ -71,6 +71,7 @@ typedef struct GorillaCompressor GorillaCompressor; typedef struct GorillaCompressed GorillaCompressed; typedef struct GorillaDecompressionIterator GorillaDecompressionIterator; +extern bool gorilla_compressed_has_nulls(const CompressedDataHeader *header); extern Compressor *gorilla_compressor_for_type(Oid element_type); extern GorillaCompressor *gorilla_compressor_alloc(void); diff --git a/tsl/src/compression/compression.c b/tsl/src/compression/compression.c index f020162b332..955c6a1cedd 100644 --- a/tsl/src/compression/compression.c +++ b/tsl/src/compression/compression.c @@ -46,6 +46,18 @@ static const CompressionAlgorithmDefinition definitions[_END_COMPRESSION_ALGORIT [COMPRESSION_ALGORITHM_DELTADELTA] = DELTA_DELTA_ALGORITHM_DEFINITION, }; +static const char *compression_algorithm_name[] = { + [_INVALID_COMPRESSION_ALGORITHM] = "INVALID", [COMPRESSION_ALGORITHM_ARRAY] = "ARRAY", + [COMPRESSION_ALGORITHM_DICTIONARY] = "DICTIONARY", [COMPRESSION_ALGORITHM_GORILLA] = "GORILLA", + [COMPRESSION_ALGORITHM_DELTADELTA] = "DELTADELTA", +}; + +const char * +compression_get_algorithm_name(CompressionAlgorithm alg) +{ + return compression_algorithm_name[alg]; +} + static Compressor * compressor_for_type(Oid type) { @@ -1934,6 +1946,59 @@ tsl_compressed_data_out(PG_FUNCTION_ARGS) PG_RETURN_CSTRING(encoded); } +/* create_hypertable record attribute numbers */ +enum Anum_compressed_info +{ + Anum_compressed_info_algorithm = 1, + Anum_compressed_info_has_nulls, + _Anum_compressed_info_max, +}; + +#define Natts_compressed_info (_Anum_compressed_info_max - 1) + +extern Datum +tsl_compressed_data_info(PG_FUNCTION_ARGS) +{ + const CompressedDataHeader *header = (CompressedDataHeader *) PG_GETARG_VARLENA_P(0); + TupleDesc tupdesc; + HeapTuple tuple; + bool has_nulls = false; + + if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("function returning record called in " + "context that cannot accept type record"))); + + switch (header->compression_algorithm) + { + case COMPRESSION_ALGORITHM_GORILLA: + has_nulls = gorilla_compressed_has_nulls(header); + break; + case COMPRESSION_ALGORITHM_DICTIONARY: + has_nulls = dictionary_compressed_has_nulls(header); + break; + case COMPRESSION_ALGORITHM_DELTADELTA: + has_nulls = deltadelta_compressed_has_nulls(header); + break; + case COMPRESSION_ALGORITHM_ARRAY: + has_nulls = array_compressed_has_nulls(header); + break; + } + + tupdesc = BlessTupleDesc(tupdesc); + + Datum values[Natts_compressed_info]; + bool nulls[Natts_compressed_info] = { false }; + + values[AttrNumberGetAttrOffset(Anum_compressed_info_algorithm)] = + CStringGetDatum(compression_get_algorithm_name(header->compression_algorithm)); + values[AttrNumberGetAttrOffset(Anum_compressed_info_has_nulls)] = BoolGetDatum(has_nulls); + tuple = heap_form_tuple(tupdesc, values, nulls); + + return HeapTupleGetDatum(tuple); +} + extern CompressionStorage compression_get_toast_storage(CompressionAlgorithm algorithm) { diff --git a/tsl/src/compression/compression.h b/tsl/src/compression/compression.h index 8153b484a0a..b1e0a2acfc2 100644 --- a/tsl/src/compression/compression.h +++ b/tsl/src/compression/compression.h @@ -296,6 +296,7 @@ extern Datum tsl_compressed_data_send(PG_FUNCTION_ARGS); extern Datum tsl_compressed_data_recv(PG_FUNCTION_ARGS); extern Datum tsl_compressed_data_in(PG_FUNCTION_ARGS); extern Datum tsl_compressed_data_out(PG_FUNCTION_ARGS); +extern Datum tsl_compressed_data_info(PG_FUNCTION_ARGS); static void pg_attribute_unused() assert_num_compression_algorithms_sane(void) @@ -320,6 +321,7 @@ pg_attribute_unused() assert_num_compression_algorithms_sane(void) "number of algorithms have changed, the asserts should be updated"); } +extern const char *compression_get_algorithm_name(CompressionAlgorithm alg); extern CompressionStorage compression_get_toast_storage(CompressionAlgorithm algo); extern CompressionAlgorithm compression_get_default_algorithm(Oid typeoid); diff --git a/tsl/src/init.c b/tsl/src/init.c index 6d567c81d63..81acbe34a43 100644 --- a/tsl/src/init.c +++ b/tsl/src/init.c @@ -144,6 +144,7 @@ CrossModuleFunctions tsl_cm_functions = { .compressed_data_recv = tsl_compressed_data_recv, .compressed_data_in = tsl_compressed_data_in, .compressed_data_out = tsl_compressed_data_out, + .compressed_data_info = tsl_compressed_data_info, .deltadelta_compressor_append = tsl_deltadelta_compressor_append, .deltadelta_compressor_finish = tsl_deltadelta_compressor_finish, .gorilla_compressor_append = tsl_gorilla_compressor_append, diff --git a/tsl/test/shared/expected/extension.out b/tsl/test/shared/expected/extension.out index 8e4dc3570f4..2ce3a89b4a6 100644 --- a/tsl/test/shared/expected/extension.out +++ b/tsl/test/shared/expected/extension.out @@ -51,6 +51,7 @@ ORDER BY pronamespace::regnamespace::text COLLATE "C", p.oid::regprocedure::text _timescaledb_functions.chunks_local_size(name,name) _timescaledb_functions.compressed_chunk_local_stats(name,name) _timescaledb_functions.compressed_data_in(cstring) + _timescaledb_functions.compressed_data_info(_timescaledb_internal.compressed_data) _timescaledb_functions.compressed_data_out(_timescaledb_internal.compressed_data) _timescaledb_functions.compressed_data_recv(internal) _timescaledb_functions.compressed_data_send(_timescaledb_internal.compressed_data)