protected NodeSet search(DBBroker broker, NodeSet contextSet, Geometry EPSG4326_geometry, int spatialOp, Connection conn)
        throws SQLException {
	String extraSelection = null;
	String bboxConstraint = null;    	
	switch (spatialOp) {
	  //BBoxes are equal
	  case SpatialOperator.EQUALS:
	    bboxConstraint = "(EPSG4326_MINX = ? AND EPSG4326_MAXX = ?)" +
	    " AND (EPSG4326_MINY = ? AND EPSG4326_MAXY = ?)";
	    break;
	  //Nothing much we can do with the BBox at this stage
	  case SpatialOperator.DISJOINT:
	    //Retrieve the BBox though...
	    extraSelection = ", EPSG4326_MINX, EPSG4326_MAXX, EPSG4326_MINY, EPSG4326_MAXY";
	    break;
	  //BBoxes intersect themselves
	  case SpatialOperator.INTERSECTS:        		
	  case SpatialOperator.TOUCHES:        		   		
	  case SpatialOperator.CROSSES:        		      		
	  case SpatialOperator.OVERLAPS: 
	    bboxConstraint = "(EPSG4326_MAXX >= ? AND EPSG4326_MINX <= ?)" +
	    " AND (EPSG4326_MAXY >= ? AND EPSG4326_MINY <= ?)";
	    break;
	  //BBox is fully within
	  case SpatialOperator.WITHIN:   
	    bboxConstraint = "(EPSG4326_MINX >= ? AND EPSG4326_MAXX <= ?)" +
	    " AND (EPSG4326_MINY >= ? AND EPSG4326_MAXY <= ?)";
	    break;
	  //BBox fully contains
	  case SpatialOperator.CONTAINS: 
	    bboxConstraint = "(EPSG4326_MINX <= ? AND EPSG4326_MAXX >= ?)" +
	    " AND (EPSG4326_MINY <= ? AND EPSG4326_MAXY >= ?)";
	    break;       		
	  default:
	    throw new IllegalArgumentException("Unsupported spatial operator:" + spatialOp);
        }
	PreparedStatement ps = conn.prepareStatement(
	"SELECT EPSG4326_WKB, DOCUMENT_URI, NODE_ID_UNITS, NODE_ID" + (extraSelection == null ? "" : extraSelection) +
	" FROM " + GMLHSQLIndex.TABLE_NAME + 
	(bboxConstraint == null ? "" : " WHERE " + bboxConstraint) + ";"
	);
	if (bboxConstraint != null) {
	  ps.setDouble(1, EPSG4326_geometry.getEnvelopeInternal().getMinX());
	  ps.setDouble(2, EPSG4326_geometry.getEnvelopeInternal().getMaxX());
	  ps.setDouble(3, EPSG4326_geometry.getEnvelopeInternal().getMinY());
	  ps.setDouble(4, EPSG4326_geometry.getEnvelopeInternal().getMaxY());
	}
	ResultSet rs = null;
	NodeSet result = null;
	try { 
	  int disjointPostFiltered = 0;
	  rs = ps.executeQuery();
	  result = new ExtArrayNodeSet(); //new ExtArrayNodeSet(docs.getLength(), 250)
	  while (rs.next()) {
	    DocumentImpl doc = null;
	    try {
	      doc = (DocumentImpl)broker.getXMLResource(XmldbURI.create(rs.getString("DOCUMENT_URI")));        			
	    } catch (PermissionDeniedException e) {
	      LOG.debug(e);
	      //Ignore since the broker has no right on the document
	      continue;
	    }
	    //contextSet == null should be use to scan the whole index
	    if (contextSet == null || contextSet.getDocumentSet().contains(doc.getDocId())) {
	      NodeId nodeId = new DLN(rs.getInt("NODE_ID_UNITS"), rs.getBytes("NODE_ID"), 0); 
	      NodeProxy p = new NodeProxy((DocumentImpl)doc, nodeId);
	      if (contextSet == null || contextSet.get(p) != null) {
	        boolean geometryMatches = false;
		if (spatialOp == SpatialOperator.DISJOINT) {
		  //No BBox intersection : obviously disjoint
		  if (rs.getDouble("EPSG4326_MAXX") < EPSG4326_geometry.getEnvelopeInternal().getMinX() ||	        			
		  rs.getDouble("EPSG4326_MINX") > EPSG4326_geometry.getEnvelopeInternal().getMaxX() ||	        			
		  rs.getDouble("EPSG4326_MAXY") < EPSG4326_geometry.getEnvelopeInternal().getMinY() ||	        			
		  rs.getDouble("EPSG4326_MINY") > EPSG4326_geometry.getEnvelopeInternal().getMaxY()) {
		    geometryMatches = true;
		    disjointPostFiltered++;
		  }
		}
		//Possible match : check the geometry
		if (!geometryMatches) {	
		  try {	        	
		    Geometry geometry = wkbReader.read(rs.getBytes("EPSG4326_WKB"));
		    switch (spatialOp) {
		      case SpatialOperator.EQUALS:
		        geometryMatches = geometry.equals(EPSG4326_geometry);
			break;
		      case SpatialOperator.DISJOINT:        		
		        geometryMatches = geometry.disjoint(EPSG4326_geometry);
		        break;  		
		      case SpatialOperator.INTERSECTS:        		
		        geometryMatches = geometry.intersects(EPSG4326_geometry);
		        break;
		      case SpatialOperator.TOUCHES:
		        geometryMatches = geometry.touches(EPSG4326_geometry);
		        break; 		
		      case SpatialOperator.CROSSES:
		        geometryMatches = geometry.crosses(EPSG4326_geometry);
		        break;
		      case SpatialOperator.WITHIN:        		
		        geometryMatches = geometry.within(EPSG4326_geometry);
		        break; 		
		      case SpatialOperator.CONTAINS:	        		
		        geometryMatches = geometry.contains(EPSG4326_geometry);
		        break;
		      case SpatialOperator.OVERLAPS:	        		
		        geometryMatches = geometry.overlaps(EPSG4326_geometry);
		        break;
		    }
		  } catch (ParseException e) {
		    //Transforms the exception into an SQLException.
		    //Very unlikely to happen though...
		    SQLException ee = new SQLException(e.getMessage());
		    ee.initCause(e);
		    throw ee;
		  }
		}
		if (geometryMatches)        	
		  result.add(p);
	      }
	    }
	  }
	  if (LOG.isDebugEnabled()) {
	    LOG.debug(rs.getRow() + " eligible geometries, " + result.getItemCount() + "selected" +
	    (spatialOp == SpatialOperator.DISJOINT ? "(" + disjointPostFiltered + " post filtered)" : ""));
	    }
	    return result;	    	
        } finally { 
          if (rs != null)
	    rs.close();
	  if (ps != null)
	    ps.close();	    		
        }
      }