Merge "db: Don't pass strings to Connection.execute()"

This commit is contained in:
Zuul 2023-09-13 09:34:00 +00:00 committed by Gerrit Code Review
commit fc3e21d01b
4 changed files with 47 additions and 49 deletions

View File

@ -12,6 +12,8 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
from sqlalchemy import sql
def has_migrations(engine): def has_migrations(engine):
"""Returns true if at least one data row can be migrated. """Returns true if at least one data row can be migrated.
@ -22,16 +24,20 @@ def has_migrations(engine):
Note: This method can return a false positive if data migrations Note: This method can return a false positive if data migrations
are running in the background as it's being called. are running in the background as it's being called.
""" """
sql_query = ("select meta_data from image_locations where " sql_query = sql.text(
"INSTR(meta_data, '\"backend\":') > 0") "select meta_data from image_locations where "
"INSTR(meta_data, '\"backend\":') > 0"
)
# NOTE(abhishekk): INSTR function doesn't supported in postgresql # NOTE(abhishekk): INSTR function doesn't supported in postgresql
if engine.name == 'postgresql': if engine.name == 'postgresql':
sql_query = ("select meta_data from image_locations where " sql_query = sql.text(
"POSITION('\"backend\":' IN meta_data) > 0") "select meta_data from image_locations where "
"POSITION('\"backend\":' IN meta_data) > 0"
)
with engine.connect() as con: with engine.connect() as conn, conn.begin():
metadata_backend = con.execute(sql_query) metadata_backend = conn.execute(sql_query)
if metadata_backend.rowcount > 0: if metadata_backend.rowcount > 0:
return True return True
@ -40,16 +46,20 @@ def has_migrations(engine):
def migrate(engine): def migrate(engine):
"""Replace 'backend' with 'store' in meta_data column of image_locations""" """Replace 'backend' with 'store' in meta_data column of image_locations"""
sql_query = ("UPDATE image_locations SET meta_data = REPLACE(meta_data, " sql_query = sql.text(
"'\"backend\":', '\"store\":') where INSTR(meta_data, " "UPDATE image_locations SET meta_data = REPLACE(meta_data, "
" '\"backend\":') > 0") "'\"backend\":', '\"store\":') where INSTR(meta_data, "
" '\"backend\":') > 0"
)
# NOTE(abhishekk): INSTR function doesn't supported in postgresql # NOTE(abhishekk): INSTR function doesn't supported in postgresql
if engine.name == 'postgresql': if engine.name == 'postgresql':
sql_query = ("UPDATE image_locations SET meta_data = REPLACE(" sql_query = sql.text(
"meta_data, '\"backend\":', '\"store\":') where " "UPDATE image_locations SET meta_data = REPLACE("
"POSITION('\"backend\":' IN meta_data) > 0") "meta_data, '\"backend\":', '\"store\":') where "
"POSITION('\"backend\":' IN meta_data) > 0"
)
with engine.connect() as con: with engine.connect() as conn, conn.begin():
migrated_rows = con.execute(sql_query) migrated_rows = conn.execute(sql_query)
return migrated_rows.rowcount return migrated_rows.rowcount

View File

@ -2104,7 +2104,7 @@ class DBPurgeTests(test_utils.BaseTestCase):
dialect = engine.url.get_dialect() dialect = engine.url.get_dialect()
if dialect == sqlite.dialect: if dialect == sqlite.dialect:
connection.execute("PRAGMA foreign_keys = ON") connection.exec_driver_sql("PRAGMA foreign_keys = ON")
images = sqlalchemyutils.get_table( images = sqlalchemyutils.get_table(
engine, "images") engine, "images")

View File

@ -23,6 +23,7 @@ from alembic import script as alembic_script
from oslo_db.sqlalchemy import enginefacade from oslo_db.sqlalchemy import enginefacade
from oslo_db.sqlalchemy import test_fixtures from oslo_db.sqlalchemy import test_fixtures
from oslo_db.sqlalchemy import test_migrations from oslo_db.sqlalchemy import test_migrations
from sqlalchemy import sql
import sqlalchemy.types as types import sqlalchemy.types as types
from glance.db.sqlalchemy import alembic_migrations from glance.db.sqlalchemy import alembic_migrations
@ -154,21 +155,29 @@ class TestMysqlMigrations(test_fixtures.OpportunisticDBTestMixin,
def test_mysql_innodb_tables(self): def test_mysql_innodb_tables(self):
test_utils.db_sync(engine=self.engine) test_utils.db_sync(engine=self.engine)
total = self.engine.execute( with self.engine.connect() as conn:
"SELECT COUNT(*) " total = conn.execute(
"FROM information_schema.TABLES " sql.text(
"WHERE TABLE_SCHEMA='%s'" "SELECT COUNT(*) "
% self.engine.url.database) "FROM information_schema.TABLES "
"WHERE TABLE_SCHEMA=:database"
),
{'database': self.engine.url.database},
)
self.assertGreater(total.scalar(), 0, "No tables found. Wrong schema?") self.assertGreater(total.scalar(), 0, "No tables found. Wrong schema?")
noninnodb = self.engine.execute( with self.engine.connect() as conn:
"SELECT count(*) " noninnodb = conn.execute(
"FROM information_schema.TABLES " sql.text(
"WHERE TABLE_SCHEMA='%s' " "SELECT count(*) "
"AND ENGINE!='InnoDB' " "FROM information_schema.TABLES "
"AND TABLE_NAME!='migrate_version'" "WHERE TABLE_SCHEMA=:database "
% self.engine.url.database) "AND ENGINE!='InnoDB' "
count = noninnodb.scalar() "AND TABLE_NAME!='migrate_version'"
),
{'database': self.engine.url.database},
)
count = noninnodb.scalar()
self.assertEqual(0, count, "%d non InnoDB tables created" % count) self.assertEqual(0, count, "%d non InnoDB tables created" % count)

View File

@ -192,27 +192,6 @@ class WarningsFixture(pyfixtures.Fixture):
message='Using non-integer/slice indices on Row is deprecated ', message='Using non-integer/slice indices on Row is deprecated ',
) )
warnings.filterwarnings(
'ignore',
module='glance',
category=sqla_exc.SADeprecationWarning,
message=r'Passing a string to Connection.execute\(\) ',
)
warnings.filterwarnings(
'ignore',
module='glance',
category=sqla_exc.SADeprecationWarning,
message=r'The Engine.execute\(\) method is considered legacy ',
)
warnings.filterwarnings(
'ignore',
module='glance',
category=sqla_exc.SADeprecationWarning,
message=r'The Executable.execute\(\) method is considered legacy ',
)
# Enable general SQLAlchemy warnings also to ensure we're not doing # Enable general SQLAlchemy warnings also to ensure we're not doing
# silly stuff. It's possible that we'll need to filter things out here # silly stuff. It's possible that we'll need to filter things out here
# with future SQLAlchemy versions, but that's a good thing # with future SQLAlchemy versions, but that's a good thing