# Buggy code
def handle_output(name, output, hidden=None):
    if output.parent:
        parent_to_child_pairs.append((output.parent, name))
        child_dataset_names.add(name)
    # What is the following hack for? Need to document under what
    # conditions can the following occur? (james@bx.psu.edu)
    # HACK: the output data has already been created
    #      this happens i.e. as a result of the async controller
    if name in incoming:
        dataid = incoming[name]
        data = trans.sa_session.query(app.model.HistoryDatasetAssociation).get(dataid)
        assert data is not None
        out_data[name] = data
    else:
        ext = determine_output_format(
            output,
            wrapped_params.params,
            inp_data,
            inp_dataset_collections,
            input_ext,
            python_template_version=tool.python_template_version,
        )
        create_datasets = True
        dataset = None

        if completed_job:
            for output_dataset in completed_job.output_datasets:
                if output_dataset.name == name:
                    create_datasets = False
                    completed_data = output_dataset.dataset
                    dataset = output_dataset.dataset.dataset
                    break

        data = app.model.HistoryDatasetAssociation(
            extension=ext, dataset=dataset, create_dataset=create_datasets, flush=False
        )
        if create_datasets:
            from_work_dir = output.from_work_dir
            if from_work_dir is not None:
                data.dataset.created_from_basename = os.path.basename(from_work_dir)
        if hidden is None:
            hidden = output.hidden
        if (
            not hidden and dataset_collection_elements is not None
        ):  # Mapping over a collection - hide datasets
            hidden = True
        if hidden:
            data.visible = False
        if (
            dataset_collection_elements is not None
            and name in dataset_collection_elements
        ):
            dataset_collection_elements[name].hda = data
        trans.sa_session.add(data)
        if not completed_job:
            trans.app.security_agent.set_all_dataset_permissions(
                data.dataset, output_permissions, new=True
            )
    data.copy_tags_to(preserved_tags)

    if not completed_job and trans.app.config.legacy_eager_objectstore_initialization:
        # Must flush before setting object store id currently.
        trans.sa_session.flush()
        object_store_populator.set_object_store_id(data)

    # This may not be neccesary with the new parent/child associations
    data.designation = name
    # Copy metadata from one of the inputs if requested.

    # metadata source can be either a string referencing an input
    # or an actual object to copy.
    metadata_source = output.metadata_source
    if metadata_source:
        if isinstance(metadata_source, string_types):
            metadata_source = inp_data.get(metadata_source)

    if metadata_source is not None:
        data.init_meta(copy_from=metadata_source)
    else:
        data.init_meta()
    # Take dbkey from LAST input
    data.dbkey = str(input_dbkey)
    # Set state
    if completed_job:
        data.blurb = completed_data.blurb
        data.peek = completed_data.peek
        data._metadata = completed_data._metadata
    else:
        data.blurb = "queued"
    # Set output label
    data.name = self.get_output_name(
        output,
        data,
        tool,
        on_text,
        trans,
        incoming,
        history,
        wrapped_params.params,
        job_params,
    )
    # Store output
    out_data[name] = data
    if output.actions:
        # Apply pre-job tool-output-dataset actions; e.g. setting metadata, changing format
        output_action_params = dict(out_data)
        output_action_params.update(incoming)
        output.actions.apply_action(data, output_action_params)
    # Also set the default values of actions of type metadata
    self.set_metadata_defaults(
        output,
        data,
        tool,
        on_text,
        trans,
        incoming,
        history,
        wrapped_params.params,
        job_params,
    )
    # Flush all datasets at once.
    return data


