multi_compress 0.3.5 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +111 -0
  3. data/GET_STARTED.md +207 -0
  4. data/README.md +69 -0
  5. data/db_core/include/mcdb_format.h +113 -0
  6. data/db_core/src/mcdb_format.c +594 -0
  7. data/db_deployment/mysql/Makefile +48 -0
  8. data/db_deployment/mysql/README.md +61 -0
  9. data/db_deployment/mysql/bin/common +212 -0
  10. data/db_deployment/mysql/bin/disable +40 -0
  11. data/db_deployment/mysql/bin/doctor +64 -0
  12. data/db_deployment/mysql/bin/enable +61 -0
  13. data/db_deployment/mysql/bin/install +64 -0
  14. data/db_deployment/mysql/bin/status +67 -0
  15. data/db_deployment/mysql/bin/uninstall +47 -0
  16. data/db_deployment/mysql/bin/upgrade +127 -0
  17. data/db_deployment/mysql/bin/verify +14 -0
  18. data/db_deployment/postgres/Makefile +45 -0
  19. data/db_deployment/postgres/README.md +84 -0
  20. data/db_deployment/postgres/bin/doctor +61 -0
  21. data/db_deployment/postgres/bin/enable +138 -0
  22. data/db_deployment/postgres/bin/install +106 -0
  23. data/db_deployment/postgres/bin/uninstall +54 -0
  24. data/db_deployment/postgres/bin/verify +14 -0
  25. data/docs/database-envelope-v1.md +159 -0
  26. data/docs/database-envelope-v2.md +147 -0
  27. data/docs/rfcs/0002-mcdb2-dictionaries.md +75 -0
  28. data/exe/multi_compress +228 -0
  29. data/ext/multi_compress/extconf.rb +4 -0
  30. data/ext/multi_compress/multi_compress.c +62 -0
  31. data/lib/multi_compress/active_record.rb +61 -0
  32. data/lib/multi_compress/codec.rb +164 -0
  33. data/lib/multi_compress/database.rb +312 -0
  34. data/lib/multi_compress/db_deployment.rb +868 -0
  35. data/lib/multi_compress/version.rb +1 -1
  36. data/multi_compress.gemspec +55 -0
  37. data/mysql_udf/Makefile +96 -0
  38. data/mysql_udf/README.md +140 -0
  39. data/mysql_udf/sql/examples.sql +16 -0
  40. data/mysql_udf/sql/install.sql +39 -0
  41. data/mysql_udf/sql/uninstall.sql +10 -0
  42. data/mysql_udf/sql/views.sql +20 -0
  43. data/mysql_udf/src/multi_compress_mysql.c +472 -0
  44. data/mysql_udf/src/mysql_udf_abi_57.h +34 -0
  45. data/mysql_udf/test/mcdb_cli.c +60 -0
  46. data/mysql_udf/test/run_e2e.sh +414 -0
  47. data/postgres_extension/Makefile +74 -0
  48. data/postgres_extension/README.md +160 -0
  49. data/postgres_extension/multi_compress.control +4 -0
  50. data/postgres_extension/multi_compress_pg.exports +24 -0
  51. data/postgres_extension/sql/examples.sql +23 -0
  52. data/postgres_extension/sql/multi_compress--0.5.0--0.6.0.sql +59 -0
  53. data/postgres_extension/sql/multi_compress--0.5.0.sql +24 -0
  54. data/postgres_extension/sql/multi_compress--0.6.0.sql +85 -0
  55. data/postgres_extension/sql/uninstall.sql +2 -0
  56. data/postgres_extension/sql/views.sql +7 -0
  57. data/postgres_extension/src/mcdb_format.c +2 -0
  58. data/postgres_extension/src/multi_compress_pg.c +381 -0
  59. data/postgres_extension/test/run_e2e.sh +411 -0
  60. metadata +56 -3
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MultiCompress
4
- VERSION = "0.3.5"
4
+ VERSION = "0.6.0"
5
5
  end
