Index: src/test/org/apache/lucene/index/TestCodecs.java =================================================================== --- src/test/org/apache/lucene/index/TestCodecs.java (revision 916465) +++ src/test/org/apache/lucene/index/TestCodecs.java (working copy) @@ -511,7 +511,7 @@ DocsAndPositionsEnum postings = termsEnum.docsAndPositions(null, null); final DocsEnum docsEnum; - if (postings != null) { + if (postings != DocsAndPositionsEnum.EMPTY) { docsEnum = postings; } else { docsEnum = docs; Index: src/java/org/apache/lucene/search/FilteredTermsEnum.java =================================================================== --- src/java/org/apache/lucene/search/FilteredTermsEnum.java (revision 916465) +++ src/java/org/apache/lucene/search/FilteredTermsEnum.java (working copy) @@ -63,12 +63,7 @@ * Creates a filtered {@link TermsEnum} for the given field name and reader. */ public FilteredTermsEnum(final IndexReader reader, final String field) throws IOException { - final Terms terms = MultiFields.getTerms(reader, field); - if (terms != null) { - tenum = terms.iterator(); - } else { - tenum = null; - } + tenum = MultiFields.getTerms(reader, field).iterator(); } /** @@ -122,22 +117,22 @@ /* if we have no tenum, we return a new attributes instance, * to prevent NPE in subclasses that use attributes. * in all other cases we share the attributes with our delegate. */ - return (tenum == null) ? super.attributes() : tenum.attributes(); + return tenum.attributes(); } @Override public BytesRef term() throws IOException { - return (tenum == null) ? null : tenum.term(); + return tenum.term(); } @Override public BytesRef.Comparator getComparator() throws IOException { - return (tenum == null) ? null : tenum.getComparator(); + return tenum.getComparator(); } @Override public int docFreq() { - return (tenum == null) ? -1 : tenum.docFreq(); + return tenum.docFreq(); } /** This enum does not support seeking! @@ -158,23 +153,21 @@ @Override public long ord() throws IOException { - return (tenum == null) ? -1 : tenum.ord(); + return tenum.ord(); } @Override public DocsEnum docs(Bits bits, DocsEnum reuse) throws IOException { - return (tenum == null) ? null : tenum.docs(bits, reuse); + return tenum.docs(bits, reuse); } @Override public DocsAndPositionsEnum docsAndPositions(Bits bits, DocsAndPositionsEnum reuse) throws IOException { - return (tenum == null) ? null : tenum.docsAndPositions(bits, reuse); + return tenum.docsAndPositions(bits, reuse); } @Override public BytesRef next() throws IOException { - if (tenum == null) - return null; for (;;) { // Seek or forward the iterator if (doSeek) { Index: src/java/org/apache/lucene/search/PrefixQuery.java =================================================================== --- src/java/org/apache/lucene/search/PrefixQuery.java (revision 916465) +++ src/java/org/apache/lucene/search/PrefixQuery.java (working copy) @@ -52,8 +52,7 @@ @Override protected TermsEnum getTermsEnum(IndexReader reader) throws IOException { if (prefix.text().length() == 0) { - final Terms terms = MultiFields.getTerms(reader, getField()); - return (terms != null) ? terms.iterator() : TermsEnum.EMPTY; + return MultiFields.getTerms(reader, getField()).iterator(); } return new PrefixTermsEnum(reader, prefix); } Index: src/java/org/apache/lucene/search/PhraseQuery.java =================================================================== --- src/java/org/apache/lucene/search/PhraseQuery.java (revision 916465) +++ src/java/org/apache/lucene/search/PhraseQuery.java (working copy) @@ -24,6 +24,7 @@ import org.apache.lucene.index.Term; import org.apache.lucene.util.BytesRef; import org.apache.lucene.index.DocsAndPositionsEnum; +import org.apache.lucene.index.DocsEnum; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.MultiFields; import org.apache.lucene.search.Explanation.IDFExplanation; @@ -164,11 +165,16 @@ delDocs, t.field(), text); - if (postingsEnum == null) { + assert postingsEnum != null: "reader=" + reader; + + // try to notify user when they are running + // PhraseQuery on a field that did not index + // positions. + if (postingsEnum == DocsAndPositionsEnum.EMPTY) { if (MultiFields.getTermDocsEnum(reader, delDocs, t.field(), - text) != null) { + text) != DocsEnum.EMPTY) { // term does exist, but has no positions throw new IllegalStateException("field \"" + t.field() + "\" was indexed with Field.omitTermFreqAndPositions=true; cannot run PhraseQuery (term=" + t.text() + ")"); } else { Index: src/java/org/apache/lucene/search/TermRangeQuery.java =================================================================== --- src/java/org/apache/lucene/search/TermRangeQuery.java (revision 916465) +++ src/java/org/apache/lucene/search/TermRangeQuery.java (working copy) @@ -143,8 +143,7 @@ if ((lowerTerm == null || (collator == null && includeLower && "".equals(lowerTerm))) && upperTerm == null) { // NOTE: debateably, the caller should never pass in a // multi reader... - final Terms terms = MultiFields.getTerms(reader, field); - return (terms != null) ? terms.iterator() : TermsEnum.EMPTY; + return MultiFields.getTerms(reader, field).iterator(); } return new TermRangeTermsEnum(reader, field, lowerTerm, upperTerm, includeLower, includeUpper, collator); Index: src/java/org/apache/lucene/search/AutomatonQuery.java =================================================================== --- src/java/org/apache/lucene/search/AutomatonQuery.java (revision 916465) +++ src/java/org/apache/lucene/search/AutomatonQuery.java (working copy) @@ -79,9 +79,7 @@ // matches all possible strings if (BasicOperations.isTotal(automaton)) { - final Terms terms = MultiFields.getTerms(reader, getField()); - // nocommit -- should we just return null? singleton? - return (terms != null) ? terms.iterator() : TermsEnum.EMPTY; + return MultiFields.getTerms(reader, getField()).iterator(); } // matches a fixed string in singleton representation Index: src/java/org/apache/lucene/index/FieldsEnum.java =================================================================== --- src/java/org/apache/lucene/index/FieldsEnum.java (revision 916465) +++ src/java/org/apache/lucene/index/FieldsEnum.java (working copy) @@ -28,15 +28,15 @@ public abstract class FieldsEnum { - public final static FieldsEnum[] EMPTY_ARRAY = new FieldsEnum[0]; - private AttributeSource atts = null; /** * Returns the related attributes. */ public AttributeSource attributes() { - if (atts == null) atts = new AttributeSource(); + if (atts == null) { + atts = new AttributeSource(); + } return atts; } @@ -54,7 +54,23 @@ /** Get {@link TermsEnum} for the current field. You * should not call {@link #next()} until you're done * using this {@link TermsEnum}. After {@link #next} - * returns null, this method should not be called. */ + * returns null, this method should not be called. This + * method will not return null. */ public abstract TermsEnum terms() throws IOException; + + public final static FieldsEnum[] EMPTY_ARRAY = new FieldsEnum[0]; + + /** Provides zero fields */ + public final static FieldsEnum EMPTY = new FieldsEnum() { + + @Override + public String next() { + return null; + } + + @Override + public TermsEnum terms() { + throw new IllegalStateException("this method should never be called"); + } + }; } - Index: src/java/org/apache/lucene/index/MultiTerms.java =================================================================== --- src/java/org/apache/lucene/index/MultiTerms.java (revision 916465) +++ src/java/org/apache/lucene/index/MultiTerms.java (working copy) @@ -1,6 +1,5 @@ package org.apache.lucene.index; - /** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with @@ -72,7 +71,7 @@ if (termsEnums.size() > 0) { return new MultiTermsEnum(subSlices).reset(termsEnums.toArray(MultiTermsEnum.TermsEnumIndex.EMPTY_ARRAY)); } else { - return null; + return TermsEnum.EMPTY; } } Index: src/java/org/apache/lucene/index/ParallelReader.java =================================================================== --- src/java/org/apache/lucene/index/ParallelReader.java (revision 916465) +++ src/java/org/apache/lucene/index/ParallelReader.java (working copy) @@ -171,7 +171,7 @@ if (terms != null) { return terms.iterator(); } else { - return null; + return TermsEnum.EMPTY; } } } Index: src/java/org/apache/lucene/index/CheckIndex.java =================================================================== --- src/java/org/apache/lucene/index/CheckIndex.java (revision 916465) +++ src/java/org/apache/lucene/index/CheckIndex.java (working copy) @@ -615,7 +615,7 @@ postings = terms.docsAndPositions(delDocs, postings); final DocsEnum docs2; - if (postings != null) { + if (postings != DocsAndPositionsEnum.EMPTY) { docs2 = postings; } else { docs2 = docs; @@ -645,7 +645,7 @@ } int lastPos = -1; - if (postings != null) { + if (postings != DocsAndPositionsEnum.EMPTY) { for(int j=0;j threadEnums = new CloseableThreadLocal(); - /** Returns an iterator that will step through all terms */ + /** Returns an iterator that will step through all + * terms. This method will not return null.*/ public abstract TermsEnum iterator() throws IOException; /** Return the BytesRef Comparator used to sort terms - * provided by the iterator. NOTE: this may return null - * if there are no terms. This method may be invoked - * many times; it's best to cache a single instance & - * reuse it. */ + * provided by the iterator. This method will not return + * null. This method may be invoked many times; it's + * best to cache a single instance & reuse it. */ public abstract BytesRef.Comparator getComparator() throws IOException; /** Returns the number of documents containing the @@ -58,25 +56,25 @@ } // nocommit -- or maybe make a separate positions(...) method? - /** Get DocsEnum for the specified term. Returns null if - * the term does not exist. */ + /** Get DocsEnum for the specified term. This method will + * not return null. */ public DocsEnum docs(Bits skipDocs, BytesRef text, DocsEnum reuse) throws IOException { final TermsEnum termsEnum = getThreadTermsEnum(); if (termsEnum.seek(text) == TermsEnum.SeekStatus.FOUND) { return termsEnum.docs(skipDocs, reuse); } else { - return null; + return DocsEnum.EMPTY; } } - /** Get DocsEnum for the specified term. Returns null if - * the term does not exist. */ + /** Get DocsEnum for the specified term. This method will + * not return null. */ public DocsAndPositionsEnum docsAndPositions(Bits skipDocs, BytesRef text, DocsAndPositionsEnum reuse) throws IOException { final TermsEnum termsEnum = getThreadTermsEnum(); if (termsEnum.seek(text) == TermsEnum.SeekStatus.FOUND) { return termsEnum.docsAndPositions(skipDocs, reuse); } else { - return null; + return DocsAndPositionsEnum.EMPTY; } } @@ -97,4 +95,38 @@ protected void close() { threadEnums.close(); } + public final static Terms[] EMPTY_ARRAY = new Terms[0]; + + /** Provides zero terms */ + public final static Terms EMPTY = new Terms() { + @Override + public TermsEnum iterator() { + return TermsEnum.EMPTY; + } + + @Override + public BytesRef.Comparator getComparator() { + return BytesRef.getUTF8SortedAsUTF16Comparator(); + } + + @Override + public int docFreq(BytesRef text) { + return 0; + } + + @Override + public DocsEnum docs(Bits skipDocs, BytesRef text, DocsEnum reuse) { + return DocsEnum.EMPTY; + } + + @Override + public DocsAndPositionsEnum docsAndPositions(Bits skipDocs, BytesRef text, DocsAndPositionsEnum reuse) { + return DocsAndPositionsEnum.EMPTY; + } + + @Override + public long getUniqueTermCount() { + return 0; + } + }; } Index: src/java/org/apache/lucene/index/DocsAndPositionsEnum.java =================================================================== --- src/java/org/apache/lucene/index/DocsAndPositionsEnum.java (revision 916465) +++ src/java/org/apache/lucene/index/DocsAndPositionsEnum.java (working copy) @@ -41,4 +41,47 @@ public final int read(int[] docs, int[] freqs) { throw new UnsupportedOperationException(); } + + /** Provides zero docs */ + public static final DocsAndPositionsEnum EMPTY = new DocsAndPositionsEnum() { + @Override + public int nextDoc() { + return NO_MORE_DOCS; + } + + @Override + public int advance(int target) { + return NO_MORE_DOCS; + } + + @Override + public int freq() { + throw new IllegalStateException("this method should never be called"); + } + + @Override + public int docID() { + throw new IllegalStateException("this method should never be called"); + } + + @Override + public int nextPosition() { + throw new IllegalStateException("this method should never be called"); + } + + @Override + public int getPayloadLength() { + throw new IllegalStateException("this method should never be called"); + } + + @Override + public BytesRef getPayload() { + throw new IllegalStateException("this method should never be called"); + } + + @Override + public boolean hasPayload() { + throw new IllegalStateException("this method should never be called"); + } + }; } Index: src/java/org/apache/lucene/index/DocsEnum.java =================================================================== --- src/java/org/apache/lucene/index/DocsEnum.java (revision 916465) +++ src/java/org/apache/lucene/index/DocsEnum.java (working copy) @@ -67,4 +67,33 @@ } return count; } + + /** Provides zero docs */ + public static final DocsEnum EMPTY = new DocsEnum() { + + @Override + public int nextDoc() { + return NO_MORE_DOCS; + } + + @Override + public int advance(int target) { + return NO_MORE_DOCS; + } + + @Override + public int freq() { + throw new IllegalStateException("this method should never be called"); + } + + @Override + public int docID() { + throw new IllegalStateException("this method should never be called"); + } + + @Override + public int read(int[] docs, int[] freqs) { + return 0; + } + }; } Index: src/java/org/apache/lucene/index/DirectoryReader.java =================================================================== --- src/java/org/apache/lucene/index/DirectoryReader.java (revision 916465) +++ src/java/org/apache/lucene/index/DirectoryReader.java (working copy) @@ -786,7 +786,7 @@ @Override public Fields fields() throws IOException { if (subReaders.length == 0) { - return null; + return Fields.EMPTY; } else { throw new UnsupportedOperationException("please use MultiFields.getFields if you really need a top level Fields for this reader"); } Index: src/java/org/apache/lucene/index/MultiFieldsEnum.java =================================================================== --- src/java/org/apache/lucene/index/MultiFieldsEnum.java (revision 916465) +++ src/java/org/apache/lucene/index/MultiFieldsEnum.java (working copy) @@ -107,7 +107,7 @@ } if (termsEnums.size() == 0) { - return null; + return TermsEnum.EMPTY; } else { return terms.reset(termsEnums.toArray(MultiTermsEnum.TermsEnumIndex.EMPTY_ARRAY)); } Index: src/java/org/apache/lucene/index/TermsEnum.java =================================================================== --- src/java/org/apache/lucene/index/TermsEnum.java (revision 916465) +++ src/java/org/apache/lucene/index/TermsEnum.java (working copy) @@ -91,19 +91,24 @@ * {@link SeekStatus#END}.*/ public abstract int docFreq(); - // nocommit -- clarify if this may return null + // nocommit -- need some way to state this postings does + // not store positions? // nocommit -- maybe require up front boolean doPositions? // nocommit -- or maybe make a separate positions(...) method? /** Get {@link DocsEnum} for the current term. Do not - * call this before calling next() for the first time, - * after next() returns null or seek returns {@link - * SeekStatus#END}. + * call this before calling {@link #next} or {@link + * #seek} for the first time. This method will not + * return null. * * @param skipDocs set bits are documents that should not * be returned * @param reuse pass a prior DocsEnum for possible reuse */ public abstract DocsEnum docs(Bits skipDocs, DocsEnum reuse) throws IOException; + /** Get {@link DocsAndPositionsEnum} for the current term. + * Do not call this before calling {@link #next} or + * {@link #seek} for the first time. This method will + * not return null. */ public abstract DocsAndPositionsEnum docsAndPositions(Bits skipDocs, DocsAndPositionsEnum reuse) throws IOException; /** Return the {@link BytesRef} Comparator used to sort @@ -128,7 +133,9 @@ public SeekStatus seek(long ord) { return SeekStatus.END; } @Override - public BytesRef term() { return null; } + public BytesRef term() { + throw new IllegalStateException("this method should never be called"); + } @Override public BytesRef.Comparator getComparator() { @@ -137,21 +144,29 @@ } @Override - public int docFreq() { return -1; } + public int docFreq() { + throw new IllegalStateException("this method should never be called"); + } @Override - public long ord() { return -1; } + public long ord() { + throw new IllegalStateException("this method should never be called"); + } @Override - public DocsEnum docs(Bits bits, DocsEnum reuse) { return null; } + public DocsEnum docs(Bits bits, DocsEnum reuse) { + throw new IllegalStateException("this method should never be called"); + } @Override public DocsAndPositionsEnum docsAndPositions(Bits bits, DocsAndPositionsEnum reuse) { - return null; + throw new IllegalStateException("this method should never be called"); } @Override - public BytesRef next() { return null; } + public BytesRef next() { + return null; + } @Override // make it synchronized here, to prevent double lazy init public synchronized AttributeSource attributes() { Index: src/java/org/apache/lucene/index/IndexReader.java =================================================================== --- src/java/org/apache/lucene/index/IndexReader.java (revision 916465) +++ src/java/org/apache/lucene/index/IndexReader.java (working copy) @@ -883,7 +883,7 @@ public abstract TermEnum terms() throws IOException; /** Flex API: returns {@link Fields} for this reader. - * This may return null if there are no fields. + * This method will not return null. * *

