Skip to content

Commit

Permalink
fix(snowflake): reset the schema and database to the original schema …
Browse files Browse the repository at this point in the history
…after creating them
  • Loading branch information
cpcloud authored and gforsyth committed Aug 3, 2023
1 parent e10a6e5 commit 54ce26a
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 0 deletions.
28 changes: 28 additions & 0 deletions ibis/backends/snowflake/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from sqlalchemy.ext.compiler import compiles

import ibis
import ibis.common.exceptions as com
import ibis.expr.datatypes as dt
import ibis.expr.operations as ops
import ibis.expr.types as ir
Expand Down Expand Up @@ -505,12 +506,23 @@ def _get_temp_view_definition(
yield f"CREATE OR REPLACE TEMPORARY VIEW {name} AS {definition}"

def create_database(self, name: str, force: bool = False) -> None:
current_database = self.current_database
name = self._quote(name)
if_not_exists = "IF NOT EXISTS " * force
with self.begin() as con:
con.exec_driver_sql(f"CREATE DATABASE {if_not_exists}{name}")
# Snowflake automatically switches to the new database after creating
# it per
# https://docs.snowflake.com/en/sql-reference/sql/create-database#general-usage-notes
# so we switch back to the original database
con.exec_driver_sql(f"USE DATABASE {self._quote(current_database)}")

def drop_database(self, name: str, force: bool = False) -> None:
current_database = self.current_database
if name == current_database:
raise com.UnsupportedOperationError(
"Dropping the current database is not supported because its behavior is undefined"
)
name = self._quote(name)
if_exists = "IF EXISTS " * force
with self.begin() as con:
Expand All @@ -521,12 +533,28 @@ def create_schema(
) -> None:
name = ".".join(map(self._quote, filter(None, [database, name])))
if_not_exists = "IF NOT EXISTS " * force
current_database = self.current_database
current_schema = self.current_schema
with self.begin() as con:
con.exec_driver_sql(f"CREATE SCHEMA {if_not_exists}{name}")
# Snowflake automatically switches to the new schema after creating
# it per
# https://docs.snowflake.com/en/sql-reference/sql/create-schema#usage-notes
# so we switch back to the original schema
con.exec_driver_sql(
f"USE SCHEMA {self._quote(current_database)}.{self._quote(current_schema)}"
)

def drop_schema(
self, name: str, database: str | None = None, force: bool = False
) -> None:
if self.current_schema == name and (
database is None or self.current_database == database
):
raise com.UnsupportedOperationError(
"Dropping the current schema is not supported because its behavior is undefined"
)

name = ".".join(map(self._quote, filter(None, [database, name])))
if_exists = "IF EXISTS " * force
with self.begin() as con:
Expand Down
79 changes: 79 additions & 0 deletions ibis/backends/snowflake/tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import pytest

import ibis
import ibis.common.exceptions as com
from ibis.backends.snowflake.tests.conftest import _get_url
from ibis.util import gen_name

Expand Down Expand Up @@ -81,3 +82,81 @@ def test_timestamp_tz_column(simple_con):
).mutate(ts=lambda t: t.ts.to_timestamp("YYYY-MM-DD HH24-MI-SS"))
expr = t.ts
assert expr.execute().empty


def test_create_schema(simple_con):
schema = gen_name("test_create_schema")

cur_schema = simple_con.current_schema
cur_db = simple_con.current_database

simple_con.create_schema(schema)

assert simple_con.current_schema == cur_schema
assert simple_con.current_database == cur_db

simple_con.drop_schema(schema)

assert simple_con.current_schema == cur_schema
assert simple_con.current_database == cur_db


def test_create_database(simple_con):
database = gen_name("test_create_database")
cur_db = simple_con.current_database

simple_con.create_database(database)
assert simple_con.current_database == cur_db

simple_con.drop_database(database)
assert simple_con.current_database == cur_db


@pytest.fixture(scope="session")
def db_con():
return ibis.connect(_get_url())


@pytest.fixture(scope="session")
def schema_con():
return ibis.connect(_get_url())


def test_drop_current_db_not_allowed(db_con):
database = gen_name("test_create_database")
cur_db = db_con.current_database

db_con.create_database(database)

assert db_con.current_database == cur_db

with db_con.begin() as c:
c.exec_driver_sql(f'USE DATABASE "{database}"')

with pytest.raises(com.UnsupportedOperationError, match="behavior is undefined"):
db_con.drop_database(database)

with db_con.begin() as c:
c.exec_driver_sql(f"USE DATABASE {cur_db}")

db_con.drop_database(database)


def test_drop_current_schema_not_allowed(schema_con):
schema = gen_name("test_create_schema")
cur_schema = schema_con.current_schema

schema_con.create_schema(schema)

assert schema_con.current_schema == cur_schema

with schema_con.begin() as c:
c.exec_driver_sql(f'USE SCHEMA "{schema}"')

with pytest.raises(com.UnsupportedOperationError, match="behavior is undefined"):
schema_con.drop_schema(schema)

with schema_con.begin() as c:
c.exec_driver_sql(f"USE SCHEMA {cur_schema}")

schema_con.drop_schema(schema)

1 comment on commit 54ce26a

@ibis-squawk-bot
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Performance Alert ⚠️

Possible performance regression was detected for benchmark.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 3.

Benchmark suite Current: 54ce26a Previous: d585128 Ratio
ibis/tests/benchmarks/test_benchmarks.py::test_compile[medium-impala] 195.5899286645935 iter/sec (stddev: 0.02298798214952853) 635.6201377785405 iter/sec (stddev: 0.00004151384351205381) 3.25

This comment was automatically generated by workflow using github-action-benchmark.

Please sign in to comment.