Remove GROUP BY clause from CellMapping.get_by_project_id

Under postgresql, the GROUP BY clause in this query fails with:

  DBError: (psycopg2.ProgrammingError) column "instance_mappings.created_at"
  must appear in the GROUP BY clause or be used in an aggregate function

And we're getting lucky with using this under mysql because we don't
have the ONLY_FULL_GROUP_BY mode set (but we probably should).

This change removes the GROUP BY clause and re-writes the query
to avoid the joinedload() from the instance_mappings table and
simply do a subquery to get the cell_ids and then do a simple
IN query with the cell_mappings table. This fixes the GROUP BY
issue and should also make the query more efficient since we
won't have to load InstanceMappings ORM objects.

Change-Id: Idc9b5ad019205f447c82a702dd3391fa5dd20228
Closes-Bug: #1804271
(cherry picked from commit 248750578a)
This commit is contained in:
Matt Riedemann 2018-11-20 13:55:55 -05:00
parent 510bf75548
commit 25dc6a467c
1 changed files with 8 additions and 8 deletions

View File

@ -13,7 +13,6 @@
from oslo_log import log as logging from oslo_log import log as logging
from oslo_utils import versionutils from oslo_utils import versionutils
import six.moves.urllib.parse as urlparse import six.moves.urllib.parse as urlparse
from sqlalchemy.orm import joinedload
from sqlalchemy.sql.expression import asc from sqlalchemy.sql.expression import asc
from sqlalchemy.sql import false from sqlalchemy.sql import false
from sqlalchemy.sql import true from sqlalchemy.sql import true
@ -276,13 +275,14 @@ class CellMappingList(base.ObjectListBase, base.NovaObject):
@staticmethod @staticmethod
@db_api.api_context_manager.reader @db_api.api_context_manager.reader
def _get_by_project_id_from_db(context, project_id): def _get_by_project_id_from_db(context, project_id):
mappings = context.session.query( # SELECT DISTINCT cell_id FROM instance_mappings \
api_models.InstanceMapping).\ # WHERE project_id = $project_id;
filter_by(project_id=project_id).\ cell_ids = context.session.query(
group_by(api_models.InstanceMapping.cell_id).\ api_models.InstanceMapping.cell_id).filter_by(
options(joinedload('cell_mapping', innerjoin=True)).\ project_id=project_id).distinct().subquery()
all() # SELECT cell_mappings WHERE cell_id IN ($cell_ids);
return (mapping.cell_mapping for mapping in mappings) return context.session.query(api_models.CellMapping).filter(
api_models.CellMapping.id.in_(cell_ids)).all()
@classmethod @classmethod
def get_by_project_id(cls, context, project_id): def get_by_project_id(cls, context, project_id):