@@ -313,6 +313,38 @@ def test_unregister_problematic_behavior(self, duckdb_cursor):
313313 # This should not have affected the existing view:
314314 assert duckdb_cursor .execute ("select * from vw" ).fetchone () == (0 ,)
315315
316+ def test_unregister_quoted_table_names (self , duckdb_cursor ):
317+ """Test that unregister works for quoted tables."""
318+ rel = duckdb_cursor .sql ("select 'test', 'data'" )
319+
320+ table_name = 'test with .s and "s and s'
321+ duckdb_cursor .register (table_name , rel )
322+ duckdb_cursor .unregister (table_name )
323+
324+ escaped_table_name = table_name .replace ('"' , '""' )
325+ with pytest .raises (duckdb .CatalogException ):
326+ duckdb_cursor .sql (f'select * from "{ escaped_table_name } "' )
327+
328+ def test_unregister_with_scary_name (self , duckdb_cursor ):
329+ """Test that unregister doesn't have side effects."""
330+ rel = duckdb_cursor .sql ("select 'test', 'data'" )
331+
332+ scary_name = 'test";create table foo as select * from range(10);--'
333+ # make sure a view with the name "test" exists
334+ duckdb_cursor .register ("test" , rel )
335+ duckdb_cursor .register (scary_name , rel )
336+ # try to trick unregister (which uses DROP VIEW) to run another statement
337+ duckdb_cursor .unregister (scary_name )
338+
339+ # hopefully that didn't happen
340+ with pytest .raises (duckdb .CatalogException ):
341+ duckdb_cursor .sql ("select * from foo" )
342+
343+ # verify the scary name table was properly unregistered
344+ escaped_scary_name = scary_name .replace ('"' , '""' )
345+ with pytest .raises (duckdb .CatalogException ):
346+ duckdb_cursor .sql (f'select * from "{ escaped_scary_name } "' )
347+
316348 @pytest .mark .parametrize ("pandas" , [NumpyPandas (), ArrowPandas ()])
317349 def test_relation_out_of_scope (self , pandas ):
318350 def temporary_scope ():
0 commit comments