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.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +76 -0
  3. data/GET_STARTED.md +188 -0
  4. data/README.md +56 -0
  5. data/db_core/include/mcdb_format.h +55 -0
  6. data/db_core/src/mcdb_format.c +341 -0
  7. data/db_deployment/mysql/Makefile +48 -0
  8. data/db_deployment/mysql/README.md +42 -0
  9. data/db_deployment/mysql/bin/common +160 -0
  10. data/db_deployment/mysql/bin/disable +40 -0
  11. data/db_deployment/mysql/bin/doctor +64 -0
  12. data/db_deployment/mysql/bin/enable +57 -0
  13. data/db_deployment/mysql/bin/install +64 -0
  14. data/db_deployment/mysql/bin/status +65 -0
  15. data/db_deployment/mysql/bin/uninstall +47 -0
  16. data/db_deployment/mysql/bin/upgrade +115 -0
  17. data/db_deployment/mysql/bin/verify +14 -0
  18. data/db_deployment/postgres/Makefile +45 -0
  19. data/db_deployment/postgres/README.md +60 -0
  20. data/db_deployment/postgres/bin/doctor +61 -0
  21. data/db_deployment/postgres/bin/enable +136 -0
  22. data/db_deployment/postgres/bin/install +104 -0
  23. data/db_deployment/postgres/bin/uninstall +54 -0
  24. data/db_deployment/postgres/bin/verify +14 -0
  25. data/docs/database-envelope-v1.md +159 -0
  26. data/exe/multi_compress +228 -0
  27. data/ext/multi_compress/extconf.rb +4 -0
  28. data/ext/multi_compress/multi_compress.c +30 -0
  29. data/lib/multi_compress/active_record.rb +61 -0
  30. data/lib/multi_compress/codec.rb +164 -0
  31. data/lib/multi_compress/database.rb +106 -0
  32. data/lib/multi_compress/db_deployment.rb +456 -0
  33. data/lib/multi_compress/version.rb +1 -1
  34. data/multi_compress.gemspec +55 -0
  35. data/mysql_udf/Makefile +96 -0
  36. data/mysql_udf/README.md +95 -0
  37. data/mysql_udf/sql/examples.sql +11 -0
  38. data/mysql_udf/sql/install.sql +15 -0
  39. data/mysql_udf/sql/uninstall.sql +4 -0
  40. data/mysql_udf/sql/views.sql +8 -0
  41. data/mysql_udf/src/multi_compress_mysql.c +133 -0
  42. data/mysql_udf/src/mysql_udf_abi_57.h +34 -0
  43. data/mysql_udf/test/mcdb_cli.c +60 -0
  44. data/mysql_udf/test/run_e2e.sh +296 -0
  45. data/postgres_extension/Makefile +74 -0
  46. data/postgres_extension/README.md +112 -0
  47. data/postgres_extension/multi_compress.control +4 -0
  48. data/postgres_extension/multi_compress_pg.exports +12 -0
  49. data/postgres_extension/sql/examples.sql +12 -0
  50. data/postgres_extension/sql/multi_compress--0.5.0.sql +24 -0
  51. data/postgres_extension/sql/uninstall.sql +2 -0
  52. data/postgres_extension/sql/views.sql +7 -0
  53. data/postgres_extension/src/mcdb_format.c +2 -0
  54. data/postgres_extension/src/multi_compress_pg.c +96 -0
  55. data/postgres_extension/test/run_e2e.sh +323 -0
  56. 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"