def _build_search(structured_query):
    """Construct search statment for db execution.

    Produces the search statement and argument dictionary to be executed
    by the DBAPI v2 execute method.
    For example, ``cursor.execute(*_build_search(query, weights))``

    :param query: containing terms, filters, and sorts.
    :type query: Query
    :param weights: weight values to assign to each keyword search field
    :type weights: dictionary of field names to weight integers
    :returns: the build statement and the arguments used against it
    :rtype: a two value tuple of a SQL template and a dictionary of
            arguments to pass into that template
    """
    arguments = {}

    # get text terms and filter out common words
    text_terms = [term for ttype, term in structured_query.terms
                  if ttype == 'text']

    text_terms_wo_stopwords = [term for term in text_terms
                               if term.lower() not in STOPWORDS]
    # sql where clauses
    conditions = {'text_terms': '', 'pubYear': '', 'authorID': '', 'type': '',
                  'keyword': '', 'subject': '', 'language': '', 'title': '',
                  'author': '', 'abstract': ''}

    # if there are other search terms (not type "text") or if the text
    # terms do not only consist of stopwords, then use the text terms
    # without stopwords
    if arguments or text_terms_wo_stopwords:
        text_terms = text_terms_wo_stopwords
    arguments.update({'text_terms': ' '.join(text_terms)})
    # raise Exception(structured_query.filters, structured_query.terms)

    if len(text_terms) > 0:
        conditions['text_terms'] = 'AND module_idx \
                                    @@ plainto_tsquery(%(text_terms)s)'

    # build fulltext keys
    fulltext_key = []
    for term in text_terms_wo_stopwords:
        fulltext_key.append(term + '-::-fulltext')
    arguments.update({'fulltext_key':  ';--;'.join(fulltext_key)})

    idx = 0
    invalid_filters = []
    filters = _convert(structured_query.filters, [])

    while idx < len(filters):
        keyword = filters[idx][0]
        value = filters[idx][1]
        if keyword == 'pubYear':
            conditions['pubYear'] = 'AND extract(year from cm.revised) = \
                                     %(pubYear)s'
            arguments.update({'pubYear': value[0]})
        elif keyword == 'authorID':
            conditions['authorID'] = 'AND ARRAY[%(authorID)s] \
                                      <@ cm.authors'
            arguments.update({'authorID': value[0]})
        elif keyword == 'type':
            value[0] = value[0].lower()

            conditions['type'] = 'AND cm.portal_type = %(type)s'
            if value[0] != 'book' and value[0] != 'collection' and \
                    value[0] != 'page' and value[0] != 'module':
                invalid_filters.append(idx)
            value[0] = 'Collection' if (value[0] == 'book' or
                                        value[0] == 'collection') else 'Module'
            arguments.update({'type': value[0]})
        elif keyword == 'keyword':
            value = _upper(value)
            conditions['keyword'] = 'AND cm.module_ident = \
                                     ANY(WITH target AS ( \
                                     SELECT lm.module_ident AS id, \
                                     array_agg(UPPER(kw.word)) AS akw \
                                     FROM latest_modules lm, \
                                     modulekeywords mk, \
                                     keywords kw \
                                     WHERE lm.module_ident = mk.module_ident \
                                     AND kw.keywordid = mk.keywordid \
                                     GROUP BY id) \
                                     SELECT target.id FROM target WHERE \
                                     target.akw @> %(keyword)s)'
            arguments.update({'keyword': value})
        elif keyword == 'subject':
            conditions['subject'] = 'AND cm.module_ident = \
                                     ANY(WITH sub AS ( \
                                     SELECT module_ident AS id, \
                                     array_agg(tag) AS atag \
                                     FROM latest_modules \
                                     NATURAL JOIN \
                                     moduletags NATURAL JOIN \
                                     tags GROUP BY id) \
                                     SELECT sub.id FROM sub WHERE \
                                     sub.atag @> %(subject)s)'
            arguments.update({'subject': value})
        elif keyword == 'language':
            conditions['language'] = 'AND cm.language = %(language)s'
            arguments.update({'language': value[0]})
        elif keyword == 'title':
            conditions['title'] = 'AND strip_html(cm.name) ~* \
                                   %(title)s'
            arguments.update({'title': value[0]})
        elif keyword == 'author':
            conditions['author'] = 'AND cm.module_ident = \
                                    ANY(WITH name AS ( \
                                    SELECT username FROM users u WHERE \
                                    u.first_name||\' \'||u.last_name \
                                    ~* %(author)s) \
                                    SELECT lm.module_ident \
                                    FROM latest_modules lm \
                                    JOIN name n ON ARRAY[n.username] \
                                    <@ lm.authors)'
            arguments.update({'author': value[0]})
        elif keyword == 'abstract':
            conditions['abstract'] = 'AND cm.module_ident = \
                                      ANY(SELECT lm.module_ident FROM \
                                      latest_modules lm, \
                                      abstracts ab WHERE\
                                      lm.abstractid = ab.abstractid \
                                      AND ab.abstract \
                                      ~* %(abstract)s)'
            arguments.update({'abstract': value[0]})
        else:
            # Invalid filter!
            invalid_filters.append(idx)
        idx += 1

    if len(invalid_filters) == len(structured_query.filters) and \
            len(structured_query.terms) == 0:
        # Either query terms are all invalid filters
        # or we received a null query.
        # Clear the filter list in this case.
        structured_query.filters = []
        return None, None

    for invalid_filter_idx in invalid_filters:
        # Remove invalid filters.
        del structured_query.filters[invalid_filter_idx]

    # Add the arguments for sorting.
    sorts = ['portal_type']
    if structured_query.sorts:
        for sort in structured_query.sorts:
            # These sort values are not the name of the column used
            #   in the database.
            stmt = _transmute_sort(sort)
            sorts.append(stmt)
    sorts.extend(('weight DESC', 'uuid DESC',))
    sorts = ', '.join(sorts)

    statement = SQL_QUICK_SELECT_WRAPPER.format(conditions['pubYear'],
                                                conditions['authorID'],
                                                conditions['type'],
                                                conditions['keyword'],
                                                conditions['subject'],
                                                conditions['text_terms'],
                                                conditions['language'],
                                                conditions['title'],
                                                conditions['author'],
                                                conditions['abstract'],
                                                sorts=sorts)
    return statement, arguments