diff --git a/src/databricks/sql/utils.py b/src/databricks/sql/utils.py index 2961a1f59..87eae8c5a 100644 --- a/src/databricks/sql/utils.py +++ b/src/databricks/sql/utils.py @@ -144,9 +144,9 @@ def escape_string(self, item): if isinstance(item, bytes): item = item.decode("utf-8") # This is good enough when backslashes are literal, newlines are just followed, and the way - # to escape a single quote is to put two single quotes. + # to escape a single quote is to precede it with 2 backslashes. # (i.e. only special character is single quote) - return "'{}'".format(item.replace("'", "''")) + return "'{}'".format(item.replace("'", "\\'")) def escape_sequence(self, item): l = map(str, map(self.escape_item, item)) diff --git a/tests/e2e/driver_tests.py b/tests/e2e/driver_tests.py index 9e400770d..439737242 100644 --- a/tests/e2e/driver_tests.py +++ b/tests/e2e/driver_tests.py @@ -288,6 +288,20 @@ def test_get_columns(self): for table in table_names: cursor.execute('DROP TABLE IF EXISTS {}'.format(table)) + def test_escape_single_quotes(self): + with self.cursor({}) as cursor: + table_name = 'table_{uuid}'.format(uuid=str(uuid4()).replace('-', '_')) + # Test escape syntax directly + cursor.execute("CREATE TABLE IF NOT EXISTS {} AS (SELECT 'you\\'re' AS col_1)".format(table_name)) + cursor.execute("SELECT * FROM {} WHERE col_1 LIKE 'you\\'re'".format(table_name)) + rows = cursor.fetchall() + assert rows[0]["col_1"] == "you're" + + # Test escape syntax in parameter + cursor.execute("SELECT * FROM {} WHERE {}.col_1 LIKE %(var)s".format(table_name, table_name), parameters={"var": "you're"}) + rows = cursor.fetchall() + assert rows[0]["col_1"] == "you're" + def test_get_schemas(self): with self.cursor({}) as cursor: database_name = 'db_{uuid}'.format(uuid=str(uuid4()).replace('-', '_'))