You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by da...@apache.org on 2011/08/15 05:57:48 UTC

svn commit: r1157706 - in /couchdb/branches/1.1.x: ./ etc/default/couchdb share/www/script/test/all_docs.js share/www/script/test/view_collation_raw.js src/couchdb/couch_btree.erl src/couchdb/couch_httpd_db.erl src/couchdb/couch_httpd_view.erl

Author: davisp
Date: Mon Aug 15 03:57:48 2011
New Revision: 1157706

URL: http://svn.apache.org/viewvc?rev=1157706&view=rev
Log:
Fix empty range check for raw collation.

The check for empty ranges was not taking into account the
view option for raw collation. This fixes that by passing
the couch_btree:less/2 function into the check.

Patch by: Jason Smith
Back port of: 1156506, 1156507, 1156509, 1156509, 1156610



Modified:
    couchdb/branches/1.1.x/   (props changed)
    couchdb/branches/1.1.x/etc/default/couchdb   (props changed)
    couchdb/branches/1.1.x/share/www/script/test/all_docs.js
    couchdb/branches/1.1.x/share/www/script/test/view_collation_raw.js
    couchdb/branches/1.1.x/src/couchdb/couch_btree.erl
    couchdb/branches/1.1.x/src/couchdb/couch_httpd_db.erl
    couchdb/branches/1.1.x/src/couchdb/couch_httpd_view.erl

Propchange: couchdb/branches/1.1.x/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Mon Aug 15 03:57:48 2011
@@ -6,4 +6,4 @@
 /couchdb/branches/list-iterator:782292-784593
 /couchdb/branches/tail_header:775760-778477
 /couchdb/tags/0.10.0:825400
-/couchdb/trunk:1045203,1064417,1081107-1083320,1083714,1095523,1095557,1095569,1095581,1096098,1097300,1099479,1102006
+/couchdb/trunk:1045203,1064417,1081107-1083320,1083714,1095523,1095557,1095569,1095581,1096098,1097300,1099479,1102006,1156506-1156509,1156610

Propchange: couchdb/branches/1.1.x/etc/default/couchdb
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Mon Aug 15 03:57:48 2011
@@ -6,5 +6,5 @@
 /couchdb/branches/list-iterator/etc/default/couchdb:782292-784593
 /couchdb/branches/tail_header/etc/default/couchdb:775760-778477
 /couchdb/tags/0.10.0/etc/default/couchdb:825400
-/couchdb/trunk/etc/default/couchdb:1045203,1064417,1081107-1083320,1083714,1095523,1095557,1095569,1095581,1096098,1097300,1099479,1102006
+/couchdb/trunk/etc/default/couchdb:1045203,1064417,1081107-1083320,1083714,1095523,1095557,1095569,1095581,1096098,1097300,1099479,1102006,1156506-1156509,1156610
 /incubator/couchdb/trunk/etc/default/couchdb:642419-694440

Modified: couchdb/branches/1.1.x/share/www/script/test/all_docs.js
URL: http://svn.apache.org/viewvc/couchdb/branches/1.1.x/share/www/script/test/all_docs.js?rev=1157706&r1=1157705&r2=1157706&view=diff
==============================================================================
--- couchdb/branches/1.1.x/share/www/script/test/all_docs.js (original)
+++ couchdb/branches/1.1.x/share/www/script/test/all_docs.js Mon Aug 15 03:57:48 2011
@@ -41,6 +41,13 @@ couchTests.all_docs = function(debug) {
   var all = db.allDocs({startkey:"2"});
   T(all.offset == 2);
 
+  // Confirm that queries may assume raw collation.
+  var raw = db.allDocs({
+    startkey: "org.couchdb.user:",
+    endkey: "org.couchdb.user;"
+  });
+  TEquals(0, raw.rows.length);
+
   // check that the docs show up in the seq view in the order they were created
   var changes = db.changes();
   var ids = ["0","3","1","2"];

Modified: couchdb/branches/1.1.x/share/www/script/test/view_collation_raw.js
URL: http://svn.apache.org/viewvc/couchdb/branches/1.1.x/share/www/script/test/view_collation_raw.js?rev=1157706&r1=1157705&r2=1157706&view=diff
==============================================================================
--- couchdb/branches/1.1.x/share/www/script/test/view_collation_raw.js (original)
+++ couchdb/branches/1.1.x/share/www/script/test/view_collation_raw.js Mon Aug 15 03:57:48 2011
@@ -76,12 +76,19 @@ couchTests.view_collation_raw = function
     }
   }
   T(db.save(designDoc).ok);
