diff --git a/CHANGES.rst b/CHANGES.rst index c807a20..2d8e8cf 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -4,10 +4,11 @@ Changelog Here you can see the full list of changes between each SQLAlchemy-Utils release. -0.29.3 (2015-xx-xx) +0.29.3 (2015-01-24) ^^^^^^^^^^^^^^^^^^^ - Fixed analyze function runtime property handling for PostgreSQL >= 9.4 +- Fixed drop_database and create_database identifier quoting (#122) 0.29.2 (2015-01-08) diff --git a/sqlalchemy_utils/functions/database.py b/sqlalchemy_utils/functions/database.py index 8642290..b89442b 100644 --- a/sqlalchemy_utils/functions/database.py +++ b/sqlalchemy_utils/functions/database.py @@ -8,6 +8,8 @@ from sqlalchemy.engine.url import make_url from sqlalchemy.exc import ProgrammingError, OperationalError from sqlalchemy_utils.expressions import explain_analyze +from .orm import quote + class PlanAnalysis(object): def __init__(self, plan): @@ -429,20 +431,25 @@ def create_database(url, encoding='utf8', template=None): if not template: template = 'template0' - text = "CREATE DATABASE %s ENCODING '%s' TEMPLATE %s" % ( - database, encoding, template + text = "CREATE DATABASE {0} ENCODING '{1}' TEMPLATE {2}".format( + quote(engine, database), + encoding, + quote(engine, template) ) engine.execute(text) elif engine.dialect.name == 'mysql': - text = "CREATE DATABASE %s CHARACTER SET = '%s'" % (database, encoding) + text = "CREATE DATABASE {0} CHARACTER SET = '{1}'".format( + quote(engine, database), + encoding + ) engine.execute(text) elif engine.dialect.name == 'sqlite' and database != ':memory:': open(database, 'w').close() else: - text = "CREATE DATABASE %s" % database + text = 'CREATE DATABASE {0}'.format(quote(engine, database)) engine.execute(text) @@ -481,7 +488,7 @@ def drop_database(url): version = list( map( int, - engine.execute('SHOW server_version;').first()[0].split('.') + engine.execute('SHOW server_version').first()[0].split('.') ) ) pid_column = ( @@ -496,9 +503,9 @@ def drop_database(url): engine.execute(text) # Drop the database. - text = "DROP DATABASE %s" % database + text = 'DROP DATABASE {0}'.format(quote(engine, database)) engine.execute(text) else: - text = "DROP DATABASE %s" % database + text = 'DROP DATABASE {0}'.format(quote(engine, database)) engine.execute(text) diff --git a/tests/functions/test_database.py b/tests/functions/test_database.py index 24ff99f..49c13f1 100644 --- a/tests/functions/test_database.py +++ b/tests/functions/test_database.py @@ -28,7 +28,6 @@ class DatabaseTest(TestCase): class TestDatabaseSQLite(DatabaseTest): - url = 'sqlite:///sqlalchemy_utils.db' def setup(self): @@ -44,6 +43,30 @@ class TestDatabaseMySQL(DatabaseTest): url = 'mysql+pymysql://travis@localhost/db_test_sqlalchemy_util' +@mark.skipif('pymysql is None') +class TestDatabaseMySQLWithQuotedName(DatabaseTest): + url = 'mysql+pymysql://travis@localhost/db_test_sqlalchemy-util' + + +class TestDatabasePostgresWithQuotedName(DatabaseTest): + url = 'postgres://postgres@localhost/db_test_sqlalchemy-util' + + def test_template(self): + ( + flexmock(sa.engine.Engine) + .should_receive('execute') + .with_args( + '''CREATE DATABASE "db_test_sqlalchemy-util"''' + " ENCODING 'utf8' " + 'TEMPLATE "my-template"' + ) + ) + create_database( + 'postgres://postgres@localhost/db_test_sqlalchemy-util', + template='my-template' + ) + + class TestDatabasePostgres(DatabaseTest): url = 'postgres://postgres@localhost/db_test_sqlalchemy_util'