Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion private/functions/Get-LoginPasswordHash.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,9 @@ function Get-LoginPasswordHash {
$hashedPass = $server.ConnectionContext.ExecuteScalar($sql)
} catch {
try {
$hashedPassDt = $server.Databases["master"].ExecuteWithResults($sql)
# Same query as above, so it runs on the connection as well. Going through the master
# database would leave the connection of the caller there. See #10555.
$hashedPassDt = $server.ConnectionContext.ExecuteWithResults($sql)
$hashedPass = $hashedPassDt.Tables[0].Rows[0].Item(0)
} catch {
Stop-Function -Message "Failed to retrieve password hash for login $($Login.Name)" -ErrorRecord $_ -Target $Login -Continue
Expand Down
4 changes: 3 additions & 1 deletion private/functions/Get-OfflineSqlFileStructure.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ Internal function. Returns dictionary object that contains file structures for S

if ($filestream) {
$sql = "SELECT COALESCE(SERVERPROPERTY('FilestreamConfiguredLevel'),0) AS fs"
$fscheck = $server.databases['master'].ExecuteWithResults($sql)
# SERVERPROPERTY does not depend on the current database, so this runs on the connection. Going
# through the master database would leave the connection of the caller there. See #10555.
$fscheck = $server.ConnectionContext.ExecuteWithResults($sql)
if ($fscheck.tables.fs -eq 0) { return $false }
}

Expand Down
4 changes: 3 additions & 1 deletion public/Connect-DbaInstance.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ function Connect-DbaInstance {
https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlconnectionstringbuilder.aspx
https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlconnection.aspx

To execute SQL commands directly: $server.ConnectionContext.ExecuteReader($sql) or $server.Databases['master'].ExecuteNonQuery($sql)
To execute SQL commands directly: $server.ConnectionContext.ExecuteReader($sql) or $server.ConnectionContext.ExecuteNonQuery($sql)

Run statements through the connection context rather than through a database object. A database object executes on the same connection and leaves it in that database, which changes the database of every later command that reuses the connection.

.PARAMETER SqlInstance
The target SQL Server instance or instances. This can be a collection and receive pipeline input to allow the function to be executed against multiple SQL Server instances.
Expand Down
4 changes: 3 additions & 1 deletion public/Export-DbaLogin.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,9 @@ function Export-DbaLogin {
try {
$hashedPass = $server.ConnectionContext.ExecuteScalar($sql)
} catch {
$hashedPassDt = $server.Databases['master'].ExecuteWithResults($sql)
# Same query as above, so it runs on the connection as well. Going through the
# master database would leave the connection of the caller there. See #10555.
$hashedPassDt = $server.ConnectionContext.ExecuteWithResults($sql)
$hashedPass = $hashedPassDt.Tables[0].Rows[0].Item(0)
}

Expand Down
4 changes: 3 additions & 1 deletion public/Get-DbaDbDetachedFileInfo.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,9 @@ function Get-DbaDbDetachedFileInfo {
$collationsql = "SELECT name FROM fn_helpcollations() WHERE COLLATIONPROPERTY(name, N'COLLATIONID') = $collationid"

try {
$dataset = $server.databases['master'].ExecuteWithResults($collationsql)
# fn_helpcollations is available in every database, so this runs on the connection. Going
# through the master database would leave the connection of the caller there. See #10555.
$dataset = $server.ConnectionContext.ExecuteWithResults($collationsql)
$collation = "$($dataset.Tables[0].Rows[0].Item(0))"
} catch {
$collation = $collationid
Expand Down
4 changes: 3 additions & 1 deletion public/New-DbaLogin.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,9 @@ function New-DbaLogin {
try {
$hashedPass = $sourceServer.ConnectionContext.ExecuteScalar($sql)
} catch {
$hashedPassDt = $sourceServer.Databases['master'].ExecuteWithResults($sql)
# Same query as above, so it runs on the connection as well. Going through the
# master database would leave the connection of the caller there. See #10555.
$hashedPassDt = $sourceServer.ConnectionContext.ExecuteWithResults($sql)
$hashedPass = $hashedPassDt.Tables[0].Rows[0].Item(0)
}

Expand Down
6 changes: 4 additions & 2 deletions public/Remove-DbaAgentJob.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,10 @@ function Remove-DbaAgentJob {
$dropSchedule = 0
}
Write-Message -Level SomewhatVerbose -Message "Removing job"
$dropJobQuery = ("EXEC dbo.sp_delete_job @job_name = '{0}', @delete_history = {1}, @delete_unused_schedule = {2}" -f $currentJob.Name.Replace("'", "''"), $dropHistory, $dropSchedule)
$server.Databases['msdb'].ExecuteNonQuery($dropJobQuery)
# The procedure is named in full so that it does not need the connection to be in msdb.
# Going through the msdb database would leave the connection of the caller there. See #10555.
$dropJobQuery = ("EXEC msdb.dbo.sp_delete_job @job_name = '{0}', @delete_history = {1}, @delete_unused_schedule = {2}" -f $currentJob.Name.Replace("'", "''"), $dropHistory, $dropSchedule)
$server.ConnectionContext.ExecuteNonQuery($dropJobQuery)
$server.JobServer.Jobs.Refresh()
Remove-TeppCacheItem -SqlInstance $server -Type job -Name $currentJob.Name
[PSCustomObject]@{
Expand Down
5 changes: 4 additions & 1 deletion public/Set-DbaTempDbConfig.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,10 @@ ORDER BY file_id;
} else {
if ($Pscmdlet.ShouldProcess($instance, "Executing query and informing that a restart is required.")) {
try {
$server.Databases['master'].ExecuteNonQuery($sql)
# ALTER DATABASE does not depend on the current database, so this runs on the
# connection. Going through the master database would leave the connection of the
# caller there. See #10555.
$server.ConnectionContext.ExecuteNonQuery($sql)
Write-Message -Level Verbose -Message "tempdb successfully reconfigured."

[PSCustomObject]@{
Expand Down
34 changes: 34 additions & 0 deletions tests/Get-DbaDbDetachedFileInfo.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,38 @@ Describe $CommandName -Tag IntegrationTests {
$results.LogFiles | Should -Not -BeNullOrEmpty
}
}

Context "The connection of the caller keeps its database (#10555)" {
BeforeAll {
$PSDefaultParameterValues["*-Dba*:EnableException"] = $true

# The collation lookup used to run through the master database, which leaves the connection of
# the caller there. Only a non-pooled connection shows it, because SMO reopens a pooled one at
# its default database.
$callerServer = Connect-DbaInstance -SqlInstance $TestConfig.InstanceSingle -Database msdb -NonPooledConnection
$callerResult = Get-DbaDbDetachedFileInfo -SqlInstance $callerServer -Path $path

$PSDefaultParameterValues.Remove("*-Dba*:EnableException")
}

AfterAll {
$PSDefaultParameterValues["*-Dba*:EnableException"] = $true

$null = $callerServer | Disconnect-DbaInstance

$PSDefaultParameterValues.Remove("*-Dba*:EnableException")
}

It "still reads the detached file" {
$callerResult.Name | Should -Be $dbname
}

It "still resolves the collation" {
$callerResult.Collation | Should -Not -BeNullOrEmpty
}

It "leaves the connection in the database it was on" {
$callerServer.ConnectionContext.ExecuteScalar("SELECT DB_NAME()") | Should -Be "msdb"
}
}
}
34 changes: 34 additions & 0 deletions tests/Remove-DbaAgentJob.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -159,4 +159,38 @@ Describe $CommandName -Tag IntegrationTests {
(Get-DbaAgentJob -SqlInstance $TestConfig.InstanceSingle -Job dbatoolsci_testjob_validation) | Should -Not -BeNullOrEmpty
}
}

Context "The connection of the caller keeps its database (#10555)" {
BeforeAll {
$PSDefaultParameterValues["*-Dba*:EnableException"] = $true

$contextJobName = "dbatoolsci_testjob_context"
$null = New-DbaAgentJob -SqlInstance $TestConfig.InstanceSingle -Job $contextJobName

# sp_delete_job used to be run through the msdb database, which leaves the connection of the
# caller there. Only a non-pooled connection shows it, because SMO reopens a pooled one at its
# default database.
$callerServer = Connect-DbaInstance -SqlInstance $TestConfig.InstanceSingle -NonPooledConnection
$null = Remove-DbaAgentJob -SqlInstance $callerServer -Job $contextJobName

$PSDefaultParameterValues.Remove("*-Dba*:EnableException")
}

AfterAll {
$PSDefaultParameterValues["*-Dba*:EnableException"] = $true

$null = $callerServer | Disconnect-DbaInstance
$null = Get-DbaAgentJob -SqlInstance $TestConfig.InstanceSingle -Job $contextJobName | Remove-DbaAgentJob -ErrorAction SilentlyContinue

$PSDefaultParameterValues.Remove("*-Dba*:EnableException")
}

It "still removes the job" {
Get-DbaAgentJob -SqlInstance $TestConfig.InstanceSingle -Job $contextJobName | Should -BeNullOrEmpty
}

It "leaves the connection in the database it was on" {
$callerServer.ConnectionContext.ExecuteScalar("SELECT DB_NAME()") | Should -Be "master"
}
}
}