+
+  // Confirm that everything collates correctly.
   var rows = db.view("test/test").rows;
   for (i=0; i<values.length; i++) {
     T(equals(rows[i].key, values[i]));
   }
 
-  // everything has collated correctly. Now to check the descending output
+  // Confirm that couch allows raw semantics in key ranges.
+  rows = db.view("test/test", {startkey:"Z", endkey:"a"}).rows;
+  TEquals(1, rows.length);
+  TEquals("a", rows[0].key);
+
+  // Check the descending output.
   rows = db.view("test/test", {descending: true}).rows;
   for (i=0; i<values.length; i++) {
     T(equals(rows[i].key, values[values.length - 1 -i]));

Modified: couchdb/branches/1.1.x/src/couchdb/couch_btree.erl
URL: http://svn.apache.org/viewvc/couchdb/branches/1.1.x/src/couchdb/couch_btree.erl?rev=1157706&r1=1157705&r2=1157706&view=diff
==============================================================================
--- couchdb/branches/1.1.x/src/couchdb/couch_btree.erl (original)
+++ couchdb/branches/1.1.x/src/couchdb/couch_btree.erl Mon Aug 15 03:57:48 2011
@@ -15,6 +15,7 @@
 -export([open/2, open/3, query_modify/4, add/2, add_remove/3]).
 -export([fold/4, full_reduce/1, final_reduce/2, foldl/3, foldl/4]).
 -export([fold_reduce/4, lookup/2, get_state/1, set_options/2]).
+-export([less/3]).
 
 -define(CHUNK_THRESHOLD, 16#4ff).
 

Modified: couchdb/branches/1.1.x/src/couchdb/couch_httpd_db.erl
URL: http://svn.apache.org/viewvc/couchdb/branches/1.1.x/src/couchdb/couch_httpd_db.erl?rev=1157706&r1=1157705&r2=1157706&view=diff
==============================================================================
--- couchdb/branches/1.1.x/src/couchdb/couch_httpd_db.erl (original)
+++ couchdb/branches/1.1.x/src/couchdb/couch_httpd_db.erl Mon Aug 15 03:57:48 2011
@@ -477,6 +477,7 @@ db_req(#httpd{path_parts=[_, DocId | Fil
     db_attachment_req(Req, Db, DocId, FileNameParts).
 
 all_docs_view(Req, Db, Keys) ->
+    RawCollator = fun(A, B) -> A < B end,
     #view_query_args{
         start_key = StartKey,
         start_docid = StartDocId,
@@ -486,7 +487,8 @@ all_docs_view(Req, Db, Keys) ->
         skip = SkipCount,
         direction = Dir,
         inclusive_end = Inclusive
-    } = QueryArgs = couch_httpd_view:parse_view_params(Req, Keys, map),
+    } = QueryArgs
+      = couch_httpd_view:parse_view_params(Req, Keys, map, RawCollator),
     {ok, Info} = couch_db:get_db_info(Db),
     CurrentEtag = couch_httpd:make_etag(Info),
     couch_httpd:etag_respond(Req, CurrentEtag, fun() ->

Modified: couchdb/branches/1.1.x/src/couchdb/couch_httpd_view.erl
URL: http://svn.apache.org/viewvc/couchdb/branches/1.1.x/src/couchdb/couch_httpd_view.erl?rev=1157706&r1=1157705&r2=1157706&view=diff
==============================================================================
--- couchdb/branches/1.1.x/src/couchdb/couch_httpd_view.erl (original)
+++ couchdb/branches/1.1.x/src/couchdb/couch_httpd_view.erl Mon Aug 15 03:57:48 2011
@@ -15,7 +15,7 @@
 
 -export([handle_view_req/3,handle_temp_view_req/2]).
 
--export([parse_view_params/3]).
+-export([parse_view_params/4]).
 -export([make_view_fold_fun/7, finish_view_fold/4, finish_view_fold/5, view_row_obj/4]).
 -export([view_etag/5, make_reduce_fold_funs/6]).
 -export([design_doc_view/5, parse_bool_param/1, doc_member/3]).
@@ -34,18 +34,19 @@ design_doc_view(Req, Db, DName, ViewName
     Reduce = get_reduce_type(Req),
     Result = case couch_view:get_map_view(Db, DesignId, ViewName, Stale) of
     {ok, View, Group} ->
-        QueryArgs = parse_view_params(Req, Keys, map),
+        QueryArgs = parse_view_params(Req, Keys, map, view_collator(View)),
         output_map_view(Req, View, Group, Db, QueryArgs, Keys);
     {not_found, Reason} ->
         case couch_view:get_reduce_view(Db, DesignId, ViewName, Stale) of
         {ok, ReduceView, Group} ->
+            Collator = view_collator(ReduceView),
             case Reduce of
             false ->
-                QueryArgs = parse_view_params(Req, Keys, red_map),
+                QueryArgs = parse_view_params(Req, Keys, red_map, Collator),
                 MapView = couch_view:extract_map_view(ReduceView),
                 output_map_view(Req, MapView, Group, Db, QueryArgs, Keys);
             _ ->
-                QueryArgs = parse_view_params(Req, Keys, reduce),
+                QueryArgs = parse_view_params(Req, Keys, reduce, Collator),
                 output_reduce_view(Req, Db, ReduceView, Group, QueryArgs, Keys)
             end;
         _ ->
@@ -90,19 +91,19 @@ handle_temp_view_req(#httpd{method='POST
     Reduce = get_reduce_type(Req),
     case couch_util:get_value(<<"reduce">>, Props, null) of
     null ->
-        QueryArgs = parse_view_params(Req, Keys, map),
         {ok, View, Group} = couch_view:get_temp_map_view(Db, Language,
             DesignOptions, MapSrc),
+        QueryArgs = parse_view_params(Req, Keys, map, view_collator(View)),
         output_map_view(Req, View, Group, Db, QueryArgs, Keys);
     _ when Reduce =:= false ->
-        QueryArgs = parse_view_params(Req, Keys, red_map),
         {ok, View, Group} = couch_view:get_temp_map_view(Db, Language,
             DesignOptions, MapSrc),
+        QueryArgs = parse_view_params(Req, Keys, red_map, view_collator(View)),
         output_map_view(Req, View, Group, Db, QueryArgs, Keys);
     RedSrc ->
-        QueryArgs = parse_view_params(Req, Keys, reduce),
         {ok, View, Group} = couch_view:get_temp_reduce_view(Db, Language,
             DesignOptions, MapSrc, RedSrc),
+        QueryArgs = parse_view_params(Req, Keys, reduce, view_collator(View)),
         output_reduce_view(Req, Db, View, Group, QueryArgs, Keys)
     end;
 
@@ -209,18 +210,19 @@ load_view(Req, Db, {ViewDesignId, ViewNa
     Reduce = get_reduce_type(Req),
     case couch_view:get_map_view(Db, ViewDesignId, ViewName, Stale) of
     {ok, View, Group} ->
-        QueryArgs = parse_view_params(Req, Keys, map),
+        QueryArgs = parse_view_params(Req, Keys, map, view_collator(View)),
         {map, View, Group, QueryArgs};
     {not_found, _Reason} ->
         case couch_view:get_reduce_view(Db, ViewDesignId, ViewName, Stale) of
         {ok, ReduceView, Group} ->
+            Collator = view_collator(ReduceView),
             case Reduce of
             false ->
-                QueryArgs = parse_view_params(Req, Keys, map_red),
+                QueryArgs = parse_view_params(Req, Keys, map_red, Collator),
                 MapView = couch_view:extract_map_view(ReduceView),
                 {map, MapView, Group, QueryArgs};
             _ ->
-                QueryArgs = parse_view_params(Req, Keys, reduce),
+                QueryArgs = parse_view_params(Req, Keys, reduce, Collator),
                 {reduce, ReduceView, Group, QueryArgs}
             end;
         {not_found, Reason} ->
@@ -228,12 +230,30 @@ load_view(Req, Db, {ViewDesignId, ViewNa
         end
     end.
 
+view_collator({reduce, _N, _Lang, View}) ->
+    view_collator(View);
+
+view_collator({temp_reduce, View}) ->
+    view_collator(View);
+
+view_collator(#view{btree=Btree}) ->
+    % Return an "is-less-than" predicate by calling into the btree's
+    % collator. For raw collation, couch_btree compares arbitrary
+    % Erlang terms, but for normal (ICU) collation, it expects
+    % {Json, Id} tuples.
+    fun
+        ({_JsonA, _IdA}=A, {_JsonB, _IdB}=B) ->
+            couch_btree:less(Btree, A, B);
+        (JsonA, JsonB) ->
+            couch_btree:less(Btree, {JsonA, null}, {JsonB, null})
+    end.
+
 % query_parse_error could be removed
 % we wouldn't need to pass the view type, it'd just parse params.
 % I'm not sure what to do about the error handling, but
 % it might simplify things to have a parse_view_params function
 % that doesn't throw().
-parse_view_params(Req, Keys, ViewType) ->
+parse_view_params(Req, Keys, ViewType, LessThan) ->
     QueryList = couch_httpd:qs(Req),
     QueryParams =
     lists:foldl(fun({K, V}, Acc) ->
@@ -247,7 +267,7 @@ parse_view_params(Req, Keys, ViewType) -
     QueryArgs = lists:foldl(fun({K, V}, Args2) ->
         validate_view_query(K, V, Args2)
     end, Args, lists:reverse(QueryParams)), % Reverse to match QS order.
-    warn_on_empty_key_range(QueryArgs),
+    warn_on_empty_key_range(QueryArgs, LessThan),
     GroupLevel = QueryArgs#view_query_args.group_level,
     case {ViewType, GroupLevel, IsMultiGet} of
     {reduce, exact, true} ->
@@ -328,15 +348,15 @@ parse_view_param("callback", _) ->
 parse_view_param(Key, Value) ->
     [{extra, {Key, Value}}].
 
-warn_on_empty_key_range(#view_query_args{start_key=undefined}) ->
+warn_on_empty_key_range(#view_query_args{start_key=undefined}, _Lt) ->
     ok;
-warn_on_empty_key_range(#view_query_args{end_key=undefined}) ->
+warn_on_empty_key_range(#view_query_args{end_key=undefined}, _Lt) ->
     ok;
-warn_on_empty_key_range(#view_query_args{start_key=A, end_key=A}) ->
+warn_on_empty_key_range(#view_query_args{start_key=A, end_key=A}, _Lt) ->
     ok;
 warn_on_empty_key_range(#view_query_args{
-    start_key=StartKey, end_key=EndKey, direction=Dir}) ->
-    case {Dir, couch_view:less_json(StartKey, EndKey)} of
+    start_key=StartKey, end_key=EndKey, direction=Dir}, LessThan) ->
+    case {Dir, LessThan(StartKey, EndKey)} of
         {fwd, false} ->
             throw({query_parse_error,
             <<"No rows can match your key range, reverse your ",