#!/bin/sh # Runs in the MySQL client container, never in the application's web root. set -eu : "${MYSQL_HOST:?Missing MYSQL_HOST}" : "${MYSQL_DATABASE:?Missing MYSQL_DATABASE}" : "${MYSQL_USER:?Missing MYSQL_USER}" : "${MYSQL_PASSWORD:?Missing MYSQL_PASSWORD}" export MYSQL_PWD="$MYSQL_PASSWORD" mysql_run() { mysql --protocol=TCP --host="$MYSQL_HOST" --port="${MYSQL_PORT:-3306}" \ --user="$MYSQL_USER" --database="$MYSQL_DATABASE" \ --batch --skip-column-names "$@" } fail() { printf '%s\n' "Database initialization refused: $*" >&2 exit 1 } require_tables() { count=$(mysql_run -e "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_type = 'BASE TABLE' AND table_name IN ($1)") [ "$count" = "$2" ] || fail "Required recruitment tables are missing. Review the database manually; no automatic reimport will be attempted." } marker=$(mysql_run -e "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = 'rec_bootstrap_state'") if [ "$marker" = 1 ]; then status=$(mysql_run -e "SELECT status FROM rec_bootstrap_state WHERE id = 1") [ "$status" = imported ] || fail "A previous import did not finish. SQL imports are not transactional; inspect or restore this database before retrying." require_tables "'in_daper', 'in_soal', 'in_jawab'" 3 printf '%s\n' 'Initial SQL was already imported; preserving existing data.' exit 0 fi tables=$(mysql_run -e "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE()") if [ "$tables" != 0 ]; then # Adopt a previously initialized deployment, but reject a bare/partial schema. require_tables "'in_daper', 'in_soal', 'in_jawab', 'rec_admin', 'rec_exam_attempt', 'rec_exam_event', 'rec_candidate_login_guard'" 7 printf '%s\n' 'Existing recruitment database detected; skipping SQL import.' exit 0 fi sql_file=${DB_INIT_SQL_FILE:-/bootstrap/initial.sql} [ -f "$sql_file" ] && [ -r "$sql_file" ] && [ -s "$sql_file" ] \ || fail "The initial SQL file is missing, unreadable, or empty. Set DB_INIT_SQL_PATH to a trusted dump on the Docker host." # The dump must not replace our safety marker with a previously imported one. # Exclude this setup-only table when creating backups (see deployment guide). if grep -iFq 'rec_bootstrap_state' "$sql_file"; then fail "The dump references the reserved rec_bootstrap_state table. Re-export without that table before importing." fi # Persist the in-progress marker BEFORE any DROP/CREATE statements in the dump. # Do not use IF NOT EXISTS: concurrent first imports must not both proceed. mysql_run -e "CREATE TABLE rec_bootstrap_state ( id TINYINT UNSIGNED NOT NULL PRIMARY KEY, status VARCHAR(20) NOT NULL ) ENGINE=InnoDB; INSERT INTO rec_bootstrap_state (id, status) VALUES (1, 'importing');" printf '%s\n' 'Importing initial SQL into the empty database...' mysql_run < "$sql_file" require_tables "'in_daper', 'in_soal', 'in_jawab'" 3 mysql_run -e "UPDATE rec_bootstrap_state SET status = 'imported' WHERE id = 1" printf '%s\n' 'Initial SQL import complete.'