<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def search(self, catalogue, ngrams, output_fh):
 """Returns `output_fh` populated with CSV results for each n-gram in `ngrams` that occurs within labelled witnesses in `catalogue`. If `ngrams` is empty, include all n-grams. :param catalogue: catalogue matching filenames to labels :type catalogue: `Catalogue` :param ngrams: n-grams to search for :type ngrams: `list` of `str` :param output_fh: object to write results to :type output_fh: file-like object :rtype: file-like object """

        labels = list(self._set_labels(catalogue))
        label_placeholders = self._get_placeholders(labels)
        if ngrams:
            self._add_temporary_ngrams(ngrams)
            query = constants.SELECT_SEARCH_SQL.format(label_placeholders)
        else:
            query = constants.SELECT_SEARCH_ALL_SQL.format(label_placeholders)
        self._logger.info('Running search query')
        self._logger.debug('Query: {}\nN-grams: {}'.format(
            query, ', '.join(ngrams)))
        self._log_query_plan(query, labels)
        cursor = self._conn.execute(query, labels)
        return self._csv(cursor, constants.QUERY_FIELDNAMES, output_fh)