#!/usr/bin/env bash # Re-create decomp/schema/ from schema/*.mdf without touching the originals. # # How it works: # - The .mdf/.ldf files are in SQL Server 2022 on-disk format (database version # 957). SQL Server 2019 rejects them with Msg 948. # - The script copies them to a scratch dir and attaches the copies to a # throwaway mssql:2022 container. # - It dumps the catalog metadata and module definitions. No table data is # exported, only row counts. # # Usage: decomp/scripts/dump_schema.sh (from the repo root; needs docker) set -euo pipefail ROOT=$(pwd); SCRATCH=${SCRATCH:-/tmp/opencode/mssql}; OUT=$ROOT/decomp/schema NAME=rh-mssql; PW='Re_Only_2026!' # throwaway local container, loopback only DBS="RustyHearts:RustyHearts_log RustyHearts_Auth:RustyHearts_Auth_log RustyHearts_Account:RustyHearts_Account_log RustyHearts_Log:RustyHearts_Log_log GMRustyHearts:GMRustyHearts_log" rm -rf "$SCRATCH"; mkdir -p "$SCRATCH"; cp schema/* "$SCRATCH"/; chmod -R 777 "$SCRATCH" docker rm -f $NAME >/dev/null 2>&1 || true docker run -d --name $NAME -e ACCEPT_EULA=Y -e "MSSQL_SA_PASSWORD=$PW" -v "$SCRATCH":/data \ mcr.microsoft.com/mssql/server:2022-latest >/dev/null sq() { docker exec -i $NAME /opt/mssql-tools18/bin/sqlcmd -C -S localhost -U sa -P "$PW" -b "$@"; } until sq -Q "select 1" >/dev/null 2>&1; do sleep 2; done for e in $DBS; do n=${e%%:*}; l=${e##*:} sq -Q "CREATE DATABASE [$n] ON (FILENAME='/data/$n.mdf'),(FILENAME='/data/$l.ldf') FOR ATTACH" done for e in $DBS; do db=${e%%:*}; d=$OUT/$db; mkdir -p "$d/procs"; rm -f "$d"/procs/*.sql sq -d $db -W -s$'\t' -Q "set nocount on; select s.name+'.'+t.name as [table], c.column_id, c.name as [column], ty.name as type, c.max_length, c.precision, c.scale, c.is_nullable, c.is_identity, isnull(dc.definition,'') as [default] from sys.tables t join sys.schemas s on s.schema_id=t.schema_id join sys.columns c on c.object_id=t.object_id join sys.types ty on ty.user_type_id=c.user_type_id left join sys.default_constraints dc on dc.object_id=c.default_object_id order by 1,2" | grep -v '^-' > "$d/columns.tsv" sq -d $db -W -s$'\t' -Q "set nocount on; select object_name(i.object_id) as [table], i.name as [index], i.type_desc, i.is_primary_key, i.is_unique, c.name as col, ic.key_ordinal from sys.indexes i join sys.index_columns ic on ic.object_id=i.object_id and ic.index_id=i.index_id join sys.columns c on c.object_id=ic.object_id and c.column_id=ic.column_id where objectproperty(i.object_id,'IsUserTable')=1 and ic.key_ordinal>0 order by 1,2,7" | grep -v '^-' > "$d/indexes.tsv" sq -d $db -W -s$'\t' -Q "set nocount on; select object_name(fk.parent_object_id) child, col_name(fc.parent_object_id,fc.parent_column_id) child_col, object_name(fk.referenced_object_id) parent, col_name(fc.referenced_object_id,fc.referenced_column_id) parent_col from sys.foreign_keys fk join sys.foreign_key_columns fc on fc.constraint_object_id=fk.object_id" | grep -v '^-' > "$d/foreign_keys.tsv" sq -d $db -W -s$'\t' -Q "set nocount on; select o.type_desc, o.name, p.parameter_id, p.name as param, type_name(p.user_type_id) type, p.max_length, p.is_output from sys.objects o left join sys.parameters p on p.object_id=o.object_id where o.type in ('P','FN','IF','TF','V','TR') and o.is_ms_shipped=0 order by 2,3" | grep -v '^-' > "$d/routines.tsv" sq -d $db -W -s$'\t' -h-1 -Q "set nocount on; select t.name, sum(p.rows), (select count(*) from sys.columns c where c.object_id=t.object_id) from sys.tables t join sys.partitions p on p.object_id=t.object_id and p.index_id in (0,1) group by t.object_id,t.name order by t.name" > "$d/tables.tsv" for p in $(sq -d $db -h-1 -W -Q "set nocount on; select name from sys.objects where type in ('P','FN','IF','TF','V','TR') and is_ms_shipped=0"); do sq -d $db -y0 -Q "set nocount on; select object_definition(object_id('[$p]'))" | tr -d '\r' > "$d/procs/$p.sql" done done echo "done; container '$NAME' left running (docker rm -f $NAME to remove)"