Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Connect-DbaInstance - Open connection to get CurrentDatabase #9308

Merged
merged 5 commits into from
Apr 12, 2024

Conversation

andreasjordan
Copy link
Contributor

@andreasjordan andreasjordan commented Mar 31, 2024

Type of Change

  • Bug fix (non-breaking change, fixes Restore-DbaDatabase fails when using server-SMO as SqlInstance #9307)
  • New feature (non-breaking change, adds functionality, fixes # )
  • Breaking change (affects multiple commands or functionality, fixes # )
  • Ran manual Pester test and has passed (.\tests\manual.pester.ps1)
  • Adding code coverage to existing functionality
  • Pester test is included
  • If new file reference added for test, has is been added to github.com/dataplat/appveyor-lab ?
  • Unit test is included
  • Documentation
  • Build system

Purpose

To be able to reliably evaluate property CurrentDatabase, the connection must first be opened.

See #9307 for more details.

@andreasjordan
Copy link
Contributor Author

No idea why the datamasking tests fail. Do you need more details on this pull request?

@wsmelton
Copy link
Member

I don't have an instance at work to test this but curious what affect (with your fix) does it have using a DedicatedAdminConnection ?

And then can we ensure at most doing a connection to Azure SQL still functions correctly? (just to double-check)

@andreasjordan
Copy link
Contributor Author

Should not have any effect on DAC as DAC is always NonPooled.

Will test Azure SQL now...

@andreasjordan
Copy link
Contributor Author

andreasjordan commented Apr 11, 2024

Works on Azure as well. Here I have some screenshots.

Old version:
image

Because of the empty $inputObject.ConnectionContext.CurrentDatabase a copy of the connection context is triggered - but both connection go to the same database: master.

New version:
image

Now the connection is opened during the second run of Connect-DbaInstance and the $inputObject.ConnectionContext.CurrentDatabase is not empty but filled with the correct value "master". So it is the correct database and no copy of the connection context is triggered.

Also did some query tests - everything works fine.

@andreasjordan
Copy link
Contributor Author

I can reproduce the failing test on my local lab. Will analyse the issue and add additional commits to this branch.

@andreasjordan
Copy link
Contributor Author

So this is really strange.

$dbTable.Columns.Refresh()

This refresh just clears the SMO at this point, so .Columns is empty resulting in an invalid SQL statement some lines later. This issue was not seen without my change to Connect-DbaInstance, because the SMO would be rebuild because of some calls to Connect-DbaInstance later.

If we force a NonPooled connection, the SMO is not cleared. So this issue might be related to the way SMO handles the connection pooling. As the data masking commands are not a central part of the module, I would like to leave it like this and use a non pooled connection to solve the issue.

@andreasjordan
Copy link
Contributor Author

Here is code that shows the problem:

$db = New-DbaDatabase -SqlInstance SQL01 -Name test
$db.Query('CREATE TABLE test (id int)')
$db.Tables['test'].Columns.Name      # shows id
Invoke-DbaQuery -SqlInstance $db.Parent -Database $db.Name -Query 'ALTER TABLE test ADD id2 int'
$db.Tables['test'].Columns.Name      # shows id
$db.Tables['test'].Columns.Refresh()
$db.Tables['test'].Columns.Name      # shows nothing
$null = Remove-DbaDatabase -SqlInstance $db.Parent -Database $db.Name -Confirm:$false

Here is code that works as expected:

$db = New-DbaDatabase -SqlInstance SQL01 -Name test
$db.Query('CREATE TABLE test (id int)')
$db.Tables['test'].Columns.Name      # shows id
$db.Query('ALTER TABLE test ADD id2 int')
$db.Tables['test'].Columns.Name      # shows id
$db.Tables['test'].Columns.Refresh()
$db.Tables['test'].Columns.Name      # shows id and id2
$null = Remove-DbaDatabase -SqlInstance $db.Parent -Database $db.Name -Confirm:$false

So the problem is somewhere inside of Invoke-DbaQuery.

I will try to find some time in the next days to get the root cause.

@andreasjordan
Copy link
Contributor Author

While analyzing, I discovered a bug that was introduced with #8764 into Invoke-DbaQuery.

$startedWithAnOpenConnection is only $true if not only $server is a SMO, but it also have the correct database context. If the target database context is different, we run Connect-DbaInstance which copies the connection context.

In this case, $null = $server | Disconnect-DbaInstance -Verbose:$false is executed and thus the initial $server is disconnected even we want to use it in the future. And with a disconnected connection, the .Refresh() just empties the SMO in that case.

This works:

$db = New-DbaDatabase -SqlInstance SQL01 -Name test1
$db.Query('CREATE TABLE test (id int)')
$db.Tables['test'].Columns.Name      # shows id
Invoke-DbaQuery -SqlInstance $db.Parent -Database $db.Name -Query 'ALTER TABLE test ADD id2 int' -Debug  # debug says: [Disconnect-DbaInstance] removing from connection hash
$db.Parent.ConnectionContext.Connect()   # reconnect the disconnected session
$db.Tables['test'].Columns.Name      # shows id
$db.Tables['test'].Columns.Refresh()
$db.Tables['test'].Columns.Name      # shows id, id2
$null = Remove-DbaDatabase -SqlInstance $db.Parent -Database $db.Name -Confirm:$false

I have seen another issue in Invoke-DbaQuery - so I will open an issue for that and provide a fix for that first. Then I will come back to this pull request again (probably open a new one).

@andreasjordan andreasjordan marked this pull request as draft April 12, 2024 08:03
@andreasjordan andreasjordan marked this pull request as ready for review April 12, 2024 10:49
@andreasjordan
Copy link
Contributor Author

Sorry about the back and forth on this pull requst. My initial aproch was not good and had some side effects. Now I optimized the code to only do the necessary steps. So only if the database context needs to be checked and only if the connection is closed and thus the CurrentDatabase is empty, we open the connection to get the value.

This solves the initial issue, test on DataMasking pass now without changing the code there and it works on Azure SQL Database as well without problems.

@potatoqualitee
Copy link
Member

I very much appreciate the time you took to investigate this, thank you. that was so interesting, and only one command across a whole suite! amazing. the fix looks perfect in scope 🙏🏼

@potatoqualitee potatoqualitee merged commit eacee59 into development Apr 12, 2024
12 checks passed
@potatoqualitee potatoqualitee deleted the ConnectDbaInstance_get_spid branch April 12, 2024 10:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Restore-DbaDatabase fails when using server-SMO as SqlInstance
3 participants