def check_all_columns(state, allow_extra=True, too_many_cols_msg=None, expand_msg=None):
    """Zoom in on the columns that are specified by the solution
    
    Behind the scenes, this is using ``check_column()`` for every column that is in the solution query result.
    Afterwards, it's selecting only these columns from the student query result and stores them in a child
    state that is returned, so you can use ``has_equal_value()`` on it.

    This function does not allow you to customize the messages for ``check_column()``. If you want to manually
    set those, simply use ``check_column()`` explicitly.

    Args:
        allow_extra: True by default, this determines whether students are allowed to have included
                     other columns in their query result.
        too_many_cols_msg: If specified, this overrides the automatically generated feedback message in
                           case ``allow_extra`` is False and the student's query returned extra columns when
                           comparing the so the solution query result.
        expand_msg: if specified, this overrides the automatically generated feedback 
                    message that is prepended to feedback messages that are thrown
                    further in the SCT chain.

    :Example:

        Consider the following solution and SCT: ::

            # solution
            SELECT artist_id as id, name FROM artists

            # sct
            Ex().check_all_columns()

            # passing submission
            SELECT artist_id as id, name FROM artists

            # failing submission (wrong names)
            SELECT artist_id, name FROM artists

            # passing submission (allow_extra is True by default)
            SELECT artist_id as id, name, label FROM artists
    """

    if too_many_cols_msg is None:
        too_many_cols_msg = (
            "Your query result contains the column {{col}} but shouldn't."
        )
    if expand_msg is None:
        expand_msg = "Have another look at your query result. "

    child_stu_result = {}
    child_sol_result = {}

    for col in state.solution_result:
        child = check_column(state, col)
        child_stu_result.update(**child.student_result)
        child_sol_result.update(**child.solution_result)

    cols_not_in_sol = list(
        set(state.student_result.keys()) - set(child_stu_result.keys())
    )
    if not allow_extra and len(cols_not_in_sol) > 0:
        _msg = state.build_message(
            "Your query result contains the column `{{col}}` but shouldn't.",
            fmt_kwargs={"col": cols_not_in_sol[0]},
        )
        state.do_test(_msg)

    return state.to_child(
        append_message={"msg": expand_msg, "kwargs": {}},
        student_result=child_stu_result,
        solution_result=child_sol_result,
    )