def drop_all_keys(session, key_table, candidate_classes):
if not candidate_classes:<EOL><INDENT>return<EOL><DEDENT>candidate_classes = set([c.__tablename__ for c in candidate_classes])<EOL>all_rows = (<EOL>session.query(key_table)<EOL>.filter(<EOL>key_table.candidate_classes.overlap(cast(candidate_classes, ARRAY(String)))<EOL>)<EOL>.all()<EOL>)<EOL>to_delete = set()<EOL>to_update = []<EOL>for row in all_rows:<EOL><INDENT>row.candidate_classes = list(<EOL>set(row.candidate_classes) - set(candidate_classes)<EOL>)<EOL>if len(row.candidate_classes) == <NUM_LIT:0>:<EOL><INDENT>to_delete.add(row.name)<EOL><DEDENT>else:<EOL><INDENT>to_update.append(<EOL>{"<STR_LIT:name>": row.name, "<STR_LIT>": row.candidate_classes}<EOL>)<EOL><DEDENT><DEDENT>if to_delete:<EOL><INDENT>query = session.query(key_table).filter(key_table.name.in_(to_delete))<EOL>query.delete(synchronize_session="<STR_LIT>")<EOL><DEDENT>if to_update:<EOL><INDENT>for batch in _batch_postgres_query(key_table, to_update):<EOL><INDENT>stmt = insert(key_table.__table__)<EOL>stmt = stmt.on_conflict_do_update(<EOL>constraint=key_table.__table__.primary_key,<EOL>set_={<EOL>"<STR_LIT:name>": stmt.excluded.get("<STR_LIT:name>"),<EOL>"<STR_LIT>": stmt.excluded.get("<STR_LIT>"),<EOL>},<EOL>)<EOL>session.execute(stmt, batch)<EOL>session.commit()<EOL><DEDENT><DEDENT>
Bulk drop annotation keys for all the candidate_classes in the table.

    Rather than directly dropping the keys, this removes the candidate_classes
    specified for the given keys only. If all candidate_classes are removed for
    a key, the key is dropped.

    :param key_table: The sqlalchemy class to insert into.
    :param candidate_classes: A list of candidate classes to drop.