@@ -75,16 +75,19 @@ class Response(list):
7575 packet received from the server.
7676 '''
7777
78- def __init__ (self , _socket , field_types = None ):
78+ def __init__ (self , header , body , field_types = None ):
7979 '''\
8080 Create an instance of `Response` using data received from the server.
8181
8282 __init__() itself reads data from the socket, parses response body and
8383 sets appropriate instance attributes.
8484
85- :params _socket: socket connected to the server
86- :type _socket: instance of socket.socket class (from stdlib)
85+ :param header: header of the response
86+ :type header: array of bytes
87+ :param body: body of the response
88+ :type body: array of bytes
8789 '''
90+
8891 # This is not necessary, because underlying list data structures are created in the __new__(). But let it be.
8992 super (Response , self ).__init__ ()
9093
@@ -97,57 +100,10 @@ def __init__(self, _socket, field_types=None):
97100 self ._rowcount = None
98101 self .field_types = field_types
99102
100- # Read response header
101- buff = ctypes .create_string_buffer (16 )
102- nbytes = _socket .recv_into (buff , 16 , )
103-
104- # Immediately raises an exception if the data cannot be read
105- if nbytes != 16 :
106- raise socket .error (socket .errno .ECONNABORTED , "Software caused connection abort" )
107-
108- # Unpack header (including <return_code> attribute)
109- self ._request_type , self ._body_length , self ._request_id , self ._return_code = struct_LLLL .unpack (buff )
110-
111- # Separate return_code and completion_code
112- self ._completion_status = self ._return_code & 0x00ff
113- self ._return_code = self ._return_code >> 8
114-
115- # Unpack body if there is one (i.e. not PING)
116- if self ._body_length != 0 :
117-
118- # In the protocol description <body_length> includes 4 bytes of <return_code>
119- self ._body_length -= 4
120-
121- # Read response body
122- buff = ctypes .create_string_buffer (self ._body_length )
123- nbytes = _socket .recv_into (buff )
124-
125- # Immediately raises an exception if the data cannot be read
126- if nbytes != self ._body_length :
127- raise socket .error (socket .errno .ECONNABORTED , "Software caused connection abort" )
128-
129- if self ._return_code == 0 :
130- # If no errors, unpack response body
131- self ._unpack_body (buff )
132- else :
133- # In case of error unpack body as error message
134- self ._unpack_message (buff )
135- if self ._completion_status == 2 :
136- raise DatabaseError (self ._return_code , self ._return_message )
137-
138-
139- def _unpack_message (self , buff ):
140- '''\
141- Extract error message from response body
142- Called when return_code! = 0.
143-
144- :param buff: buffer containing request body
145- :type byff: ctypes buffer
146- :return: error message
147- :rtype: str
148- '''
149-
150- self ._return_message = unicode (buff .value , "utf8" , "replace" )
103+ # Unpack header
104+ self ._request_type , self ._body_length , self ._request_id = struct_LLL .unpack (header )
105+ if body :
106+ self ._unpack_body (body )
151107
152108
153109 @staticmethod
@@ -209,16 +165,26 @@ def _unpack_body(self, buff):
209165 :type byff: ctypes buffer
210166 '''
211167
212- # Unpack <count> (first 4 bytes) - how many records returned
213- self ._rowcount = struct_L .unpack_from (buff )[0 ]
168+ # Unpack <return_code> and <count> (how many records affected or selected)
169+ self ._return_code , self ._rowcount = struct_LL .unpack_from (buff , offset = 0 )
170+
171+ # Separate return_code and completion_code
172+ self ._completion_status = self ._return_code & 0x00ff
173+ self ._return_code = self ._return_code >> 8
174+
175+ # In case of an error unpack the body as an error message
176+ if self ._return_code != 0 :
177+ self ._return_message = unicode (buff .value , "utf8" , "replace" )
178+ if self ._completion_status == 2 :
179+ raise DatabaseError (self ._return_code , self ._return_message )
214180
215- # If the response body contains only <count> - there is no tuples to unpack
216- if self ._body_length == 4 :
181+ # If the response don't contains any tuples - there is no tuples to unpack
182+ if self ._body_length == 8 :
217183 return
218184
219185 # Parse response tuples (<fq_tuple>)
220186 if self ._rowcount > 0 :
221- offset = 4 # The first 4 bytes in the response body is the <count> we have already read
187+ offset = 8 # The first 4 bytes in the response body is the <count> we have already read
222188 while offset < self ._body_length :
223189 '''
224190 # In resonse tuples have the form <size><tuple> (<fq_tuple> ::= <size><tuple>).
0 commit comments