Files
2026-08-13 17:51:39 +09:00

114 lines
3.8 KiB
Bash
Executable File

#!/usr/bin/env bash
# TROAD Oracle 컨테이너에 sql/*.sql 을 순서대로 적용한다.
#
# 사용법:
# ./apply-sql.sh # sql/ 전체 (파일명 순)
# ./apply-sql.sh sql/10_v_incident_ftms.sql sql/20_v_incident_ftms_data.sql
#
# 컨테이너가 기동/healthy 상태여야 한다. (start-all-server.sh 또는 docker compose up)
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CONTAINER="${ORACLE_CONTAINER:-exaichatbot-agent-oracle-troad}"
PDB="${ORACLE_PDB:-ORCL2}"
SYS_PASSWORD="${ORACLE_SYS_PASSWORD:-OracleExdev!2026}"
REMOTE_DIR="/tmp/troad-sql"
log() { printf '\033[36m[oracle-sql]\033[0m %s\n' "$*"; }
err() { printf '\033[31m[oracle-sql]\033[0m %s\n' "$*" >&2; }
if ! docker inspect "$CONTAINER" >/dev/null 2>&1; then
err "컨테이너를 찾을 수 없습니다: $CONTAINER"
err "먼저 기동하세요: docker compose -f docker-compose.oracle.yml up -d"
exit 1
fi
state="$(docker inspect -f '{{.State.Status}}' "$CONTAINER")"
if [[ "$state" != "running" ]]; then
err "컨테이너가 running 상태가 아닙니다 (현재: $state)"
exit 1
fi
# healthcheck 통과 대기 (최대 10분)
for _ in $(seq 1 120); do
health="$(docker inspect -f '{{if .State.Health}}{{.State.Health.Status}}{{else}}none{{end}}' "$CONTAINER")"
[[ "$health" == "healthy" || "$health" == "none" ]] && break
sleep 5
done
if [[ "${health:-}" != "healthy" && "${health:-}" != "none" ]]; then
err "Oracle 이 healthy 상태가 아닙니다 (현재: ${health:-unknown})"
exit 1
fi
if [[ $# -gt 0 ]]; then
FILES=("$@")
else
FILES=()
while IFS= read -r f; do FILES+=("$f"); done < <(find "$SCRIPT_DIR/sql" -maxdepth 1 -name '*.sql' | sort)
fi
if [[ ${#FILES[@]} -eq 0 ]]; then
err "적용할 SQL 파일이 없습니다."
exit 1
fi
docker exec "$CONTAINER" mkdir -p "$REMOTE_DIR"
for file in "${FILES[@]}"; do
path="$file"
[[ -f "$path" ]] || path="$SCRIPT_DIR/$file"
if [[ ! -f "$path" ]]; then
err "파일 없음: $file"
exit 1
fi
base="$(basename "$path")"
log "적용: $base"
docker cp "$path" "$CONTAINER:$REMOTE_DIR/$base"
# 한글 데이터를 위해 NLS_LANG 을 AL32UTF8 로 고정하고 PDB 에 접속한다.
output="$(docker exec -e NLS_LANG=.AL32UTF8 -i "$CONTAINER" bash -lc "
sqlplus -S -L sys/'${SYS_PASSWORD}'@localhost:1521/${PDB} as sysdba <<'EOSQL'
WHENEVER SQLERROR EXIT SQL.SQLCODE
WHENEVER OSERROR EXIT FAILURE
SET ECHO OFF
SET FEEDBACK OFF
SET PAGESIZE 0
SET LINESIZE 200
@${REMOTE_DIR}/${base}
EXIT
EOSQL
" 2>&1)" || {
err "실패: $base"
printf '%s\n' "$output" >&2
exit 1
}
[[ -n "${output// /}" ]] && printf '%s\n' "$output"
done
log "검증"
docker exec -e NLS_LANG=.AL32UTF8 -i "$CONTAINER" bash -lc "
sqlplus -S -L sys/'${SYS_PASSWORD}'@localhost:1521/${PDB} as sysdba <<'EOSQL'
SET PAGESIZE 50
SET LINESIZE 200
COLUMN OWNER FORMAT A12
COLUMN OBJECT_NAME FORMAT A30
COLUMN OBJECT_TYPE FORMAT A12
SELECT OWNER, OBJECT_NAME, OBJECT_TYPE, STATUS
FROM ALL_OBJECTS
WHERE (OWNER = 'OPR_MAIN' AND OBJECT_NAME IN ('T_INCIDENT_FTMS', 'V_INCIDENT_FTMS', 'V_ROUTE_NEW_NM', 'V_ROUTE_TRFC_VER001', 'V_ACDT_BRNWS_VER001'))
OR (OWNER = 'TROAD_APP' AND OBJECT_NAME IN ('V_ROUTE_NEW_NM', 'V_ROUTE_TRFC_VER001', 'V_ACDT_BRNWS_VER001', 'T_ROUTE_NEW_NM', 'T_ROUTE_TRFC_VER001', 'T_ACDT_BRNWS_VER001'))
OR (OWNER = 'TLISDEV' AND OBJECT_NAME IN ('T_TRMB_CD_INFO01M1'))
ORDER BY OWNER, OBJECT_TYPE, OBJECT_NAME;
SELECT (SELECT COUNT(*) FROM OPR_MAIN.V_INCIDENT_FTMS) AS V_INCIDENT_FTMS_ROWS FROM DUAL;
SELECT (SELECT COUNT(*) FROM TROAD_APP.V_ROUTE_NEW_NM) AS V_ROUTE_NEW_NM_ROWS FROM DUAL;
SELECT (SELECT COUNT(*) FROM TROAD_APP.V_ROUTE_TRFC_VER001) AS V_ROUTE_TRFC_ROWS FROM DUAL;
SELECT (SELECT COUNT(*) FROM TROAD_APP.V_ACDT_BRNWS_VER001) AS V_ACDT_BRNWS_ROWS FROM DUAL;
SELECT (SELECT COUNT(*) FROM TLISDEV.T_TRMB_CD_INFO01M1) AS T_TRMB_CD_INFO_ROWS FROM DUAL;
EXIT
EOSQL
"
log "완료"