summaryrefslogtreecommitdiff
path: root/src/couchdb
diff options
context:
space:
mode:
authorPaul Joseph Davis <davisp@apache.org>2011-08-15 03:57:48 +0000
committerPaul Joseph Davis <davisp@apache.org>2011-08-15 03:57:48 +0000
commit0dc0f8b41f627876f65183ea1d99c68b16abeae0 (patch)
treecc8b672ac2c4f3b7a38c05c3c0de0be023369b15 /src/couchdb
parent2eb62337efc1171d1ea1e4392f8cacf0dabc1ab0 (diff)
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 git-svn-id: https://svn.apache.org/repos/asf/couchdb/branches/1.1.x@1157706 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/couchdb')
-rw-r--r--src/couchdb/couch_btree.erl1
-rw-r--r--src/couchdb/couch_httpd_db.erl4
-rw-r--r--src/couchdb/couch_httpd_view.erl54
3 files changed, 41 insertions, 18 deletions
diff --git a/src/couchdb/couch_btree.erl b/src/couchdb/couch_btree.erl
index 91bc8f1b..0ddf7a48 100644
--- a/src/couchdb/couch_btree.erl
+++ b/src/couchdb/couch_btree.erl
@@ -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).
diff --git a/src/couchdb/couch_httpd_db.erl b/src/couchdb/couch_httpd_db.erl
index 71204598..db430bbd 100644
--- a/src/couchdb/couch_httpd_db.erl
+++ b/src/couchdb/couch_httpd_db.erl
@@ -477,6 +477,7 @@ db_req(#httpd{path_parts=[_, DocId | FileNameParts]}=Req, Db) ->
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() ->
diff --git a/src/couchdb/couch_httpd_view.erl b/src/couchdb/couch_httpd_view.erl
index 1f279417..082a5039 100644
--- a/src/couchdb/couch_httpd_view.erl
+++ b/src/couchdb/couch_httpd_view.erl
@@ -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, Keys) ->
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'}=Req, Db) ->
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, ViewName}, Keys) ->
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, ViewName}, Keys) ->
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 ",