刘光辉
15 小时以前 34981c30a78e8bbd7791131059a9210f9928b62c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#!/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] 完成 ✓"