Source code for datacube.drivers.common_psql._ownership

# This file is part of the Open Data Cube, see https://opendatacube.org for more information
#
# Copyright (c) 2015-2026 ODC Contributors
# SPDX-License-Identifier: Apache-2.0

import logging
from typing import Literal

from sqlalchemy import Connection, text
from sqlalchemy.exc import ProgrammingError

from ._utils import as_role

_LOG = logging.getLogger(__name__)


[docs] def transfers_required( conn: Connection, new_owner: str, schema: str, object_type: Literal["tables", "matviews", "views"], objects: list[str] | None = None, prefix: str | None = None, ) -> list[tuple[str, str]]: """ Determine which objects in a schema need to be transferred to a new owner. One and only one of objects or prefix must be specified. :param conn: A SQLAlchemy connection object :param new_owner: The new owner, the database role that should own the objects. :param schema: The schema containing the objects. :param object_type: The type of objects to check. One of "tables", "matviews", "views". :param objects: A list of object names to check. :param prefix: An object name prefix to check. :return: A list of (name, old_owner) tuples of matching objects. """ if objects is None == prefix is None: raise ValueError("Must specify one of either objects or prefix") transfers: list[tuple[str, str]] = [] defs = { "tables": ("tablename", "tableowner", "pg_tables"), "matviews": ("matviewname", "matviewowner", "pg_matviews"), "views": ("viewname", "viewowner", "pg_views"), } n, o, t = defs[object_type] sql = f"select {n}, {o} from {t} where schemaname = '{schema}'" if objects is not None: sql += f" and {n} in {tuple(objects)}" else: sql += f" and {n} like '{prefix}%'" for row in conn.execute(text(sql)): if row[1] != new_owner: transfers.append((row[0], row[1])) return transfers
[docs] def transfer_ownership( conn: Connection, schema: str, obj_name: str, current_owner: str, new_owner: str, object_type: Literal["tables", "matviews", "views"], ) -> bool: """ Transfer ownership of a database object to a new owner. :param conn: A SQLAlchemy connection object :param schema: The schema containing the object. :param obj_name: The name of the object. :param current_owner: The current owner of the object. :param new_owner: The desired new owner of the object. :param object_type: The type of object, one of "tables", "matviews", "views". :return: True if the transfer succeeded, False otherwise. """ objs = { "tables": "table", "matviews": "materialized view", "views": "view", } sql = f"alter {objs[object_type]} {schema}.{obj_name} owner to {new_owner}" try: # Attempt as session user # (hopefully we're a superuser or have both roles and required perms) conn.execute(text(sql)) return True except ProgrammingError: _LOG.info( "Cannot transfer ownership as session user. Trying with appropriate role..." ) matviews = object_type == "matviews" desired_role = new_owner if matviews else current_owner try: with as_role(conn, desired_role) as attempt_conn: attempt_conn.execute(text(sql)) return True except ProgrammingError: _LOG.warning( f"Cannot transfer ownership of {objs[object_type]} {obj_name} " f"from {current_owner} to {new_owner}: session user is not a " f"superuser or session user cannot become {desired_role} or " f"{desired_role} does not have CREATE permission on {schema} schema." ) return False