NOTE: if this is a multi reader ({@link * #getSequentialSubReaders} is not null) then this @@ -920,12 +920,7 @@ * account deleted documents that have not yet been * merged away. */ public int docFreq(String field, BytesRef term) throws IOException { - final Terms terms = fields().terms(field); - if (terms != null) { - return terms.docFreq(term); - } else { - return 0; - } + return fields().terms(field).docFreq(term); } /** Returns an enumeration of all the documents which contain @@ -951,63 +946,25 @@ } public Terms terms(String field) throws IOException { - final Fields fields = fields(); - if (fields != null) { - return fields.terms(field); - } else { - return null; - } + return fields().terms(field); } /** Returns {@link DocsEnum} for the specified field & * term. This may return null, for example if either the * field or term does not exist. */ public DocsEnum termDocsEnum(Bits skipDocs, String field, BytesRef term) throws IOException { - assert field != null; assert term != null; - final Fields fields = fields(); - if (fields != null) { - final Terms terms = fields.terms(field); - if (terms != null) { - if (Codec.DEBUG) { - System.out.println("ir.termDocsEnum field=" + field + " term=" + term + " terms=" + terms + " this=" + this); - } - final DocsEnum docs = terms.docs(skipDocs, term, null); - if (Codec.DEBUG) { - System.out.println("ir.termDocsEnum field=" + field + " docs=" +docs); - } - return docs; - } - } - - return null; + return fields().terms(field).docs(skipDocs, term, null); } /** Returns {@link DocsAndPositionsEnum} for the specified * field & term. This may return null, for example if * either the field or term does not exist. */ public DocsAndPositionsEnum termPositionsEnum(Bits skipDocs, String field, BytesRef term) throws IOException { - assert field != null; assert term != null; - - final Fields fields = fields(); - if (fields != null) { - final Terms terms = fields.terms(field); - if (terms != null) { - if (Codec.DEBUG) { - System.out.println("ir.termPositionsEnum field=" + field + " term=" + term + " terms=" + terms + " this=" + this); - } - final DocsAndPositionsEnum postings = terms.docsAndPositions(skipDocs, term, null); - if (Codec.DEBUG) { - System.out.println("ir.termPositionsEnum field=" + field + " postings=" +postings); - } - return postings; - } - } - - return null; + return fields().terms(field).docsAndPositions(skipDocs, term, null); } /** Returns an unpositioned {@link TermDocs} enumerator. Index: src/java/org/apache/lucene/index/MultiTermsEnum.java =================================================================== --- src/java/org/apache/lucene/index/MultiTermsEnum.java (revision 916465) +++ src/java/org/apache/lucene/index/MultiTermsEnum.java (working copy) @@ -23,6 +23,7 @@ import org.apache.lucene.util.BitsSlice; import org.apache.lucene.util.MultiBits; import org.apache.lucene.util.ReaderUtil; +import org.apache.lucene.index.TermsEnum; import java.io.IOException; @@ -93,7 +94,7 @@ /** The terms array must be newly created TermsEnum, ie * {@link TermsEnum#next} has not yet been called. */ - public MultiTermsEnum reset(TermsEnumIndex[] termsEnumsIndex) throws IOException { + public TermsEnum reset(TermsEnumIndex[] termsEnumsIndex) throws IOException { assert termsEnumsIndex.length <= top.length; numSubs = 0; numTop = 0; @@ -128,7 +129,7 @@ } if (queue.size() == 0) { - return null; + return TermsEnum.EMPTY; } else { return this; } @@ -280,7 +281,7 @@ } if (upto == 0) { - return null; + return DocsEnum.EMPTY; } else { return docsEnum.reset(subDocs, upto); } @@ -339,7 +340,7 @@ } if (upto == 0) { - return null; + return DocsAndPositionsEnum.EMPTY; } else { return docsAndPositionsEnum.reset(subDocsAndPositions, upto); } Index: src/java/org/apache/lucene/index/Fields.java =================================================================== --- src/java/org/apache/lucene/index/Fields.java (revision 916465) +++ src/java/org/apache/lucene/index/Fields.java (working copy) @@ -19,18 +19,33 @@ import java.io.IOException; -/** Access to fields and terms +/** Flex API for access to fields and terms * @lucene.experimental */ public abstract class Fields { - public final static Fields[] EMPTY_ARRAY = new Fields[0]; - /** Returns an iterator that will step through all fields - * names */ + * names. This method will not return null. */ public abstract FieldsEnum iterator() throws IOException; - /** Get the {@link Terms} for this field */ + /** Get the {@link Terms} for this field. This method + * will not return null. */ public abstract Terms terms(String field) throws IOException; + + public final static Fields[] EMPTY_ARRAY = new Fields[0]; + + /** Provides zero fields */ + public final static Fields EMPTY = new Fields() { + + @Override + public FieldsEnum iterator() { + return FieldsEnum.EMPTY; + } + + @Override + public Terms terms(String field) { + return Terms.EMPTY; + } + }; } Index: src/java/org/apache/lucene/index/codecs/TermsConsumer.java =================================================================== --- src/java/org/apache/lucene/index/codecs/TermsConsumer.java (revision 916465) +++ src/java/org/apache/lucene/index/codecs/TermsConsumer.java (working copy) @@ -51,6 +51,7 @@ public void merge(MergeState mergeState, TermsEnum termsEnum) throws IOException { BytesRef term; + assert termsEnum != null; if (mergeState.fieldInfo.omitTermFreqAndPositions) { if (docsEnum == null) { @@ -61,14 +62,11 @@ MultiDocsEnum docsEnumIn = null; while((term = termsEnum.next()) != null) { - MultiDocsEnum docsEnumIn2 = (MultiDocsEnum) termsEnum.docs(mergeState.multiDeletedDocs, docsEnumIn); - if (docsEnumIn2 != null) { - docsEnumIn = docsEnumIn2; - docsEnum.reset(docsEnumIn); - final PostingsConsumer postingsConsumer = startTerm(term); - final int numDocs = postingsConsumer.merge(mergeState, docsEnum); - finishTerm(term, numDocs); - } + docsEnumIn = (MultiDocsEnum) termsEnum.docs(mergeState.multiDeletedDocs, docsEnumIn); + docsEnum.reset(docsEnumIn); + final PostingsConsumer postingsConsumer = startTerm(term); + final int numDocs = postingsConsumer.merge(mergeState, docsEnum); + finishTerm(term, numDocs); } } else { if (postingsEnum == null) { @@ -77,14 +75,12 @@ postingsEnum.setMergeState(mergeState); MultiDocsAndPositionsEnum postingsEnumIn = null; while((term = termsEnum.next()) != null) { - MultiDocsAndPositionsEnum postingsEnumIn2 = (MultiDocsAndPositionsEnum) termsEnum.docsAndPositions(mergeState.multiDeletedDocs, postingsEnumIn); - if (postingsEnumIn2 != null) { - postingsEnumIn = postingsEnumIn2; - postingsEnum.reset(postingsEnumIn); - final PostingsConsumer postingsConsumer = startTerm(term); - final int numDocs = postingsConsumer.merge(mergeState, postingsEnum); - finishTerm(term, numDocs); - } + postingsEnumIn = (MultiDocsAndPositionsEnum) termsEnum.docsAndPositions(mergeState.multiDeletedDocs, postingsEnumIn); + assert postingsEnumIn != null; + postingsEnum.reset(postingsEnumIn); + final PostingsConsumer postingsConsumer = startTerm(term); + final int numDocs = postingsConsumer.merge(mergeState, postingsEnum); + finishTerm(term, numDocs); } } } Index: src/java/org/apache/lucene/index/codecs/standard/StandardTermsDictReader.java =================================================================== --- src/java/org/apache/lucene/index/codecs/standard/StandardTermsDictReader.java (revision 916465) +++ src/java/org/apache/lucene/index/codecs/standard/StandardTermsDictReader.java (working copy) @@ -205,7 +205,12 @@ if (Codec.DEBUG) { System.out.println("stdr.terms field=" + field + " found=" + fields.get(field)); } - return fields.get(field); + final Terms terms = fields.get(field); + if (terms == null) { + return Terms.EMPTY; + } else { + return terms; + } } // Iterates through all fields @@ -552,6 +557,7 @@ System.out.println("stdr.docs"); } DocsEnum docsEnum = postingsReader.docs(fieldInfo, state, skipDocs, reuse); + assert docsEnum != null; if (Codec.DEBUG) { docsEnum.desc = fieldInfo.name + ":" + bytesReader.term.utf8ToString(); } @@ -564,13 +570,12 @@ System.out.println("stdr.docsAndPositions omitTF=" + fieldInfo.omitTermFreqAndPositions); } if (fieldInfo.omitTermFreqAndPositions) { - return null; + return DocsAndPositionsEnum.EMPTY; } else { DocsAndPositionsEnum postingsEnum = postingsReader.docsAndPositions(fieldInfo, state, skipDocs, reuse); + assert postingsEnum != null; if (Codec.DEBUG) { - if (postingsEnum != null) { - postingsEnum.desc = fieldInfo.name + ":" + bytesReader.term.utf8ToString(); - } + postingsEnum.desc = fieldInfo.name + ":" + bytesReader.term.utf8ToString(); } if (Codec.DEBUG) { Codec.debug(" return enum=" + postingsEnum); Index: src/java/org/apache/lucene/index/codecs/standard/StandardPostingsReaderImpl.java =================================================================== --- src/java/org/apache/lucene/index/codecs/standard/StandardPostingsReaderImpl.java (revision 916465) +++ src/java/org/apache/lucene/index/codecs/standard/StandardPostingsReaderImpl.java (working copy) @@ -165,7 +165,8 @@ @Override public DocsEnum docs(FieldInfo fieldInfo, TermState termState, Bits skipDocs, DocsEnum reuse) throws IOException { final SegmentDocsEnum docsEnum; - if (reuse == null) { + // nocommit messy + if (reuse == null || !(reuse instanceof SegmentDocsEnum)) { docsEnum = new SegmentDocsEnum(freqIn); } else { docsEnum = (SegmentDocsEnum) reuse; @@ -176,10 +177,10 @@ @Override public DocsAndPositionsEnum docsAndPositions(FieldInfo fieldInfo, TermState termState, Bits skipDocs, DocsAndPositionsEnum reuse) throws IOException { if (fieldInfo.omitTermFreqAndPositions) { - return null; + return DocsAndPositionsEnum.EMPTY; } final SegmentDocsAndPositionsEnum docsEnum; - if (reuse == null) { + if (reuse == null || !(reuse instanceof SegmentDocsAndPositionsEnum)) { docsEnum = new SegmentDocsAndPositionsEnum(freqIn, proxIn); } else { docsEnum = (SegmentDocsAndPositionsEnum) reuse; Index: src/java/org/apache/lucene/index/codecs/FieldsConsumer.java =================================================================== --- src/java/org/apache/lucene/index/codecs/FieldsConsumer.java (revision 916465) +++ src/java/org/apache/lucene/index/codecs/FieldsConsumer.java (working copy) @@ -41,14 +41,12 @@ public void merge(MergeState mergeState, Fields fields) throws IOException { FieldsEnum fieldsEnum = fields.iterator(); + assert fieldsEnum != null; String field; while((field = fieldsEnum.next()) != null) { mergeState.fieldInfo = mergeState.fieldInfos.fieldInfo(field); final TermsConsumer termsConsumer = addField(mergeState.fieldInfo); - final TermsEnum termsEnum = fieldsEnum.terms(); - if (termsEnum != null) { - termsConsumer.merge(mergeState, termsEnum); - } + termsConsumer.merge(mergeState, fieldsEnum.terms()); } } } Index: src/java/org/apache/lucene/index/codecs/preflex/PreFlexFields.java =================================================================== --- src/java/org/apache/lucene/index/codecs/preflex/PreFlexFields.java (revision 916465) +++ src/java/org/apache/lucene/index/codecs/preflex/PreFlexFields.java (working copy) @@ -124,7 +124,7 @@ if (fi != null) { return new PreTerms(fi); } else { - return null; + return Terms.EMPTY; } } Index: src/java/org/apache/lucene/index/MultiFields.java =================================================================== --- src/java/org/apache/lucene/index/MultiFields.java (revision 916465) +++ src/java/org/apache/lucene/index/MultiFields.java (working copy) @@ -45,8 +45,9 @@ public final class MultiFields extends Fields { private final Fields[] subs; private final ReaderUtil.Slice[] subSlices; - private final Map terms = new HashMap(); + private final Map terms = new HashMap(); + /** This method will not return null.*/ public static Fields getFields(IndexReader r) throws IOException { final IndexReader[] subs = r.getSequentialSubReaders(); if (subs == null) { @@ -64,7 +65,7 @@ ReaderUtil.gatherSubFields(null, fields, slices, r, 0); if (fields.size() == 0) { - return null; + return Fields.EMPTY; } else if (fields.size() == 1) { currentFields = fields.get(0); } else { @@ -77,66 +78,27 @@ } } + /** This method will not return null.*/ public static Terms getTerms(IndexReader r, String field) throws IOException { - final Fields fields = getFields(r); - if (fields != null) { - return fields.terms(field); - } else { - return null; - } + return getFields(r).terms(field); } /** Returns {@link DocsEnum} for the specified field & - * term. This may return null, for example if either the - * field or term does not exist. */ + * term. This method will not return null. */ public static DocsEnum getTermDocsEnum(IndexReader r, Bits skipDocs, String field, BytesRef term) throws IOException { - assert field != null; assert term != null; - final Fields fields = getFields(r); - if (fields != null) { - final Terms terms = fields.terms(field); - if (terms != null) { - if (Codec.DEBUG) { - System.out.println("mf.termDocsEnum field=" + field + " term=" + term + " terms=" + terms); - } - final DocsEnum docs = terms.docs(skipDocs, term, null); - if (Codec.DEBUG) { - System.out.println("mf.termDocsEnum field=" + field + " docs=" +docs); - } - return docs; - } - } - - return null; + return getFields(r).terms(field).docs(skipDocs, term, null); } /** Returns {@link DocsAndPositionsEnum} for the specified - * field & term. This may return null, for example if - * either the field or term does not exist. */ + * field & term. This method will not return null. */ public static DocsAndPositionsEnum getTermPositionsEnum(IndexReader r, Bits skipDocs, String field, BytesRef term) throws IOException { assert field != null; assert term != null; - - final Fields fields = getFields(r); - if (fields != null) { - final Terms terms = fields.terms(field); - if (terms != null) { - if (Codec.DEBUG) { - System.out.println("mf.termPositionsEnum field=" + field + " term=" + term + " terms=" + terms); - } - final DocsAndPositionsEnum postings = terms.docsAndPositions(skipDocs, term, null); - if (Codec.DEBUG) { - System.out.println("mf.termPositionsEnum field=" + field + " postings=" +postings); - } - return postings; - } - } - - return null; + return getFields(r).terms(field).docsAndPositions(skipDocs, term, null); } - public MultiFields(Fields[] subs, ReaderUtil.Slice[] subSlices) { this.subs = subs; this.subSlices = subSlices; @@ -148,14 +110,11 @@ final List fieldsEnums = new ArrayList(); final List fieldsSlices = new ArrayList(); for(int i=0;i