diff --git a/src/riak_kv_pb_ts.erl b/src/riak_kv_pb_ts.erl index b0d95df17a..ad81164e25 100644 --- a/src/riak_kv_pb_ts.erl +++ b/src/riak_kv_pb_ts.erl @@ -87,5 +87,9 @@ encode_response({reply, {tsgetresp, {CNames, CTypes, Rows}}, State}) -> R = riak_pb_ts_codec:encode_rows(CTypes, Rows), Encoded = #tsgetresp{columns = C, rows = R}, {reply, Encoded, State}; + +encode_response({reply, {tscoverageresp, Entries}, State}) -> + Encoded = #tscoverageresp{entries = riak_pb_ts_codec:encode_cover_list(Entries)}, + {reply, Encoded, State}; encode_response(Response) -> Response. diff --git a/src/riak_kv_ts_svc.erl b/src/riak_kv_ts_svc.erl index 190294e2e3..4b856f07d4 100644 --- a/src/riak_kv_ts_svc.erl +++ b/src/riak_kv_ts_svc.erl @@ -355,148 +355,27 @@ sub_tslistkeysreq(Mod, DDL, #tslistkeysreq{table = Table, sub_tscoveragereq(Mod, _DDL, #tscoveragereq{table = Table, query = Q}, State) -> - case compile(Mod, catch decode_query(Q, undefined)) of - {error, #rpberrorresp{} = Error} -> - {reply, Error, State}; - {error, _} -> + Client = {riak_client, [node(), undefined]}, + %% all we need from decode_query is to compile the query, + %% but also to check permissions + case decode_query(Q, undefined) of + {_QryType, {ok, SQL}} -> + case riak_kv_ts_api:compile_to_per_quantum_queries(Mod, SQL) of + {ok, Compiled} -> + Bucket = riak_kv_ts_util:table_to_bucket(Table), + {reply, + {tscoverageresp, riak_kv_ts_util:sql_to_cover(Client, Compiled, Bucket, [])}, + State}; + {error, Reason} -> + {reply, make_rpberrresp( + ?E_BAD_QUERY, flat_format("Failed to compile query: ~p", [Reason])), State} + end; + {error, Reason} -> {reply, make_rpberrresp( - ?E_BAD_QUERY, "Failed to compile query"), - State}; - SQL -> - %% SQL is a list of queries (1 per quantum) - Bucket = riak_kv_ts_util:table_to_bucket(Table), - Client = {riak_client, [node(), undefined]}, - convert_cover_list(sql_to_cover(Client, SQL, Bucket, []), State) + ?E_BAD_QUERY, flat_format("Failed to parse query: ~p", [Reason])), + State} end. -%% Copied and modified from riak_kv_pb_coverage:convert_list. Would -%% be nice to collapse them back together, probably with a closure, -%% but time and effort. -convert_cover_list({error, Error}, State) -> - {error, Error, State}; -convert_cover_list(Results, State) -> - %% Pull hostnames & ports - %% Wrap each element of this list into a rpbcoverageentry - Resp = #tscoverageresp{ - entries = - [begin - Node = proplists:get_value(node, Cover), - {IP, Port} = riak_kv_pb_coverage:node_to_pb_details(Node), - #tscoverageentry{ - cover_context = riak_kv_pb_coverage:term_to_checksum_binary( - {Cover, Range}), - ip = IP, port = Port, - range = assemble_ts_range(Range, SQLtext) - } - end || {Cover, Range, SQLtext} <- Results] - }, - {reply, Resp, State}. - -assemble_ts_range({FieldName, {{StartVal, StartIncl}, {EndVal, EndIncl}}}, Text) -> - #tsrange{ - field_name = FieldName, - lower_bound = StartVal, - lower_bound_inclusive = StartIncl, - upper_bound = EndVal, - upper_bound_inclusive = EndIncl, - desc = Text - }. - - -%% Result from riak_client:get_cover is a nested list of coverage plan -%% because KV coverage requests are designed that way, but in our case -%% all we want is the singleton head - -%% If any of the results from get_cover are errors, we want that tuple -%% to be the sole return value -sql_to_cover(_Client, [], _Bucket, Accum) -> - lists:reverse(Accum); -sql_to_cover(Client, [SQL|Tail], Bucket, Accum) -> - case Client:get_cover(riak_kv_qry_coverage_plan, Bucket, undefined, - {SQL, Bucket}) of - {error, Error} -> - {error, Error}; - [Cover] -> - {Description, RangeReplacement} = reverse_sql(SQL), - sql_to_cover(Client, Tail, Bucket, [{Cover, RangeReplacement, - Description}|Accum]) - end. - -%% Generate a human-readable description of the target -%% <<"