2626
2727import bson
2828from bson .codec_options import DEFAULT_CODEC_OPTIONS
29- from bson .py3compat import b , StringIO
29+ from bson .py3compat import b , StringIO , u
3030from bson .son import SON
3131try :
3232 from pymongo import _cmessage
6060 _DELETE : b'\x04 deletes\x00 \x00 \x00 \x00 \x00 ' ,
6161}
6262
63+ _UJOIN = u ("%s.%s" )
64+
6365
6466def _randint ():
6567 """Generate a pseudo random 32 bit integer."""
@@ -201,14 +203,15 @@ def _gen_get_more_command(cursor_id, coll, batch_size, max_time_ms):
201203class _Query (object ):
202204 """A query operation."""
203205
204- __slots__ = ('flags' , 'ns ' , 'ntoskip ' , 'ntoreturn ' , 'spec ' , 'fields ' ,
205- 'codec_options ' , 'read_preference ' , 'limit ' , 'batch_size ' ,
206- 'name' )
206+ __slots__ = ('flags' , 'db ' , 'coll ' , 'ntoskip ' , 'ntoreturn ' , 'spec ' ,
207+ 'fields ' , 'codec_options ' , 'read_preference ' , 'limit ' ,
208+ 'batch_size' , ' name' )
207209
208- def __init__ (self , flags , ns , ntoskip , ntoreturn , spec , fields ,
210+ def __init__ (self , flags , db , coll , ntoskip , ntoreturn , spec , fields ,
209211 codec_options , read_preference , limit , batch_size ):
210212 self .flags = flags
211- self .ns = ns
213+ self .db = db
214+ self .coll = coll
212215 self .ntoskip = ntoskip
213216 self .ntoreturn = ntoreturn
214217 self .spec = spec
@@ -224,51 +227,77 @@ def as_command(self):
224227
225228 Should be called *after* get_message.
226229 """
227- dbn , coll = self .ns .split ('.' , 1 )
228230 if '$explain' in self .spec :
229231 self .name = 'explain'
230232 return _gen_explain_command (
231- coll , self .spec , self .fields , self .ntoskip ,
232- self .limit , self .batch_size , self .flags ), dbn
233- return _gen_find_command (coll , self .spec , self .fields , self .ntoskip ,
234- self .limit , self .batch_size , self .flags ), dbn
233+ self .coll , self .spec , self .fields , self .ntoskip ,
234+ self .limit , self .batch_size , self .flags ), self .db
235+ return _gen_find_command (
236+ self .coll , self .spec , self .fields , self .ntoskip , self .limit ,
237+ self .batch_size , self .flags ), self .db
235238
236- def get_message (self , set_slave_ok , is_mongos ):
239+ def get_message (self , set_slave_ok , is_mongos , use_cmd = False ):
237240 """Get a query message, possibly setting the slaveOk bit."""
238- if is_mongos :
239- self .spec = _maybe_add_read_preference (self .spec ,
240- self .read_preference )
241241 if set_slave_ok :
242242 # Set the slaveOk bit.
243243 flags = self .flags | 4
244244 else :
245245 flags = self .flags
246- return query (flags , self .ns , self .ntoskip , self .ntoreturn ,
247- self .spec , self .fields , self .codec_options )
246+
247+ ns = _UJOIN % (self .db , self .coll )
248+ spec = self .spec
249+ ntoreturn = self .ntoreturn
250+
251+ if use_cmd :
252+ ns = _UJOIN % (self .db , "$cmd" )
253+ spec = self .as_command ()[0 ]
254+ ntoreturn = - 1 # All DB commands return 1 document
255+
256+ if is_mongos :
257+ spec = _maybe_add_read_preference (spec ,
258+ self .read_preference )
259+
260+ return query (flags , ns , self .ntoskip , ntoreturn ,
261+ spec , self .fields , self .codec_options )
248262
249263
250264class _GetMore (object ):
251265 """A getmore operation."""
252266
253- __slots__ = ('ns' , 'ntoreturn' , 'cursor_id' , 'max_time_ms' )
267+ __slots__ = ('db' , 'coll' , 'ntoreturn' , 'cursor_id' , 'max_time_ms' ,
268+ 'codec_options' , 'cmd_cursor' )
254269
255270 name = 'getMore'
256271
257- def __init__ (self , ns , ntoreturn , cursor_id , max_time_ms = None ):
258- self .ns = ns
272+ def __init__ (self , db , coll , ntoreturn , cursor_id , codec_options ,
273+ max_time_ms = None , cmd_cursor = False ):
274+ self .db = db
275+ self .coll = coll
259276 self .ntoreturn = ntoreturn
260277 self .cursor_id = cursor_id
278+ self .codec_options = codec_options
261279 self .max_time_ms = max_time_ms
280+ # XXX: Temporarily keep track of if this getMore is for a command cursor
281+ # so we can use OP_KILLCURSORS until find support for mongos is completed.
282+ self .cmd_cursor = cmd_cursor
262283
263284 def as_command (self ):
264285 """Return a getMore command document for this query."""
265- dbn , coll = self .ns .split ('.' , 1 )
266- return _gen_get_more_command (
267- self .cursor_id , coll , self .ntoreturn , self .max_time_ms ), dbn
286+ return _gen_get_more_command (self .cursor_id , self .coll ,
287+ self .ntoreturn , self .max_time_ms ), self .db
268288
269- def get_message (self , dummy0 , dummy1 ):
289+ def get_message (self , dummy0 , dummy1 , use_cmd = False ):
270290 """Get a getmore message."""
271- return get_more (self .ns , self .ntoreturn , self .cursor_id )
291+
292+ ns = _UJOIN % (self .db , self .coll )
293+
294+ if use_cmd and not self .cmd_cursor :
295+ ns = _UJOIN % (self .db , "$cmd" )
296+ spec = self .as_command ()[0 ]
297+
298+ return query (4 , ns , 0 , - 1 , spec , None , self .codec_options )
299+
300+ return get_more (ns , self .ntoreturn , self .cursor_id )
272301
273302
274303class _CursorAddress (tuple ):
0 commit comments