File Coverage

blib/lib/MongoDB/Role/_OpReplyParser.pm
Criterion Covered Total %
statement 24 43 55.8
branch 0 18 0.0
condition n/a
subroutine 8 9 88.8
pod n/a
total 32 70 45.7


line stmt bran cond sub pod time code
1             # Copyright 2016 - present MongoDB, Inc.
2             #
3             # Licensed under the Apache License, Version 2.0 (the "License");
4             # you may not use this file except in compliance with the License.
5             # You may obtain a copy of the License at
6             #
7             # http://www.apache.org/licenses/LICENSE-2.0
8             #
9             # Unless required by applicable law or agreed to in writing, software
10             # distributed under the License is distributed on an "AS IS" BASIS,
11             # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12             # See the License for the specific language governing permissions and
13             # limitations under the License.
14              
15 59     59   86984 use strict;
  59         4709  
  59         2153  
16 59     59   395 use warnings;
  59         124  
  59         2169  
17             package MongoDB::Role::_OpReplyParser;
18              
19             # MongoDB interface for sending OP_QUERY|OP_GETMORE and parsing OP_REPLY
20              
21 59     59   307 use version;
  59         144  
  59         343  
22             our $VERSION = 'v2.2.1';
23              
24 59     59   4546 use Moo::Role;
  59         185  
  59         398  
25              
26 59     59   20246 use MongoDB::Error;
  59         150  
  59         7258  
27 59     59   431 use MongoDB::_Protocol;
  59         146  
  59         1422  
28 59     59   335 use MongoDB::_Constants;
  59         290  
  59         7503  
29              
30 59     59   393 use namespace::clean;
  59         115  
  59         357  
31              
32             with $_ for qw(
33             MongoDB::Role::_CommandMonitoring
34             );
35              
36             requires '_as_command';
37              
38             # Sends a BSON query/get-more string, then read, parse and validate the reply.
39             # Throws various errors if the results indicate a problem. Returns
40             # a "result" structure generated by MongoDB::_Protocol, but with
41             # the 'docs' field replaced with inflated documents.
42              
43             # as this is the hot loop, we do a number of odd things in the name of
44             # optimization, such as chaining lots of operations with ',' to keep them
45             # in a single statement
46              
47             sub _query_and_receive {
48 0     0     my ($self, $link, $op_bson, $request_id) = @_;
49              
50 0           my ($result, $doc_bson, $bson_codec, $docs, $len, $i);
51              
52 0 0         $self->publish_command_started( $link, $self->_as_command, $request_id )
53             if $self->monitoring_callback;
54              
55 0           eval {
56             $link->write( $op_bson ),
57             ( $result = MongoDB::_Protocol::parse_reply( $link->read, $request_id ) ),
58             ( $doc_bson = $result->{docs} ),
59             ( $docs = $result->{docs} = [] ),
60             ( ( $bson_codec, $i ) = ( $self->bson_codec, 0 ) ),
61 0           ( $#$docs = $result->{number_returned} - 1 );
62              
63             # XXX should address be added to result here?
64              
65             MongoDB::CursorNotFoundError->throw("cursor not found")
66 0 0         if $result->{flags}{cursor_not_found};
67              
68             # XXX eventually, BSON needs an API to do this efficiently for us without a
69             # loop here. Alternatively, BSON strings could be returned as objects that
70             # inflate lazily
71              
72 0           while ( length($doc_bson) ) {
73 0           $len = unpack( P_INT32, $doc_bson );
74 0 0         MongoDB::ProtocolError->throw("document in response at index $i was truncated")
75             if $len > length($doc_bson);
76 0           $docs->[ $i++ ] = $bson_codec->decode_one( substr( $doc_bson, 0, $len, '' ) );
77             }
78              
79             MongoDB::ProtocolError->throw(
80             sprintf(
81             "unexpected number of documents: got %s, expected %s",
82             scalar @$docs,
83             $result->{number_returned}
84             )
85 0 0         ) if scalar @$docs != $result->{number_returned};
86             };
87 0 0         if ( my $err = $@ ) {
88 0 0         $self->publish_command_exception($err) if $self->monitoring_callback;
89 0           die $err;
90             }
91              
92 0 0         if ($result->{flags}{query_failure}) {
93 0 0         $self->publish_legacy_query_error( $result->{docs}[0] )
94             if $self->monitoring_callback;
95             # had query_failure, so pretend the query was a command and assert it here
96             MongoDB::CommandResult->_new(
97 0           output => $result->{docs}[0],
98             address => $link->address
99             )->assert;
100             }
101              
102 0 0         $self->publish_legacy_reply_succeeded($result)
103             if $self->monitoring_callback;
104              
105 0           return $result
106             }
107              
108             1;