multi_compress 0.3.5 → 0.5.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 +76 -0
- data/GET_STARTED.md +188 -0
- data/README.md +56 -0
- data/db_core/include/mcdb_format.h +55 -0
- data/db_core/src/mcdb_format.c +341 -0
- data/db_deployment/mysql/Makefile +48 -0
- data/db_deployment/mysql/README.md +42 -0
- data/db_deployment/mysql/bin/common +160 -0
- data/db_deployment/mysql/bin/disable +40 -0
- data/db_deployment/mysql/bin/doctor +64 -0
- data/db_deployment/mysql/bin/enable +57 -0
- data/db_deployment/mysql/bin/install +64 -0
- data/db_deployment/mysql/bin/status +65 -0
- data/db_deployment/mysql/bin/uninstall +47 -0
- data/db_deployment/mysql/bin/upgrade +115 -0
- data/db_deployment/mysql/bin/verify +14 -0
- data/db_deployment/postgres/Makefile +45 -0
- data/db_deployment/postgres/README.md +60 -0
- data/db_deployment/postgres/bin/doctor +61 -0
- data/db_deployment/postgres/bin/enable +136 -0
- data/db_deployment/postgres/bin/install +104 -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/exe/multi_compress +228 -0
- data/ext/multi_compress/extconf.rb +4 -0
- data/ext/multi_compress/multi_compress.c +30 -0
- data/lib/multi_compress/active_record.rb +61 -0
- data/lib/multi_compress/codec.rb +164 -0
- data/lib/multi_compress/database.rb +106 -0
- data/lib/multi_compress/db_deployment.rb +456 -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 +95 -0
- data/mysql_udf/sql/examples.sql +11 -0
- data/mysql_udf/sql/install.sql +15 -0
- data/mysql_udf/sql/uninstall.sql +4 -0
- data/mysql_udf/sql/views.sql +8 -0
- data/mysql_udf/src/multi_compress_mysql.c +133 -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 +296 -0
- data/postgres_extension/Makefile +74 -0
- data/postgres_extension/README.md +112 -0
- data/postgres_extension/multi_compress.control +4 -0
- data/postgres_extension/multi_compress_pg.exports +12 -0
- data/postgres_extension/sql/examples.sql +12 -0
- data/postgres_extension/sql/multi_compress--0.5.0.sql +24 -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 +96 -0
- data/postgres_extension/test/run_e2e.sh +323 -0
- metadata +52 -3
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
#include "mcdb_format.h"
|
|
2
|
+
|
|
3
|
+
#include <stdlib.h>
|
|
4
|
+
#include <string.h>
|
|
5
|
+
#include <stdio.h>
|
|
6
|
+
|
|
7
|
+
#include <zstd.h>
|
|
8
|
+
|
|
9
|
+
typedef char
|
|
10
|
+
mcdb_envelope_bound_check[(MCDB_MAX_ENVELOPE ==
|
|
11
|
+
(unsigned)(MCDB_HEADER_SIZE + ZSTD_COMPRESSBOUND(MCDB_MAX_OUTPUT)))
|
|
12
|
+
? 1
|
|
13
|
+
: -1];
|
|
14
|
+
|
|
15
|
+
static const uint32_t MCDB_CRC32_TABLE[256] = {
|
|
16
|
+
0x00000000U, 0x77073096U, 0xEE0E612CU, 0x990951BAU, 0x076DC419U, 0x706AF48FU, 0xE963A535U,
|
|
17
|
+
0x9E6495A3U, 0x0EDB8832U, 0x79DCB8A4U, 0xE0D5E91EU, 0x97D2D988U, 0x09B64C2BU, 0x7EB17CBDU,
|
|
18
|
+
0xE7B82D07U, 0x90BF1D91U, 0x1DB71064U, 0x6AB020F2U, 0xF3B97148U, 0x84BE41DEU, 0x1ADAD47DU,
|
|
19
|
+
0x6DDDE4EBU, 0xF4D4B551U, 0x83D385C7U, 0x136C9856U, 0x646BA8C0U, 0xFD62F97AU, 0x8A65C9ECU,
|
|
20
|
+
0x14015C4FU, 0x63066CD9U, 0xFA0F3D63U, 0x8D080DF5U, 0x3B6E20C8U, 0x4C69105EU, 0xD56041E4U,
|
|
21
|
+
0xA2677172U, 0x3C03E4D1U, 0x4B04D447U, 0xD20D85FDU, 0xA50AB56BU, 0x35B5A8FAU, 0x42B2986CU,
|
|
22
|
+
0xDBBBC9D6U, 0xACBCF940U, 0x32D86CE3U, 0x45DF5C75U, 0xDCD60DCFU, 0xABD13D59U, 0x26D930ACU,
|
|
23
|
+
0x51DE003AU, 0xC8D75180U, 0xBFD06116U, 0x21B4F4B5U, 0x56B3C423U, 0xCFBA9599U, 0xB8BDA50FU,
|
|
24
|
+
0x2802B89EU, 0x5F058808U, 0xC60CD9B2U, 0xB10BE924U, 0x2F6F7C87U, 0x58684C11U, 0xC1611DABU,
|
|
25
|
+
0xB6662D3DU, 0x76DC4190U, 0x01DB7106U, 0x98D220BCU, 0xEFD5102AU, 0x71B18589U, 0x06B6B51FU,
|
|
26
|
+
0x9FBFE4A5U, 0xE8B8D433U, 0x7807C9A2U, 0x0F00F934U, 0x9609A88EU, 0xE10E9818U, 0x7F6A0DBBU,
|
|
27
|
+
0x086D3D2DU, 0x91646C97U, 0xE6635C01U, 0x6B6B51F4U, 0x1C6C6162U, 0x856530D8U, 0xF262004EU,
|
|
28
|
+
0x6C0695EDU, 0x1B01A57BU, 0x8208F4C1U, 0xF50FC457U, 0x65B0D9C6U, 0x12B7E950U, 0x8BBEB8EAU,
|
|
29
|
+
0xFCB9887CU, 0x62DD1DDFU, 0x15DA2D49U, 0x8CD37CF3U, 0xFBD44C65U, 0x4DB26158U, 0x3AB551CEU,
|
|
30
|
+
0xA3BC0074U, 0xD4BB30E2U, 0x4ADFA541U, 0x3DD895D7U, 0xA4D1C46DU, 0xD3D6F4FBU, 0x4369E96AU,
|
|
31
|
+
0x346ED9FCU, 0xAD678846U, 0xDA60B8D0U, 0x44042D73U, 0x33031DE5U, 0xAA0A4C5FU, 0xDD0D7CC9U,
|
|
32
|
+
0x5005713CU, 0x270241AAU, 0xBE0B1010U, 0xC90C2086U, 0x5768B525U, 0x206F85B3U, 0xB966D409U,
|
|
33
|
+
0xCE61E49FU, 0x5EDEF90EU, 0x29D9C998U, 0xB0D09822U, 0xC7D7A8B4U, 0x59B33D17U, 0x2EB40D81U,
|
|
34
|
+
0xB7BD5C3BU, 0xC0BA6CADU, 0xEDB88320U, 0x9ABFB3B6U, 0x03B6E20CU, 0x74B1D29AU, 0xEAD54739U,
|
|
35
|
+
0x9DD277AFU, 0x04DB2615U, 0x73DC1683U, 0xE3630B12U, 0x94643B84U, 0x0D6D6A3EU, 0x7A6A5AA8U,
|
|
36
|
+
0xE40ECF0BU, 0x9309FF9DU, 0x0A00AE27U, 0x7D079EB1U, 0xF00F9344U, 0x8708A3D2U, 0x1E01F268U,
|
|
37
|
+
0x6906C2FEU, 0xF762575DU, 0x806567CBU, 0x196C3671U, 0x6E6B06E7U, 0xFED41B76U, 0x89D32BE0U,
|
|
38
|
+
0x10DA7A5AU, 0x67DD4ACCU, 0xF9B9DF6FU, 0x8EBEEFF9U, 0x17B7BE43U, 0x60B08ED5U, 0xD6D6A3E8U,
|
|
39
|
+
0xA1D1937EU, 0x38D8C2C4U, 0x4FDFF252U, 0xD1BB67F1U, 0xA6BC5767U, 0x3FB506DDU, 0x48B2364BU,
|
|
40
|
+
0xD80D2BDAU, 0xAF0A1B4CU, 0x36034AF6U, 0x41047A60U, 0xDF60EFC3U, 0xA867DF55U, 0x316E8EEFU,
|
|
41
|
+
0x4669BE79U, 0xCB61B38CU, 0xBC66831AU, 0x256FD2A0U, 0x5268E236U, 0xCC0C7795U, 0xBB0B4703U,
|
|
42
|
+
0x220216B9U, 0x5505262FU, 0xC5BA3BBEU, 0xB2BD0B28U, 0x2BB45A92U, 0x5CB36A04U, 0xC2D7FFA7U,
|
|
43
|
+
0xB5D0CF31U, 0x2CD99E8BU, 0x5BDEAE1DU, 0x9B64C2B0U, 0xEC63F226U, 0x756AA39CU, 0x026D930AU,
|
|
44
|
+
0x9C0906A9U, 0xEB0E363FU, 0x72076785U, 0x05005713U, 0x95BF4A82U, 0xE2B87A14U, 0x7BB12BAEU,
|
|
45
|
+
0x0CB61B38U, 0x92D28E9BU, 0xE5D5BE0DU, 0x7CDCEFB7U, 0x0BDBDF21U, 0x86D3D2D4U, 0xF1D4E242U,
|
|
46
|
+
0x68DDB3F8U, 0x1FDA836EU, 0x81BE16CDU, 0xF6B9265BU, 0x6FB077E1U, 0x18B74777U, 0x88085AE6U,
|
|
47
|
+
0xFF0F6A70U, 0x66063BCAU, 0x11010B5CU, 0x8F659EFFU, 0xF862AE69U, 0x616BFFD3U, 0x166CCF45U,
|
|
48
|
+
0xA00AE278U, 0xD70DD2EEU, 0x4E048354U, 0x3903B3C2U, 0xA7672661U, 0xD06016F7U, 0x4969474DU,
|
|
49
|
+
0x3E6E77DBU, 0xAED16A4AU, 0xD9D65ADCU, 0x40DF0B66U, 0x37D83BF0U, 0xA9BCAE53U, 0xDEBB9EC5U,
|
|
50
|
+
0x47B2CF7FU, 0x30B5FFE9U, 0xBDBDF21CU, 0xCABAC28AU, 0x53B39330U, 0x24B4A3A6U, 0xBAD03605U,
|
|
51
|
+
0xCDD70693U, 0x54DE5729U, 0x23D967BFU, 0xB3667A2EU, 0xC4614AB8U, 0x5D681B02U, 0x2A6F2B94U,
|
|
52
|
+
0xB40BBE37U, 0xC30C8EA1U, 0x5A05DF1BU, 0x2D02EF8DU,
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
static uint32_t mcdb_crc32(const unsigned char *data, size_t len) {
|
|
56
|
+
uint32_t crc = 0xFFFFFFFFU;
|
|
57
|
+
size_t i;
|
|
58
|
+
|
|
59
|
+
for (i = 0; i < len; i++) {
|
|
60
|
+
crc = MCDB_CRC32_TABLE[(crc ^ data[i]) & 0xFFU] ^ (crc >> 8);
|
|
61
|
+
}
|
|
62
|
+
return crc ^ 0xFFFFFFFFU;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
static uint64_t read_u64_le(const unsigned char *p) {
|
|
66
|
+
uint64_t v = 0;
|
|
67
|
+
int i;
|
|
68
|
+
|
|
69
|
+
for (i = 0; i < 8; i++)
|
|
70
|
+
v |= (uint64_t)p[i] << (8 * i);
|
|
71
|
+
return v;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
static uint32_t read_u32_le(const unsigned char *p) {
|
|
75
|
+
return (uint32_t)p[0] | ((uint32_t)p[1] << 8) | ((uint32_t)p[2] << 16) | ((uint32_t)p[3] << 24);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
static int mcdb_is_valid_utf8(const unsigned char *s, size_t len) {
|
|
79
|
+
size_t i = 0;
|
|
80
|
+
|
|
81
|
+
while (i < len) {
|
|
82
|
+
unsigned char c;
|
|
83
|
+
size_t n;
|
|
84
|
+
uint32_t cp;
|
|
85
|
+
unsigned char lo2;
|
|
86
|
+
unsigned char hi2;
|
|
87
|
+
size_t k;
|
|
88
|
+
|
|
89
|
+
c = s[i];
|
|
90
|
+
n = 0;
|
|
91
|
+
cp = 0;
|
|
92
|
+
lo2 = 0x80;
|
|
93
|
+
hi2 = 0xBF;
|
|
94
|
+
|
|
95
|
+
if (c < 0x80) {
|
|
96
|
+
if (c == 0)
|
|
97
|
+
return 0;
|
|
98
|
+
i += 1;
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if ((c & 0xE0) == 0xC0) {
|
|
103
|
+
n = 2;
|
|
104
|
+
cp = c & 0x1F;
|
|
105
|
+
if (c < 0xC2)
|
|
106
|
+
return 0;
|
|
107
|
+
} else if ((c & 0xF0) == 0xE0) {
|
|
108
|
+
n = 3;
|
|
109
|
+
cp = c & 0x0F;
|
|
110
|
+
if (c == 0xE0)
|
|
111
|
+
lo2 = 0xA0; /* no overlong */
|
|
112
|
+
if (c == 0xED)
|
|
113
|
+
hi2 = 0x9F; /* no surrogates */
|
|
114
|
+
} else if ((c & 0xF8) == 0xF0) {
|
|
115
|
+
n = 4;
|
|
116
|
+
cp = c & 0x07;
|
|
117
|
+
if (c < 0xF0 || c > 0xF4)
|
|
118
|
+
return 0;
|
|
119
|
+
if (c == 0xF0)
|
|
120
|
+
lo2 = 0x90; /* no overlong */
|
|
121
|
+
if (c == 0xF4)
|
|
122
|
+
hi2 = 0x8F; /* <= U+10FFFF */
|
|
123
|
+
} else {
|
|
124
|
+
return 0;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (i + n > len)
|
|
128
|
+
return 0;
|
|
129
|
+
for (k = 1; k < n; k++) {
|
|
130
|
+
unsigned char cc;
|
|
131
|
+
unsigned char lo;
|
|
132
|
+
unsigned char hi;
|
|
133
|
+
|
|
134
|
+
cc = s[i + k];
|
|
135
|
+
lo = (k == 1) ? lo2 : 0x80;
|
|
136
|
+
hi = (k == 1) ? hi2 : 0xBF;
|
|
137
|
+
if (cc < lo || cc > hi)
|
|
138
|
+
return 0;
|
|
139
|
+
cp = (cp << 6) | (cc & 0x3F);
|
|
140
|
+
}
|
|
141
|
+
(void)cp;
|
|
142
|
+
i += n;
|
|
143
|
+
}
|
|
144
|
+
return 1;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
mcdb_status mcdb_validate_header(const unsigned char *in, size_t in_len,
|
|
148
|
+
uint64_t *out_original_size) {
|
|
149
|
+
uint64_t original_size;
|
|
150
|
+
|
|
151
|
+
if (in == NULL || in_len < MCDB_HEADER_SIZE)
|
|
152
|
+
return MCDB_ERR_TRUNCATED;
|
|
153
|
+
if (in_len > MCDB_MAX_ENVELOPE)
|
|
154
|
+
return MCDB_ERR_ENVELOPE_SIZE;
|
|
155
|
+
if (in[0] != MCDB_MAGIC0 || in[1] != MCDB_MAGIC1 || in[2] != MCDB_MAGIC2 ||
|
|
156
|
+
in[3] != MCDB_MAGIC3)
|
|
157
|
+
return MCDB_ERR_MAGIC;
|
|
158
|
+
if (in[4] != MCDB_VERSION)
|
|
159
|
+
return MCDB_ERR_VERSION;
|
|
160
|
+
if (in[5] != MCDB_CODEC_ZSTD)
|
|
161
|
+
return MCDB_ERR_CODEC;
|
|
162
|
+
if (in[6] != MCDB_FLAGS_V1)
|
|
163
|
+
return MCDB_ERR_FLAGS;
|
|
164
|
+
|
|
165
|
+
original_size = read_u64_le(in + 7);
|
|
166
|
+
if (original_size > MCDB_MAX_OUTPUT)
|
|
167
|
+
return MCDB_ERR_SIZE_LIMIT;
|
|
168
|
+
|
|
169
|
+
if (out_original_size)
|
|
170
|
+
*out_original_size = original_size;
|
|
171
|
+
return MCDB_OK;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
static mcdb_status mcdb_decode_payload(const unsigned char *in, size_t in_len,
|
|
175
|
+
uint64_t original_size, unsigned char *out,
|
|
176
|
+
size_t out_capacity, size_t *out_len, char *errbuf) {
|
|
177
|
+
const unsigned char *frame;
|
|
178
|
+
size_t frame_len;
|
|
179
|
+
size_t frame_size;
|
|
180
|
+
unsigned long long frame_content_size;
|
|
181
|
+
size_t produced;
|
|
182
|
+
uint32_t expected_crc;
|
|
183
|
+
uint32_t actual_crc;
|
|
184
|
+
|
|
185
|
+
if (out_len)
|
|
186
|
+
*out_len = 0;
|
|
187
|
+
|
|
188
|
+
if (out == NULL || out_capacity < (size_t)original_size) {
|
|
189
|
+
if (errbuf)
|
|
190
|
+
snprintf(errbuf, MCDB_ERRLEN, "MCDB: output buffer is too small");
|
|
191
|
+
return MCDB_ERR_SIZE_MISMATCH;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
frame = in + MCDB_HEADER_SIZE;
|
|
195
|
+
frame_len = in_len - MCDB_HEADER_SIZE;
|
|
196
|
+
frame_size = ZSTD_findFrameCompressedSize(frame, frame_len);
|
|
197
|
+
if (ZSTD_isError(frame_size)) {
|
|
198
|
+
if (errbuf)
|
|
199
|
+
snprintf(errbuf, MCDB_ERRLEN, "MCDB: invalid zstd frame: %s",
|
|
200
|
+
ZSTD_getErrorName(frame_size));
|
|
201
|
+
return MCDB_ERR_DECOMPRESS;
|
|
202
|
+
}
|
|
203
|
+
if (frame_size != frame_len) {
|
|
204
|
+
if (errbuf)
|
|
205
|
+
snprintf(errbuf, MCDB_ERRLEN,
|
|
206
|
+
"MCDB: zstd frame has trailing bytes or concatenated frames");
|
|
207
|
+
return MCDB_ERR_TRAILING_DATA;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
frame_content_size = ZSTD_getFrameContentSize(frame, frame_len);
|
|
211
|
+
if (frame_content_size == ZSTD_CONTENTSIZE_ERROR ||
|
|
212
|
+
frame_content_size == ZSTD_CONTENTSIZE_UNKNOWN || frame_content_size != original_size) {
|
|
213
|
+
if (errbuf)
|
|
214
|
+
snprintf(errbuf, MCDB_ERRLEN, "MCDB: zstd frame content size does not match header");
|
|
215
|
+
return MCDB_ERR_FRAME_CONTENT_SIZE;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
produced = ZSTD_decompress(out, (size_t)original_size, frame, frame_len);
|
|
219
|
+
if (ZSTD_isError(produced)) {
|
|
220
|
+
if (errbuf)
|
|
221
|
+
snprintf(errbuf, MCDB_ERRLEN, "MCDB: zstd error: %s", ZSTD_getErrorName(produced));
|
|
222
|
+
return MCDB_ERR_DECOMPRESS;
|
|
223
|
+
}
|
|
224
|
+
if (produced != original_size) {
|
|
225
|
+
if (errbuf)
|
|
226
|
+
snprintf(errbuf, MCDB_ERRLEN, "MCDB: size mismatch (header %llu, got %zu)",
|
|
227
|
+
(unsigned long long)original_size, produced);
|
|
228
|
+
return MCDB_ERR_SIZE_MISMATCH;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
expected_crc = read_u32_le(in + MCDB_CRC_OFFSET);
|
|
232
|
+
actual_crc = mcdb_crc32(out, produced);
|
|
233
|
+
if (actual_crc != expected_crc) {
|
|
234
|
+
if (errbuf)
|
|
235
|
+
snprintf(errbuf, MCDB_ERRLEN, "MCDB: crc32 mismatch (header %u, computed %u)",
|
|
236
|
+
expected_crc, actual_crc);
|
|
237
|
+
return MCDB_ERR_CRC;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
if (!mcdb_is_valid_utf8(out, produced)) {
|
|
241
|
+
if (errbuf)
|
|
242
|
+
snprintf(errbuf, MCDB_ERRLEN,
|
|
243
|
+
"MCDB: payload is not valid UTF-8 text or contains a NUL byte");
|
|
244
|
+
return MCDB_ERR_UTF8;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
if (out_len)
|
|
248
|
+
*out_len = produced;
|
|
249
|
+
return MCDB_OK;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
mcdb_status mcdb_decode_into(const unsigned char *in, size_t in_len, unsigned char *out,
|
|
253
|
+
size_t out_capacity, size_t *out_len, char *errbuf) {
|
|
254
|
+
uint64_t original_size = 0;
|
|
255
|
+
|
|
256
|
+
if (out_len)
|
|
257
|
+
*out_len = 0;
|
|
258
|
+
if (errbuf)
|
|
259
|
+
errbuf[0] = '\0';
|
|
260
|
+
|
|
261
|
+
original_size = read_u64_le(in + 7);
|
|
262
|
+
return mcdb_decode_payload(in, in_len, original_size, out, out_capacity, out_len, errbuf);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
mcdb_status mcdb_decode(const unsigned char *in, size_t in_len, unsigned char **out,
|
|
266
|
+
size_t *out_len, char *errbuf) {
|
|
267
|
+
uint64_t original_size = 0;
|
|
268
|
+
mcdb_status st;
|
|
269
|
+
unsigned char *buf;
|
|
270
|
+
|
|
271
|
+
if (out)
|
|
272
|
+
*out = NULL;
|
|
273
|
+
if (out_len)
|
|
274
|
+
*out_len = 0;
|
|
275
|
+
if (errbuf)
|
|
276
|
+
errbuf[0] = '\0';
|
|
277
|
+
|
|
278
|
+
st = mcdb_validate_header(in, in_len, &original_size);
|
|
279
|
+
if (st != MCDB_OK) {
|
|
280
|
+
if (errbuf)
|
|
281
|
+
snprintf(errbuf, MCDB_ERRLEN, "MCDB: %s", mcdb_status_str(st));
|
|
282
|
+
return st;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
buf = (unsigned char *)malloc(original_size ? original_size : 1);
|
|
286
|
+
if (buf == NULL) {
|
|
287
|
+
if (errbuf)
|
|
288
|
+
snprintf(errbuf, MCDB_ERRLEN, "MCDB: out of memory");
|
|
289
|
+
return MCDB_ERR_ALLOC;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
st =
|
|
293
|
+
mcdb_decode_payload(in, in_len, original_size, buf, (size_t)original_size, out_len, errbuf);
|
|
294
|
+
if (st != MCDB_OK) {
|
|
295
|
+
free(buf);
|
|
296
|
+
return st;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
if (out)
|
|
300
|
+
*out = buf;
|
|
301
|
+
else
|
|
302
|
+
free(buf);
|
|
303
|
+
return MCDB_OK;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
const char *mcdb_status_str(mcdb_status s) {
|
|
307
|
+
switch (s) {
|
|
308
|
+
case MCDB_OK:
|
|
309
|
+
return "ok";
|
|
310
|
+
case MCDB_ERR_TRUNCATED:
|
|
311
|
+
return "truncated envelope";
|
|
312
|
+
case MCDB_ERR_ENVELOPE_SIZE:
|
|
313
|
+
return "stored envelope too large";
|
|
314
|
+
case MCDB_ERR_MAGIC:
|
|
315
|
+
return "bad magic";
|
|
316
|
+
case MCDB_ERR_VERSION:
|
|
317
|
+
return "unsupported version";
|
|
318
|
+
case MCDB_ERR_CODEC:
|
|
319
|
+
return "unsupported codec";
|
|
320
|
+
case MCDB_ERR_FLAGS:
|
|
321
|
+
return "reserved flags must be 0";
|
|
322
|
+
case MCDB_ERR_SIZE_LIMIT:
|
|
323
|
+
return "declared size over limit";
|
|
324
|
+
case MCDB_ERR_DECOMPRESS:
|
|
325
|
+
return "corrupt zstd payload";
|
|
326
|
+
case MCDB_ERR_TRAILING_DATA:
|
|
327
|
+
return "trailing bytes or concatenated zstd frames";
|
|
328
|
+
case MCDB_ERR_FRAME_CONTENT_SIZE:
|
|
329
|
+
return "zstd frame content size mismatch";
|
|
330
|
+
case MCDB_ERR_SIZE_MISMATCH:
|
|
331
|
+
return "size mismatch";
|
|
332
|
+
case MCDB_ERR_CRC:
|
|
333
|
+
return "crc32 mismatch";
|
|
334
|
+
case MCDB_ERR_UTF8:
|
|
335
|
+
return "payload is not valid UTF-8 text or contains a NUL byte";
|
|
336
|
+
case MCDB_ERR_ALLOC:
|
|
337
|
+
return "out of memory";
|
|
338
|
+
default:
|
|
339
|
+
return "unknown error";
|
|
340
|
+
}
|
|
341
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
SHELL := /bin/bash
|
|
2
|
+
|
|
3
|
+
MYSQL ?= mysql
|
|
4
|
+
MYSQL_DEFAULTS_FILE ?=
|
|
5
|
+
MYSQL_SOCKET ?=
|
|
6
|
+
CONFIRM ?=
|
|
7
|
+
|
|
8
|
+
.PHONY: help verify doctor status install enable upgrade disable uninstall
|
|
9
|
+
|
|
10
|
+
help:
|
|
11
|
+
@printf '%s\n' \
|
|
12
|
+
'MultiCompress MySQL 5.7 deployment bundle' \
|
|
13
|
+
'' \
|
|
14
|
+
' make verify' \
|
|
15
|
+
' make doctor [MYSQL_DEFAULTS_FILE=/etc/mysql/admin.cnf] [MYSQL_SOCKET=/run/mysqld/mysqld.sock]' \
|
|
16
|
+
' make status [MYSQL_DEFAULTS_FILE=/etc/mysql/admin.cnf] [MYSQL_SOCKET=/run/mysqld/mysqld.sock]' \
|
|
17
|
+
' sudo make install [MYSQL_DEFAULTS_FILE=/etc/mysql/admin.cnf] [MYSQL_SOCKET=/run/mysqld/mysqld.sock]' \
|
|
18
|
+
' make enable [MYSQL_DEFAULTS_FILE=/etc/mysql/admin.cnf] [MYSQL_SOCKET=/run/mysqld/mysqld.sock]' \
|
|
19
|
+
' sudo make upgrade CONFIRM=UPGRADE_MULTI_COMPRESS [MYSQL_DEFAULTS_FILE=/etc/mysql/admin.cnf] [MYSQL_SOCKET=/run/mysqld/mysqld.sock]' \
|
|
20
|
+
' make disable CONFIRM=DISABLE_MULTI_COMPRESS [MYSQL_DEFAULTS_FILE=/etc/mysql/admin.cnf] [MYSQL_SOCKET=/run/mysqld/mysqld.sock]' \
|
|
21
|
+
' sudo make uninstall CONFIRM=REMOVE_MULTI_COMPRESS [MYSQL_DEFAULTS_FILE=/etc/mysql/admin.cnf] [MYSQL_SOCKET=/run/mysqld/mysqld.sock]'
|
|
22
|
+
|
|
23
|
+
verify:
|
|
24
|
+
./bin/verify
|
|
25
|
+
|
|
26
|
+
doctor:
|
|
27
|
+
MYSQL_SOCKET="$(MYSQL_SOCKET)" ./bin/doctor --mysql "$(MYSQL)" $(if $(MYSQL_DEFAULTS_FILE),--defaults-extra-file "$(MYSQL_DEFAULTS_FILE)")
|
|
28
|
+
|
|
29
|
+
status:
|
|
30
|
+
MYSQL_SOCKET="$(MYSQL_SOCKET)" ./bin/status --mysql "$(MYSQL)" $(if $(MYSQL_DEFAULTS_FILE),--defaults-extra-file "$(MYSQL_DEFAULTS_FILE)")
|
|
31
|
+
|
|
32
|
+
install: verify
|
|
33
|
+
MYSQL_SOCKET="$(MYSQL_SOCKET)" ./bin/install --mysql "$(MYSQL)" $(if $(MYSQL_DEFAULTS_FILE),--defaults-extra-file "$(MYSQL_DEFAULTS_FILE)")
|
|
34
|
+
|
|
35
|
+
enable:
|
|
36
|
+
MYSQL_SOCKET="$(MYSQL_SOCKET)" ./bin/enable --mysql "$(MYSQL)" $(if $(MYSQL_DEFAULTS_FILE),--defaults-extra-file "$(MYSQL_DEFAULTS_FILE)")
|
|
37
|
+
|
|
38
|
+
upgrade:
|
|
39
|
+
@test "$(CONFIRM)" = "UPGRADE_MULTI_COMPRESS" || { echo 'upgrade requires CONFIRM=UPGRADE_MULTI_COMPRESS' >&2; exit 2; }
|
|
40
|
+
MYSQL_SOCKET="$(MYSQL_SOCKET)" ./bin/upgrade --mysql "$(MYSQL)" $(if $(MYSQL_DEFAULTS_FILE),--defaults-extra-file "$(MYSQL_DEFAULTS_FILE)")
|
|
41
|
+
|
|
42
|
+
disable:
|
|
43
|
+
@test "$(CONFIRM)" = "DISABLE_MULTI_COMPRESS" || { echo 'disable requires CONFIRM=DISABLE_MULTI_COMPRESS' >&2; exit 2; }
|
|
44
|
+
MYSQL_SOCKET="$(MYSQL_SOCKET)" ./bin/disable --mysql "$(MYSQL)" $(if $(MYSQL_DEFAULTS_FILE),--defaults-extra-file "$(MYSQL_DEFAULTS_FILE)")
|
|
45
|
+
|
|
46
|
+
uninstall:
|
|
47
|
+
@test "$(CONFIRM)" = "REMOVE_MULTI_COMPRESS" || { echo 'uninstall requires CONFIRM=REMOVE_MULTI_COMPRESS' >&2; exit 2; }
|
|
48
|
+
MYSQL_SOCKET="$(MYSQL_SOCKET)" ./bin/uninstall --mysql "$(MYSQL)" $(if $(MYSQL_DEFAULTS_FILE),--defaults-extra-file "$(MYSQL_DEFAULTS_FILE)")
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# MultiCompress MySQL 5.7 deployment bundle
|
|
2
|
+
|
|
3
|
+
This bundle is generated by the exact `multi_compress` gem version used by the
|
|
4
|
+
application. Build the native UDF on the MySQL host so its libc and server ABI
|
|
5
|
+
match the running MySQL 5.7 process.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
make verify
|
|
9
|
+
make doctor MYSQL_DEFAULTS_FILE=/etc/mysql/admin.cnf MYSQL_SOCKET=/run/mysqld/mysqld.sock
|
|
10
|
+
sudo make install MYSQL_DEFAULTS_FILE=/etc/mysql/admin.cnf MYSQL_SOCKET=/run/mysqld/mysqld.sock
|
|
11
|
+
make enable MYSQL_DEFAULTS_FILE=/etc/mysql/admin.cnf MYSQL_SOCKET=/run/mysqld/mysqld.sock
|
|
12
|
+
make status MYSQL_DEFAULTS_FILE=/etc/mysql/admin.cnf MYSQL_SOCKET=/run/mysqld/mysqld.sock
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
The bundle forces a local Unix-socket connection so its library is installed in
|
|
16
|
+
the plugin directory of that same mysqld. `install` is fresh-install only; a
|
|
17
|
+
healthy second `enable` is a no-op. Use the controlled maintenance flow for an
|
|
18
|
+
upgrade:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
sudo make upgrade CONFIRM=UPGRADE_MULTI_COMPRESS \
|
|
22
|
+
MYSQL_DEFAULTS_FILE=/etc/mysql/admin.cnf MYSQL_SOCKET=/run/mysqld/mysqld.sock
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Destructive actions require exact confirmation:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
make disable CONFIRM=DISABLE_MULTI_COMPRESS \
|
|
29
|
+
MYSQL_DEFAULTS_FILE=/etc/mysql/admin.cnf MYSQL_SOCKET=/run/mysqld/mysqld.sock
|
|
30
|
+
sudo make uninstall CONFIRM=REMOVE_MULTI_COMPRESS \
|
|
31
|
+
MYSQL_DEFAULTS_FILE=/etc/mysql/admin.cnf MYSQL_SOCKET=/run/mysqld/mysqld.sock
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
The application stores `MultiCompress::Database.compress(text)` in a `LONGBLOB`
|
|
35
|
+
column. Generate the DBeaver/read-side view in the application repository and
|
|
36
|
+
grant the DBeaver role `SELECT` on it. The generated MySQL view uses
|
|
37
|
+
`CONVERT(... USING utf8mb4)` so Cyrillic, Kazakh text and emoji display
|
|
38
|
+
correctly. Filter by indexed, uncompressed columns before selecting through it.
|
|
39
|
+
|
|
40
|
+
`make verify` catches accidental corruption after extraction; it does not
|
|
41
|
+
authenticate an archive. The mysql client uses `--max_allowed_packet=32M`, but
|
|
42
|
+
mysqld, the Ruby driver and DBeaver/JDBC must each allow the 16 MiB MCDB1 limit.
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
MCDB_UDF_LIBRARY='multi_compress_mysql.so'
|
|
4
|
+
MCDB_EMPTY_ENVELOPE_HEX='4d43444201010000000000000000000000000028b52ffd2000010000'
|
|
5
|
+
MCDB_UDF_NAMES=(
|
|
6
|
+
multi_compress_db_version
|
|
7
|
+
multi_compress_db_is_valid
|
|
8
|
+
multi_compress_db_decompress
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
mcdb_die() {
|
|
12
|
+
echo "multi_compress mysql: $*" >&2
|
|
13
|
+
exit 2
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
mcdb_resolve_mysql() {
|
|
17
|
+
if [[ "$MYSQL" == */* ]]; then
|
|
18
|
+
[ -x "$MYSQL" ] || mcdb_die "mysql client is not executable: $MYSQL"
|
|
19
|
+
else
|
|
20
|
+
MYSQL="$(command -v "$MYSQL" || true)"
|
|
21
|
+
[ -n "$MYSQL" ] || mcdb_die "mysql client was not found"
|
|
22
|
+
fi
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
mcdb_mysql_args() {
|
|
26
|
+
MYSQL_ARGS=(--batch --skip-column-names --raw --max_allowed_packet=32M --protocol=SOCKET)
|
|
27
|
+
if [ -n "$DEFAULTS_FILE" ]; then
|
|
28
|
+
[ -f "$DEFAULTS_FILE" ] || mcdb_die "defaults file does not exist: $DEFAULTS_FILE"
|
|
29
|
+
MYSQL_ARGS=("--defaults-extra-file=$DEFAULTS_FILE" "${MYSQL_ARGS[@]}")
|
|
30
|
+
fi
|
|
31
|
+
if [ -n "${MYSQL_SOCKET:-}" ]; then
|
|
32
|
+
MYSQL_ARGS+=("--socket=$MYSQL_SOCKET")
|
|
33
|
+
fi
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
mcdb_query() {
|
|
37
|
+
"$MYSQL" "${MYSQL_ARGS[@]}" -e "$1"
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
mcdb_server_version() {
|
|
41
|
+
mcdb_query 'SELECT VERSION();' | tr -d '\r\n'
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
mcdb_require_mysql57() {
|
|
45
|
+
local version
|
|
46
|
+
version="$(mcdb_server_version)"
|
|
47
|
+
case "$version" in
|
|
48
|
+
5.7.*) ;;
|
|
49
|
+
*) mcdb_die "this bundle targets MySQL 5.7; server reports $version" ;;
|
|
50
|
+
esac
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
mcdb_plugin_dir() {
|
|
54
|
+
mcdb_query 'SELECT @@plugin_dir;' | tr -d '\r\n'
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
mcdb_server_socket() {
|
|
58
|
+
mcdb_query 'SELECT @@socket;' | tr -d '\r\n'
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
mcdb_server_hostname() {
|
|
62
|
+
mcdb_query 'SELECT @@hostname;' | tr -d '\r\n'
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
mcdb_server_max_allowed_packet() {
|
|
66
|
+
mcdb_query 'SELECT @@GLOBAL.max_allowed_packet;' | tr -d '\r\n'
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
mcdb_require_expected_socket() {
|
|
70
|
+
local actual_socket
|
|
71
|
+
actual_socket="$(mcdb_server_socket)"
|
|
72
|
+
[ -n "$actual_socket" ] || mcdb_die 'MySQL returned an empty @@socket'
|
|
73
|
+
if [ -n "${MYSQL_SOCKET:-}" ] && [ "$MYSQL_SOCKET" != "$actual_socket" ]; then
|
|
74
|
+
mcdb_die "connected server socket $actual_socket does not match MYSQL_SOCKET $MYSQL_SOCKET"
|
|
75
|
+
fi
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
mcdb_read_udf_state() {
|
|
79
|
+
local rows name dl
|
|
80
|
+
|
|
81
|
+
MCDB_EXPECTED_OWNED=0
|
|
82
|
+
MCDB_FOREIGN_EXPECTED=0
|
|
83
|
+
MCDB_UNEXPECTED_LIBRARY=0
|
|
84
|
+
MCDB_REGISTERED_ROWS=()
|
|
85
|
+
|
|
86
|
+
rows="$(mcdb_query "SELECT name, dl FROM mysql.func WHERE dl = '${MCDB_UDF_LIBRARY}' OR name IN ('multi_compress_db_version', 'multi_compress_db_is_valid', 'multi_compress_db_decompress') ORDER BY name;")"
|
|
87
|
+
while IFS=$'\t' read -r name dl; do
|
|
88
|
+
[ -n "$name" ] || continue
|
|
89
|
+
MCDB_REGISTERED_ROWS+=("$name"$'\t'"$dl")
|
|
90
|
+
case "$name" in
|
|
91
|
+
multi_compress_db_version|multi_compress_db_is_valid|multi_compress_db_decompress)
|
|
92
|
+
if [ "$dl" = "$MCDB_UDF_LIBRARY" ]; then
|
|
93
|
+
MCDB_EXPECTED_OWNED=$((MCDB_EXPECTED_OWNED + 1))
|
|
94
|
+
else
|
|
95
|
+
MCDB_FOREIGN_EXPECTED=$((MCDB_FOREIGN_EXPECTED + 1))
|
|
96
|
+
fi
|
|
97
|
+
;;
|
|
98
|
+
*)
|
|
99
|
+
if [ "$dl" = "$MCDB_UDF_LIBRARY" ]; then
|
|
100
|
+
MCDB_UNEXPECTED_LIBRARY=$((MCDB_UNEXPECTED_LIBRARY + 1))
|
|
101
|
+
fi
|
|
102
|
+
;;
|
|
103
|
+
esac
|
|
104
|
+
done <<< "$rows"
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
mcdb_state_is_clean_absent() {
|
|
108
|
+
[ "$MCDB_EXPECTED_OWNED" -eq 0 ] && [ "$MCDB_FOREIGN_EXPECTED" -eq 0 ] && [ "$MCDB_UNEXPECTED_LIBRARY" -eq 0 ]
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
mcdb_state_is_clean_enabled() {
|
|
112
|
+
[ "$MCDB_EXPECTED_OWNED" -eq 3 ] && [ "$MCDB_FOREIGN_EXPECTED" -eq 0 ] && [ "$MCDB_UNEXPECTED_LIBRARY" -eq 0 ]
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
mcdb_require_clean_owned_state() {
|
|
116
|
+
if [ "$MCDB_FOREIGN_EXPECTED" -ne 0 ]; then
|
|
117
|
+
mcdb_die 'one or more expected UDF names are registered to a foreign SONAME; refusing to modify them'
|
|
118
|
+
fi
|
|
119
|
+
if [ "$MCDB_UNEXPECTED_LIBRARY" -ne 0 ]; then
|
|
120
|
+
mcdb_die "unexpected registrations reference ${MCDB_UDF_LIBRARY}; refusing to modify the shared library"
|
|
121
|
+
fi
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
mcdb_smoke_check() {
|
|
125
|
+
local version decoded
|
|
126
|
+
version="$(mcdb_query 'SELECT multi_compress_db_version();' | tr -d '\r\n')"
|
|
127
|
+
case "$version" in
|
|
128
|
+
*'MCDB1'*) ;;
|
|
129
|
+
*) mcdb_die "version() smoke check failed: $version" ;;
|
|
130
|
+
esac
|
|
131
|
+
decoded="$(mcdb_query "SELECT multi_compress_db_decompress(UNHEX('${MCDB_EMPTY_ENVELOPE_HEX}')) = '';" | tr -d '\r\n')"
|
|
132
|
+
[ "$decoded" = '1' ] || mcdb_die 'decode smoke check failed'
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
mcdb_drop_owned_udfs() {
|
|
136
|
+
mcdb_read_udf_state
|
|
137
|
+
mcdb_require_clean_owned_state
|
|
138
|
+
for name in "${MCDB_UDF_NAMES[@]}"; do
|
|
139
|
+
if mcdb_query "SELECT COUNT(*) FROM mysql.func WHERE name = '${name}' AND dl = '${MCDB_UDF_LIBRARY}';" | tr -d '\r\n' | grep -qx '1'; then
|
|
140
|
+
mcdb_query "DROP FUNCTION ${name};"
|
|
141
|
+
fi
|
|
142
|
+
done
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
mcdb_register_expected_udfs() {
|
|
146
|
+
"$MYSQL" "${MYSQL_ARGS[@]}" < "$ROOT/mysql_udf/sql/install.sql"
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
mcdb_library_checksum() {
|
|
150
|
+
local library="$1"
|
|
151
|
+
if [ ! -f "$library" ]; then
|
|
152
|
+
printf '%s\n' 'missing'
|
|
153
|
+
elif command -v sha256sum >/dev/null 2>&1; then
|
|
154
|
+
sha256sum "$library" | awk '{print $1}'
|
|
155
|
+
elif command -v shasum >/dev/null 2>&1; then
|
|
156
|
+
shasum -a 256 "$library" | awk '{print $1}'
|
|
157
|
+
else
|
|
158
|
+
printf '%s\n' 'unavailable (sha256sum or shasum is required)'
|
|
159
|
+
fi
|
|
160
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
5
|
+
MYSQL="${MYSQL:-mysql}"
|
|
6
|
+
DEFAULTS_FILE=""
|
|
7
|
+
MYSQL_SOCKET="${MYSQL_SOCKET:-}"
|
|
8
|
+
|
|
9
|
+
usage() {
|
|
10
|
+
cat <<'TEXT'
|
|
11
|
+
Usage: MYSQL_SOCKET=/run/mysqld/mysqld.sock ./bin/disable [--mysql PATH] [--defaults-extra-file PATH]
|
|
12
|
+
|
|
13
|
+
Removes only MultiCompress-owned UDF registrations and leaves the native library in place.
|
|
14
|
+
TEXT
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
while [ "$#" -gt 0 ]; do
|
|
18
|
+
case "$1" in
|
|
19
|
+
--mysql)
|
|
20
|
+
[ "$#" -ge 2 ] || { echo '--mysql requires a path' >&2; exit 2; }
|
|
21
|
+
MYSQL="$2"; shift 2 ;;
|
|
22
|
+
--defaults-extra-file)
|
|
23
|
+
[ "$#" -ge 2 ] || { echo '--defaults-extra-file requires a path' >&2; exit 2; }
|
|
24
|
+
DEFAULTS_FILE="$2"; shift 2 ;;
|
|
25
|
+
--help|-h)
|
|
26
|
+
usage; exit 0 ;;
|
|
27
|
+
*)
|
|
28
|
+
echo "multi_compress mysql disable: unknown option: $1" >&2; exit 2 ;;
|
|
29
|
+
esac
|
|
30
|
+
done
|
|
31
|
+
|
|
32
|
+
# shellcheck source=common
|
|
33
|
+
source "$ROOT/bin/common"
|
|
34
|
+
mcdb_resolve_mysql
|
|
35
|
+
mcdb_mysql_args
|
|
36
|
+
mcdb_require_mysql57
|
|
37
|
+
mcdb_require_expected_socket
|
|
38
|
+
mcdb_drop_owned_udfs
|
|
39
|
+
|
|
40
|
+
echo 'MultiCompress MySQL UDFs are disabled.'
|