# Traceback (sqlalchemy.exc.ProgrammingError)
2020-01-20T10:34:14.9786332Z 2020-01-20 10:34:14,974 ERROR [galaxy.tools] Exception caught while attempting tool execution:
2020-01-20T10:34:14.9787128Z Traceback (most recent call last):
2020-01-20T10:34:14.9789375Z   File "/home/runner/.planemo/gx_venv_3.7_release_20.01/lib/python3.7/site-packages/sqlalchemy/engine/base.py", line 1246, in _execute_context
2020-01-20T10:34:14.9790073Z     cursor, statement, parameters, context
2020-01-20T10:34:14.9790998Z   File "/home/runner/.planemo/gx_venv_3.7_release_20.01/lib/python3.7/site-packages/sqlalchemy/engine/default.py", line 581, in do_execute
2020-01-20T10:34:14.9791567Z     cursor.execute(statement, parameters)
2020-01-20T10:34:14.9792168Z psycopg2.errors.UndefinedFunction: operator does not exist: integer = boolean
2020-01-20T10:34:14.9792461Z LINE 3: WHERE history_dataset_association.id = true
2020-01-20T10:34:14.9792893Z                                              ^
2020-01-20T10:34:14.9793157Z HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
2020-01-20T10:34:14.9793379Z
2020-01-20T10:34:14.9793559Z
2020-01-20T10:34:14.9793800Z The above exception was the direct cause of the following exception:
2020-01-20T10:34:14.9793992Z
2020-01-20T10:34:14.9794231Z Traceback (most recent call last):
2020-01-20T10:34:14.9794979Z   File "/tmp/tmpvahl86j6/galaxy-dev/lib/galaxy/tools/__init__.py", line 1517, in handle_single_execution
2020-01-20T10:34:14.9803112Z     collection_info=collection_info,
2020-01-20T10:34:14.9804371Z   File "/tmp/tmpvahl86j6/galaxy-dev/lib/galaxy/tools/__init__.py", line 1599, in execute
2020-01-20T10:34:14.9845469Z     return self.tool_action.execute(self, trans, incoming=incoming, set_output_hid=set_output_hid, history=history, **kwargs)
2020-01-20T10:34:14.9846453Z   File "/tmp/tmpvahl86j6/galaxy-dev/lib/galaxy/tools/actions/__init__.py", line 517, in execute
2020-01-20T10:34:14.9846652Z     handle_output(name, output)
2020-01-20T10:34:14.9847218Z   File "/tmp/tmpvahl86j6/galaxy-dev/lib/galaxy/tools/actions/__init__.py", line 374, in handle_output
2020-01-20T10:34:14.9901226Z     data = trans.sa_session.query(app.model.HistoryDatasetAssociation).get(dataid)
2020-01-20T10:34:14.9902192Z   File "/home/runner/.planemo/gx_venv_3.7_release_20.01/lib/python3.7/site-packages/sqlalchemy/orm/query.py", line 982, in get
2020-01-20T10:34:14.9902563Z     return self._get_impl(ident, loading.load_on_pk_identity)
2020-01-20T10:34:14.9903210Z   File "/home/runner/.planemo/gx_venv_3.7_release_20.01/lib/python3.7/site-packages/sqlalchemy/orm/query.py", line 1094, in _get_impl
2020-01-20T10:34:14.9903870Z     return db_load_fn(self, primary_key_identity)
2020-01-20T10:34:14.9904659Z   File "/home/runner/.planemo/gx_venv_3.7_release_20.01/lib/python3.7/site-packages/sqlalchemy/orm/loading.py", line 284, in load_on_pk_identity
2020-01-20T10:34:14.9905130Z     return q.one()
2020-01-20T10:34:14.9905712Z   File "/home/runner/.planemo/gx_venv_3.7_release_20.01/lib/python3.7/site-packages/sqlalchemy/orm/query.py", line 3325, in one
2020-01-20T10:34:14.9906010Z     ret = self.one_or_none()
2020-01-20T10:34:14.9906608Z   File "/home/runner/.planemo/gx_venv_3.7_release_20.01/lib/python3.7/site-packages/sqlalchemy/orm/query.py", line 3294, in one_or_none
2020-01-20T10:34:14.9906934Z     ret = list(self)
2020-01-20T10:34:14.9907533Z   File "/home/runner/.planemo/gx_venv_3.7_release_20.01/lib/python3.7/site-packages/sqlalchemy/orm/query.py", line 3367, in __iter__
2020-01-20T10:34:14.9908680Z     return self._execute_and_instances(context)
2020-01-20T10:34:14.9909655Z   File "/home/runner/.planemo/gx_venv_3.7_release_20.01/lib/python3.7/site-packages/sqlalchemy/orm/query.py", line 3392, in _execute_and_instances
2020-01-20T10:34:14.9910213Z     result = conn.execute(querycontext.statement, self._params)
2020-01-20T10:34:14.9910856Z   File "/home/runner/.planemo/gx_venv_3.7_release_20.01/lib/python3.7/site-packages/sqlalchemy/engine/base.py", line 982, in execute
2020-01-20T10:34:14.9911149Z     return meth(self, multiparams, params)
2020-01-20T10:34:14.9911929Z   File "/home/runner/.planemo/gx_venv_3.7_release_20.01/lib/python3.7/site-packages/sqlalchemy/sql/elements.py", line 287, in _execute_on_connection
2020-01-20T10:34:14.9912190Z     return connection._execute_clauseelement(self, multiparams, params)
2020-01-20T10:34:14.9913022Z   File "/home/runner/.planemo/gx_venv_3.7_release_20.01/lib/python3.7/site-packages/sqlalchemy/engine/base.py", line 1101, in _execute_clauseelement
2020-01-20T10:34:14.9913329Z     distilled_params,
2020-01-20T10:34:14.9914298Z   File "/home/runner/.planemo/gx_venv_3.7_release_20.01/lib/python3.7/site-packages/sqlalchemy/engine/base.py", line 1250, in _execute_context
2020-01-20T10:34:14.9914575Z     e, statement, parameters, cursor, context
2020-01-20T10:34:14.9915355Z   File "/home/runner/.planemo/gx_venv_3.7_release_20.01/lib/python3.7/site-packages/sqlalchemy/engine/base.py", line 1476, in _handle_dbapi_exception
2020-01-20T10:34:14.9915624Z     util.raise_from_cause(sqlalchemy_exception, exc_info)
2020-01-20T10:34:14.9916183Z   File "/home/runner/.planemo/gx_venv_3.7_release_20.01/lib/python3.7/site-packages/sqlalchemy/util/compat.py", line 398, in raise_from_cause
2020-01-20T10:34:14.9916453Z     reraise(type(exception), exception, tb=exc_tb, cause=cause)
2020-01-20T10:34:14.9917093Z   File "/home/runner/.planemo/gx_venv_3.7_release_20.01/lib/python3.7/site-packages/sqlalchemy/util/compat.py", line 152, in reraise
2020-01-20T10:34:14.9918037Z     raise value.with_traceback(tb)
2020-01-20T10:34:14.9918720Z   File "/home/runner/.planemo/gx_venv_3.7_release_20.01/lib/python3.7/site-packages/sqlalchemy/engine/base.py", line 1246, in _execute_context
2020-01-20T10:34:14.9919011Z     cursor, statement, parameters, context
2020-01-20T10:34:14.9919626Z   File "/home/runner/.planemo/gx_venv_3.7_release_20.01/lib/python3.7/site-packages/sqlalchemy/engine/default.py", line 581, in do_execute
2020-01-20T10:34:14.9919938Z     cursor.execute(statement, parameters)
2020-01-20T10:34:14.9920164Z sqlalchemy.exc.ProgrammingError: (psycopg2.errors.UndefinedFunction) operator does not exist: integer = boolean
2020-01-20T10:34:14.9920430Z LINE 3: WHERE history_dataset_association.id = true
2020-01-20T10:34:14.9920667Z                                              ^
2020-01-20T10:34:14.9920906Z HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
2020-01-20T10:34:14.9921594Z
2020-01-20T10:34:14.9923082Z [SQL: SELECT history_dataset_association.id AS history_dataset_association_id, history_dataset_association.history_id AS history_dataset_association_history_id, history_dataset_association.dataset_id AS history_dataset_association_dataset_id, history_dataset_association.create_time AS history_dataset_association_create_time, history_dataset_association.update_time AS history_dataset_association_update_time, history_dataset_association.state AS history_dataset_association_state, history_dataset_association.copied_from_history_dataset_association_id AS history_dataset_association_copied_from_history_dataset_a_1, history_dataset_association.copied_from_library_dataset_dataset_association_id AS history_dataset_association_copied_from_library_dataset_d_2, history_dataset_association.name AS history_dataset_association_name, history_dataset_association.info AS history_dataset_association_info, history_dataset_association.blurb AS history_dataset_association_blurb, history_dataset_association.peek AS history_dataset_association_peek, history_dataset_association.tool_version AS history_dataset_association_tool_version, history_dataset_association.extension AS history_dataset_association_extension, history_dataset_association.parent_id AS history_dataset_association_parent_id, history_dataset_association.designation AS history_dataset_association_designation, history_dataset_association.deleted AS history_dataset_association_deleted, history_dataset_association.visible AS history_dataset_association_visible, history_dataset_association.extended_metadata_id AS history_dataset_association_extended_metadata_id, history_dataset_association.version AS history_dataset_association_version, history_dataset_association.hid AS history_dataset_association_hid, history_dataset_association.purged AS history_dataset_association_purged, history_dataset_association.validated_state AS history_dataset_association_validated_state, history_dataset_association.validated_state_message AS history_dataset_association_validated_state_message, history_dataset_association.hidden_beneath_collection_instance_id AS history_dataset_association_hidden_beneath_collection_ins_3, dataset_1.id AS dataset_1_id, dataset_1.create_time AS dataset_1_create_time, dataset_1.update_time AS dataset_1_update_time, dataset_1.state AS dataset_1_state, dataset_1.deleted AS dataset_1_deleted, dataset_1.purged AS dataset_1_purged, dataset_1.purgable AS dataset_1_purgable, dataset_1.object_store_id AS dataset_1_object_store_id, dataset_1.external_filename AS dataset_1_external_filename, dataset_1._extra_files_path AS dataset_1__extra_files_path, dataset_1.created_from_basename AS dataset_1_created_from_basename, dataset_1.file_size AS dataset_1_file_size, dataset_1.total_size AS dataset_1_total_size, dataset_1.uuid AS dataset_1_uuid
2020-01-20T10:34:14.9924421Z FROM history_dataset_association LEFT OUTER JOIN dataset AS dataset_1 ON dataset_1.id = history_dataset_association.dataset_id
2020-01-20T10:34:14.9925146Z WHERE history_dataset_association.id = %(param_1)s]
2020-01-20T10:34:14.9925764Z [parameters: {'param_1': True}]
2020-01-20T10:34:14.9926632Z (Background on this error at: http://sqlalche.me/e/f405)
2020-01-20T10:34:14.9927166Z 2020-01-20 10:34:14,978 WARNI [galaxy.tools.execute] There was a failure executing a job for tool [disco] - Error executing tool: (psycopg2.errors.UndefinedFunction) operator does not exist: integer = boolean
2020-01-20T10:34:14.9927664Z LINE 3: WHERE history_dataset_association.id = true
2020-01-20T10:34:14.9927807Z                                              ^
2020-01-20T10:34:14.9928361Z HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
2020-01-20T10:34:14.9928441Z
2020-01-20T10:34:14.9929588Z [SQL: SELECT history_dataset_association.id AS history_dataset_association_id, history_dataset_association.history_id AS history_dataset_association_history_id, history_dataset_association.dataset_id AS history_dataset_association_dataset_id, history_dataset_association.create_time AS history_dataset_association_create_time, history_dataset_association.update_time AS history_dataset_association_update_time, history_dataset_association.state AS history_dataset_association_state, history_dataset_association.copied_from_history_dataset_association_id AS history_dataset_association_copied_from_history_dataset_a_1, history_dataset_association.copied_from_library_dataset_dataset_association_id AS history_dataset_association_copied_from_library_dataset_d_2, history_dataset_association.name AS history_dataset_association_name, history_dataset_association.info AS history_dataset_association_info, history_dataset_association.blurb AS history_dataset_association_blurb, history_dataset_association.peek AS history_dataset_association_peek, history_dataset_association.tool_version AS history_dataset_association_tool_version, history_dataset_association.extension AS history_dataset_association_extension, history_dataset_association.parent_id AS history_dataset_association_parent_id, history_dataset_association.designation AS history_dataset_association_designation, history_dataset_association.deleted AS history_dataset_association_deleted, history_dataset_association.visible AS history_dataset_association_visible, history_dataset_association.extended_metadata_id AS history_dataset_association_extended_metadata_id, history_dataset_association.version AS history_dataset_association_version, history_dataset_association.hid AS history_dataset_association_hid, history_dataset_association.purged AS history_dataset_association_purged, history_dataset_association.validated_state AS history_dataset_association_validated_state, history_dataset_association.validated_state_message AS history_dataset_association_validated_state_message, history_dataset_association.hidden_beneath_collection_instance_id AS history_dataset_association_hidden_beneath_collection_ins_3, dataset_1.id AS dataset_1_id, dataset_1.create_time AS dataset_1_create_time, dataset_1.update_time AS dataset_1_update_time, dataset_1.state AS dataset_1_state, dataset_1.deleted AS dataset_1_deleted, dataset_1.purged AS dataset_1_purged, dataset_1.purgable AS dataset_1_purgable, dataset_1.object_store_id AS dataset_1_object_store_id, dataset_1.external_filename AS dataset_1_external_filename, dataset_1._extra_files_path AS dataset_1__extra_files_path, dataset_1.created_from_basename AS dataset_1_created_from_basename, dataset_1.file_size AS dataset_1_file_size, dataset_1.total_size AS dataset_1_total_size, dataset_1.uuid AS dataset_1_uuid
2020-01-20T10:34:14.9930717Z FROM history_dataset_association LEFT OUTER JOIN dataset AS dataset_1 ON dataset_1.id = history_dataset_association.dataset_id
2020-01-20T10:34:14.9930866Z WHERE history_dataset_association.id = %(param_1)s]
2020-01-20T10:34:14.9931266Z [parameters: {'param_1': True}]
2020-01-20T10:34:14.9931395Z (Background on this error at: http://sqlalche.me/e/f405)
2020-01-20T10:34:14.9931685Z ERROR

# Fixed code
def handle_output(name, output, hidden=None):
    if output.parent:
        parent_to_child_pairs.append((output.parent, name))
        child_dataset_names.add(name)
    if async_tool and name in incoming:
        # HACK: output data has already been created as a result of the async controller
        dataid = incoming[name]
        data = trans.sa_session.query(app.model.HistoryDatasetAssociation).get(dataid)
        assert data is not None
        out_data[name] = data
    else:
        ext = determine_output_format(
            output,
            wrapped_params.params,
            inp_data,
            inp_dataset_collections,
            input_ext,
            python_template_version=tool.python_template_version,
        )
        create_datasets = True
        dataset = None

        if completed_job:
            for output_dataset in completed_job.output_datasets:
                if output_dataset.name == name:
                    create_datasets = False
                    completed_data = output_dataset.dataset
                    dataset = output_dataset.dataset.dataset
                    break

        data = app.model.HistoryDatasetAssociation(
            extension=ext, dataset=dataset, create_dataset=create_datasets, flush=False
        )
        if create_datasets:
            from_work_dir = output.from_work_dir
            if from_work_dir is not None:
                data.dataset.created_from_basename = os.path.basename(from_work_dir)
        if hidden is None:
            hidden = output.hidden
        if (
            not hidden and dataset_collection_elements is not None
        ):  # Mapping over a collection - hide datasets
            hidden = True
        if hidden:
            data.visible = False
        if (
            dataset_collection_elements is not None
            and name in dataset_collection_elements
        ):
            dataset_collection_elements[name].hda = data
        trans.sa_session.add(data)
        if not completed_job:
            trans.app.security_agent.set_all_dataset_permissions(
                data.dataset, output_permissions, new=True
            )
    data.copy_tags_to(preserved_tags)

    if not completed_job and trans.app.config.legacy_eager_objectstore_initialization:
        # Must flush before setting object store id currently.
        trans.sa_session.flush()
        object_store_populator.set_object_store_id(data)

    # This may not be neccesary with the new parent/child associations
    data.designation = name
    # Copy metadata from one of the inputs if requested.

    # metadata source can be either a string referencing an input
    # or an actual object to copy.
    metadata_source = output.metadata_source
    if metadata_source:
        if isinstance(metadata_source, string_types):
            metadata_source = inp_data.get(metadata_source)

    if metadata_source is not None:
        data.init_meta(copy_from=metadata_source)
    else:
        data.init_meta()
    # Take dbkey from LAST input
    data.dbkey = str(input_dbkey)
    # Set state
    if completed_job:
        data.blurb = completed_data.blurb
        data.peek = completed_data.peek
        data._metadata = completed_data._metadata
    else:
        data.blurb = "queued"
    # Set output label
    data.name = self.get_output_name(
        output,
        data,
        tool,
        on_text,
        trans,
        incoming,
        history,
        wrapped_params.params,
        job_params,
    )
    # Store output
    out_data[name] = data
    if output.actions:
        # Apply pre-job tool-output-dataset actions; e.g. setting metadata, changing format
        output_action_params = dict(out_data)
        output_action_params.update(incoming)
        output.actions.apply_action(data, output_action_params)
    # Also set the default values of actions of type metadata
    self.set_metadata_defaults(
        output,
        data,
        tool,
        on_text,
        trans,
        incoming,
        history,
        wrapped_params.params,
        job_params,
    )
    # Flush all datasets at once.
    return data