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,212 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
MCDB_UDF_LIBRARY='multi_compress_mysql.so'
|
|
4
|
+
MCDB_V1_UDF_NAMES=(
|
|
5
|
+
multi_compress_db_version
|
|
6
|
+
multi_compress_db_is_valid
|
|
7
|
+
multi_compress_db_decompress
|
|
8
|
+
)
|
|
9
|
+
MCDB_EMPTY_ENVELOPE_HEX='4d43444201010000000000000000000000000028b52ffd2000010000'
|
|
10
|
+
MCDB_UDF_NAMES=(
|
|
11
|
+
multi_compress_db_version
|
|
12
|
+
multi_compress_db_is_valid
|
|
13
|
+
multi_compress_db_decompress
|
|
14
|
+
multi_compress_db_original_size
|
|
15
|
+
multi_compress_db_dictionary_ref
|
|
16
|
+
multi_compress_db_dictionary_zstd_id
|
|
17
|
+
multi_compress_db_dictionary_sha256
|
|
18
|
+
multi_compress_db_is_valid_dict
|
|
19
|
+
multi_compress_db_decompress_dict
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
mcdb_die() {
|
|
23
|
+
echo "multi_compress mysql: $*" >&2
|
|
24
|
+
exit 2
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
mcdb_resolve_mysql() {
|
|
28
|
+
if [[ "$MYSQL" == */* ]]; then
|
|
29
|
+
[ -x "$MYSQL" ] || mcdb_die "mysql client is not executable: $MYSQL"
|
|
30
|
+
else
|
|
31
|
+
MYSQL="$(command -v "$MYSQL" || true)"
|
|
32
|
+
[ -n "$MYSQL" ] || mcdb_die "mysql client was not found"
|
|
33
|
+
fi
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
mcdb_mysql_args() {
|
|
37
|
+
MYSQL_ARGS=(--batch --skip-column-names --raw --max_allowed_packet=32M --protocol=SOCKET)
|
|
38
|
+
if [ -n "$DEFAULTS_FILE" ]; then
|
|
39
|
+
[ -f "$DEFAULTS_FILE" ] || mcdb_die "defaults file does not exist: $DEFAULTS_FILE"
|
|
40
|
+
MYSQL_ARGS=("--defaults-extra-file=$DEFAULTS_FILE" "${MYSQL_ARGS[@]}")
|
|
41
|
+
fi
|
|
42
|
+
if [ -n "${MYSQL_SOCKET:-}" ]; then
|
|
43
|
+
MYSQL_ARGS+=("--socket=$MYSQL_SOCKET")
|
|
44
|
+
fi
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
mcdb_query() {
|
|
48
|
+
"$MYSQL" "${MYSQL_ARGS[@]}" -e "$1"
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
mcdb_server_version() {
|
|
52
|
+
mcdb_query 'SELECT VERSION();' | tr -d '\r\n'
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
mcdb_require_mysql57() {
|
|
56
|
+
local version
|
|
57
|
+
version="$(mcdb_server_version)"
|
|
58
|
+
case "$version" in
|
|
59
|
+
5.7.*) ;;
|
|
60
|
+
*) mcdb_die "this bundle targets MySQL 5.7; server reports $version" ;;
|
|
61
|
+
esac
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
mcdb_plugin_dir() {
|
|
65
|
+
mcdb_query 'SELECT @@plugin_dir;' | tr -d '\r\n'
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
mcdb_server_socket() {
|
|
69
|
+
mcdb_query 'SELECT @@socket;' | tr -d '\r\n'
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
mcdb_server_hostname() {
|
|
73
|
+
mcdb_query 'SELECT @@hostname;' | tr -d '\r\n'
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
mcdb_server_max_allowed_packet() {
|
|
77
|
+
mcdb_query 'SELECT @@GLOBAL.max_allowed_packet;' | tr -d '\r\n'
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
mcdb_require_expected_socket() {
|
|
81
|
+
local actual_socket
|
|
82
|
+
actual_socket="$(mcdb_server_socket)"
|
|
83
|
+
[ -n "$actual_socket" ] || mcdb_die 'MySQL returned an empty @@socket'
|
|
84
|
+
if [ -n "${MYSQL_SOCKET:-}" ] && [ "$MYSQL_SOCKET" != "$actual_socket" ]; then
|
|
85
|
+
mcdb_die "connected server socket $actual_socket does not match MYSQL_SOCKET $MYSQL_SOCKET"
|
|
86
|
+
fi
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
mcdb_read_udf_state() {
|
|
90
|
+
local rows name dl
|
|
91
|
+
|
|
92
|
+
MCDB_EXPECTED_OWNED=0
|
|
93
|
+
MCDB_FOREIGN_EXPECTED=0
|
|
94
|
+
MCDB_UNEXPECTED_LIBRARY=0
|
|
95
|
+
MCDB_REGISTERED_ROWS=()
|
|
96
|
+
|
|
97
|
+
local names_sql=""
|
|
98
|
+
local expected=()
|
|
99
|
+
for name in "${MCDB_UDF_NAMES[@]}"; do
|
|
100
|
+
expected+=("'${name}'")
|
|
101
|
+
done
|
|
102
|
+
names_sql="$(IFS=,; printf '%s' "${expected[*]}")"
|
|
103
|
+
|
|
104
|
+
rows="$(mcdb_query "SELECT name, dl FROM mysql.func WHERE dl = '${MCDB_UDF_LIBRARY}' OR name IN (${names_sql}) ORDER BY name;")"
|
|
105
|
+
while IFS=$'\t' read -r name dl; do
|
|
106
|
+
[ -n "$name" ] || continue
|
|
107
|
+
MCDB_REGISTERED_ROWS+=("$name"$'\t'"$dl")
|
|
108
|
+
local expected_name=0
|
|
109
|
+
local candidate
|
|
110
|
+
for candidate in "${MCDB_UDF_NAMES[@]}"; do
|
|
111
|
+
if [ "$candidate" = "$name" ]; then expected_name=1; break; fi
|
|
112
|
+
done
|
|
113
|
+
if [ "$expected_name" -eq 1 ]; then
|
|
114
|
+
if [ "$dl" = "$MCDB_UDF_LIBRARY" ]; then
|
|
115
|
+
MCDB_EXPECTED_OWNED=$((MCDB_EXPECTED_OWNED + 1))
|
|
116
|
+
else
|
|
117
|
+
MCDB_FOREIGN_EXPECTED=$((MCDB_FOREIGN_EXPECTED + 1))
|
|
118
|
+
fi
|
|
119
|
+
elif [ "$dl" = "$MCDB_UDF_LIBRARY" ]; then
|
|
120
|
+
MCDB_UNEXPECTED_LIBRARY=$((MCDB_UNEXPECTED_LIBRARY + 1))
|
|
121
|
+
fi
|
|
122
|
+
done <<< "$rows"
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
mcdb_state_is_clean_absent() {
|
|
126
|
+
[ "$MCDB_EXPECTED_OWNED" -eq 0 ] && [ "$MCDB_FOREIGN_EXPECTED" -eq 0 ] && [ "$MCDB_UNEXPECTED_LIBRARY" -eq 0 ]
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
mcdb_state_is_clean_enabled() {
|
|
130
|
+
[ "$MCDB_EXPECTED_OWNED" -eq "${#MCDB_UDF_NAMES[@]}" ] && [ "$MCDB_FOREIGN_EXPECTED" -eq 0 ] && [ "$MCDB_UNEXPECTED_LIBRARY" -eq 0 ]
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
mcdb_has_owned_registration() {
|
|
134
|
+
local target="$1" registration name dl
|
|
135
|
+
for registration in "${MCDB_REGISTERED_ROWS[@]}"; do
|
|
136
|
+
IFS=$'\t' read -r name dl <<< "$registration"
|
|
137
|
+
[ "$name" = "$target" ] && [ "$dl" = "$MCDB_UDF_LIBRARY" ] && return 0
|
|
138
|
+
done
|
|
139
|
+
return 1
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
# A 0.5.x host has only the three MCDB1 UDF registrations. It is a known,
|
|
143
|
+
# upgradeable state, not a partial installation. The 0.6 upgrade replaces the
|
|
144
|
+
# library using MySQL's required DROP -> replace -> CREATE order and registers
|
|
145
|
+
# the full MCDB1/MCDB2 surface.
|
|
146
|
+
mcdb_state_is_clean_v1_enabled() {
|
|
147
|
+
local name
|
|
148
|
+
[ "$MCDB_EXPECTED_OWNED" -eq "${#MCDB_V1_UDF_NAMES[@]}" ] || return 1
|
|
149
|
+
[ "$MCDB_FOREIGN_EXPECTED" -eq 0 ] || return 1
|
|
150
|
+
[ "$MCDB_UNEXPECTED_LIBRARY" -eq 0 ] || return 1
|
|
151
|
+
for name in "${MCDB_V1_UDF_NAMES[@]}"; do
|
|
152
|
+
mcdb_has_owned_registration "$name" || return 1
|
|
153
|
+
done
|
|
154
|
+
return 0
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
mcdb_require_clean_owned_state() {
|
|
158
|
+
if [ "$MCDB_FOREIGN_EXPECTED" -ne 0 ]; then
|
|
159
|
+
mcdb_die 'one or more expected UDF names are registered to a foreign SONAME; refusing to modify them'
|
|
160
|
+
fi
|
|
161
|
+
if [ "$MCDB_UNEXPECTED_LIBRARY" -ne 0 ]; then
|
|
162
|
+
mcdb_die "unexpected registrations reference ${MCDB_UDF_LIBRARY}; refusing to modify the shared library"
|
|
163
|
+
fi
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
mcdb_v1_smoke_check() {
|
|
167
|
+
local version decoded
|
|
168
|
+
version="$(mcdb_query 'SELECT multi_compress_db_version();' | tr -d '\r\n')"
|
|
169
|
+
case "$version" in
|
|
170
|
+
*'MCDB1'*) ;;
|
|
171
|
+
*) mcdb_die "MCDB1 version() smoke check failed: $version" ;;
|
|
172
|
+
esac
|
|
173
|
+
decoded="$(mcdb_query "SELECT multi_compress_db_decompress(UNHEX('${MCDB_EMPTY_ENVELOPE_HEX}')) = '';" | tr -d '\r\n')"
|
|
174
|
+
[ "$decoded" = '1' ] || mcdb_die 'decode smoke check failed'
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
mcdb_smoke_check() {
|
|
178
|
+
local version
|
|
179
|
+
mcdb_v1_smoke_check
|
|
180
|
+
version="$(mcdb_query 'SELECT multi_compress_db_version();' | tr -d '\r\n')"
|
|
181
|
+
case "$version" in
|
|
182
|
+
*'MCDB1'*'MCDB2'*) ;;
|
|
183
|
+
*) mcdb_die "MCDB1/MCDB2 version() smoke check failed: $version" ;;
|
|
184
|
+
esac
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
mcdb_drop_owned_udfs() {
|
|
188
|
+
mcdb_read_udf_state
|
|
189
|
+
mcdb_require_clean_owned_state
|
|
190
|
+
for name in "${MCDB_UDF_NAMES[@]}"; do
|
|
191
|
+
if mcdb_query "SELECT COUNT(*) FROM mysql.func WHERE name = '${name}' AND dl = '${MCDB_UDF_LIBRARY}';" | tr -d '\r\n' | grep -qx '1'; then
|
|
192
|
+
mcdb_query "DROP FUNCTION ${name};"
|
|
193
|
+
fi
|
|
194
|
+
done
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
mcdb_register_expected_udfs() {
|
|
198
|
+
"$MYSQL" "${MYSQL_ARGS[@]}" < "$ROOT/mysql_udf/sql/install.sql"
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
mcdb_library_checksum() {
|
|
202
|
+
local library="$1"
|
|
203
|
+
if [ ! -f "$library" ]; then
|
|
204
|
+
printf '%s\n' 'missing'
|
|
205
|
+
elif command -v sha256sum >/dev/null 2>&1; then
|
|
206
|
+
sha256sum "$library" | awk '{print $1}'
|
|
207
|
+
elif command -v shasum >/dev/null 2>&1; then
|
|
208
|
+
shasum -a 256 "$library" | awk '{print $1}'
|
|
209
|
+
else
|
|
210
|
+
printf '%s\n' 'unavailable (sha256sum or shasum is required)'
|
|
211
|
+
fi
|
|
212
|
+
}
|
|
@@ -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.'
|
|
@@ -0,0 +1,64 @@
|
|
|
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/doctor [--mysql PATH] [--defaults-extra-file PATH]
|
|
12
|
+
|
|
13
|
+
Run this on the MySQL 5.7 host. The bundle uses a local Unix socket so the UDF
|
|
14
|
+
library is installed into the plugin_dir of that same mysqld.
|
|
15
|
+
TEXT
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
while [ "$#" -gt 0 ]; do
|
|
19
|
+
case "$1" in
|
|
20
|
+
--mysql)
|
|
21
|
+
[ "$#" -ge 2 ] || { echo '--mysql requires a path' >&2; exit 2; }
|
|
22
|
+
MYSQL="$2"; shift 2 ;;
|
|
23
|
+
--defaults-extra-file)
|
|
24
|
+
[ "$#" -ge 2 ] || { echo '--defaults-extra-file requires a path' >&2; exit 2; }
|
|
25
|
+
DEFAULTS_FILE="$2"; shift 2 ;;
|
|
26
|
+
--help|-h)
|
|
27
|
+
usage; exit 0 ;;
|
|
28
|
+
*)
|
|
29
|
+
echo "multi_compress mysql doctor: unknown option: $1" >&2; exit 2 ;;
|
|
30
|
+
esac
|
|
31
|
+
done
|
|
32
|
+
|
|
33
|
+
# shellcheck source=common
|
|
34
|
+
source "$ROOT/bin/common"
|
|
35
|
+
mcdb_resolve_mysql
|
|
36
|
+
mcdb_mysql_args
|
|
37
|
+
command -v make >/dev/null 2>&1 || mcdb_die 'make is required'
|
|
38
|
+
command -v cc >/dev/null 2>&1 || mcdb_die 'a C compiler is required (cc/gcc/clang)'
|
|
39
|
+
command -v ar >/dev/null 2>&1 || mcdb_die 'ar is required'
|
|
40
|
+
mcdb_require_mysql57
|
|
41
|
+
mcdb_require_expected_socket
|
|
42
|
+
|
|
43
|
+
PLUGIN_DIR="$(mcdb_plugin_dir)"
|
|
44
|
+
SERVER_SOCKET="$(mcdb_server_socket)"
|
|
45
|
+
SERVER_HOSTNAME="$(mcdb_server_hostname)"
|
|
46
|
+
MAX_ALLOWED_PACKET="$(mcdb_server_max_allowed_packet)"
|
|
47
|
+
[ -n "$PLUGIN_DIR" ] || mcdb_die 'MySQL returned an empty @@plugin_dir'
|
|
48
|
+
[ -d "$PLUGIN_DIR" ] || mcdb_die "@@plugin_dir is not a local directory: $PLUGIN_DIR"
|
|
49
|
+
case "$MAX_ALLOWED_PACKET" in
|
|
50
|
+
''|*[!0-9]*) mcdb_die "MySQL returned an invalid @@GLOBAL.max_allowed_packet: $MAX_ALLOWED_PACKET" ;;
|
|
51
|
+
esac
|
|
52
|
+
if [ "$MAX_ALLOWED_PACKET" -lt 33554432 ]; then
|
|
53
|
+
echo "multi_compress mysql doctor: WARNING @@GLOBAL.max_allowed_packet is ${MAX_ALLOWED_PACKET}; configure at least 32M for the 16 MiB MCDB1 limit" >&2
|
|
54
|
+
fi
|
|
55
|
+
|
|
56
|
+
printf '%s\n' \
|
|
57
|
+
"MySQL: $(mcdb_server_version)" \
|
|
58
|
+
"mysql client: $MYSQL" \
|
|
59
|
+
"server hostname: $SERVER_HOSTNAME" \
|
|
60
|
+
"server socket: $SERVER_SOCKET" \
|
|
61
|
+
"plugin directory: $PLUGIN_DIR" \
|
|
62
|
+
"max_allowed_packet: $MAX_ALLOWED_PACKET" \
|
|
63
|
+
"bundle: $ROOT" \
|
|
64
|
+
'doctor: OK'
|
|
@@ -0,0 +1,61 @@
|
|
|
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/enable [--mysql PATH] [--defaults-extra-file PATH]
|
|
12
|
+
|
|
13
|
+
Registers the MultiCompress MCDB1/MCDB2 UDFs once. Existing healthy registrations are
|
|
14
|
+
left untouched; this command never drops functions automatically.
|
|
15
|
+
TEXT
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
while [ "$#" -gt 0 ]; do
|
|
19
|
+
case "$1" in
|
|
20
|
+
--mysql)
|
|
21
|
+
[ "$#" -ge 2 ] || { echo '--mysql requires a path' >&2; exit 2; }
|
|
22
|
+
MYSQL="$2"; shift 2 ;;
|
|
23
|
+
--defaults-extra-file)
|
|
24
|
+
[ "$#" -ge 2 ] || { echo '--defaults-extra-file requires a path' >&2; exit 2; }
|
|
25
|
+
DEFAULTS_FILE="$2"; shift 2 ;;
|
|
26
|
+
--help|-h)
|
|
27
|
+
usage; exit 0 ;;
|
|
28
|
+
*)
|
|
29
|
+
echo "multi_compress mysql enable: unknown option: $1" >&2; exit 2 ;;
|
|
30
|
+
esac
|
|
31
|
+
done
|
|
32
|
+
|
|
33
|
+
# shellcheck source=common
|
|
34
|
+
source "$ROOT/bin/common"
|
|
35
|
+
mcdb_resolve_mysql
|
|
36
|
+
mcdb_mysql_args
|
|
37
|
+
mcdb_require_mysql57
|
|
38
|
+
mcdb_require_expected_socket
|
|
39
|
+
mcdb_read_udf_state
|
|
40
|
+
|
|
41
|
+
if mcdb_state_is_clean_absent; then
|
|
42
|
+
mcdb_register_expected_udfs
|
|
43
|
+
mcdb_read_udf_state
|
|
44
|
+
mcdb_state_is_clean_enabled || mcdb_die 'registration did not create the expected UDF state'
|
|
45
|
+
mcdb_smoke_check
|
|
46
|
+
echo 'MultiCompress MySQL UDFs are enabled. Apply the generated readable-view SQL in the application migration.'
|
|
47
|
+
exit 0
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
if mcdb_state_is_clean_enabled; then
|
|
51
|
+
mcdb_smoke_check
|
|
52
|
+
echo 'MultiCompress MySQL UDFs are already enabled; no changes made.'
|
|
53
|
+
exit 0
|
|
54
|
+
fi
|
|
55
|
+
|
|
56
|
+
if mcdb_state_is_clean_v1_enabled; then
|
|
57
|
+
mcdb_die 'MCDB1-only UDF registrations were found; run make upgrade to install the MCDB2 reader surface'
|
|
58
|
+
fi
|
|
59
|
+
|
|
60
|
+
mcdb_require_clean_owned_state
|
|
61
|
+
mcdb_die 'UDF registrations are partial; run make status and resolve the state before enabling'
|
|
@@ -0,0 +1,64 @@
|
|
|
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: sudo MYSQL_SOCKET=/run/mysqld/mysqld.sock ./bin/install [--mysql PATH] [--defaults-extra-file PATH]
|
|
12
|
+
|
|
13
|
+
Builds and installs a fresh MySQL 5.7 UDF library. It refuses to replace a
|
|
14
|
+
library while any expected UDF is registered; use ./bin/upgrade for upgrades.
|
|
15
|
+
TEXT
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
while [ "$#" -gt 0 ]; do
|
|
19
|
+
case "$1" in
|
|
20
|
+
--mysql)
|
|
21
|
+
[ "$#" -ge 2 ] || { echo '--mysql requires a path' >&2; exit 2; }
|
|
22
|
+
MYSQL="$2"; shift 2 ;;
|
|
23
|
+
--defaults-extra-file)
|
|
24
|
+
[ "$#" -ge 2 ] || { echo '--defaults-extra-file requires a path' >&2; exit 2; }
|
|
25
|
+
DEFAULTS_FILE="$2"; shift 2 ;;
|
|
26
|
+
--help|-h)
|
|
27
|
+
usage; exit 0 ;;
|
|
28
|
+
*)
|
|
29
|
+
echo "multi_compress mysql install: unknown option: $1" >&2; exit 2 ;;
|
|
30
|
+
esac
|
|
31
|
+
done
|
|
32
|
+
|
|
33
|
+
[ "${EUID:-$(id -u)}" -eq 0 ] || { echo 'multi_compress mysql install: run as root: sudo ./bin/install ...' >&2; exit 2; }
|
|
34
|
+
DOCTOR_ARGS=(--mysql "$MYSQL")
|
|
35
|
+
if [ -n "$DEFAULTS_FILE" ]; then
|
|
36
|
+
DOCTOR_ARGS+=(--defaults-extra-file "$DEFAULTS_FILE")
|
|
37
|
+
fi
|
|
38
|
+
MYSQL_SOCKET="$MYSQL_SOCKET" "$ROOT/bin/doctor" "${DOCTOR_ARGS[@]}"
|
|
39
|
+
|
|
40
|
+
# shellcheck source=common
|
|
41
|
+
source "$ROOT/bin/common"
|
|
42
|
+
mcdb_resolve_mysql
|
|
43
|
+
mcdb_mysql_args
|
|
44
|
+
mcdb_read_udf_state
|
|
45
|
+
if ! mcdb_state_is_clean_absent; then
|
|
46
|
+
mcdb_die 'fresh install refuses to replace a library while UDF registrations exist; run status or upgrade instead'
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
PLUGIN_DIR="$(mcdb_plugin_dir)"
|
|
50
|
+
TEMP_LIBRARY="$PLUGIN_DIR/.${MCDB_UDF_LIBRARY}.$$.$RANDOM.tmp"
|
|
51
|
+
trap 'rm -f "$TEMP_LIBRARY"' EXIT
|
|
52
|
+
|
|
53
|
+
make -C "$ROOT/mysql_udf" clean udf MYSQL_UDF_ABI=mysql57
|
|
54
|
+
install -d -m 0755 "$PLUGIN_DIR"
|
|
55
|
+
install -m 0755 "$ROOT/mysql_udf/build/$MCDB_UDF_LIBRARY" "$TEMP_LIBRARY"
|
|
56
|
+
mv -f "$TEMP_LIBRARY" "$PLUGIN_DIR/$MCDB_UDF_LIBRARY"
|
|
57
|
+
trap - EXIT
|
|
58
|
+
|
|
59
|
+
printf '%s\n' \
|
|
60
|
+
'MultiCompress MySQL UDF library installed.' \
|
|
61
|
+
" library: $PLUGIN_DIR/$MCDB_UDF_LIBRARY" \
|
|
62
|
+
'' \
|
|
63
|
+
'Register the UDFs once on this MySQL server:' \
|
|
64
|
+
' make enable'
|
|
@@ -0,0 +1,67 @@
|
|
|
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/status [--mysql PATH] [--defaults-extra-file PATH]
|
|
12
|
+
|
|
13
|
+
Reports MultiCompress UDF registrations. This command needs SELECT on mysql.func.
|
|
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 status: 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
|
+
PLUGIN_DIR="$(mcdb_plugin_dir)"
|
|
39
|
+
LIBRARY="$PLUGIN_DIR/$MCDB_UDF_LIBRARY"
|
|
40
|
+
mcdb_read_udf_state
|
|
41
|
+
|
|
42
|
+
printf '%s\n' \
|
|
43
|
+
"MySQL: $(mcdb_server_version)" \
|
|
44
|
+
"server hostname: $(mcdb_server_hostname)" \
|
|
45
|
+
"server socket: $(mcdb_server_socket)" \
|
|
46
|
+
"plugin directory: $PLUGIN_DIR" \
|
|
47
|
+
"library: $LIBRARY" \
|
|
48
|
+
"library sha256: $(mcdb_library_checksum "$LIBRARY")"
|
|
49
|
+
|
|
50
|
+
if [ "${#MCDB_REGISTERED_ROWS[@]}" -eq 0 ]; then
|
|
51
|
+
echo 'registrations: none'
|
|
52
|
+
else
|
|
53
|
+
echo 'registrations:'
|
|
54
|
+
printf ' %s\n' "${MCDB_REGISTERED_ROWS[@]}"
|
|
55
|
+
fi
|
|
56
|
+
|
|
57
|
+
if mcdb_state_is_clean_enabled; then
|
|
58
|
+
mcdb_smoke_check
|
|
59
|
+
echo 'state: enabled'
|
|
60
|
+
elif mcdb_state_is_clean_v1_enabled; then
|
|
61
|
+
echo 'state: MCDB1-only; run make upgrade before writing MCDB2 values'
|
|
62
|
+
elif mcdb_state_is_clean_absent; then
|
|
63
|
+
echo 'state: absent'
|
|
64
|
+
else
|
|
65
|
+
echo 'state: inconsistent or foreign registration detected'
|
|
66
|
+
exit 2
|
|
67
|
+
fi
|
|
@@ -0,0 +1,47 @@
|
|
|
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: sudo MYSQL_SOCKET=/run/mysqld/mysqld.sock ./bin/uninstall [--mysql PATH] [--defaults-extra-file PATH]
|
|
12
|
+
|
|
13
|
+
Removes MultiCompress-owned UDF registrations and its native library. The Makefile
|
|
14
|
+
requires CONFIRM=REMOVE_MULTI_COMPRESS before this script can run.
|
|
15
|
+
TEXT
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
while [ "$#" -gt 0 ]; do
|
|
19
|
+
case "$1" in
|
|
20
|
+
--mysql)
|
|
21
|
+
[ "$#" -ge 2 ] || { echo '--mysql requires a path' >&2; exit 2; }
|
|
22
|
+
MYSQL="$2"; shift 2 ;;
|
|
23
|
+
--defaults-extra-file)
|
|
24
|
+
[ "$#" -ge 2 ] || { echo '--defaults-extra-file requires a path' >&2; exit 2; }
|
|
25
|
+
DEFAULTS_FILE="$2"; shift 2 ;;
|
|
26
|
+
--help|-h)
|
|
27
|
+
usage; exit 0 ;;
|
|
28
|
+
*)
|
|
29
|
+
echo "multi_compress mysql uninstall: unknown option: $1" >&2; exit 2 ;;
|
|
30
|
+
esac
|
|
31
|
+
done
|
|
32
|
+
|
|
33
|
+
[ "${EUID:-$(id -u)}" -eq 0 ] || { echo 'multi_compress mysql uninstall: run as root' >&2; exit 2; }
|
|
34
|
+
|
|
35
|
+
# shellcheck source=common
|
|
36
|
+
source "$ROOT/bin/common"
|
|
37
|
+
mcdb_resolve_mysql
|
|
38
|
+
mcdb_mysql_args
|
|
39
|
+
mcdb_require_mysql57
|
|
40
|
+
mcdb_require_expected_socket
|
|
41
|
+
mcdb_read_udf_state
|
|
42
|
+
mcdb_require_clean_owned_state
|
|
43
|
+
PLUGIN_DIR="$(mcdb_plugin_dir)"
|
|
44
|
+
mcdb_drop_owned_udfs
|
|
45
|
+
rm -f "$PLUGIN_DIR/$MCDB_UDF_LIBRARY"
|
|
46
|
+
|
|
47
|
+
echo "MultiCompress MySQL UDFs disabled and library removed from $PLUGIN_DIR."
|
|
@@ -0,0 +1,127 @@
|
|
|
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: sudo MYSQL_SOCKET=/run/mysqld/mysqld.sock ./bin/upgrade [--mysql PATH] [--defaults-extra-file PATH]
|
|
12
|
+
|
|
13
|
+
Performs the required MySQL UDF upgrade order: DROP FUNCTION, replace the
|
|
14
|
+
library, CREATE FUNCTION, then smoke-check. The Makefile requires
|
|
15
|
+
CONFIRM=UPGRADE_MULTI_COMPRESS before this script can run.
|
|
16
|
+
TEXT
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
while [ "$#" -gt 0 ]; do
|
|
20
|
+
case "$1" in
|
|
21
|
+
--mysql)
|
|
22
|
+
[ "$#" -ge 2 ] || { echo '--mysql requires a path' >&2; exit 2; }
|
|
23
|
+
MYSQL="$2"; shift 2 ;;
|
|
24
|
+
--defaults-extra-file)
|
|
25
|
+
[ "$#" -ge 2 ] || { echo '--defaults-extra-file requires a path' >&2; exit 2; }
|
|
26
|
+
DEFAULTS_FILE="$2"; shift 2 ;;
|
|
27
|
+
--help|-h)
|
|
28
|
+
usage; exit 0 ;;
|
|
29
|
+
*)
|
|
30
|
+
echo "multi_compress mysql upgrade: unknown option: $1" >&2; exit 2 ;;
|
|
31
|
+
esac
|
|
32
|
+
done
|
|
33
|
+
|
|
34
|
+
[ "${EUID:-$(id -u)}" -eq 0 ] || { echo 'multi_compress mysql upgrade: run as root' >&2; exit 2; }
|
|
35
|
+
DOCTOR_ARGS=(--mysql "$MYSQL")
|
|
36
|
+
if [ -n "$DEFAULTS_FILE" ]; then
|
|
37
|
+
DOCTOR_ARGS+=(--defaults-extra-file "$DEFAULTS_FILE")
|
|
38
|
+
fi
|
|
39
|
+
MYSQL_SOCKET="$MYSQL_SOCKET" "$ROOT/bin/doctor" "${DOCTOR_ARGS[@]}"
|
|
40
|
+
|
|
41
|
+
# shellcheck source=common
|
|
42
|
+
source "$ROOT/bin/common"
|
|
43
|
+
mcdb_resolve_mysql
|
|
44
|
+
mcdb_mysql_args
|
|
45
|
+
mcdb_read_udf_state
|
|
46
|
+
mcdb_require_clean_owned_state
|
|
47
|
+
LEGACY_MCDB1_ONLY=0
|
|
48
|
+
if mcdb_state_is_clean_v1_enabled; then
|
|
49
|
+
LEGACY_MCDB1_ONLY=1
|
|
50
|
+
elif ! mcdb_state_is_clean_enabled; then
|
|
51
|
+
mcdb_die 'upgrade requires either a complete MCDB1-only or MCDB1/MCDB2 owned UDF state'
|
|
52
|
+
fi
|
|
53
|
+
CAPTURED_REGISTRATIONS=("${MCDB_REGISTERED_ROWS[@]}")
|
|
54
|
+
if [ "$LEGACY_MCDB1_ONLY" -eq 1 ]; then
|
|
55
|
+
# A genuine 0.5.x library does not advertise MCDB2 yet. Verify only its
|
|
56
|
+
# MCDB1 surface before the required DROP -> replace -> CREATE transition.
|
|
57
|
+
mcdb_v1_smoke_check
|
|
58
|
+
else
|
|
59
|
+
mcdb_smoke_check
|
|
60
|
+
fi
|
|
61
|
+
|
|
62
|
+
restore_captured_registrations() {
|
|
63
|
+
local registration name dl returns
|
|
64
|
+
|
|
65
|
+
for registration in "${CAPTURED_REGISTRATIONS[@]}"; do
|
|
66
|
+
IFS=$'\t' read -r name dl <<< "$registration"
|
|
67
|
+
case "$name" in
|
|
68
|
+
multi_compress_db_version|multi_compress_db_decompress|multi_compress_db_dictionary_sha256|multi_compress_db_decompress_dict) returns='STRING' ;;
|
|
69
|
+
multi_compress_db_is_valid|multi_compress_db_original_size|multi_compress_db_dictionary_ref|multi_compress_db_dictionary_zstd_id|multi_compress_db_is_valid_dict) returns='INTEGER' ;;
|
|
70
|
+
*) mcdb_die "captured unexpected UDF registration: $name" ;;
|
|
71
|
+
esac
|
|
72
|
+
mcdb_query "CREATE FUNCTION ${name} RETURNS ${returns} SONAME '${dl}';"
|
|
73
|
+
done
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
PLUGIN_DIR="$(mcdb_plugin_dir)"
|
|
77
|
+
LIBRARY="$PLUGIN_DIR/$MCDB_UDF_LIBRARY"
|
|
78
|
+
[ -f "$LIBRARY" ] || mcdb_die "installed library is missing: $LIBRARY"
|
|
79
|
+
BACKUP="$PLUGIN_DIR/.${MCDB_UDF_LIBRARY}.backup.$$.$RANDOM"
|
|
80
|
+
TEMP_LIBRARY="$PLUGIN_DIR/.${MCDB_UDF_LIBRARY}.new.$$.$RANDOM.tmp"
|
|
81
|
+
RESTORED=0
|
|
82
|
+
cleanup() {
|
|
83
|
+
rm -f "$TEMP_LIBRARY"
|
|
84
|
+
if [ "$RESTORED" -eq 1 ]; then
|
|
85
|
+
rm -f "$BACKUP"
|
|
86
|
+
fi
|
|
87
|
+
}
|
|
88
|
+
trap cleanup EXIT
|
|
89
|
+
|
|
90
|
+
make -C "$ROOT/mysql_udf" clean udf MYSQL_UDF_ABI=mysql57
|
|
91
|
+
install -m 0755 "$ROOT/mysql_udf/build/$MCDB_UDF_LIBRARY" "$TEMP_LIBRARY"
|
|
92
|
+
|
|
93
|
+
if ! mcdb_drop_owned_udfs; then
|
|
94
|
+
mcdb_die 'could not drop existing MultiCompress UDFs; library was not replaced'
|
|
95
|
+
fi
|
|
96
|
+
if ! cp -p "$LIBRARY" "$BACKUP"; then
|
|
97
|
+
restore_captured_registrations || true
|
|
98
|
+
mcdb_die 'could not back up the installed library; original registrations were restored when possible'
|
|
99
|
+
fi
|
|
100
|
+
|
|
101
|
+
mv -f "$TEMP_LIBRARY" "$LIBRARY"
|
|
102
|
+
if mcdb_register_expected_udfs && mcdb_smoke_check; then
|
|
103
|
+
mcdb_read_udf_state
|
|
104
|
+
mcdb_state_is_clean_enabled || mcdb_die 'upgrade did not register the complete MCDB1/MCDB2 UDF surface'
|
|
105
|
+
rm -f "$BACKUP"
|
|
106
|
+
RESTORED=1
|
|
107
|
+
echo 'MultiCompress MySQL UDFs upgraded successfully.'
|
|
108
|
+
exit 0
|
|
109
|
+
fi
|
|
110
|
+
|
|
111
|
+
ROLLBACK_OK=1
|
|
112
|
+
mcdb_drop_owned_udfs || ROLLBACK_OK=0
|
|
113
|
+
if [ -f "$BACKUP" ]; then
|
|
114
|
+
mv -f "$BACKUP" "$LIBRARY" || ROLLBACK_OK=0
|
|
115
|
+
else
|
|
116
|
+
ROLLBACK_OK=0
|
|
117
|
+
fi
|
|
118
|
+
if ! restore_captured_registrations || ! mcdb_smoke_check; then
|
|
119
|
+
ROLLBACK_OK=0
|
|
120
|
+
fi
|
|
121
|
+
if [ "$ROLLBACK_OK" -eq 1 ]; then
|
|
122
|
+
RESTORED=1
|
|
123
|
+
echo 'multi_compress mysql upgrade: failed; previous library and registrations were restored' >&2
|
|
124
|
+
else
|
|
125
|
+
echo 'multi_compress mysql upgrade: failed and rollback did not complete; inspect mysql.func and plugin_dir immediately' >&2
|
|
126
|
+
fi
|
|
127
|
+
exit 1
|