Index: solr/core/src/java/org/apache/solr/response/CSVResponseWriter.java =================================================================== --- solr/core/src/java/org/apache/solr/response/CSVResponseWriter.java (revision 1468535) +++ solr/core/src/java/org/apache/solr/response/CSVResponseWriter.java (working copy) @@ -235,19 +235,27 @@ // encapsulator will already be disabled if it wasn't specified } - Collection fields = returnFields.getLuceneFieldNames(); + Collection fields = returnFields.getRequestedFieldNames(); Object responseObj = rsp.getValues().get("response"); boolean returnOnlyStored = false; - if (fields==null) { + if (fields==null||returnFields.hasPatternMatching()) { if (responseObj instanceof SolrDocumentList) { // get the list of fields from the SolrDocumentList - fields = new LinkedHashSet(); + if(fields==null) { + fields = new LinkedHashSet(); + } for (SolrDocument sdoc: (SolrDocumentList)responseObj) { fields.addAll(sdoc.getFieldNames()); } } else { // get the list of fields from the index - fields = req.getSearcher().getFieldNames(); + Collection all = req.getSearcher().getFieldNames(); + if(fields==null) { + fields = all; + } + else { + fields.addAll(all); + } } if (returnFields.wantsScore()) { fields.add("score"); Index: solr/core/src/java/org/apache/solr/search/ReturnFields.java =================================================================== --- solr/core/src/java/org/apache/solr/search/ReturnFields.java (revision 1468535) +++ solr/core/src/java/org/apache/solr/search/ReturnFields.java (working copy) @@ -35,6 +35,13 @@ */ public abstract Set getLuceneFieldNames(); + /** + * The requested field names (includes pseudo fields) + *

+ * @return Set of field names or null (all fields). + */ + public abstract Set getRequestedFieldNames(); + /** Returns true if the specified field should be returned. */ public abstract boolean wantsField(String name); @@ -44,6 +51,9 @@ /** Returns true if the score should be returned. */ public abstract boolean wantsScore(); + /** Returns true if the fieldnames should be picked with a pattern */ + public abstract boolean hasPatternMatching(); + /** Returns the DocTransformer used to modify documents, or null */ public abstract DocTransformer getTransformer(); } Index: solr/core/src/java/org/apache/solr/search/SolrReturnFields.java =================================================================== --- solr/core/src/java/org/apache/solr/search/SolrReturnFields.java (revision 1468535) +++ solr/core/src/java/org/apache/solr/search/SolrReturnFields.java (working copy) @@ -52,14 +52,14 @@ private final List globs = new ArrayList(1); // The lucene field names to request from the SolrIndexSearcher - // Order is important for CSVResponseWriter - private final Set fields = new LinkedHashSet(); + private final Set fields = new HashSet(); // Field names that are OK to include in the response. // This will include pseudo fields, lucene fields, and matching globs private Set okFieldNames = new HashSet(); // The list of explicitly requested fields + // Order is important for CSVResponseWriter private Set reqFieldNames = null; protected DocTransformer transformer; @@ -122,7 +122,7 @@ if(from.equals(rename.getName(j))) { rename.setName(j, to); // copy from the current target if(reqFieldNames==null) { - reqFieldNames = new HashSet(); + reqFieldNames = new LinkedHashSet(); } reqFieldNames.add(to); // don't rename our current target } @@ -360,12 +360,16 @@ private void addField(String field, String key, DocTransformers augmenters, SolrQueryRequest req) { + if(reqFieldNames==null) { + reqFieldNames = new LinkedHashSet(); + } + if(key==null) { - if(reqFieldNames==null) { - reqFieldNames = new HashSet(); - } reqFieldNames.add(field); } + else { + reqFieldNames.add(key); + } fields.add(field); // need to put in the map to maintain order for things like CSVResponseWriter okFieldNames.add( field ); @@ -386,6 +390,19 @@ } @Override + public Set getRequestedFieldNames() { + if(_wantsAllFields || reqFieldNames==null || reqFieldNames.isEmpty()) { + return null; + } + return reqFieldNames; + } + + @Override + public boolean hasPatternMatching() { + return !globs.isEmpty(); + } + + @Override public boolean wantsField(String name) { if( _wantsAllFields || okFieldNames.contains( name ) ){ Index: solr/core/src/test/org/apache/solr/response/TestCSVResponseWriter.java =================================================================== --- solr/core/src/test/org/apache/solr/response/TestCSVResponseWriter.java (revision 1468535) +++ solr/core/src/test/org/apache/solr/response/TestCSVResponseWriter.java (working copy) @@ -59,7 +59,7 @@ // test multivalued assertEquals("2,\"hi,there\"\n" , h.query(req("q","id:2", "wt","csv", "csv.header","false", "fl","id,v_ss"))); - + // test separator change assertEquals("2|\"hi|there\"\n" , h.query(req("q","id:2", "wt","csv", "csv.header","false", "csv.separator","|", "fl","id,v_ss"))); @@ -193,7 +193,22 @@ req.close(); } + + @Test + public void testPseudoFields() throws Exception { + // Use Pseudo Field + assertEquals("1,hi", + h.query(req("q","id:1", "wt","csv", "csv.header","false", "fl","XXX:id,foo_s")).trim()); + + String txt = h.query(req("q","id:1", "wt","csv", "csv.header","true", "fl","XXX:id,YYY:[docid],FOO:foo_s")); + String[] lines = txt.split("\n"); + assertEquals(2, lines.length); + assertEquals("XXX,YYY,FOO", lines[0] ); + assertEquals("1,0,hi", lines[1] ); + } + + /* * Utility method to sort a comma separated list of strings, for easier comparison regardless of platform */