Skip to content

Instantly share code, notes, and snippets.

@ahmad-moussawi
Created December 23, 2021 14:47
Show Gist options
  • Save ahmad-moussawi/c9d3593cffe592f556078eca7dbf12bc to your computer and use it in GitHub Desktop.
Save ahmad-moussawi/c9d3593cffe592f556078eca7dbf12bc to your computer and use it in GitHub Desktop.
A shell script that change the schema of the SQL Server DACPAC file
#!/bin/bash
# This uitlity help to convert a dacpac from one schema to another
# taking into consideration some edge cases like when converting from/to dbo
# it assumes that you have 7-zip installed
in=${1:?Select dacpac file, usage: $0 <file>.dacpac <target_schema>}
schema=${2:?schema cannot be empty, usage: $0 <file>.dacpac <target_schema>}
# zip command
zip="/c/Program\\ Files/7-Zip/7z.exe"
if [[ ! -f $in ]]; then
echo ">> $in is not a readable file"
exit 1
fi
unzip -o -d .tmp $in
# Detecting current schema
current_schemas=( $(grep '"SqlTable"' .tmp/model.xml | grep -oE '"\[[^]]+\]\.' | sort | uniq | sed 's/[][".]//g') )
if [[ ${#current_schemas[@]} > 1 ]]; then
echo ">> multiple schemas found, select the source schema"
for i in "${!current_schemas[@]}"; do
echo "$i: ${current_schemas[i]}"
done
read -p '<< Your option: ' current
current="${current_schemas[current]}"
elif [[ ${#current_schemas[@]} -eq 1 ]]; then
current="${current_schemas[0]}"
else
current="dbo"
fi
if [[ $current == $schema ]]; then
echo ">> The current schema is already $schema, aborting."
rm -rf .tmp
exit 1
fi
echo ">> Converting from $current -> $schema"
# pre manipulation add/remove some elements based on the target schema
if [[ $schema == 'dbo' ]]; then
# remove the SqlSchema Element since it's not needed when the target is dbo
sed -i "/<Element Type=\"SqlSchema\" Name=\"\[$current\]\"/,/<\/Element>/ d" .tmp/model.xml
# add the ExternalSource="BuiltIns" attribute for Schema references
sed -i "s:<References Name=\"\[$current\]\" />:<References ExternalSource=\"BuiltIns\" Name=\"[dbo]\" />:" .tmp/model.xml
else
# remove ExternalSource="BuiltIns" for Schema references
sed -i "s:<References ExternalSource=\"BuiltIns\" Name=\"\[dbo\]\" />:<References Name=\"[$schema]\" />:" .tmp/model.xml
# add the SqlSchema Element definition
sed -i "0,/<\/Element>/ s::</Element>\n<Element Type=\"SqlSchema\" Name=\"[$schema]\">\n\
<Relationship Name=\"Authorizer\">\n\
<Entry>\n\
<References ExternalSource=\"BuiltIns\" Name=\"[DBOKEEP]\" />\n\
</Entry>\n\
</Relationship>\n\
</Element>:" .tmp/model.xml
fi
files=('predeploy.sql' 'postdeploy.sql' 'model.xml')
for i in "${files[@]}"; do
file=".tmp/$i"
if [[ -f $file ]]; then
echo ">> replacing [$current] with [$schema] in $file"
sed -i "s/\[$current\]/[$schema]/gI" $file
# some cases where we have the schema without []
# trying to match anyword followed directly by .
echo ">> replacing $current. with [$schema]. in $file"
sed -i "s/\<$current\./[$schema]./gI" $file
fi
done
sed -i 's/DBOKEEP/dbo/' .tmp/model.xml
# update checksum
checksum=$(sha256sum .tmp/model.xml | awk '{print $1}')
sed -i -e '/Checksum>/ d' -e "/<Checksums>/ a <Checksum Uri=\"/model.xml\">${checksum^^}</Checksum>" .tmp/Origin.xml
(cd .tmp; eval "$zip a -tzip ../${in%.dacpac}-$schema.dacpac *")
rm -rf .tmp
echo "Conversion done"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment