#!/usr/bin/env bash # m11b-1a 实库验证:拉起一次性本地 MariaDB(独立 datadir + 独立端口), # 用**部署同款路径**(mariadb CLI + DELIMITER)装载生成器产出的 DDL, # 再跑 tests/test_m11b1a_ddl_runtime.py 的 A+B 两层,结束后彻底销毁。 # # 为什么自造库而不是连 projects/pbls/env/test.json: # verify_db()/prune_partitions 会真做 DROP PARTITION 与 INSERT/DELETE 探针, # 在共享测试库上跑等于拿别人的数据做破坏性实验;且本沙箱内 3306 端口的 # MariaDB 对 pbls 账号是 unix_socket 鉴权(1698 Access denied),根本连不上。 # 连接参数(user/dbname/password)仍从 env/test.json 读取,不硬编码凭据。 # # 装载方式说明:生成器产出的 B/C 段含多语句过程体,按文件头注释规定必须用 # mysql/mariadb CLI(DELIMITER)执行;故本 runner 用 CLI 装载, # 顺带证明 --emit/full_script() 产出的 SQL 在 MariaDB 10.6 上可原样执行。 # # 用法:bash tests/run_m11b1a_localdb.sh (退出码 0 = 全 PASS) set -u HERE="$(cd "$(dirname "$0")" && pwd)" MODULE_DIR="$(dirname "$HERE")" D="${TMPDIR:-/tmp}/m11b1a_localdb_$$" PORT="${M11B1A_DB_PORT:-13306}" SOCK="$D/my.sock" LOG="$D/server.err" cleanup() { if [[ -f "$D/my.pid" ]]; then kill "$(cat "$D/my.pid")" 2>/dev/null || true sleep 1 fi pkill -f "datadir=$D" 2>/dev/null || true rm -rf "$D" } trap cleanup EXIT INT TERM echo "[runner] datadir=$D port=$PORT" mkdir -p "$D" mariadb-install-db --user="$(id -un)" --datadir="$D" \ --auth-root-authentication-method=normal > "$D/install.log" 2>&1 || { echo "[runner] FAIL: mariadb-install-db 失败"; tail -20 "$D/install.log"; exit 1; } mariadbd --user="$(id -un)" --datadir="$D" --socket="$SOCK" \ --port="$PORT" --bind-address=127.0.0.1 --pid-file="$D/my.pid" \ --skip-name-resolve --log-error="$LOG" > /dev/null 2>&1 & for i in $(seq 1 40); do if mariadb --protocol=tcp -h 127.0.0.1 -P "$PORT" -u root -e "SELECT 1" >/dev/null 2>&1; then echo "[runner] mariadbd ready (${i}s)"; break fi sleep 1 done if ! mariadb --protocol=tcp -h 127.0.0.1 -P "$PORT" -u root -e "SELECT VERSION()" >/dev/null 2>&1; then echo "[runner] FAIL: mariadbd 未在 40s 内就绪"; tail -20 "$LOG" 2>/dev/null; exit 1 fi # 按 env/test.json 建库建号(凭据只在进程内使用,不 echo、不落盘、不 commit) python3 - "$MODULE_DIR" "$PORT" <<'PY' || exit 1 import json, os, subprocess, sys module_dir, port = sys.argv[1], sys.argv[2] ws = os.path.dirname(os.path.dirname(module_dir)) db = json.load(open(os.path.join(ws, "projects", "pbls", "env", "test.json"), encoding="utf-8"))["db"] name, user, pw = db["dbname"], db["user"], db["password"] sql = ("CREATE DATABASE IF NOT EXISTS `%s` CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;\n" "CREATE USER IF NOT EXISTS '%s'@'%%' IDENTIFIED BY '%s';\n" "GRANT ALL PRIVILEGES ON *.* TO '%s'@'%%' WITH GRANT OPTION;\n" "FLUSH PRIVILEGES;\n" % (name, user, pw.replace("'", "''"), user)) r = subprocess.run(["mariadb", "--protocol=tcp", "-h", "127.0.0.1", "-P", port, "-u", "root"], input=sql, capture_output=True, text=True) if r.returncode: print("[runner] FAIL: 建库建号失败(错误信息已脱敏): %s" % r.stderr.replace(pw, "***")[:300]) sys.exit(1) print("[runner] db=%s user=%s 就绪(一次性库,与项目 test/prod 无关)" % (name, user)) PY # 生成器产出的完整脚本(A 建表 + B append-only + C 分区维护 + D 一次性改造)落到临时目录, # 用 mariadb CLI(支持 DELIMITER)装载 —— 与部署执行路径一致。 python3 - "$MODULE_DIR" "$D/full.sql" <<'PY' || exit 1 import importlib.util, os, sys module_dir, out = sys.argv[1], sys.argv[2] script = os.path.join(module_dir, "scripts", "pbl_runtime_event_ddl.py") spec = importlib.util.spec_from_file_location("pbl_runtime_event_ddl", script) mod = importlib.util.module_from_spec(spec) spec.loader.exec_module(mod) open(out, "w", encoding="utf-8").write(mod.full_script()) print("[runner] full_script() 渲染 %d bytes -> %s" % (os.path.getsize(out), out)) PY echo "[runner] 装载 DDL(mariadb CLI + DELIMITER)" mariadb --protocol=tcp -h 127.0.0.1 -P "$PORT" -u root pbls < "$D/full.sql" 2> "$D/load.err" LOAD_RC=$? if [[ "$LOAD_RC" != "0" ]]; then echo "[runner] FAIL: DDL 装载 rc=$LOAD_RC" sed -e "s/'[^']*'@/'***'@/g" "$D/load.err" | head -20 else echo "[runner] DDL 装载 rc=0(stderr 见下,应为空)" head -5 "$D/load.err" fi export M11B1A_LOCAL_DB=1 export M11B1A_DB_HOST=127.0.0.1 export M11B1A_DB_PORT="$PORT" python3 "$HERE/test_m11b1a_ddl_runtime.py" rc=$? echo "[runner] harness rc=$rc" exit $rc