Skip to content

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

Merged
tavplubix merged 5 commits intoClickHouse:masterfrom
kafka1991:rename_support_ifexists
Nov 12, 2021
Merged

rename/exchange database/table/dictionary support IF EXISTS syntax#31081
tavplubix merged 5 commits intoClickHouse:masterfrom
kafka1991:rename_support_ifexists

Conversation

@kafka1991
Copy link
Copy Markdown
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
Copy Markdown
Contributor Author

Needs 'can be tested' label
@alexey-milovidov

@tavplubix tavplubix self-assigned this Nov 6, 2021
RENAME TABLE t0 TO t1; -- { serverError 57 }
DROP TABLE t1;
RENAME TABLE t0 TO t1;

Copy link
Copy Markdown
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
Copy Markdown
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.

ASTPtr from_db;
ASTPtr to_db;
ParserIdentifier db_name_p;
bool if_exists = s_if_exists.ignore(pos, expected);
Copy link
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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.

4 participants