machbaseapi 2.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,318 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import re
5
+ from typing import Any, Callable, Dict, List, Optional, Sequence
6
+
7
+ from .connector import MachbaseConnection
8
+ from .errors import Error, ProgrammingError
9
+
10
+ gCharset = "UTF-8"
11
+ _SELECT_PREFIX = re.compile(r"^\s*(SELECT|WITH|DESC|DESCRIBE|SHOW)\b", re.IGNORECASE)
12
+
13
+
14
+ def _stringify(value: Any) -> Any:
15
+ if value is None:
16
+ return None
17
+ if isinstance(value, (bytes, bytearray, memoryview)):
18
+ value = bytes(value)
19
+ return value.hex().upper()
20
+ if isinstance(value, float):
21
+ return str(int(value)) if value.is_integer() else str(value)
22
+ if isinstance(value, bool):
23
+ return "1" if value else "0"
24
+ return str(value)
25
+
26
+
27
+ def _encode_row(row: Dict[str, Any]) -> str:
28
+ encoded = {str(key).lower(): _stringify(value) for key, value in row.items()}
29
+ if "_arrival_time" in encoded and "_ARRIVAL_TIME" not in encoded:
30
+ encoded["_ARRIVAL_TIME"] = encoded["_arrival_time"]
31
+ return json.dumps(encoded, separators=(",", ":"))
32
+
33
+
34
+ def _encode_rows(rows: Sequence[Dict[str, Any]]) -> str:
35
+ return ",".join(_encode_row(row) for row in rows)
36
+
37
+
38
+ class machbaseAPI(object):
39
+ pass
40
+
41
+
42
+ class machbase(object):
43
+ def __init__(self):
44
+ self._conn: Optional[MachbaseConnection] = None
45
+ self._opened = False
46
+ self._append_session = None
47
+ self._rows: List[Dict[str, Any]] = []
48
+ self._last_result: str = ""
49
+ self._append_types: Optional[List[int]] = None
50
+
51
+ def _set_ok(self, text: str) -> int:
52
+ self._last_result = json.dumps({"EXECUTE RESULT": text}, separators=(",", ":"))
53
+ return 1
54
+
55
+ def _set_error(self, text: str, detail: str = "") -> int:
56
+ payload = {"EXECUTE ERROR": text}
57
+ if detail:
58
+ payload["MACHBASE_ERROR"] = detail
59
+ self._last_result = json.dumps(payload, separators=(",", ":"))
60
+ return 0
61
+
62
+ def _ensure_conn(self) -> MachbaseConnection:
63
+ if self._conn is None:
64
+ raise RuntimeError("Connection is not open")
65
+ return self._conn
66
+
67
+ @staticmethod
68
+ def _normalize_append_payload(
69
+ types_or_values: Any,
70
+ explicit_values: Any = None,
71
+ ) -> tuple[Optional[List[int]], List[Sequence[Any]]]:
72
+ if explicit_values is not None:
73
+ if types_or_values is None:
74
+ types = None
75
+ else:
76
+ types = [int(value) for value in types_or_values]
77
+ raw_rows = explicit_values
78
+ else:
79
+ types = None
80
+ raw_rows = types_or_values
81
+
82
+ if raw_rows is None:
83
+ return types, []
84
+
85
+ if isinstance(raw_rows, (list, tuple)):
86
+ if len(raw_rows) == 0:
87
+ return types, []
88
+ if isinstance(raw_rows[0], (list, tuple)):
89
+ rows = [list(row) for row in raw_rows]
90
+ else:
91
+ rows = [list(raw_rows)]
92
+ else:
93
+ raise ProgrammingError("Append values must be sequence of rows.")
94
+
95
+ return types, rows
96
+
97
+ def isConnected(self):
98
+ return 1 if self._conn and self._conn.is_connected() else 0
99
+
100
+ def isOpened(self):
101
+ return 1 if self._opened else 0
102
+
103
+ def open(self, aHost="127.0.0.1", aUser="SYS", aPw="MANAGER", aPort=5656):
104
+ try:
105
+ self._conn = MachbaseConnection(host=aHost, user=aUser.upper(), password=aPw, port=int(aPort))
106
+ self._opened = True
107
+ return 1
108
+ except Exception as exc:
109
+ self._conn = None
110
+ self._opened = False
111
+ return self._set_error("Connection error.", str(exc))
112
+
113
+ def openEx(self, aHost="127.0.0.1", aUser="SYS", aPw="MANAGER", aPort=5656, aConnStr=""):
114
+ try:
115
+ self._conn = MachbaseConnection(
116
+ host=aHost,
117
+ user=aUser.upper(),
118
+ password=aPw,
119
+ port=int(aPort),
120
+ connection_string=aConnStr,
121
+ )
122
+ self._opened = True
123
+ return 1
124
+ except Exception as exc:
125
+ self._conn = None
126
+ self._opened = False
127
+ return self._set_error("Connection error.", str(exc))
128
+
129
+ def close(self):
130
+ if self._conn is None:
131
+ self._opened = False
132
+ return 1
133
+ try:
134
+ self._conn.close()
135
+ self._opened = False
136
+ self._conn = None
137
+ self._append_session = None
138
+ self._rows = []
139
+ return 1
140
+ except Exception as exc:
141
+ return self._set_error("Connection close error.", str(exc))
142
+
143
+ def execute(self, aSql):
144
+ try:
145
+ if _SELECT_PREFIX.match(aSql):
146
+ if self.select(aSql) == 0:
147
+ return 0
148
+ return 1
149
+ self._ensure_conn()._client.exec_direct(aSql)
150
+ self._rows = []
151
+ return self._set_ok("Execute Success")
152
+ except Exception as exc:
153
+ return self._set_error("SQLPrepare error.", str(exc))
154
+
155
+ def select(self, aSql):
156
+ try:
157
+ result = self._ensure_conn()._client.query(aSql)
158
+ self._rows = list(result.rows)
159
+ self._last_result = _encode_rows(self._rows)
160
+ return 1
161
+ except Exception as exc:
162
+ self._rows = []
163
+ return self._set_error("SQLPrepare error.", str(exc))
164
+
165
+ def fetch(self):
166
+ if not self._rows:
167
+ return 0, None
168
+ return 1, _encode_row(self._rows.pop(0))
169
+
170
+ def selectClose(self):
171
+ self._rows = []
172
+ return 1
173
+
174
+ def column(self, aTableName):
175
+ return self.columns(aTableName)
176
+
177
+ def statistics(self, aTableName, aUser="SYS"):
178
+ sql = (
179
+ "select name, type, colcount from m$tables "
180
+ "where user_id = (select user_id from m$users where name = '%s') and name = '%s'"
181
+ % (aUser.upper(), aTableName.upper())
182
+ )
183
+ return self.select(sql)
184
+
185
+ def schema(self, aSql):
186
+ return self.execute(aSql)
187
+
188
+ def tables(self):
189
+ sql = (
190
+ "select t.NAME as name, u.NAME as username, t.COLCOUNT as colcount "
191
+ "from m$sys_tables t, m$sys_users u where u.user_id=t.user_id"
192
+ )
193
+ return self.select(sql)
194
+
195
+ def columns(self, aTableName):
196
+ if aTableName is None:
197
+ sql = (
198
+ "select c.name name, c.type type, c.length length "
199
+ "from m$sys_columns c, m$sys_tables t where c.table_id = t.id "
200
+ "and c.id not in(0,65534) order by c.id"
201
+ )
202
+ else:
203
+ name = aTableName.upper()
204
+ if name.startswith("M$"):
205
+ sql = (
206
+ "select name,type,length from m$columns where table_id = "
207
+ "(select id from m$tables where name = '%s') and id not in(0,65534) order by id" % name
208
+ )
209
+ elif name.startswith("V$"):
210
+ sql = (
211
+ "select name,type,length from v$columns where table_id = "
212
+ "(select id from v$tables where name = '%s') and id not in(0,65534) order by id" % name
213
+ )
214
+ else:
215
+ sql = (
216
+ "select name,type,length from m$sys_columns where table_id = "
217
+ "(select id from m$sys_tables where name = '%s') and name not in('_RID','_ARRIVAL_TIME') order by id"
218
+ % name
219
+ )
220
+ return self.select(sql)
221
+
222
+ def appendOpen(self, aTableName, aTypes=None):
223
+ try:
224
+ self._append_session = self._ensure_conn()._client.append_open(aTableName)
225
+ self._append_types = [int(v) for v in aTypes] if aTypes else None
226
+ return 1
227
+ except Exception as exc:
228
+ return self._set_error("Append open error.", str(exc))
229
+
230
+ def appendClose(self):
231
+ if self._append_session is None:
232
+ return 0
233
+ try:
234
+ self._ensure_conn()._client.append_close(self._append_session)
235
+ self._append_session = None
236
+ self._append_types = None
237
+ return self._set_ok("Append success")
238
+ except Exception as exc:
239
+ return self._set_error("Append close error.", str(exc))
240
+
241
+ def appendData(
242
+ self,
243
+ aTableName,
244
+ aTypes,
245
+ aValues=None,
246
+ aFormat="YYYY-MM-DD HH24:MI:SS",
247
+ on_ack: Optional[Callable[[dict], None]] = None,
248
+ ):
249
+ _ = aTableName, aFormat
250
+ if self._append_session is None:
251
+ return 0
252
+ try:
253
+ types, rows = self._normalize_append_payload(aTypes, aValues)
254
+ self._ensure_conn()._client.append_data(
255
+ self._append_session,
256
+ rows,
257
+ types=types or self._append_types,
258
+ on_ack=on_ack,
259
+ )
260
+ return 1
261
+ except Exception as exc:
262
+ return self._set_error("Append data error.", str(exc))
263
+
264
+ def appendDataByTime(
265
+ self,
266
+ aTableName,
267
+ aTypes,
268
+ aValues,
269
+ aFormat="YYYY-MM-DD HH24:MI:SS",
270
+ aTimes=None,
271
+ on_ack: Optional[Callable[[dict], None]] = None,
272
+ ):
273
+ _ = aTableName, aFormat
274
+ if self._append_session is None:
275
+ return 0
276
+ try:
277
+ types, rows = self._normalize_append_payload(aTypes, aValues)
278
+ self._ensure_conn()._client.append_data(
279
+ self._append_session,
280
+ rows,
281
+ types=types or self._append_types,
282
+ times=aTimes,
283
+ on_ack=on_ack,
284
+ )
285
+ return 1
286
+ except Exception as exc:
287
+ return self._set_error("Append data error.", str(exc))
288
+
289
+ def appendFlush(self):
290
+ return 1 if self._append_session is not None else 0
291
+
292
+ def append(self, aTableName, aTypes, aValues=None, aFormat="YYYY-MM-DD HH24:MI:SS"):
293
+ _ = aFormat
294
+ types, rows = self._normalize_append_payload(aTypes, aValues)
295
+ if not rows:
296
+ return 0
297
+ try:
298
+ count = self._ensure_conn()._client.append(aTableName, rows, types=types)
299
+ self._last_result = json.dumps({"EXECUTE RESULT": "Append success"}, separators=(",", ":"))
300
+ return 1
301
+ except Exception as exc:
302
+ return self._set_error("Append error.", str(exc))
303
+
304
+ def appendByTime(self, aTableName, aTypes, aValues=None, aFormat="YYYY-MM-DD HH24:MI:SS", aTimes=None):
305
+ _ = aFormat
306
+ if aValues is None and isinstance(aTypes, (list, tuple)) and aTimes is not None and aTypes and isinstance(aTypes[0], (list, tuple)):
307
+ aValues = aTypes
308
+ aTypes = None
309
+ try:
310
+ types, rows = self._normalize_append_payload(aTypes, aValues)
311
+ count = self._ensure_conn()._client.append(aTableName, rows, types=types, times=aTimes)
312
+ self._last_result = json.dumps({"EXECUTE RESULT": "Append success"}, separators=(",", ":"))
313
+ return 1
314
+ except Exception as exc:
315
+ return self._set_error("Append error.", str(exc))
316
+
317
+ def result(self):
318
+ return self._last_result
machbaseAPI/marshal.py ADDED
@@ -0,0 +1,225 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from typing import Dict, Iterable, Iterator, List, Optional, Union
5
+
6
+ from .constants import CMI_BINARY_TYPE, CMI_PACKET_MAX_BODY, CMI_ROWS_TYPE, CMI_STRING_TYPE
7
+
8
+
9
+ MarshalPrimitive = Union[int, float, bool, bytes, bytearray, str, None]
10
+
11
+
12
+ @dataclass
13
+ class MarshalUnit:
14
+ id: int
15
+ type: int
16
+ length: int
17
+ data: bytes
18
+
19
+
20
+ def _align8(length: int) -> int:
21
+ return (length + 7) & ~7
22
+
23
+
24
+ def _read_u32le(payload: bytes) -> int:
25
+ if len(payload) < 4:
26
+ return 0
27
+ return int.from_bytes(payload[:4], "big")
28
+
29
+
30
+ def _read_fixed_size(type_id: int) -> Optional[int]:
31
+ if type_id in {
32
+ CMI_STRING_TYPE,
33
+ CMI_BINARY_TYPE,
34
+ 0x0000000C,
35
+ 0x000000F1,
36
+ 0x000000F2,
37
+ 0x0000000D,
38
+ }:
39
+ return None
40
+ if type_id in {0x00000004, 0x00000005}:
41
+ return 1
42
+ if type_id in {0x00000006, 0x00000007}: # 16-bit
43
+ return 2
44
+ if type_id in {0x00000008, 0x00000009, 0x00000018, 0x00000019}: # 32-bit
45
+ return 4
46
+ return 8
47
+
48
+
49
+ def decode_scalar(unit: MarshalUnit) -> MarshalPrimitive:
50
+ if unit.type in {
51
+ CMI_STRING_TYPE,
52
+ 0x0000000C,
53
+ 0x000000F1,
54
+ 0x000000F2,
55
+ 0x0000000D,
56
+ }:
57
+ try:
58
+ return unit.data.decode("utf-8")
59
+ except Exception:
60
+ return unit.data.decode("utf-8", errors="replace")
61
+ if unit.type == 0x00000004:
62
+ return unit.data[0] if unit.data else 0
63
+ if unit.type == 0x00000005:
64
+ return unit.data[0] if unit.data else 0
65
+ if unit.type == 0x00000006:
66
+ return int.from_bytes(unit.data[:2], "little", signed=True) if len(unit.data) >= 2 else 0
67
+ if unit.type == 0x00000007:
68
+ return int.from_bytes(unit.data[:2], "little", signed=False) if len(unit.data) >= 2 else 0
69
+ if unit.type == 0x00000008:
70
+ return int.from_bytes(unit.data[:4], "little", signed=True) if len(unit.data) >= 4 else 0
71
+ if unit.type == 0x00000009:
72
+ return int.from_bytes(unit.data[:4], "little", signed=False) if len(unit.data) >= 4 else 0
73
+ if unit.type == 0x0000000A:
74
+ return int.from_bytes(unit.data[:8], "little", signed=True) if len(unit.data) >= 8 else 0
75
+ if unit.type == 0x0000000B:
76
+ return int.from_bytes(unit.data[:8], "little", signed=False) if len(unit.data) >= 8 else 0
77
+ return unit.data
78
+
79
+
80
+ class MarshalWriter:
81
+ """Build marshal units and split them into protocol packets."""
82
+
83
+ HEADER_SIZE = 16
84
+
85
+ def __init__(self, protocol_id: int, stmt_id: int, adds: int = 0):
86
+ self.protocol_id = protocol_id & 0xFF
87
+ self.stmt_id = stmt_id & 0xFFFFFFFF
88
+ self.adds = adds & 0xFFFF
89
+ self._units: List[bytes] = []
90
+ self._current_length = 0
91
+ self._bodies: List[bytes] = []
92
+
93
+ def add_string(self, unit_id: int, value: str) -> None:
94
+ payload = value.encode("utf-8")
95
+ self._add_variable(unit_id, CMI_STRING_TYPE, payload)
96
+
97
+ def add_binary(self, unit_id: int, value: Union[bytes, bytearray]) -> None:
98
+ self._add_variable(unit_id, CMI_BINARY_TYPE, bytes(value))
99
+
100
+ def add_uint32(self, unit_id: int, value: int) -> None:
101
+ payload = value.to_bytes(4, "little", signed=False)
102
+ self._add_fixed(unit_id, 0x00000009, payload)
103
+
104
+ def add_sint32(self, unit_id: int, value: int) -> None:
105
+ payload = value.to_bytes(4, "little", signed=True)
106
+ self._add_fixed(unit_id, 0x00000008, payload)
107
+
108
+ def add_uint64(self, unit_id: int, value: int) -> None:
109
+ payload = value.to_bytes(8, "little", signed=False)
110
+ self._add_fixed(unit_id, 0x0000000B, payload)
111
+
112
+ def add_sint64(self, unit_id: int, value: int) -> None:
113
+ payload = value.to_bytes(8, "little", signed=True)
114
+ self._add_fixed(unit_id, 0x0000000A, payload)
115
+
116
+ def add_boolean(self, unit_id: int, value: bool) -> None:
117
+ payload = b"\x01" if value else b"\x00"
118
+ self._add_fixed(unit_id, 0x00000026, payload)
119
+
120
+ def finalize(self) -> List[bytes]:
121
+ self._flush_current()
122
+ if not self._bodies:
123
+ self._bodies = [b""]
124
+ count = len(self._bodies)
125
+ result = []
126
+ for index, body in enumerate(self._bodies):
127
+ if count == 1:
128
+ flag = 0
129
+ elif index == 0:
130
+ flag = 1
131
+ elif index + 1 == count:
132
+ flag = 3
133
+ else:
134
+ flag = 2
135
+ result.append(self._build_packet(body, flag))
136
+ return result
137
+
138
+ def _add_variable(self, unit_id: int, type_id: int, payload: bytes) -> None:
139
+ length = _align8(len(payload))
140
+ unit = bytearray(self.HEADER_SIZE + length)
141
+ unit[0:4] = int.to_bytes(unit_id & 0xFFFFFFFF, 4, "little")
142
+ unit[4:8] = int.to_bytes(type_id & 0xFFFFFFFF, 4, "little")
143
+ unit[8:16] = int.to_bytes(len(payload), 8, "little")
144
+ unit[16 : 16 + len(payload)] = payload
145
+ self._enqueue(bytes(unit))
146
+
147
+ def _add_fixed(self, unit_id: int, type_id: int, payload: bytes) -> None:
148
+ unit = bytearray(self.HEADER_SIZE)
149
+ unit[0:4] = int.to_bytes(unit_id & 0xFFFFFFFF, 4, "little")
150
+ unit[4:8] = int.to_bytes(type_id & 0xFFFFFFFF, 4, "little")
151
+ fixed = bytes(payload)
152
+ unit[8 : 8 + len(fixed)] = fixed
153
+ self._enqueue(bytes(unit))
154
+
155
+ def _enqueue(self, unit: bytes) -> None:
156
+ if len(unit) > CMI_PACKET_MAX_BODY:
157
+ self._flush_current()
158
+ self._bodies.append(unit)
159
+ return
160
+ if self._current_length + len(unit) > CMI_PACKET_MAX_BODY:
161
+ self._flush_current()
162
+ self._units.append(unit)
163
+ self._current_length += len(unit)
164
+
165
+ def _flush_current(self) -> None:
166
+ if not self._units:
167
+ self._current_length = 0
168
+ return
169
+ body = b"".join(self._units)
170
+ self._bodies.append(body)
171
+ self._units.clear()
172
+ self._current_length = 0
173
+
174
+ def _build_packet(self, body: bytes, flag: int) -> bytes:
175
+ length_with_flag = (flag << 30) | (len(body) & 0x3FFFFFFF)
176
+ header = bytearray(16)
177
+ header[0] = 0
178
+ header[1:3] = self.adds.to_bytes(2, "big")
179
+ header[3] = self.protocol_id & 0xFF
180
+ header[4:8] = length_with_flag.to_bytes(4, "big")
181
+ header[8:12] = self.stmt_id.to_bytes(4, "big")
182
+ return bytes(header) + body
183
+
184
+
185
+ class MarshalReader:
186
+ def __init__(self, payload: bytes):
187
+ self._payload = payload
188
+
189
+ def __iter__(self) -> Iterator[MarshalUnit]:
190
+ return self._iter_units()
191
+
192
+ def _iter_units(self) -> Iterator[MarshalUnit]:
193
+ offset = 0
194
+ while offset < len(self._payload):
195
+ if offset + 16 > len(self._payload):
196
+ raise ValueError("Incomplete marshal unit header")
197
+ unit_id = int.from_bytes(self._payload[offset : offset + 4], "little")
198
+ type_id = int.from_bytes(self._payload[offset + 4 : offset + 8], "little")
199
+ raw_length = int.from_bytes(self._payload[offset + 8 : offset + 16], "little")
200
+ body_offset = offset + 8
201
+
202
+ if type_id in {
203
+ CMI_STRING_TYPE,
204
+ CMI_BINARY_TYPE,
205
+ 0x0000000C,
206
+ 0x000000F1,
207
+ 0x000000F2,
208
+ CMI_ROWS_TYPE,
209
+ }:
210
+ aligned = _align8(raw_length)
211
+ body_offset = offset + 16
212
+ if body_offset + aligned > len(self._payload):
213
+ raise ValueError("Incomplete variable marshal payload")
214
+ data = self._payload[body_offset : body_offset + raw_length]
215
+ yield MarshalUnit(unit_id, type_id, raw_length, data)
216
+ offset = body_offset + aligned
217
+ else:
218
+ size = _read_fixed_size(type_id)
219
+ if size is None:
220
+ size = 8
221
+ if body_offset + size > offset + 16:
222
+ raise ValueError("Incomplete fixed marshal payload")
223
+ data = self._payload[body_offset : body_offset + size]
224
+ yield MarshalUnit(unit_id, type_id, size, data)
225
+ offset = offset + 16
machbaseAPI/packet.py ADDED
@@ -0,0 +1,87 @@
1
+ """Packet utilities for Machbase binary protocol."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import socket
6
+ import time
7
+ from dataclasses import dataclass
8
+ from typing import Deque, List, Optional
9
+
10
+ from collections import deque
11
+
12
+
13
+ @dataclass
14
+ class Packet:
15
+ protocol: int
16
+ flag: int
17
+ adds: int
18
+ stmt_id: int
19
+ body: bytes
20
+
21
+
22
+ class PacketReader:
23
+ HEADER_SIZE = 16
24
+
25
+ def __init__(self, sock: socket.socket):
26
+ self._socket = sock
27
+ self._buffer = b""
28
+ self._queue: Deque[Packet] = deque()
29
+ self._closed = False
30
+ self._error: Optional[BaseException] = None
31
+
32
+ def next(self, timeout_ms: Optional[int] = None) -> Packet:
33
+ if self._error:
34
+ raise self._error
35
+ if self._queue:
36
+ return self._queue.popleft()
37
+
38
+ deadline = None
39
+ if timeout_ms is not None:
40
+ deadline = time.monotonic() + timeout_ms / 1000
41
+
42
+ while True:
43
+ if self._queue:
44
+ return self._queue.popleft()
45
+ if self._closed:
46
+ raise ConnectionError("socket closed")
47
+ now = time.monotonic()
48
+ if deadline is not None and now >= deadline:
49
+ raise TimeoutError("timed out waiting packet")
50
+
51
+ timeout = None
52
+ if deadline is not None:
53
+ timeout = max(0.0, deadline - now)
54
+
55
+ try:
56
+ self._socket.settimeout(timeout)
57
+ chunk = self._socket.recv(65536)
58
+ if not chunk:
59
+ self._closed = True
60
+ if not self._queue:
61
+ raise ConnectionError("connection closed by server")
62
+ return self._queue.popleft()
63
+ self._buffer += chunk
64
+ self._parse_buffer()
65
+ except TimeoutError as exc:
66
+ raise exc
67
+ except Exception as exc:
68
+ self._error = exc
69
+ raise
70
+
71
+ def _parse_buffer(self) -> None:
72
+ while len(self._buffer) >= self.HEADER_SIZE:
73
+ length_field = int.from_bytes(self._buffer[4:8], "big")
74
+ flag = (length_field >> 30) & 0x03
75
+ body_length = length_field & 0x3FFFFFFF
76
+ total_length = self.HEADER_SIZE + body_length
77
+ if len(self._buffer) < total_length:
78
+ return
79
+ header = self._buffer[:self.HEADER_SIZE]
80
+ body = self._buffer[self.HEADER_SIZE : total_length]
81
+ self._buffer = self._buffer[total_length:]
82
+
83
+ protocol = header[3]
84
+ adds = int.from_bytes(header[1:3], "big")
85
+ stmt_id = int.from_bytes(header[8:12], "big")
86
+ self._queue.append(Packet(protocol=protocol, flag=flag, adds=adds, stmt_id=stmt_id, body=body))
87
+