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

Quote column names for ADD, RENAME and DROP COLUMN in JDBC connectors #13878

Merged
merged 3 commits into from
Aug 31, 2022

Conversation

ebyhr
Copy link
Member

@ebyhr ebyhr commented Aug 26, 2022

Description

Fixes #13839

Documentation

(x) No documentation is needed.

Release notes

(x) Release notes entries required with the following suggested text:

# ClickHouse, MariaDB, MySQL, Oracle, Phoenix, PostgreSQL, Redshift, SingleStore, SQL Server
* Fix query failure when renaming or dropping columns which should be quoted. ({issue}`13839`)

# Phoenix
* Fix query failure when adding a column which should be quoted. ({issue}`13839`)

@cla-bot cla-bot bot added the cla-signed label Aug 26, 2022
@ebyhr ebyhr force-pushed the ebi/jdbc-quote-column-names branch from a4bd8fe to d34fa91 Compare August 27, 2022 01:45
@ebyhr ebyhr changed the title Quote column names when renaming and dropping in JDBC connectors Quote column names for ADD, RENAME and DROP COLUMN in JDBC connectors Aug 27, 2022
@ebyhr ebyhr force-pushed the ebi/jdbc-quote-column-names branch 3 times, most recently from 2c992e2 to 16534ae Compare August 29, 2022 06:43
@ebyhr ebyhr marked this pull request as ready for review August 29, 2022 09:48
@ebyhr ebyhr requested review from wendigo, findepi and hashhar August 29, 2022 09:49
}

@Test(dataProvider = "testColumnNameDataProvider")
public void testDropColumnName(String columnName)
Copy link
Member

Choose a reason for hiding this comment

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

Let's merge this with testAddColumnName, since the setup isn't trivial (CREATE + exception handling)

Copy link
Member Author

Choose a reason for hiding this comment

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

Do you mean testRenameColumnName? The setup in testAddColumnName creates a table without error handling.

Copy link
Member

Choose a reason for hiding this comment

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

I meant to merge this with testAddColumnName.

that would mean two lines more in that test

assertUpdate("ALTER TABLE " + tableName + " DROP COLUMN " + nameInSql);
        assertTableColumnNames(tableName, "value");

ws the whole boilerplate of this method.

You can also rename the test method to testAddAndDropColumnName

@ebyhr ebyhr force-pushed the ebi/jdbc-quote-column-names branch from 16534ae to ddb4fb4 Compare August 30, 2022 00:17
@ebyhr ebyhr force-pushed the ebi/jdbc-quote-column-names branch 2 times, most recently from d3eef3e to 3e7d20c Compare August 30, 2022 01:30
@ebyhr
Copy link
Member Author

ebyhr commented Aug 30, 2022

Addressed comments.


private static String escape(String name)
{
return name.replace("'", "'" + "'");
Copy link
Member

Choose a reason for hiding this comment

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

"'" + "'" -> "''"

}
assertTableColumnNames(tableName, columnName.toLowerCase(ENGLISH));

String newNameInSql = toColumnNameInSql(columnName + "_new", delimited);
Copy link
Member

Choose a reason for hiding this comment

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

we don't test column name with trailing spaces.

  • let's use columnName here without appending anything
  • let's use static a;b$c column name when creating the table in this test

}

@Test(dataProvider = "testColumnNameDataProvider")
public void testDropColumnName(String columnName)
Copy link
Member

Choose a reason for hiding this comment

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

I meant to merge this with testAddColumnName.

that would mean two lines more in that test

assertUpdate("ALTER TABLE " + tableName + " DROP COLUMN " + nameInSql);
        assertTableColumnNames(tableName, "value");

ws the whole boilerplate of this method.

You can also rename the test method to testAddAndDropColumnName

@ebyhr ebyhr force-pushed the ebi/jdbc-quote-column-names branch 3 times, most recently from 1980096 to bc34280 Compare August 31, 2022 05:34
@ebyhr ebyhr force-pushed the ebi/jdbc-quote-column-names branch from bc34280 to 7306441 Compare August 31, 2022 05:40
@ebyhr ebyhr merged commit 3ebd9c2 into trinodb:master Aug 31, 2022
@ebyhr ebyhr deleted the ebi/jdbc-quote-column-names branch August 31, 2022 10:08
@ebyhr ebyhr mentioned this pull request Aug 31, 2022
@github-actions github-actions bot added this to the 395 milestone Aug 31, 2022
@hashhar
Copy link
Member

hashhar commented Sep 10, 2022

SQL Server sp_rename doesn't behave as you'd expect.

Here's a test to showcase that:

In Trino (with this PR applied):

trino:dbo> create table dbo.test2 ("crazy; drop table customer" int, "[crazy; drop table customer]" int);
CREATE TABLE
trino:dbo> describe dbo.test2;
            Column            |  Type   | Extra | Comment 
