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

rename/exchange database/table/dictionary support IF EXISTS syntax #31081

Merged
merged 5 commits into from Nov 12, 2021
Merged

rename/exchange database/table/dictionary support IF EXISTS syntax #31081

merged 5 commits into from Nov 12, 2021

Conversation

kafka1991
Copy link
Contributor

@kafka1991 kafka1991 commented Nov 4, 2021

I hereby agree to the terms of the CLA available at: https://yandex.ru/legal/cla/?lang=en

Changelog category (leave one):

  • Improvement

Changelog entry (a user-readable short description of the changes that goes to CHANGELOG.md):
Support IF EXISTS modifier for RENAME DATABASE/TABLE/DICTIONARY query, If this directive is used, one will not get an error if the DATABASE/TABLE/DICTIONARY to be renamed doesn't exist.

@robot-clickhouse robot-clickhouse added the pr-improvement Pull request with some product improvements label Nov 4, 2021
@kafka1991
Copy link
Contributor Author

Needs 'can be tested' label
@alexey-milovidov

@tavplubix tavplubix self-assigned this Nov 6, 2021
@@ -13,17 +13,23 @@ CREATE TABLE t2 ENGINE=MergeTree() ORDER BY tuple() AS SELECT rowNumberInAllBloc
EXCHANGE TABLES t1 AND t3; -- { serverError 60 }
EXCHANGE TABLES t4 AND t2; -- { serverError 60 }
RENAME TABLE t0 TO t1; -- { serverError 57 }
DROP TABLE t1;
RENAME TABLE t0 TO t1;

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's better to make new test for these queries. Or, at least, add new queries to the end of this test without modifying existing queries.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK, has fixed.

@@ -67,6 +68,7 @@ bool ParserRenameQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
ASTPtr from_db;
ASTPtr to_db;
ParserIdentifier db_name_p;
bool if_exists = s_if_exists.ignore(pos, expected);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also need to update ASTRenameQuery::formatQueryImpl(...) to make formatter consistent with parser.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.

return typeid_cast<DatabaseReplicated *>(database.get())->tryEnqueueReplicatedDDL(query_ptr, getContext());
if (rename.exchange)
{
ignore = rename.dictionary ? (!database_catalog.isDictionaryExist(StorageID(elem.to_database_name, elem.to_table_name)) ||
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like special check for dictionaries is not needed, because if an DDL-dictionary exists, then isTableExist(...) returns true.

Copy link
Contributor Author

@kafka1991 kafka1991 Nov 8, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK
It is impossible for table/dictionary with the same StorageID to exist in the same database

Comment on lines +101 to +115
bool exchange_tables;
if (rename.exchange)
{
exchange_tables = true;
}
else if (rename.rename_if_cannot_exchange)
{
exchange_tables = database_catalog.isTableExist(StorageID(elem.to_database_name, elem.to_table_name), getContext());
renamed_instead_of_exchange = !exchange_tables;
}
else
{
exchange_tables = false;
database_catalog.assertTableDoesntExist(StorageID(elem.to_database_name, elem.to_table_name), getContext());
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will this logic work correctly after the changes?

Copy link
Contributor Author

@kafka1991 kafka1991 Nov 8, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, it work correctly.
when rename.rename_if_cannot_exchange is true, rename.exchange is false, in which situation only check the source table is exists or not.

Comment on lines 94 to 95
ignore = rename.dictionary ? (!database_catalog.isDictionaryExist(StorageID(elem.to_database_name, elem.to_table_name))) :
(!database_catalog.isTableExist(StorageID(elem.to_database_name, elem.to_table_name), getContext()));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean from_database_name and from_table_name?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo.

@tavplubix
Copy link
Member

Thanks for contributing into ClickHouse!

The RENAME ... IF EXISTS a TO b query, that renames a to b if a exists and does nothing if a doesn't exist, makes sense. I've just found that people ask for this feature in MySQL for 17 years :)

However, I'm not sure what is the semantics of EXCHANGE ... IF EXISTS a AND b and how should it work, because EXCHANGE query requires that both a and b must exist, so it's not clear to which table (or dictionary) this condition should be applied and what EXCHANGE query should do if only one table (or dictionary) exists. We have rename_if_cannot_exchange flag that means "exchange a and b tables if both tables exist or rename a to b if b does not", but it's not available for users (it's only used internally in the CREATE OR REPLACE query). Maybe we can make it available, but I think that IF EXISTS is not suitable modifier, we need another syntax for this (and we need to think it over).

So I suggest not to consider EXCHANGE query for now and allow IF EXISTS modifier for RENAME query only.

@kafka1991
Copy link
Contributor Author

kafka1991 commented Nov 8, 2021

Thanks for contributing into ClickHouse!

The RENAME ... IF EXISTS a TO b query, that renames a to b if a exists and does nothing if a doesn't exist, makes sense. I've just found that people ask for this feature in MySQL for 17 years :)

However, I'm not sure what is the semantics of EXCHANGE ... IF EXISTS a AND b and how should it work, because EXCHANGE query requires that both a and b must exist, so it's not clear to which table (or dictionary) this condition should be applied and what EXCHANGE query should do if only one table (or dictionary) exists. We have rename_if_cannot_exchange flag that means "exchange a and b tables if both tables exist or rename a to b if b does not", but it's not available for users (it's only used internally in the CREATE OR REPLACE query). Maybe we can make it available, but I think that IF EXISTS is not suitable modifier, we need another syntax for this (and we need to think it over).

So I suggest not to consider EXCHANGE query for now and allow IF EXISTS modifier for RENAME query only.

For EXCHANGE ... IF EXISTS a AND b, the semantics of if existsdoes unclear, we should find a more suitable modifier. So we keep the IF EXISTS implementation and limit the sql interface here for EXCHANGE.

@kafka1991
Copy link
Contributor Author

the failed case of Integration tests has nothing to do with this pr.

@tavplubix tavplubix merged commit 209d1a2 into ClickHouse:master Nov 12, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
pr-improvement Pull request with some product improvements
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants