-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Implement DatabaseManager::SetDefaultDatabase #7878
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
Conversation
The `DatabaseManager::default_database` is returned by `DatabaseManager::GetDefaultDatabase` when the default catalog in the search path is invalid. This commit adds a method to change `default_database`. This makes it possible that new `Connection`s can use a database other than 'memory' as default.
src/main/database_manager.cpp
Outdated
auto has_active_transaction = context.transaction.HasActiveTransaction(); | ||
if (!has_active_transaction) { | ||
context.transaction.BeginTransaction(); | ||
} | ||
|
||
auto db_entry = GetDatabase(context, new_value); | ||
|
||
if (!has_active_transaction) { | ||
context.transaction.ClearTransaction(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I want to validate here that the database referred to by new_value
actually exists. However, GetDatabase
requires a transaction to be active. What is the best way to create a transaction when non is active? Or is there another way to validate that the database exists which does not require to start a transaction?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
RunFunctionInTransaction
it's part of ClientContext, client_context.cpp:969
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the hint. I changed the code to use this function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the PR! Looks good to me - one comment:
src/main/database_manager.cpp
Outdated
void DatabaseManager::SetDefaultDatabase(ClientContext &context, const string &new_value) { | ||
optional_ptr<AttachedDatabase> db_entry; | ||
|
||
context.RunFunctionInTransaction([&]() { db_entry = GetDatabase(context, new_value); }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
RunFunctionInTransaction
is very heavy-handed. It launches a new transaction if none is active (and commits it afterwards). Generally almost all code in DuckDB (be it parser, planner, optimizer, executor) is run with an active transaction already. Is this necessary only for the unittest? I imagine that when this function is used internally it will be used in locations where a transaction already exists.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed I added this to make a unit test case succeed in which I did not start a transaction before calling SetDefaultDatabase
. Otherwise, an InternalException
with message "TransactionContext::ActiveTransaction called without active transaction" would be thrown. I thought that it would be worth avoiding this exception by starting a new transaction, considering that RunFunctionInTransaction
does not have a significant overhead when there is already an active transaction, does it?
But if I understand you correctly, you think that it is better to remove RunFunctionInTransaction
and just call GetDatabase
directly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, most functions in the catalog rely on a transaction existing. I think it is better to remove it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All right, I removed the call to RunFunctionInTransaction
. Thank you for the feedback.
…faultDatabase' Most functions that call 'SetDefaultDatabase' will already have an active transaction, hence it is not necessary to create a new one.
The
DatabaseManager::default_database
is returned byDatabaseManager::GetDefaultDatabase
when the default catalog in the search path is invalid. In this PR, a methodSetDefaultDatabase
is added which can be used to changedefault_database
.With this change, new
Connection
s can use a database as default other than the one that was added first to theDatabaseManager
.The value for
default_database
can only be changed internally by callingSetDefaultDatabase
. There is noSET GLOBAL
option for this implemented in this PR.I have written a unit test for this, but did not know where to put it. If you could tell me a good location for it, I can add it to the PR, too.