Skip to content

Commit

Permalink
don't create a schema if it already exists (#446)
Browse files Browse the repository at this point in the history
* don't create a schema if it's already there

* typo
  • Loading branch information
drewbanin authored May 24, 2017
1 parent e9177e2 commit 637ebaf
Show file tree
Hide file tree
Showing 7 changed files with 60 additions and 15 deletions.
9 changes: 9 additions & 0 deletions dbt/adapters/default.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,11 @@ def query_for_existing(cls, profile, schema, model_name=None):
raise dbt.exceptions.NotImplementedException(
'`query_for_existing` is not implemented for this adapter!')

@classmethod
def check_schema_exists(cls, profile, schema):
raise dbt.exceptions.NotImplementedException(
'`check_schema_exists` is not implemented for this adapter!')

###
# FUNCTIONS THAT SHOULD BE ABSTRACT
###
Expand Down Expand Up @@ -562,6 +567,10 @@ def table_exists(cls, profile, schema, table, model_name=None):
exists = tables.get(table) is not None
return exists

@classmethod
def check_schema_exists(cls, profile, schema):
return cls.check_schema_exists(profile, schema)

@classmethod
def already_exists(cls, profile, schema, table, model_name=None):
"""
Expand Down
10 changes: 10 additions & 0 deletions dbt/adapters/postgres.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,16 @@ def query_for_existing(cls, profile, schema, model_name=None):
return dict(existing)

@classmethod
def check_schema_exists(cls, profile, schema, model_name=None):
sql = """
select count(*) from pg_namespace where nspname = '{schema}'
""".format(schema=schema).strip() # noqa

connection, cursor = cls.add_query(profile, sql, model_name)
results = cursor.fetchone()

return results[0] > 0

def cancel_connection(cls, profile, connection):
connection_name = connection.get('name')
pid = connection.get('handle').get_backend_pid()
Expand Down
14 changes: 14 additions & 0 deletions dbt/adapters/snowflake.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,20 @@ def create_schema(cls, profile, schema, model_name=None):
sql = cls.get_create_schema_sql(schema)
return cls.add_query(profile, sql, model_name, select_schema=False)

@classmethod
def check_schema_exists(cls, profile, schema, model_name=None):
sql = """
select count(*)
from INFORMATION_SCHEMA.SCHEMATA
where SCHEMA_NAME = '{schema}'
""".format(schema=schema).strip() # noqa

connection, cursor = cls.add_query(profile, sql, model_name,
select_schema=False)
results = cursor.fetchone()

return results[0] > 0

@classmethod
def add_query(cls, profile, sql, model_name=None, auto_begin=True,
select_schema=True):
Expand Down
14 changes: 12 additions & 2 deletions dbt/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -700,9 +700,19 @@ def try_create_schema(self):
profile = self.project.run_environment()
adapter = get_adapter(profile)

try:
schema_name = adapter.get_default_schema(profile)
schema_name = adapter.get_default_schema(profile)
model_name = None

connection = adapter.begin(profile)
schema_exists = adapter.check_schema_exists(profile, schema_name)
adapter.commit(connection)

if schema_exists:
logger.debug('schema {} already exists -- '
'not creating'.format(schema_name))
return

try:
connection = adapter.begin(profile)
adapter.create_schema(profile, schema_name)
adapter.commit(connection)
Expand Down
3 changes: 1 addition & 2 deletions test/integration/010_permission_tests/models/view.sql
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@

-- permission should be denied here
select * from "private"."seed"
select * from "{{ this.schema }}"."seed"
23 changes: 13 additions & 10 deletions test/integration/010_permission_tests/test_permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ class TestPermissions(DBTIntegrationTest):
def setUp(self):
DBTIntegrationTest.setUp(self)

self.run_sql_file("test/integration/010_permission_tests/tearDown.sql")
self.run_sql_file("test/integration/010_permission_tests/seed.sql")

def tearDown(self):
Expand All @@ -23,16 +22,20 @@ def models(self):
return "test/integration/010_permission_tests/models"

@attr(type='postgres')
def test_read_permissions(self):
def test_create_schema_permissions(self):
# the noaccess user does not have permissions to create a schema -- this should fail

failed = False

# run model as the noaccess user
# this will fail with a RuntimeError, which should be caught by the dbt runner

# it's not, wrapping this for now
# TODO handle RuntimeErrors for connection failure
self.run_sql('drop schema if exists "{}" cascade'.format(self.unique_schema()))
try:
self.run_dbt(['run', '--target', 'noaccess'])
except:
pass
except RuntimeError:
failed = True

self.assertTrue(failed)

# now it should work!
self.run_sql('create schema "{}"'.format(self.unique_schema()))
self.run_sql('grant usage on schema "{}" to noaccess'.format(self.unique_schema()))

self.run_dbt(['run', '--target', 'noaccess'])
2 changes: 1 addition & 1 deletion test/setup_db.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ psql -c "GRANT CREATE, CONNECT ON DATABASE dbt TO root;" -U postgres

psql -c "CREATE ROLE noaccess WITH UNENCRYPTED PASSWORD 'password' NOSUPERUSER;" -U postgres;
psql -c "ALTER ROLE noaccess WITH LOGIN;" -U postgres
psql -c "GRANT CREATE, CONNECT ON DATABASE dbt TO noaccess;" -U postgres;
psql -c "GRANT CONNECT ON DATABASE dbt TO noaccess;" -U postgres;

set +x

0 comments on commit 637ebaf

Please sign in to comment.