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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +111 -0
- data/GET_STARTED.md +207 -0
- data/README.md +69 -0
- data/db_core/include/mcdb_format.h +113 -0
- data/db_core/src/mcdb_format.c +594 -0
- data/db_deployment/mysql/Makefile +48 -0
- data/db_deployment/mysql/README.md +61 -0
- data/db_deployment/mysql/bin/common +212 -0
- data/db_deployment/mysql/bin/disable +40 -0
- data/db_deployment/mysql/bin/doctor +64 -0
- data/db_deployment/mysql/bin/enable +61 -0
- data/db_deployment/mysql/bin/install +64 -0
- data/db_deployment/mysql/bin/status +67 -0
- data/db_deployment/mysql/bin/uninstall +47 -0
- data/db_deployment/mysql/bin/upgrade +127 -0
- data/db_deployment/mysql/bin/verify +14 -0
- data/db_deployment/postgres/Makefile +45 -0
- data/db_deployment/postgres/README.md +84 -0
- data/db_deployment/postgres/bin/doctor +61 -0
- data/db_deployment/postgres/bin/enable +138 -0
- data/db_deployment/postgres/bin/install +106 -0
- data/db_deployment/postgres/bin/uninstall +54 -0
- data/db_deployment/postgres/bin/verify +14 -0
- data/docs/database-envelope-v1.md +159 -0
- data/docs/database-envelope-v2.md +147 -0
- data/docs/rfcs/0002-mcdb2-dictionaries.md +75 -0
- data/exe/multi_compress +228 -0
- data/ext/multi_compress/extconf.rb +4 -0
- data/ext/multi_compress/multi_compress.c +62 -0
- data/lib/multi_compress/active_record.rb +61 -0
- data/lib/multi_compress/codec.rb +164 -0
- data/lib/multi_compress/database.rb +312 -0
- data/lib/multi_compress/db_deployment.rb +868 -0
- data/lib/multi_compress/version.rb +1 -1
- data/multi_compress.gemspec +55 -0
- data/mysql_udf/Makefile +96 -0
- data/mysql_udf/README.md +140 -0
- data/mysql_udf/sql/examples.sql +16 -0
- data/mysql_udf/sql/install.sql +39 -0
- data/mysql_udf/sql/uninstall.sql +10 -0
- data/mysql_udf/sql/views.sql +20 -0
- data/mysql_udf/src/multi_compress_mysql.c +472 -0
- data/mysql_udf/src/mysql_udf_abi_57.h +34 -0
- data/mysql_udf/test/mcdb_cli.c +60 -0
- data/mysql_udf/test/run_e2e.sh +414 -0
- data/postgres_extension/Makefile +74 -0
- data/postgres_extension/README.md +160 -0
- data/postgres_extension/multi_compress.control +4 -0
- data/postgres_extension/multi_compress_pg.exports +24 -0
- data/postgres_extension/sql/examples.sql +23 -0
- data/postgres_extension/sql/multi_compress--0.5.0--0.6.0.sql +59 -0
- data/postgres_extension/sql/multi_compress--0.5.0.sql +24 -0
- data/postgres_extension/sql/multi_compress--0.6.0.sql +85 -0
- data/postgres_extension/sql/uninstall.sql +2 -0
- data/postgres_extension/sql/views.sql +7 -0
- data/postgres_extension/src/mcdb_format.c +2 -0
- data/postgres_extension/src/multi_compress_pg.c +381 -0
- data/postgres_extension/test/run_e2e.sh +411 -0
- metadata +56 -3
|
@@ -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
|
data/mysql_udf/Makefile
ADDED
|
@@ -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)
|
data/mysql_udf/README.md
ADDED
|
@@ -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;
|