if (mOp == null) { mOp = new NoTermQueryOperation(); }
assert(mOp != null);
    public ZimbraQuery(String queryString, java.util.TimeZone tz, Locale locale, Mailbox mbox, byte[] types, SortBy searchOrder, boolean includeTrash, boolean includeSpam, int chunkSize, boolean prefetch, Mailbox.SearchResultMode mode)     throws ParseException, ServiceException    {        mMbox = mbox;        mPrefetch = prefetch;        mMode = mode;        mTimeZone = tz;        mLocale = locale;        //        // Step 1: parse the text using the JavaCC parser        ZimbraQueryParser parser = new ZimbraQueryParser(new StringReader(queryString));        mbox.getMailboxIndex().initAnalyzer(mbox);        parser.init(mbox.getMailboxIndex().getAnalyzer(), mMbox, mTimeZone, mLocale);        mClauses = parser.Parse();        String sortByStr = parser.getSortByStr();        if (sortByStr != null)            handleSortByOverride(sortByStr);        //        // Step 2: build a parse tree and push all the "NOT's" down to the        // bottom level -- this is because we cannot invert result sets         if (ParseTree.SPEW) System.out.println("QueryString: "+queryString);        ParseTree.Node pt = ParseTree.build(mClauses);        if (ParseTree.SPEW) System.out.println("PT: "+pt.toString());        if (ParseTree.SPEW)System.out.println("Simplified:");        pt = pt.simplify();        if (ParseTree.SPEW)System.out.println("PT: "+pt.toString());        if (ParseTree.SPEW)System.out.println("Pushing nots down:");        pt.pushNotsDown();        if (ParseTree.SPEW)System.out.println("PT: "+pt.toString());        //         // Store some variables that we'll need later        mParseTree = pt;        mSearchOrder = searchOrder;        mTypes = types;        mChunkSize = chunkSize;        mOp = null;        //        // handle the special "sort:" tag in the search string        if (mSortByOverride != null) {            if (mLog.isDebugEnabled())                mLog.debug("Overriding SortBy parameter to execute ("+searchOrder.toString()+") w/ specification from QueryString: "+mSortByOverride.toString());            mSearchOrder = mSortByOverride;        }        //        // Step 3: Convert list of BaseQueries into list of QueryOperations, then Optimize the Ops        if (mClauses.size() > 0) {            // this generates all of the query operations            mOp = mParseTree.getQueryOperation();            if (mLog.isDebugEnabled()) {                mLog.debug("OP="+mOp.toString());            }            // optimize the query down            mOp = mOp.optimize(mMbox);            if (mOp == null) {                mOp = new NoTermQueryOperation();            }            if (mLog.isDebugEnabled()) {                mLog.debug("OPTIMIZED="+mOp.toString());            }            // do spam/trash hackery!            if (!includeTrash || !includeSpam) {                if (!mOp.hasSpamTrashSetting()) {                    mOp = mOp.ensureSpamTrashSetting(mMbox, includeTrash, includeSpam);                    if (mLog.isDebugEnabled()) {                        mLog.debug("AFTERTS="+mOp.toString());                    }                    mOp = mOp.optimize(mMbox); // optimize again now that we have the trash/spam setting                }            }        }    }