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 58     58   84795 use strict;
  58         4604  
  58         2095  
16 58     58   378 use warnings;
  58         115  
  58         2123  
17             package MongoDB::Role::_OpReplyParser;
18              
19             # MongoDB interface for sending OP_QUERY|OP_GETMORE and parsing OP_REPLY
20              
21 58     58   299 use version;
  58         108  
  58         345  
22             our $VERSION = 'v2.2.0';
23              
24 58     58   4414 use Moo::Role;
  58         130  
  58         413  
25              
26 58     58   19863 use MongoDB::Error;
  58         176  
  58         7186  
27 58     58   419 use MongoDB::_Protocol;
  58         157  
  58         1495  
28 58     58   349 use MongoDB::_Constants;
  58         236  
  58         7060  
29              
30 58     58   386 use namespace::clean;
  58         131  
  58         398  
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;