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,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,57 @@
|
|
|
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 three MultiCompress 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
|
+
mcdb_require_clean_owned_state
|
|
57
|
+
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,65 @@
|
|
|
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_absent; then
|
|
61
|
+
echo 'state: absent'
|
|
62
|
+
else
|
|
63
|
+
echo 'state: inconsistent or foreign registration detected'
|
|
64
|
+
exit 2
|
|
65
|
+
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,115 @@
|
|
|
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
|
+
mcdb_state_is_clean_enabled || mcdb_die 'upgrade requires all three MultiCompress UDFs to be enabled'
|
|
48
|
+
CAPTURED_REGISTRATIONS=("${MCDB_REGISTERED_ROWS[@]}")
|
|
49
|
+
mcdb_smoke_check
|
|
50
|
+
|
|
51
|
+
restore_captured_registrations() {
|
|
52
|
+
local registration name dl returns
|
|
53
|
+
|
|
54
|
+
for registration in "${CAPTURED_REGISTRATIONS[@]}"; do
|
|
55
|
+
IFS=$'\t' read -r name dl <<< "$registration"
|
|
56
|
+
case "$name" in
|
|
57
|
+
multi_compress_db_version|multi_compress_db_decompress) returns='STRING' ;;
|
|
58
|
+
multi_compress_db_is_valid) returns='INTEGER' ;;
|
|
59
|
+
*) mcdb_die "captured unexpected UDF registration: $name" ;;
|
|
60
|
+
esac
|
|
61
|
+
mcdb_query "CREATE FUNCTION ${name} RETURNS ${returns} SONAME '${dl}';"
|
|
62
|
+
done
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
PLUGIN_DIR="$(mcdb_plugin_dir)"
|
|
66
|
+
LIBRARY="$PLUGIN_DIR/$MCDB_UDF_LIBRARY"
|
|
67
|
+
[ -f "$LIBRARY" ] || mcdb_die "installed library is missing: $LIBRARY"
|
|
68
|
+
BACKUP="$PLUGIN_DIR/.${MCDB_UDF_LIBRARY}.backup.$$.$RANDOM"
|
|
69
|
+
TEMP_LIBRARY="$PLUGIN_DIR/.${MCDB_UDF_LIBRARY}.new.$$.$RANDOM.tmp"
|
|
70
|
+
RESTORED=0
|
|
71
|
+
cleanup() {
|
|
72
|
+
rm -f "$TEMP_LIBRARY"
|
|
73
|
+
if [ "$RESTORED" -eq 1 ]; then
|
|
74
|
+
rm -f "$BACKUP"
|
|
75
|
+
fi
|
|
76
|
+
}
|
|
77
|
+
trap cleanup EXIT
|
|
78
|
+
|
|
79
|
+
make -C "$ROOT/mysql_udf" clean udf MYSQL_UDF_ABI=mysql57
|
|
80
|
+
install -m 0755 "$ROOT/mysql_udf/build/$MCDB_UDF_LIBRARY" "$TEMP_LIBRARY"
|
|
81
|
+
|
|
82
|
+
if ! mcdb_drop_owned_udfs; then
|
|
83
|
+
mcdb_die 'could not drop existing MultiCompress UDFs; library was not replaced'
|
|
84
|
+
fi
|
|
85
|
+
if ! cp -p "$LIBRARY" "$BACKUP"; then
|
|
86
|
+
restore_captured_registrations || true
|
|
87
|
+
mcdb_die 'could not back up the installed library; original registrations were restored when possible'
|
|
88
|
+
fi
|
|
89
|
+
|
|
90
|
+
mv -f "$TEMP_LIBRARY" "$LIBRARY"
|
|
91
|
+
if mcdb_register_expected_udfs && mcdb_smoke_check; then
|
|
92
|
+
[ "${#CAPTURED_REGISTRATIONS[@]}" -eq 3 ] || mcdb_die 'captured registration state is incomplete'
|
|
93
|
+
rm -f "$BACKUP"
|
|
94
|
+
RESTORED=1
|
|
95
|
+
echo 'MultiCompress MySQL UDFs upgraded successfully.'
|
|
96
|
+
exit 0
|
|
97
|
+
fi
|
|
98
|
+
|
|
99
|
+
ROLLBACK_OK=1
|
|
100
|
+
mcdb_drop_owned_udfs || ROLLBACK_OK=0
|
|
101
|
+
if [ -f "$BACKUP" ]; then
|
|
102
|
+
mv -f "$BACKUP" "$LIBRARY" || ROLLBACK_OK=0
|
|
103
|
+
else
|
|
104
|
+
ROLLBACK_OK=0
|
|
105
|
+
fi
|
|
106
|
+
if ! restore_captured_registrations || ! mcdb_smoke_check; then
|
|
107
|
+
ROLLBACK_OK=0
|
|
108
|
+
fi
|
|
109
|
+
if [ "$ROLLBACK_OK" -eq 1 ]; then
|
|
110
|
+
RESTORED=1
|
|
111
|
+
echo 'multi_compress mysql upgrade: failed; previous library and registrations were restored' >&2
|
|
112
|
+
else
|
|
113
|
+
echo 'multi_compress mysql upgrade: failed and rollback did not complete; inspect mysql.func and plugin_dir immediately' >&2
|
|
114
|
+
fi
|
|
115
|
+
exit 1
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
5
|
+
cd "$ROOT"
|
|
6
|
+
|
|
7
|
+
if command -v sha256sum >/dev/null 2>&1; then
|
|
8
|
+
sha256sum -c SHA256SUMS
|
|
9
|
+
elif command -v shasum >/dev/null 2>&1; then
|
|
10
|
+
shasum -a 256 -c SHA256SUMS
|
|
11
|
+
else
|
|
12
|
+
echo "multi_compress mysql verify: sha256sum or shasum is required" >&2
|
|
13
|
+
exit 2
|
|
14
|
+
fi
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
SHELL := /bin/bash
|
|
2
|
+
|
|
3
|
+
# PG_CONFIG is the normal public override. It is used for both compilation and
|
|
4
|
+
# installation paths. BUILD_PG_CONFIG/RUNTIME_PG_CONFIG exist for uncommon
|
|
5
|
+
# containerised deployments where headers are installed separately from the
|
|
6
|
+
# running server; ordinary DBAs never need to set them.
|
|
7
|
+
PG_CONFIG ?=
|
|
8
|
+
BUILD_PG_CONFIG ?= $(PG_CONFIG)
|
|
9
|
+
RUNTIME_PG_CONFIG ?= $(PG_CONFIG)
|
|
10
|
+
DB ?=
|
|
11
|
+
SCHEMA ?= multi_compress
|
|
12
|
+
MIGRATION_ROLE ?=
|
|
13
|
+
READ_ROLE ?=
|
|
14
|
+
CONFIRM ?=
|
|
15
|
+
|
|
16
|
+
.PHONY: help verify doctor install enable uninstall
|
|
17
|
+
|
|
18
|
+
help:
|
|
19
|
+
@printf '%s\n' \
|
|
20
|
+
'MultiCompress PostgreSQL deployment bundle' \
|
|
21
|
+
'' \
|
|
22
|
+
' make verify' \
|
|
23
|
+
' make doctor [PG_CONFIG=/path/to/pg_config]' \
|
|
24
|
+
' sudo make install [PG_CONFIG=/path/to/pg_config]' \
|
|
25
|
+
' sudo -u postgres make enable DB=app_production MIGRATION_ROLE=app_migrations READ_ROLE=dbeaver_readonly [SCHEMA=multi_compress]' \
|
|
26
|
+
' sudo make uninstall CONFIRM=REMOVE_MULTI_COMPRESS [PG_CONFIG=/path/to/pg_config]'
|
|
27
|
+
|
|
28
|
+
verify:
|
|
29
|
+
./bin/verify
|
|
30
|
+
|
|
31
|
+
doctor:
|
|
32
|
+
./bin/doctor $(if $(BUILD_PG_CONFIG),--pg-config "$(BUILD_PG_CONFIG)")
|
|
33
|
+
|
|
34
|
+
install: verify
|
|
35
|
+
./bin/install $(if $(BUILD_PG_CONFIG),--build-pg-config "$(BUILD_PG_CONFIG)") $(if $(RUNTIME_PG_CONFIG),--runtime-pg-config "$(RUNTIME_PG_CONFIG)")
|
|
36
|
+
|
|
37
|
+
enable:
|
|
38
|
+
@test -n "$(DB)" || { echo 'DB is required: make enable DB=app_production' >&2; exit 2; }
|
|
39
|
+
@test -n "$(MIGRATION_ROLE)" || { echo 'MIGRATION_ROLE is required: make enable ... MIGRATION_ROLE=app_migrations' >&2; exit 2; }
|
|
40
|
+
@test -n "$(READ_ROLE)" || { echo 'READ_ROLE is required: make enable ... READ_ROLE=dbeaver_readonly' >&2; exit 2; }
|
|
41
|
+
./bin/enable --database "$(DB)" --schema "$(SCHEMA)" --migration-role "$(MIGRATION_ROLE)" --read-role "$(READ_ROLE)"
|
|
42
|
+
|
|
43
|
+
uninstall:
|
|
44
|
+
@test "$(CONFIRM)" = "REMOVE_MULTI_COMPRESS" || { echo 'uninstall requires CONFIRM=REMOVE_MULTI_COMPRESS' >&2; exit 2; }
|
|
45
|
+
./bin/uninstall $(if $(RUNTIME_PG_CONFIG),--pg-config "$(RUNTIME_PG_CONFIG)")
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# MultiCompress PostgreSQL deployment bundle
|
|
2
|
+
|
|
3
|
+
This bundle is generated by the exact `multi_compress` gem version used by the
|
|
4
|
+
application. It builds the native reader on the PostgreSQL host, avoiding any
|
|
5
|
+
assumption about glibc, CPU architecture or PostgreSQL build flags.
|
|
6
|
+
|
|
7
|
+
Install PostgreSQL server development files for the running major version and a
|
|
8
|
+
C toolchain first. On a package-managed host this is normally the matching
|
|
9
|
+
`postgresql-server-dev-<major>` package; `make doctor` checks that prerequisite
|
|
10
|
+
before changing the server.
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
make verify
|
|
14
|
+
make doctor
|
|
15
|
+
sudo make install
|
|
16
|
+
sudo -u postgres make enable DB=app_production \
|
|
17
|
+
MIGRATION_ROLE=app_migrations READ_ROLE=dbeaver_readonly
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Pass a non-default server installation explicitly:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
sudo make install PG_CONFIG=/usr/lib/postgresql/17/bin/pg_config
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
`install` only places the extension files on the host. `enable` rejects
|
|
27
|
+
non-UTF8 databases, refuses an existing extension in another schema, and grants
|
|
28
|
+
`USAGE` to the migration role plus `EXECUTE` to the migration and read roles.
|
|
29
|
+
Grant the read role `SELECT` on each generated view in the application migration.
|
|
30
|
+
Run the native install on every database host that must query MCDB1 columns,
|
|
31
|
+
including reporting databases, failover targets and restored environments.
|
|
32
|
+
|
|
33
|
+
The application stores `MultiCompress::Database.compress(text)` in a `bytea`
|
|
34
|
+
column. Generate the DBeaver/read-side view in the application repository. Use
|
|
35
|
+
`--extension-schema NAME` below only if `make enable` used a non-default schema:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
bundle exec multi_compress db view postgres \
|
|
39
|
+
--table app.events \
|
|
40
|
+
--column payload_compressed \
|
|
41
|
+
--view admin.events_readable \
|
|
42
|
+
--columns id,created_at,status \
|
|
43
|
+
--as payload \
|
|
44
|
+
--output db/views/events_readable.sql
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Commit that SQL (or put it in a Rails migration). DBeaver users then query:
|
|
48
|
+
|
|
49
|
+
```sql
|
|
50
|
+
SELECT id, created_at, status, payload
|
|
51
|
+
FROM admin.events_readable
|
|
52
|
+
WHERE id = 123;
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
The view decompresses selected rows. Always filter with indexed, uncompressed
|
|
56
|
+
columns first; do not use it for unbounded `LIKE '%text%'` searches.
|
|
57
|
+
|
|
58
|
+
`make verify` catches accidental corruption after extraction; it does not
|
|
59
|
+
authenticate an archive. Use an out-of-band SHA-256, a minisign/GPG signature,
|
|
60
|
+
or signed release provenance for a real trust chain.
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
5
|
+
PG_CONFIG="${PG_CONFIG:-pg_config}"
|
|
6
|
+
|
|
7
|
+
usage() {
|
|
8
|
+
cat <<'TEXT'
|
|
9
|
+
Usage: ./bin/doctor [--pg-config PATH]
|
|
10
|
+
|
|
11
|
+
Checks whether this PostgreSQL host can build the MultiCompress extension.
|
|
12
|
+
TEXT
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
die() {
|
|
16
|
+
echo "multi_compress postgres doctor: $*" >&2
|
|
17
|
+
exit 2
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
while [ "$#" -gt 0 ]; do
|
|
21
|
+
case "$1" in
|
|
22
|
+
--pg-config)
|
|
23
|
+
[ "$#" -ge 2 ] || die "--pg-config requires a path"
|
|
24
|
+
PG_CONFIG="$2"
|
|
25
|
+
shift 2
|
|
26
|
+
;;
|
|
27
|
+
--help|-h)
|
|
28
|
+
usage
|
|
29
|
+
exit 0
|
|
30
|
+
;;
|
|
31
|
+
*)
|
|
32
|
+
die "unknown option: $1"
|
|
33
|
+
;;
|
|
34
|
+
esac
|
|
35
|
+
done
|
|
36
|
+
|
|
37
|
+
if [[ "$PG_CONFIG" == */* ]]; then
|
|
38
|
+
[ -x "$PG_CONFIG" ] || die "pg_config is not executable: $PG_CONFIG"
|
|
39
|
+
else
|
|
40
|
+
PG_CONFIG="$(command -v "$PG_CONFIG" || true)"
|
|
41
|
+
[ -n "$PG_CONFIG" ] || die "pg_config was not found; install PostgreSQL server development files or pass --pg-config PATH"
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
command -v make >/dev/null 2>&1 || die "make is required"
|
|
45
|
+
command -v cc >/dev/null 2>&1 || die "a C compiler is required (cc/gcc/clang)"
|
|
46
|
+
command -v ar >/dev/null 2>&1 || die "ar is required"
|
|
47
|
+
|
|
48
|
+
PGXS="$($PG_CONFIG --pgxs 2>/dev/null || true)"
|
|
49
|
+
HEADERS="$($PG_CONFIG --includedir-server 2>/dev/null || true)"
|
|
50
|
+
[ -f "$PGXS" ] || die "PGXS is missing; install postgresql-server-dev for $($PG_CONFIG --version)"
|
|
51
|
+
[ -f "$HEADERS/postgres.h" ] || die "PostgreSQL server headers are missing; install postgresql-server-dev for $($PG_CONFIG --version)"
|
|
52
|
+
|
|
53
|
+
printf '%s\n' \
|
|
54
|
+
"PostgreSQL: $($PG_CONFIG --version)" \
|
|
55
|
+
"pg_config: $PG_CONFIG" \
|
|
56
|
+
"PGXS: $PGXS" \
|
|
57
|
+
"headers: $HEADERS" \
|
|
58
|
+
"library directory: $($PG_CONFIG --pkglibdir)" \
|
|
59
|
+
"extension directory: $($PG_CONFIG --sharedir)/extension" \
|
|
60
|
+
"bundle: $ROOT" \
|
|
61
|
+
"doctor: OK"
|