-
Notifications
You must be signed in to change notification settings - Fork 10
Expand file tree
/
Copy pathInitialize-Database.ps1
More file actions
128 lines (101 loc) · 3.81 KB
/
Copy pathInitialize-Database.ps1
File metadata and controls
128 lines (101 loc) · 3.81 KB
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
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$SqlServerFqdn,
[Parameter(Mandatory = $true)]
[string]$DatabaseName,
[Parameter(Mandatory = $true)]
[string]$SqlAdminLogin,
[Parameter(Mandatory = $true)]
[string]$SqlAdminPassword,
[Parameter(Mandatory = $true)]
[string]$ScriptsPath
)
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
function Get-SqlConnection {
param(
[Parameter(Mandatory = $true)][string]$Server,
[Parameter(Mandatory = $true)][string]$Database,
[Parameter(Mandatory = $true)][string]$Username,
[Parameter(Mandatory = $true)][string]$Password
)
$connectionString = "Server=tcp:$Server,1433;Initial Catalog=$Database;Persist Security Info=False;User ID=$Username;Password=$Password;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;"
return [System.Data.SqlClient.SqlConnection]::new($connectionString)
}
function Convert-SqlScriptContent {
param(
[Parameter(Mandatory = $true)][string]$Content,
[Parameter(Mandatory = $true)][string]$FileName
)
$normalizedContent = $Content -replace "`r`n", "`n"
if ($FileName -match 'create_procedure|alter_procedure') {
$normalizedContent = [System.Text.RegularExpressions.Regex]::Replace(
$normalizedContent,
'(?im)^\s*(CREATE|ALTER)\s+PROCEDURE\b',
'CREATE OR ALTER PROCEDURE'
)
}
return $normalizedContent
}
function Split-SqlBatches {
param([Parameter(Mandatory = $true)][string]$Content)
return [System.Text.RegularExpressions.Regex]::Split($Content, '(?im)^\s*GO\s*$') |
Where-Object { -not [string]::IsNullOrWhiteSpace($_) }
}
function Invoke-SqlBatch {
param(
[Parameter(Mandatory = $true)][System.Data.SqlClient.SqlConnection]$Connection,
[Parameter(Mandatory = $true)][string]$Batch,
[Parameter(Mandatory = $true)][string]$FileName,
[Parameter(Mandatory = $true)][int]$BatchNumber
)
$command = $Connection.CreateCommand()
$command.CommandText = $Batch
$command.CommandTimeout = 120
try {
[void]$command.ExecuteNonQuery()
}
catch {
throw "Failed executing batch $BatchNumber from '$FileName': $($_.Exception.Message)"
}
finally {
$command.Dispose()
}
}
if ($env:SKIP_SQL_BOOTSTRAP -eq 'true') {
Write-Host 'Skipping SQL bootstrap because SKIP_SQL_BOOTSTRAP=true.'
exit 0
}
$resolvedScriptsPath = Resolve-Path $ScriptsPath -ErrorAction Stop
$sqlFiles = Get-ChildItem -Path $resolvedScriptsPath -Filter '*.sql' | Sort-Object Name
if (-not $sqlFiles) {
Write-Host "No SQL files found in $resolvedScriptsPath."
exit 0
}
$connection = Get-SqlConnection -Server $SqlServerFqdn -Database $DatabaseName -Username $SqlAdminLogin -Password $SqlAdminPassword
# Without this, PRINT output from the scripts is discarded and diagnostics go unnoticed.
$connection.add_InfoMessage({
param($eventSender, $eventArgs)
foreach ($sqlMessage in $eventArgs.Errors) {
Write-Host " [SQL] $($sqlMessage.Message)"
}
})
try {
$connection.Open()
foreach ($sqlFile in $sqlFiles) {
Write-Host "Applying $($sqlFile.Name)"
$scriptContent = Get-Content -Path $sqlFile.FullName -Raw -Encoding UTF8
$convertedContent = Convert-SqlScriptContent -Content $scriptContent -FileName $sqlFile.Name
$batches = @(Split-SqlBatches -Content $convertedContent)
for ($index = 0; $index -lt $batches.Count; $index++) {
Invoke-SqlBatch -Connection $connection -Batch $batches[$index] -FileName $sqlFile.Name -BatchNumber ($index + 1)
}
}
}
finally {
if ($connection.State -ne [System.Data.ConnectionState]::Closed) {
$connection.Close()
}
$connection.Dispose()
}