------------------------------+---------+-------+---------
 crazy; drop table customer   | integer |       |         
 [crazy; drop table customer] | integer |       |         
(2 rows)

Query 20220910_104005_00030_ci9mm, FINISHED, 3 nodes
Splits: 17 total, 17 done (100.00%)
0.54 [2 rows, 152B] [3 rows/s, 280B/s]

trino:dbo> alter table dbo.test2 rename column "crazy; drop table customer" to "crazy; drop table nation";
RENAME COLUMN
trino:dbo> alter table dbo.test2 rename column "[crazy; drop table customer]" to "[crazy; drop table nation]";
Query 20220910_104038_00032_ci9mm failed: Unclosed quotation mark after the character string '[crazy; drop table nation], 'COLUMN''.

trino:dbo> describe dbo.test2;
            Column            |  Type   | Extra | Comment 
------------------------------+---------+-------+---------
 crazy; drop table nation     | integer |       |         
 [crazy; drop table customer] | integer |       |         
(2 rows)

Query 20220910_104042_00033_ci9mm, FINISHED, 3 nodes
Splits: 17 total, 17 done (100.00%)
0.46 [2 rows, 150B] [4 rows/s, 329B/s]

In SQL Server

CREATE TABLE dbo.test ([crazy; drop table customer] int, "[crazy; drop table customer]" int);
SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'test';
-- crazy; drop table customer
-- [crazy; drop table customer]

EXEC sp_rename 'dbo.test.crazy; drop table customer', 'crazy; drop table nation', 'COLUMN';
EXEC sp_rename 'dbo.test.[crazy; drop table customer]', '[crazy; drop table nation]', 'COLUMN';
-- Errors out with SQL Error [15248] [S0001]: Either the parameter @objname is ambiguous or the claimed @objtype (COLUMN) is wrong.
EXEC sp_rename 'dbo.test."[crazy; drop table customer]"', '[crazy; drop table nation]', 'COLUMN';
SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'test';
-- crazy; drop table nation
-- [crazy; drop table nation]

This suggests that the 2nd argument to sp_rename is treated literally. The 1st argument follows the rules for identifiers so [ and " are treated as special characters and act as delimiters instead of literal values.

@hashhar
Copy link
Member

hashhar commented Sep 10, 2022

See also this in SQL Server:

CREATE TABLE dbo.test3 ([crazy" drop table customer] int, "[crazy drop table customer]" int);
SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'test3';
-- crazy" drop table customer 
-- [crazy drop table customer]
EXEC sp_rename 'dbo.test3.[crazy" drop table customer]', '[crazy" drop table nation]', 'COLUMN';
EXEC sp_rename 'dbo.test3."[crazy drop table customer]"', '[crazy" drop table customer]', 'COLUMN';
SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'test3';
-- [crazy" drop table nation]
-- [crazy" drop table customer]

@hashhar
Copy link
Member

hashhar commented Sep 10, 2022

i.e. sp_rename treats the 2nd argument always literally but the first argument follows the identifier naming rules and hence needs quoting.

Also looks like we should delegate the work of doing the quoting to SQL Server itself using https://docs.microsoft.com/en-us/sql/t-sql/functions/quotename-transact-sql?redirectedfrom=MSDN&view=sql-server-ver16

Something like:

SELECT QUOTENAME('crazy; drop table customer');
SELECT QUOTENAME('[crazy; drop table customer');
SELECT QUOTENAME('[crazy; drop table customer]');
SELECT QUOTENAME('[crazy;" " drop table customer]');
SELECT QUOTENAME('"[crazy;" " drop table customer]"');
SELECT QUOTENAME('["[crazy;" " drop table customer]"]');

@hashhar
Copy link
Member

hashhar commented Sep 12, 2022

I'll send a draft PR with the QUOTENAME approach and we can continue there.

}

@Test(dataProvider = "testColumnNameDataProvider")
public void testRenameColumnName(String columnName)
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do we need this new method testRenameColumnName? Why cannot we use/update old one testRenameColumn? What is the principal difference between them? How the name of these methods describe that difference?

Copy link
Member Author

@ebyhr ebyhr Sep 13, 2022

Choose a reason for hiding this comment

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

testRenameColumn should execute some operations to verify RENAME COLUMN works correctly (e.g. data didn't loss after renaming). testRenameColumnName should focus on test for column names. I separated these tests because the test purpose is different.

How the name of these methods describe that difference?

Please feel free to send PR if you feel the name isn't clear,

Copy link
Contributor

Choose a reason for hiding this comment

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

Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging this pull request may close these issues.

Quote column names when renaming or dropping column in JDBC connectors
4 participants