--- omqueryinternal.cc-orig	2008-12-23 08:55:41.000000000 +0100
+++ omqueryinternal.cc	2009-01-26 08:52:02.000000000 +0100
@@ -890,14 +890,41 @@
     }
 }
 
-/// Change, eg, A NEAR (B AND C) to (A NEAR B) AND (A NEAR C)
+/// Transform a NEAR/PHRASE query until all its subqueries are leafs,
+/// which is the only kind currently accepted by the NEAR/PHRASE
+/// matcher.
+///
+/// NEAR and PHRASE are distributive over the OR Boolean operator. Ie:
+/// A NEAR (B OR C) is equivalent to (A NEAR B) OR (A NEAR C)
+/// 
+/// ** A NEAR (B AND C) is roughly equivalent to A NEAR B NEAR C. This case
+/// is currently incorrectly handled **
+///
+/// The distributing operation is performed one subquery at a time, by
+/// building a new query which then replaces (is swapped with) the
+/// original. The new object is not a NEAR/PHRASE query any more, but
+/// its subqueries are, and the process is repeated by recursively
+/// calling flatten_subqs() on them.
+///
+/// The new query is built in the following fashion:
+///  - It has an operation which is the one from the distributed
+///    subquery (OR)
+///  - Its list of subqueries is obtained by successively replacing in
+///    the father objects's subquery list the distributed subquery by
+///    each if its elements.
+/// 
 void
 Xapian::Query::Internal::flatten_subqs()
 {
-    if (op != Xapian::Query::OP_NEAR && op != Xapian::Query::OP_PHRASE) {
-	throw Xapian::UnimplementedError("NEAR or PHRASE with non-term subqueries isn't well supported currently");
-    }
+    if (!(op == Xapian::Query::OP_NEAR || op == Xapian::Query::OP_PHRASE))
+	return;
+
+    //static string tabs;
+    //fprintf(stderr, "%sflatten_subqs():%s: %s\n", tabs.c_str(),
+    //  get_op_name(op).c_str(), get_description().c_str());
+    //tabs += "  ";
 
+    // Look for a non leaf subquery. If none found, there is nothing to do.
     subquery_list::iterator sq;
     for (sq = subqs.begin(); sq != subqs.end(); sq++) {
 	if (!is_leaf((*sq)->op)) break;
@@ -910,17 +937,23 @@
 	    throw Xapian::UnimplementedError("Can't use NEAR/PHRASE with a subexpression containing NEAR or PHRASE");
 	}
 
+	// Got one non leaf subquery. Make a copy of it, and replace
+	// it by a hole in my subquery list
 	AutoPtr<Xapian::Query::Internal> flattenme(*sq);
 	*sq = 0;
+	// Note: me invalid here . Hole in subqs !
 
-	// New query to build up.
+	// New query to build up. Its operator is the one from the
+	// subquery we're distributing over
 	Xapian::Query::Internal newq(flattenme->op, 0);
 
+	// Successively place the subquery's subqueries in the empty
+	// space, and add the resulting query (me) as a subquery of
+	// the one we are building
 	subquery_list::iterator j;
 	for (j = flattenme->subqs.begin(); j != flattenme->subqs.end(); ++j) {
 	    *sq = *j;
 	    *j = 0;
-	    flatten_subqs();
 	    newq.add_subquery(this);
 	    delete *sq;
 	    *sq = 0;
@@ -930,6 +963,19 @@
 	Assert(newq2);
 	this->swap(*newq2);
     }
+
+    // I am now a boolean query combining possibly non-flat
+    // NEAR/PHRASE subqueries. Repeat the process on them. Note that
+    // while the tree has deepened, the NEAR layer also has gone down
+    // one step, which it does at each recursion. As the tree will
+    // stop deepening when all the subqueries are leafs, the recursion
+    // is finite.
+    for (sq = subqs.begin(); sq != subqs.end(); sq++) {
+    	(*sq)->flatten_subqs();
+    }
+    
+    //tabs.erase(tabs.length() - 2);
+    //fprintf(stderr, "%sdone flatten_subqs()\n", tabs.c_str());
 }
 
 void
