#!/usr/bin/env bash # ───────────────────────────────────────────────────────────────────────────── # JNPF PostgreSQL schema 初始化(全新空库专用) # 1) 建四库 jnpf_init / jnpf_flow / jnpf_xxljob / nacos_config # 2) 跑官方初始化脚本(结构,无业务数据) # 3) 跑自建表 DDL self_built_tables_pg.sql # 4) 跑数据接口修正 data_interface_pg_fixes.sql(此刻空表→幂等 no-op,数据迁移后由 migrate-data.sh 再放一次) # 5) 建 Nacos 存储库 schema(nacos_config_pg.sql) # # 前置:cx-postgres 容器已由根 compose 拉起(安全基线随根 compose,本脚本不再部署容器): # docker volume create postgres_pgdata # 全新机器 # docker compose up -d cx-postgres # 在仓库根 / 离线交付包根目录执行 # # 安全守卫:目标库已存在且含表时**拒绝执行**(官方 init 含 DROP TABLE IF EXISTS, # 重放会清空既有数据);确需重灌请显式 FORCE_RESEED=1。 # # 用法: # ./install.sh # 建库 + 建表(= schema) # ./install.sh schema # 同上(兼容旧参数写法) # # 参数(环境变量,默认=现场标准值): # CONTAINER PG 容器名 默认 cx-postgres # PGUSER 超级用户 默认 postgres(exec psql 走容器本地 trust,无需密码) # DB_INIT / DB_FLOW / DB_XXLJOB / DB_NACOS 四库名(测试时可改 *_t8 隔离) # CREATE_EXTENSIONS 是否建常用扩展(1/0),默认 1(非致命,失败仅告警) # FORCE_RESEED 目标库非空时仍强制重灌(1/0),默认 0 # ───────────────────────────────────────────────────────────────────────────── set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" SQL_DIR="$SCRIPT_DIR/sql" CONTAINER="${CONTAINER:-cx-postgres}" PGUSER="${PGUSER:-postgres}" DB_INIT="${DB_INIT:-jnpf_init}" DB_FLOW="${DB_FLOW:-jnpf_flow}" DB_XXLJOB="${DB_XXLJOB:-jnpf_xxljob}" DB_NACOS="${DB_NACOS:-nacos_config}" CREATE_EXTENSIONS="${CREATE_EXTENSIONS:-1}" FORCE_RESEED="${FORCE_RESEED:-0}" STEP="${1:-schema}" log() { printf '\033[1;34m[install]\033[0m %s\n' "$*"; } warn() { printf '\033[1;33m[install][warn]\033[0m %s\n' "$*"; } die() { printf '\033[1;31m[install][err]\033[0m %s\n' "$*" >&2; exit 1; } # 在容器内跑 psql(本地 unix socket,postgres 超级用户 trust,无需密码/端口) psql_exec() { docker exec -i "$CONTAINER" psql -U "$PGUSER" "$@"; } # 等 PG 进程就绪(首次 initdb 数十秒)。此阶段容器健康检查 unhealthy 属预期—— # 它探测的业务库正是本脚本要创建的,healthy 只会出现在本脚本成功之后 for _i in $(seq 1 60); do if docker exec "$CONTAINER" pg_isready -qU "$PGUSER" 2>/dev/null; then break; fi [ "$_i" = 60 ] && { echo "错误:等待 PG 就绪超时(docker logs $CONTAINER 查看)" >&2; exit 1; } sleep 2 done # 把宿主 SQL 文件喂给容器内 psql,遇错即停 run_sql_file() { local db="$1" file="$2" [ -f "$file" ] || die "缺 SQL 文件:${file}(git 拉码路线:先跑 ./assemble-sql-onsite.sh;离线包路线:包内 sql/ 应已组装,联系构建机)" log "→ [$db] 执行 $(basename "$file") ($(du -h "$file" | cut -f1))" psql_exec -d "$db" -v ON_ERROR_STOP=1 -q -f - < "$file" } db_exists() { psql_exec -tAc "SELECT 1 FROM pg_database WHERE datname='$1'" | grep -q 1; } create_db() { local db="$1" if db_exists "$db"; then warn "库 $db 已存在,跳过 CREATE DATABASE(幂等)" else log "创建库 $db" psql_exec -d postgres -v ON_ERROR_STOP=1 -c "CREATE DATABASE \"$db\" ENCODING 'UTF8'" fi } # 只数 BASE TABLE(排除 pg_stat_statements 等扩展视图,计数不受 CREATE_EXTENSIONS 影响) table_count() { psql_exec -tAc "SELECT count(*) FROM information_schema.tables WHERE table_schema='public' AND table_type='BASE TABLE'" -d "$1"; } # 全新 schema 基线:官方 293 张表 + 自建 99 张表(含 DMS V2.3 十表及文件对象映射表)。 verify_init_table_count() { local init_table_count init_custom_table_count init_table_count="$(table_count "$DB_INIT")" init_custom_table_count=$((init_table_count - 293)) if [ "$init_table_count" -ne 392 ] || [ "$init_custom_table_count" -ne 99 ]; then die "表数核对失败:$DB_INIT 共 ${init_table_count} 张 BASE TABLE,自建表 ${init_custom_table_count} 张;期望总数 392 张、自建 99 张" fi } # 非空守卫:init SQL 含 DROP TABLE IF EXISTS,对已有数据的库重放=清库 guard_empty() { local db="$1" n db_exists "$db" || return 0 n="$(table_count "$db")" [ "$n" -eq 0 ] && return 0 if [ "$FORCE_RESEED" = "1" ]; then warn "库 $db 已有 $n 张表,FORCE_RESEED=1 → 继续重灌(既有数据将被 init 脚本覆盖/清空)" else die "库 $db 已有 $n 张表——本脚本只用于全新空库(init 含 DROP TABLE,重放会清数据)。确需重灌:FORCE_RESEED=1 ./install.sh" fi } # ── schema:建库 + 官方 init + 自建表 + 数据接口修正 + Nacos 存储库 ────────── do_schema() { docker inspect "$CONTAINER" >/dev/null 2>&1 \ || die "容器 $CONTAINER 不在——先在仓库根/交付包根目录:docker volume create postgres_pgdata && docker compose up -d cx-postgres" log "===== 非空守卫 =====" guard_empty "$DB_INIT"; guard_empty "$DB_FLOW"; guard_empty "$DB_XXLJOB"; guard_empty "$DB_NACOS" log "===== 建四库 =====" create_db "$DB_INIT"; create_db "$DB_FLOW"; create_db "$DB_XXLJOB"; create_db "$DB_NACOS" if [ "$CREATE_EXTENSIONS" = "1" ]; then log "建常用扩展(非致命)" for ext in pg_stat_statements pg_trgm pgcrypto pg_bigm vector; do psql_exec -d "$DB_INIT" -c "CREATE EXTENSION IF NOT EXISTS \"$ext\"" >/dev/null 2>&1 \ && log " ext $ext ✓" || warn " ext $ext 跳过(镜像未含或无需)" done fi log "===== 官方初始化脚本 =====" run_sql_file "$DB_INIT" "$SQL_DIR/jnpf_dbnull_init.sql" run_sql_file "$DB_INIT" "$SQL_DIR/Update_PostgreSQL_1127.sql" run_sql_file "$DB_FLOW" "$SQL_DIR/jnpf_flow_init.sql" run_sql_file "$DB_XXLJOB" "$SQL_DIR/jnpf_xxljob_init.sql" log "===== 自建表 DDL =====" run_sql_file "$DB_INIT" "$SQL_DIR/self_built_tables_pg.sql" log "===== 自建表增量(迁移快照后的列级对齐,幂等)=====" run_sql_file "$DB_INIT" "$SQL_DIR/update_lims_huanjing_20260717.sql" run_sql_file "$DB_INIT" "$SQL_DIR/update_lims_sxt_wendingxing_20260717.sql" run_sql_file "$DB_INIT" "$SQL_DIR/update_lims_sxt_wendingxing_20260720.sql" run_sql_file "$DB_INIT" "$SQL_DIR/update_lims_sxt_flow_biz_status_20260719.sql" run_sql_file "$DB_INIT" "$SQL_DIR/update_lims_sxt_quyang_zhongzhi_shenqing_biz_status_20260723.sql" run_sql_file "$DB_INIT" "$SQL_DIR/update_lims_sxt_quyang_zhongzhi_shenqing_qingyandan_link_20260723.sql" run_sql_file "$DB_INIT" "$SQL_DIR/update_lims_sxt_plan_status_20260720.sql" run_sql_file "$DB_INIT" "$SQL_DIR/update_lims_wendingxing_biangeng_20260720.sql" run_sql_file "$DB_INIT" "$SQL_DIR/create_lims_sxt_quyang_jihua_renwu_20260724.sql" run_sql_file "$DB_INIT" "$SQL_DIR/alter_lims_sxt_quyang_jihua_renwu_jianyan_xiang_kuaizhao_20260724.sql" run_sql_file "$DB_INIT" "$SQL_DIR/create_audit_events_ext_20260724.sql" run_sql_file "$DB_INIT" "$SQL_DIR/create_audit_events_20260724.sql" run_sql_file "$DB_INIT" "$SQL_DIR/update_audit_events_title_entry_20260810.sql" run_sql_file "$DB_INIT" "$SQL_DIR/update_audit_events_ingest_merge_20260818.sql" run_sql_file "$DB_INIT" "$SQL_DIR/repair_audit_events_integrity_20260824.sql" run_sql_file "$DB_INIT" "$SQL_DIR/create_dms_permission_v2_2_20260815.sql" run_sql_file "$DB_INIT" "$SQL_DIR/upgrade_dms_permission_v2_2_to_v2_3_20260817.sql" run_sql_file "$DB_INIT" "$SQL_DIR/create_dms_file_objects_20260817.sql" run_sql_file "$DB_INIT" "$SQL_DIR/upgrade_dms_file_properties_20260820.sql" run_sql_file "$DB_INIT" "$SQL_DIR/update_audit_events_target_timeline_index_20260823.sql" log "===== 数据接口修正(空表幂等,数据迁移后 migrate-data.sh 再放一次)=====" run_sql_file "$DB_INIT" "$SQL_DIR/data_interface_pg_fixes.sql" log "===== Nacos 存储库 schema =====" run_sql_file "$DB_NACOS" "$SQL_DIR/nacos_config_pg.sql" log "===== 表数核对 =====" verify_init_table_count log " $DB_INIT BASE TABLE = $(table_count "$DB_INIT") (期望 392:官方293 + 自建99,含 DMS V2.3 十表和文件对象映射表)" log " $DB_FLOW BASE TABLE = $(table_count "$DB_FLOW") (期望 70)" log " $DB_XXLJOB BASE TABLE = $(table_count "$DB_XXLJOB") (期望 11)" log " $DB_NACOS BASE TABLE = $(table_count "$DB_NACOS") (期望 12)" log "schema 就绪。下一步:停机窗口跑 ./migrate-data.sh 迁数据;Nacos 配置内容按 docs/archive/server-pg-cutover-checklist.md SW-7 导入。" } case "$STEP" in schema) do_schema ;; container|all) die "步骤 '$STEP' 已废弃:PG 容器统一由根 compose 拉起(docker compose up -d cx-postgres),本脚本只做 schema" ;; *) die "未知步骤 '$STEP'(仅支持 schema)" ;; esac log "install.sh [$STEP] 完成 ✓"