@@ -0,0 +1,55 @@
1
+ require_relative "lib/multi_compress/version"
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = "multi_compress"
5
+ spec.version = MultiCompress::VERSION
6
+ spec.authors = ["Roman Haydarov"]
7
+ spec.email = ["romnhajdarov@gmail.com"]
8
+
9
+ spec.summary = "Modern fiber-friendly compression for Ruby: zstd, lz4, brotli in one gem"
10
+ spec.description = "Unified C-extension gem for zstd, lz4, and brotli compression. " \
11
+ "One-shot, streaming, IO wrappers, dictionary support. " \
12
+ "Fiber-friendly: cooperates with Fiber::Scheduler (async, falcon) " \
13
+ "so CPU-heavy compression never blocks the event loop. " \
14
+ "Ships vendored sources — no system libraries required."
15
+ spec.homepage = "https://github.com/roman-haidarov/multi_compress"
16
+ spec.license = "MIT"
17
+ spec.required_ruby_version = ">= 2.7.1"
18
+
19
+ spec.metadata["homepage_uri"] = spec.homepage
20
+ spec.metadata["source_code_uri"] = spec.homepage
21
+ spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/main/CHANGELOG.md"
22
+
23
+ spec.files = Dir[
24
+ "lib/**/*.rb",
25
+ "exe/*",
26
+ "docs/**/*.md",
27
+ "ext/**/*.{c,h,rb}",
28
+ "ext/multi_compress/vendor/**/*",
29
+ "ext/multi_compress/vendor/.vendored",
30
+ "db_core/**/*.{c,h}",
31
+ "postgres_extension/**/*",
32
+ "mysql_udf/**/*",
33
+ "db_deployment/**/*",
34
+ "multi_compress.gemspec",
35
+ "README.md",
36
+ "GET_STARTED.md",
37
+ "LICENSE.txt",
38
+ "THIRD_PARTY_NOTICES.md",
39
+ "CHANGELOG.md"
40
+ ].reject do |path|
41
+ File.basename(path) == ".DS_Store" ||
42
+ path.split(File::SEPARATOR).include?("build") ||
43
+ %w[.o .so .bundle .dylib .bc .d].include?(File.extname(path))
44
+ end
45
+
46
+ spec.bindir = "exe"
47
+ spec.executables = ["multi_compress"]
48
+ spec.require_paths = ["lib"]
49
+ spec.extensions = ["ext/multi_compress/extconf.rb"]
50
+
51
+ spec.add_development_dependency "bundler", "~> 2.0"
52
+ spec.add_development_dependency "rake", "~> 13.0"
53
+ spec.add_development_dependency "rake-compiler", "~> 1.2"
54
+ spec.add_development_dependency "minitest", "~> 5.0"
55
+ end
@@ -0,0 +1,96 @@
1
+ ZSTD_DIR ?= ../ext/multi_compress/vendor/zstd/lib
2
+ CORE_DIR ?= ../db_core
3
+ BUILD ?= build
4
+ CC ?= gcc
5
+ AR ?= ar
6
+ MYSQL_UDF_ABI ?= mysql57
7
+ MYSQL_INCLUDE ?= /usr/include/mysql
8
+ FIXTURES ?= ../test/fixtures/database_v1
9
+
10
+ ifeq ($(MYSQL_UDF_ABI),mysql57)
11
+ MYSQL_UDF_CPPFLAGS := -DMCDB_MYSQL_UDF_ABI_57
12
+ MYSQL_UDF_HEADER_CHECK :=
13
+ else ifeq ($(MYSQL_UDF_ABI),system)
14
+ MYSQL_UDF_CPPFLAGS := -I$(MYSQL_INCLUDE)
15
+ MYSQL_UDF_HEADER_CHECK := test -f "$(MYSQL_INCLUDE)/mysql.h" || { echo "missing mysql.h: set MYSQL_INCLUDE=/path/to/mysql/include" >&2; exit 2; }
16
+ else
17
+ $(error MYSQL_UDF_ABI must be mysql57 or system)
18
+ endif
19
+
20
+ WARNFLAGS ?= -Wall -Wextra -Werror
21
+ CFLAGS ?= -O2 -fPIC -std=c99 $(WARNFLAGS) -I$(ZSTD_DIR) -I$(CORE_DIR)/include
22
+ ZSTD_CFLAGS ?= -O2 -fPIC -std=c99 -I$(ZSTD_DIR) -I$(ZSTD_DIR)/common
23
+
24
+ ZSTD_OBJ_DIR := $(BUILD)/zstd
25
+ ZSTD_C_SRCS := $(wildcard $(ZSTD_DIR)/common/*.c) $(wildcard $(ZSTD_DIR)/decompress/*.c)
26
+ ZSTD_C_OBJS := $(patsubst $(ZSTD_DIR)/%.c,$(ZSTD_OBJ_DIR)/%.o,$(ZSTD_C_SRCS))
27
+
28
+ ARCH := $(shell uname -m)
29
+ ifneq (,$(filter x86_64 amd64,$(ARCH)))
30
+ ZSTD_ASM_SRC := $(ZSTD_DIR)/decompress/huf_decompress_amd64.S
31
+ ifneq (,$(wildcard $(ZSTD_ASM_SRC)))
32
+ ZSTD_ASM_OBJ := $(ZSTD_OBJ_DIR)/decompress/huf_decompress_amd64.o
33
+ endif
34
+ endif
35
+
36
+ ZSTD_OBJS := $(ZSTD_C_OBJS) $(ZSTD_ASM_OBJ)
37
+ ZSTD_LIB := $(BUILD)/libzstd_dec.a
38
+ UDF_SO := $(BUILD)/multi_compress_mysql.so
39
+ CLI := $(BUILD)/mcdb_cli
40
+ VALID_FIXTURES := utf8_text empty_text large_text
41
+ CORRUPT_FIXTURES := corrupt_magic wrong_version corrupt_payload corrupt_crc invalid_utf8 nul_text trailing_skippable trailing_frame
42
+
43
+ .PHONY: all udf test fixtures clean
44
+ all: udf
45
+
46
+ $(BUILD):
47
+ mkdir -p $@
48
+
49
+ $(ZSTD_OBJ_DIR)/%.o: $(ZSTD_DIR)/%.c
50
+ @mkdir -p $(dir $@)
51
+ $(CC) $(ZSTD_CFLAGS) -MMD -MP -c $< -o $@
52
+
53
+ $(ZSTD_OBJ_DIR)/%.o: $(ZSTD_DIR)/%.S
54
+ @mkdir -p $(dir $@)
55
+ $(CC) -fPIC -I$(ZSTD_DIR) -c $< -o $@
56
+
57
+ $(ZSTD_LIB): $(ZSTD_OBJS) | $(BUILD)
58
+ $(AR) rcs $@ $^
59
+
60
+ $(UDF_SO): src/multi_compress_mysql.c $(CORE_DIR)/src/mcdb_format.c $(CORE_DIR)/include/mcdb_format.h $(ZSTD_LIB) | $(BUILD)
61
+ @$(MYSQL_UDF_HEADER_CHECK)
62
+ $(CC) $(CFLAGS) $(MYSQL_UDF_CPPFLAGS) -shared \
63
+ src/multi_compress_mysql.c $(CORE_DIR)/src/mcdb_format.c $(ZSTD_LIB) \
64
+ -o $@
65
+ @echo "built $@"
66
+
67
+ udf: $(UDF_SO)
68
+
69
+ $(CLI): $(CORE_DIR)/src/mcdb_format.c $(CORE_DIR)/include/mcdb_format.h test/mcdb_cli.c $(ZSTD_LIB) | $(BUILD)
70
+ $(CC) $(CFLAGS) $(CORE_DIR)/src/mcdb_format.c test/mcdb_cli.c $(ZSTD_LIB) -o $@
71
+
72
+ fixtures:
73
+ RUBYLIB=../lib ruby $(FIXTURES)/generate.rb
74
+
75
+ test: $(CLI)
76
+ @echo "== MCDB1 Ruby<->C parity =="
77
+ @fail=0; \
78
+ for name in $(VALID_FIXTURES); do \
79
+ f=$(FIXTURES)/$$name.mcdb; exp=$(FIXTURES)/$$name.expected; \
80
+ if [ ! -f $$f ] || [ ! -f $$exp ]; then echo " MISSING $$name (run: make fixtures)"; fail=1; continue; fi; \
81
+ if $(CLI) decode $$f | cmp -s - $$exp; then echo " valid $$name OK"; \
82
+ else echo " valid $$name FAIL"; fail=1; fi; \
83
+ done; \
84
+ for name in $(CORRUPT_FIXTURES); do \
85
+ f=$(FIXTURES)/$$name.mcdb; \
86
+ if [ ! -f $$f ]; then echo " MISSING $$name (run: make fixtures)"; fail=1; continue; fi; \
87
+ if $(CLI) decode $$f >/dev/null 2>&1; then echo " corrupt $$name UNEXPECTEDLY VALID"; fail=1; \
88
+ else echo " corrupt $$name correctly rejected"; fi; \
89
+ done; \
90
+ if [ $$fail -ne 0 ]; then echo "PARITY FAILED"; exit 1; fi; \
91
+ echo "PARITY OK"
92
+
93
+ clean:
94
+ rm -rf $(BUILD)
95
+
96
+ -include $(ZSTD_C_OBJS:.o=.d)
@@ -0,0 +1,140 @@
1
+ # MultiCompress MySQL 5.7 UDF (`MCDB1` reader)
2
+
3
+ Decode-only MySQL loadable functions for the MultiCompress Database envelope v1.
4
+ The shared format contract is [`docs/database-envelope-v1.md`](../docs/database-envelope-v1.md).
5
+
6
+ ## SQL API
7
+
8
+ | Function | Returns | Purpose |
9
+ |---|---:|---|
10
+ | `multi_compress_db_version()` | STRING | reader build, MCDB1 and zstd version smoke test |
11
+ | `multi_compress_db_is_valid(blob)` | INTEGER | `1` for valid MCDB1, `0` for corruption, `NULL` for SQL NULL |
12
+ | `multi_compress_db_decompress(blob)` | STRING | decompressed UTF-8 or SQL `NULL` for corruption/SQL NULL |
13
+
14
+ A MySQL readable view cannot distinguish an original SQL `NULL` from a corrupt
15
+ MCDB1 envelope by testing `payload IS NULL`. Diagnose stored values with
16
+ `multi_compress_db_is_valid(payload_compressed)`.
17
+
18
+ ## Production deployment: generated DBA bundle
19
+
20
+ Generate a source bundle from the installed gem:
21
+
22
+ ```bash
23
+ bundle exec multi_compress db package mysql --output tmp/multi-compress-mysql.tar.gz
24
+ ```
25
+
26
+ On the MySQL 5.7 host, use its local Unix socket:
27
+
28
+ ```bash
29
+ tar -xzf multi-compress-mysql.tar.gz
30
+ cd multi_compress-mysql-0.5.0
31
+ make verify
32
+ make doctor MYSQL_DEFAULTS_FILE=/etc/mysql/admin.cnf MYSQL_SOCKET=/run/mysqld/mysqld.sock
33
+ sudo make install MYSQL_DEFAULTS_FILE=/etc/mysql/admin.cnf MYSQL_SOCKET=/run/mysqld/mysqld.sock
34
+ make enable MYSQL_DEFAULTS_FILE=/etc/mysql/admin.cnf MYSQL_SOCKET=/run/mysqld/mysqld.sock
35
+ make status MYSQL_DEFAULTS_FILE=/etc/mysql/admin.cnf MYSQL_SOCKET=/run/mysqld/mysqld.sock
36
+ ```
37
+
38
+ `install` is fresh-install only and refuses to replace a loaded library. A
39
+ healthy second `enable` is a no-op. For a library update, use the controlled
40
+ maintenance flow:
41
+
42
+ ```bash
43
+ sudo make upgrade CONFIRM=UPGRADE_MULTI_COMPRESS \
44
+ MYSQL_DEFAULTS_FILE=/etc/mysql/admin.cnf MYSQL_SOCKET=/run/mysqld/mysqld.sock
45
+ ```
46
+
47
+ `upgrade` captures registrations, drops MultiCompress-owned functions, backs up
48
+ the old library, atomically replaces the library, registers functions, and
49
+ smoke-checks the reader. On failure it restores the previous library and
50
+ registrations. `disable` and `uninstall` are destructive and require:
51
+
52
+ ```bash
53
+ make disable CONFIRM=DISABLE_MULTI_COMPRESS \
54
+ MYSQL_DEFAULTS_FILE=/etc/mysql/admin.cnf MYSQL_SOCKET=/run/mysqld/mysqld.sock
55
+ sudo make uninstall CONFIRM=REMOVE_MULTI_COMPRESS \
56
+ MYSQL_DEFAULTS_FILE=/etc/mysql/admin.cnf MYSQL_SOCKET=/run/mysqld/mysqld.sock
57
+ ```
58
+
59
+ The DBA account needs `INSERT` on `mysql` to register functions, `DELETE` to
60
+ drop them, and `SELECT` on `mysql.func` for `make status`. The bundle's mysql
61
+ client uses `--max_allowed_packet=32M`; mysqld, the Ruby driver, and
62
+ DBeaver/JDBC must each support payloads up to the 16 MiB MCDB1 limit.
63
+
64
+ ## DBeaver readable view
65
+
66
+ The application stores `MultiCompress::Database.compress(text)` in a `LONGBLOB`
67
+ column and commits generated view SQL in a migration:
68
+
69
+ ```bash
70
+ bundle exec multi_compress db view mysql \
71
+ --table app.events \
72
+ --column payload_compressed \
73
+ --view admin.events_readable \
74
+ --columns id,created_at,status \
75
+ --as payload \
76
+ --output db/views/events_readable.sql
77
+ ```
78
+
79
+ MySQL views default to `SQL SECURITY DEFINER`; create the migration with a
80
+ stable technical account and do not remove that definer without recreating the
81
+ view. Grant the DBeaver role `SELECT` on the resulting view. The generated view
82
+ uses `CONVERT(... USING utf8mb4)` so Cyrillic, Kazakh text and emoji display
83
+ correctly. Filter by indexed uncompressed columns before selecting through it.
84
+
85
+ ## Multi-host rollout
86
+
87
+ Build/install the native library on every primary, replica, reporting, failover,
88
+ and restore host that will read through the view before registering UDFs or
89
+ applying the view migration. A read-only view does not itself replicate the UDF;
90
+ replication requires the UDF on a replica only when a replicated statement
91
+ invokes it.
92
+
93
+ `make verify` catches accidental corruption after extraction; it does not
94
+ authenticate an archive. Use an out-of-band SHA-256, minisign/GPG signature, or
95
+ signed release provenance for a real trust chain.
96
+
97
+ ## MCDB2 dictionary-backed columns
98
+
99
+ MCDB2 is opt-in for one homogeneous column with many similar small JSON/text
100
+ values. Upgrade the UDF library first; the controlled `make upgrade` flow keeps
101
+ all MCDB1 and MCDB2 functions registered.
102
+
103
+ Dictionary bytes are application data. Generate the append-only registry in the
104
+ application database, register immutable versions, and retain all referenced
105
+ versions in backups and replicas:
106
+
107
+ ```bash
108
+ bundle exec multi_compress db registry mysql --database app \
109
+ --output db/mcdb_dictionary_registry.sql
110
+ ```
111
+
112
+ For a new MCDB2 column add `payload_dictionary_id BIGINT UNSIGNED NOT NULL` with
113
+ a foreign key to `mcdb_dictionary_versions(id)`, then generate the view:
114
+
115
+ ```bash
116
+ bundle exec multi_compress db view mysql \
117
+ --table app.events \
118
+ --column payload_compressed \
119
+ --dictionary-table app.mcdb_dictionary_versions \
120
+ --dictionary-id-column payload_dictionary_id \
121
+ --view admin.events_readable \
122
+ --columns id,created_at,status \
123
+ --as payload \
124
+ --output db/views/events_readable.sql
125
+ ```
126
+
127
+ The generated MCDB2 view requests `ALGORITHM=MERGE SQL SECURITY DEFINER` and uses
128
+ a source-first `STRAIGHT_JOIN` to the registry. That keeps an indexed outer source
129
+ predicate from starting at the registry. It passes payload, registry id, SHA-256
130
+ and dictionary bytes to the UDF. Keep the definition free of `DISTINCT`, aggregates,
131
+ `GROUP BY`, `UNION`, subqueries and inner `LIMIT`; validate real queries with
132
+ `EXPLAIN`: source must be a selective `range`/`ref` access and no `<derived>` row
133
+ may appear. MySQL 5.7 can still report `Using temporary; Using filesort` for an
134
+ outer `ORDER BY` over the joined projection; that is sorting, not view
135
+ materialization. A stable definer account must remain part of backup/restore
136
+ procedures.
137
+
138
+ Details are in [`docs/database-envelope-v2.md`](../docs/database-envelope-v2.md).
139
+
140
+ For MCDB2 registry DDL, pass `--payload-table`, `--payload-column`, and `--payload-dictionary-id-column` to `multi_compress db registry`; this creates the payload FK and enforces header dictionary-reference consistency.
@@ -0,0 +1,16 @@
1
+ -- Point lookup an employee runs from DBeaver:
2
+ SELECT
3
+ CONVERT(multi_compress_db_decompress(payload_compressed) USING utf8mb4) AS payload
4
+ FROM events
5
+ WHERE id = 123;
6
+
7
+ SELECT id
8
+ FROM events
9
+ WHERE multi_compress_db_is_valid(payload_compressed) = 0;
10
+
11
+ SELECT multi_compress_db_version();
12
+
13
+ -- MCDB2: use the generated ALGORITHM=MERGE readable view. Avoid filtering on
14
+ -- decoded payload text; filter/order by indexed source columns before LIMIT.
15
+ --
16
+ -- SELECT id, payload FROM admin.events_readable WHERE id >= 100 ORDER BY id LIMIT 100;
@@ -0,0 +1,39 @@
1
+ -- Install the MultiCompress MCDB1/MCDB2 reader UDFs (MySQL 5.7).
2
+
3
+ CREATE FUNCTION multi_compress_db_version
4
+ RETURNS STRING
5
+ SONAME 'multi_compress_mysql.so';
6
+
7
+ CREATE FUNCTION multi_compress_db_is_valid
8
+ RETURNS INTEGER
9
+ SONAME 'multi_compress_mysql.so';
10
+
11
+ CREATE FUNCTION multi_compress_db_decompress
12
+ RETURNS STRING
13
+ SONAME 'multi_compress_mysql.so';
14
+
15
+ CREATE FUNCTION multi_compress_db_original_size
16
+ RETURNS INTEGER
17
+ SONAME 'multi_compress_mysql.so';
18
+
19
+ CREATE FUNCTION multi_compress_db_dictionary_ref
20
+ RETURNS INTEGER
21
+ SONAME 'multi_compress_mysql.so';
22
+
23
+ CREATE FUNCTION multi_compress_db_dictionary_zstd_id
24
+ RETURNS INTEGER
25
+ SONAME 'multi_compress_mysql.so';
26
+
27
+ CREATE FUNCTION multi_compress_db_dictionary_sha256
28
+ RETURNS STRING
29
+ SONAME 'multi_compress_mysql.so';
30
+
31
+ CREATE FUNCTION multi_compress_db_is_valid_dict
32
+ RETURNS INTEGER
33
+ SONAME 'multi_compress_mysql.so';
34
+
35
+ CREATE FUNCTION multi_compress_db_decompress_dict
36
+ RETURNS STRING
37
+ SONAME 'multi_compress_mysql.so';
38
+
39
+ SELECT multi_compress_db_version();
@@ -0,0 +1,10 @@
1
+ -- Run only after verifying no generated readable view depends on these UDFs.
2
+ DROP FUNCTION IF EXISTS multi_compress_db_decompress_dict;
3
+ DROP FUNCTION IF EXISTS multi_compress_db_is_valid_dict;
4
+ DROP FUNCTION IF EXISTS multi_compress_db_dictionary_sha256;
5
+ DROP FUNCTION IF EXISTS multi_compress_db_dictionary_zstd_id;
6
+ DROP FUNCTION IF EXISTS multi_compress_db_original_size;
7
+ DROP FUNCTION IF EXISTS multi_compress_db_dictionary_ref;
8
+ DROP FUNCTION IF EXISTS multi_compress_db_decompress;
9
+ DROP FUNCTION IF EXISTS multi_compress_db_is_valid;
10
+ DROP FUNCTION IF EXISTS multi_compress_db_version;
@@ -0,0 +1,20 @@
1
+ -- MCDB1 view example. Generate production SQL with:
2
+ -- multi_compress db view mysql ...
3
+ CREATE OR REPLACE VIEW events_readable AS
4
+ SELECT
5
+ id,
6
+ CONVERT(multi_compress_db_decompress(payload_compressed) USING utf8mb4) AS payload
7
+ FROM events;
8
+
9
+ -- MCDB2 dictionary-backed shape. The generated view uses ALGORITHM=MERGE and
10
+ -- a source-first STRAIGHT_JOIN to the append-only registry, so an indexed outer
11
+ -- WHERE predicate is pushed into the source scan in MySQL 5.7. An outer ORDER BY
12
+ -- may still use filesort; that is not view materialization.
13
+ --
14
+ -- CREATE ALGORITHM=MERGE SQL SECURITY DEFINER VIEW events_readable AS
15
+ -- SELECT e.id,
16
+ -- CONVERT(multi_compress_db_decompress_dict(
17
+ -- e.payload_compressed, e.payload_dictionary_id, d.sha256, d.bytes
18
+ -- ) USING utf8mb4) AS payload
19
+ -- FROM events e
20
+ -- STRAIGHT_JOIN mcdb_dictionary_versions d ON d.id = e.payload_dictionary_id;