From 8df0f92fcf33ad7574f624811b8a20e418b445a8 Mon Sep 17 00:00:00 2001 From: Hamza-Ayed Date: Wed, 29 Jul 2026 17:04:05 +0300 Subject: [PATCH] fix(migration): apply schema fixes statement-by-statement, tolerating already-applied changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The bulk `mysql < file.sql` run aborted on the first "duplicate column" error because some columns from an earlier partial run already existed. apply_sql_tolerant.sh now runs each ALTER separately and only skips MySQL errors 1060/1061/1091/1050 (duplicate column/key, missing to drop, table exists) — any other error still stops the migration immediately. --- backend/scripts/apply_sql_tolerant.sh | 53 +++++++++++++++++++++++++++ backend/scripts/run_v2_migration.sh | 7 ++-- 2 files changed, 57 insertions(+), 3 deletions(-) create mode 100755 backend/scripts/apply_sql_tolerant.sh diff --git a/backend/scripts/apply_sql_tolerant.sh b/backend/scripts/apply_sql_tolerant.sh new file mode 100755 index 0000000..96bfdb6 --- /dev/null +++ b/backend/scripts/apply_sql_tolerant.sh @@ -0,0 +1,53 @@ +#!/usr/bin/env bash +# ============================================================ +# apply_sql_tolerant.sh — يطبّق ملف SQL عبارة-عبارة، ويتجاوز فقط +# أخطاء "الشيء موجود مسبقاً" (عمود/فهرس/جدول مكرّر) لأن هذا يعني +# أن المايغريشن طُبِّقت جزئياً من قبل — أي خطأ آخر يوقف التنفيذ فوراً. +# +# الاستخدام: +# bash apply_sql_tolerant.sh +# ============================================================ +set -euo pipefail + +CONTAINER="$1" ROOT_PW="$2" DB="$3" FILE="$4" +DC="docker compose -f $(cd "$(dirname "${BASH_SOURCE[0]}")/../../docker" && pwd)/docker-compose.yml" + +# أكواد MySQL التي تعني "طُبِّق هذا الجزء من قبل" ولا خطر في تجاوزها: +# 1060 Duplicate column 1061 Duplicate key 1091 Can't DROP (missing) +# 1050 Table already exists +TOLERATED='1060|1061|1091|1050' + +# نفصل على ';' في نهاية السطر — كل ALTER/عبارة في هذا الملف على أسطرها +# الخاصة أصلاً، وما من ; داخل نص أو تعليق يكسر هذا التقسيم هنا. +STATEMENT="" +FAILED=0 +APPLIED=0 +SKIPPED=0 + +while IFS= read -r line; do + # تجاهل التعليقات المستقلة والأسطر الفارغة قبل تجميع أي عبارة + [[ "$line" =~ ^[[:space:]]*--.*$ ]] && continue + [[ -z "${line// }" ]] && continue + + STATEMENT+="$line"$'\n' + + if [[ "$line" == *";" ]]; then + OUT=$($DC exec -T "$CONTAINER" mysql -uroot -p"$ROOT_PW" "$DB" -e "$STATEMENT" 2>&1) && { + APPLIED=$((APPLIED+1)) + } || { + if echo "$OUT" | grep -qE "ERROR ($TOLERATED)"; then + SKIPPED=$((SKIPPED+1)) + echo " … skipped (already applied): $(echo "$STATEMENT" | head -1 | cut -c1-70)" + else + echo "✘ FAILED on statement:" + echo "$STATEMENT" + echo "$OUT" + FAILED=1 + fi + } + STATEMENT="" + [[ "$FAILED" == "1" ]] && exit 1 + fi +done < "$FILE" + +echo " ✔ applied=$APPLIED skipped(already-present)=$SKIPPED" diff --git a/backend/scripts/run_v2_migration.sh b/backend/scripts/run_v2_migration.sh index fa6463b..53dc5b3 100755 --- a/backend/scripts/run_v2_migration.sh +++ b/backend/scripts/run_v2_migration.sh @@ -143,11 +143,12 @@ $DC exec -T mysql mysqldump -uroot -p"$ROOT_PW" --single-transaction --routines echo " ✔ $(du -h "$BACKUP" | cut -f1)" # ── 5) إصلاحات المخطط ─────────────────────────────────────── +# تُطبَّق عبارة-عبارة وتتجاوز فقط "موجود مسبقاً" — يجعل التشغيل قابلاً +# لإعادة المحاولة إن كانت المايغريشن قد طُبِّقت جزئياً من قبل. echo echo "── [5/8] applying schema fixes" -$DC exec -T mysql mysql -uroot -p"$ROOT_PW" "$DST_DB" \ - < "$REPO/backend/migrations/2026_07_29_v2_migration_schema_fixes.sql" -echo " ✔ applied" +bash "$REPO/backend/scripts/apply_sql_tolerant.sh" mysql "$ROOT_PW" "$DST_DB" \ + "$REPO/backend/migrations/2026_07_29_v2_migration_schema_fixes.sql" # ── 6) فحص المفتاح ────────────────────────────────────────── echo