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,32 @@
1
+ from .connector import (
2
+ DataError,
3
+ DatabaseError,
4
+ Error,
5
+ IntegrityError,
6
+ InterfaceError,
7
+ MachbaseConnection,
8
+ MachbaseCursor,
9
+ NotSupportedError,
10
+ OperationalError,
11
+ ProgrammingError,
12
+ Warning,
13
+ connect,
14
+ )
15
+ from .machbaseAPI import machbase, machbaseAPI
16
+
17
+ __all__ = [
18
+ "connect",
19
+ "MachbaseConnection",
20
+ "MachbaseCursor",
21
+ "machbase",
22
+ "machbaseAPI",
23
+ "Error",
24
+ "Warning",
25
+ "InterfaceError",
26
+ "DatabaseError",
27
+ "OperationalError",
28
+ "IntegrityError",
29
+ "NotSupportedError",
30
+ "ProgrammingError",
31
+ "DataError",
32
+ ]
@@ -0,0 +1,251 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import re
5
+ from typing import Any, Iterable, List, Optional, Sequence
6
+
7
+ from .errors import (
8
+ DataError,
9
+ DatabaseError,
10
+ Error,
11
+ IntegrityError,
12
+ InterfaceError,
13
+ NotSupportedError,
14
+ OperationalError,
15
+ ProgrammingError,
16
+ Warning,
17
+ )
18
+ from .protocol import MachbaseProtocolClient
19
+
20
+
21
+ _SELECT_PREFIX = re.compile(r"^\s*(SELECT|WITH|DESC|DESCRIBE|SHOW)\b", re.IGNORECASE)
22
+
23
+
24
+ def connect(**kwargs: Any) -> "MachbaseConnection":
25
+ return MachbaseConnection(**kwargs)
26
+
27
+
28
+ def _normalize_append_rows(
29
+ rows: Any,
30
+ *,
31
+ strict: bool = False,
32
+ ) -> List[Sequence[Any]]:
33
+ if rows is None:
34
+ return []
35
+ if isinstance(rows, str):
36
+ raise ProgrammingError("Append rows must be a sequence, not a string.")
37
+ if not isinstance(rows, (list, tuple)):
38
+ raise ProgrammingError("Append rows must be a sequence of rows.")
39
+
40
+ normalized = list(rows)
41
+ if len(normalized) == 0:
42
+ return []
43
+
44
+ if strict and not isinstance(normalized[0], (list, tuple)):
45
+ raise ProgrammingError("Append rows must be sequence objects when strict mode is enabled.")
46
+
47
+ if not isinstance(normalized[0], (list, tuple)):
48
+ return [tuple(normalized)] # single row
49
+
50
+ if any(not isinstance(item, (list, tuple)) for item in normalized):
51
+ if strict:
52
+ raise ProgrammingError("Append rows must be a sequence of sequences when strict mode is enabled.")
53
+ raise ProgrammingError("Mixed append row type is not supported.")
54
+
55
+ return [tuple(item) for item in normalized]
56
+
57
+
58
+ class MachbaseConnection:
59
+ _BANNED_POOL_KEYS = {"pool_name", "pool_size", "pool_reset_session"}
60
+
61
+ def __init__(
62
+ self,
63
+ host: str = "127.0.0.1",
64
+ port: int = 5656,
65
+ user: str = "SYS",
66
+ password: str = "MANAGER",
67
+ database: str = "data",
68
+ connect_timeout: int = 5,
69
+ query_timeout: int = 60,
70
+ autocommit: bool = True,
71
+ connection_string: str = "",
72
+ client_id: str = "PYMCB",
73
+ **kwargs: Any,
74
+ ):
75
+ for key in self._BANNED_POOL_KEYS:
76
+ if key in kwargs:
77
+ raise NotSupportedError(f"Pooling is not supported. Unsupported option: {key}")
78
+ if kwargs:
79
+ raise InterfaceError(f"Unknown connection option(s): {', '.join(sorted(kwargs.keys()))}")
80
+ if not autocommit:
81
+ raise NotSupportedError("Machbase is auto-commit only.")
82
+ show_hidden = "SHOW_HIDDEN_COLS=1" in connection_string.upper()
83
+ self._client = MachbaseProtocolClient(
84
+ host=host,
85
+ port=int(port),
86
+ user=user,
87
+ password=password,
88
+ database=database,
89
+ timeout_ms=int(connect_timeout) * 1000,
90
+ query_timeout_ms=int(query_timeout) * 1000,
91
+ client_id=client_id,
92
+ show_hidden_columns=show_hidden,
93
+ )
94
+ self._closed = False
95
+ self._result: Any = None
96
+ self._client.connect()
97
+
98
+ def close(self) -> None:
99
+ if self._closed:
100
+ return
101
+ self._client.close()
102
+ self._closed = True
103
+
104
+ def is_connected(self) -> bool:
105
+ return not self._closed and self._client.connected
106
+
107
+ def commit(self) -> None:
108
+ raise NotSupportedError("Machbase transaction APIs are not supported.")
109
+
110
+ def rollback(self) -> None:
111
+ raise NotSupportedError("Machbase transaction APIs are not supported.")
112
+
113
+ def begin(self) -> None:
114
+ raise NotSupportedError("Machbase transaction APIs are not supported.")
115
+
116
+ def cursor(self, dictionary: bool = True, raw: bool = False) -> "MachbaseCursor":
117
+ return MachbaseCursor(self, dictionary=dictionary, raw=raw)
118
+
119
+ def execute(self, sql: str, params: Optional[Any] = None) -> "MachbaseCursor":
120
+ cursor = self.cursor()
121
+ cursor.execute(sql, params=params)
122
+ return cursor
123
+
124
+ def append(
125
+ self,
126
+ table: str,
127
+ rows: Iterable[Sequence[Any]],
128
+ *,
129
+ types: Optional[Sequence[int]] = None,
130
+ times: Optional[Sequence[Any]] = None,
131
+ date_format: str = "YYYY-MM-DD HH24:MI:SS",
132
+ strict: bool = False,
133
+ ) -> int:
134
+ _ = date_format
135
+ payload = _normalize_append_rows(rows, strict=strict)
136
+ if not payload:
137
+ return 0
138
+ count = self._client.append(table, payload, types=types, times=times)
139
+ self._result = {"table": table, "rows": count}
140
+ return count
141
+
142
+ def append_flush(self) -> None:
143
+ return None
144
+
145
+ def result(self) -> Any:
146
+ return self._result
147
+
148
+
149
+ class MachbaseCursor:
150
+ def __init__(self, conn: MachbaseConnection, dictionary: bool = True, raw: bool = False):
151
+ self._conn = conn
152
+ self._dictionary = dictionary
153
+ self._raw = raw
154
+ self._rows: List[Any] = []
155
+ self._rowcount = -1
156
+ self._description = None
157
+
158
+ def execute(self, operation: str, params: Optional[Any] = None) -> "MachbaseCursor":
159
+ if self._conn._closed:
160
+ raise InterfaceError("Connection is closed.")
161
+ sql = _render_sql(operation, params)
162
+ if _SELECT_PREFIX.match(sql):
163
+ result = self._conn._client.query(sql)
164
+ self._description = tuple((col.name, None, None, None, None, None, None) for col in result.columns)
165
+ if self._raw:
166
+ self._rows = result.rows
167
+ elif self._dictionary:
168
+ self._rows = result.rows
169
+ else:
170
+ self._rows = [tuple(row[col.name] for col in result.columns) for row in result.rows]
171
+ self._rowcount = len(self._rows)
172
+ self._conn._result = result.rows
173
+ else:
174
+ result = self._conn._client.exec_direct(sql)
175
+ self._rows = []
176
+ self._rowcount = result.rows_affected
177
+ self._description = None
178
+ self._conn._result = {"rows_affected": result.rows_affected, "message": result.message}
179
+ return self
180
+
181
+ def executemany(self, operation: str, seq_of_params: Iterable[Any]) -> int:
182
+ count = 0
183
+ for params in seq_of_params:
184
+ self.execute(operation, params)
185
+ count += 1
186
+ return count
187
+
188
+ def fetchone(self) -> Optional[Any]:
189
+ if not self._rows:
190
+ return None
191
+ return self._rows.pop(0)
192
+
193
+ def fetchmany(self, size: int = 1) -> List[Any]:
194
+ out: List[Any] = []
195
+ for _ in range(size):
196
+ row = self.fetchone()
197
+ if row is None:
198
+ break
199
+ out.append(row)
200
+ return out
201
+
202
+ def fetchall(self) -> List[Any]:
203
+ rows = list(self._rows)
204
+ self._rows = []
205
+ return rows
206
+
207
+ def close(self) -> None:
208
+ self._rows = []
209
+
210
+ @property
211
+ def description(self):
212
+ return self._description
213
+
214
+ @property
215
+ def rowcount(self) -> int:
216
+ return self._rowcount
217
+
218
+
219
+ def _render_sql(sql: str, params: Optional[Any]) -> str:
220
+ if params is None:
221
+ return sql
222
+ if isinstance(params, dict):
223
+ rendered = sql
224
+ for key, value in params.items():
225
+ rendered = rendered.replace(f"%({key})s", _render_value(value))
226
+ return rendered
227
+ if not isinstance(params, (list, tuple)):
228
+ params = (params,)
229
+ parts = sql.split("%s")
230
+ if len(parts) - 1 != len(params):
231
+ raise ProgrammingError("Parameter count does not match placeholders.")
232
+ chunks: List[str] = []
233
+ for index, part in enumerate(parts[:-1]):
234
+ chunks.append(part)
235
+ chunks.append(_render_value(params[index]))
236
+ chunks.append(parts[-1])
237
+ return "".join(chunks)
238
+
239
+
240
+ def _render_value(value: Any) -> str:
241
+ if value is None:
242
+ return "NULL"
243
+ if isinstance(value, bool):
244
+ return "1" if value else "0"
245
+ if isinstance(value, (int, float)):
246
+ return str(value)
247
+ if isinstance(value, str):
248
+ return "'" + value.replace("'", "''") + "'"
249
+ if isinstance(value, (list, tuple, dict)):
250
+ return "'" + json.dumps(value, ensure_ascii=False).replace("'", "''") + "'"
251
+ return "'" + str(value).replace("'", "''") + "'"
@@ -0,0 +1,27 @@
1
+ #******************************************************************************
2
+ # Copyright of this product 2013-2023,
3
+ # MACHBASE Corporation(or Inc.) or its subsidiaries.
4
+ # All Rights reserved.
5
+ #******************************************************************************
6
+
7
+ import os
8
+ from machbaseAPI.machbaseAPI import machbase
9
+
10
+ def connect():
11
+ port = int(os.environ['MACHBASE_PORT_NO'])
12
+ db = machbase()
13
+ if db.open('192.168.0.148','SYS','MANAGER',port) == 0 :
14
+ return db.result()
15
+
16
+ if db.execute('select count(*) from m$tables') == 0 :
17
+ return db.result()
18
+
19
+ result = db.result()
20
+
21
+ if db.close() == 0 :
22
+ return db.result()
23
+
24
+ return result
25
+
26
+ if __name__=="__main__":
27
+ print(connect())
@@ -0,0 +1,189 @@
1
+ """Machbase native protocol constants."""
2
+
3
+ CMI_PACKET_MAX_BODY = 64 * 1024
4
+
5
+ CMI_PROTO_CNT = 9
6
+ CMI_HANDSHAKE_PREFIX = "CMI_INET"
7
+ CMI_HANDSHAKE_ENDIAN_LITTLE = "0"
8
+ CMI_HANDSHAKE_READY = "CMI_READY"
9
+
10
+ CMI_PROTOCOL_MAJOR_VERSION = 4
11
+ CMI_PROTOCOL_MINOR_VERSION = 0
12
+ CMI_PROTOCOL_FIX_VERSION = 0
13
+
14
+ CMI_CONNECT_PROTOCOL = 0
15
+ CMI_DISCONNECT_PROTOCOL = 1
16
+ CMI_INVALID_PROTOCOL = 2
17
+ CMI_LARGE_PROTOCOL = 3
18
+ CMI_TIMEOUT_PROTOCOL = 4
19
+ CMI_ADMIN_PROTOCOL = 5
20
+ CMI_PREPARE_PROTOCOL = 6
21
+ CMI_EXECUTE_PROTOCOL = 7
22
+ CMI_EXECDIRECT_PROTOCOL = 8
23
+ CMI_FETCH_PROTOCOL = 9
24
+ CMI_FREE_PROTOCOL = 10
25
+ CMI_APPEND_OPEN_PROTOCOL = 11
26
+ CMI_APPEND_DATA_PROTOCOL = 12
27
+ CMI_APPEND_CLOSE_PROTOCOL = 13
28
+ CMI_COLLECTOR_MANAGER_PROTOCOL = 14
29
+ CMI_COLLECTOR_META_PROTOCOL = 15
30
+ CMI_COLLECTOR_SOURCE_PROTOCOL = 16
31
+ CMI_MSG_PROTOCOL = 17
32
+ CMI_EXECARRAY_PROTOCOL = 18
33
+ CMI_APPEND_BATCH_PROTOCOL = 19
34
+
35
+ CMI_C_VERSION_ID = 0x00000001
36
+ CMI_C_CLIENT_ID = 0x00000002
37
+ CMI_C_LANG_ID = 0x00000003
38
+ CMI_C_DATABASE_ID = 0x00000004
39
+ CMI_C_ENDIAN_ID = 0x00000005
40
+ CMI_C_USER_ID = 0x00000006
41
+ CMI_C_PASSWORD_ID = 0x00000007
42
+ CMI_C_TIMEOUT_ID = 0x00000008
43
+ CMI_C_SLANG_ID = 0x00000009
44
+ CMI_C_SID_ID = 0x00000040
45
+ CMI_C_SHC_ID = 0x00000041
46
+ CMI_C_IP_ID = 0x00000042
47
+ CMI_C_NODE_STATE = 0x00000050
48
+ CMI_C_TIMEZONE_ID = 0x00000070
49
+
50
+ CMI_R_RESULT_ID = 0x00000010
51
+ CMI_R_MESSAGE_ID = 0x00000011
52
+ CMI_R_EMESSAGE_ID = 0x00000012
53
+
54
+ CMI_P_STATEMENT_ID = 0x00000020
55
+ CMI_P_BINDS_ID = 0x00000021
56
+ CMI_P_ID_ID = 0x00000022
57
+ CMI_P_ROWS_ID = 0x00000023
58
+ CMI_P_COLUMNS_ID = 0x00000024
59
+ CMI_P_TABLE_ID = 0x00000025
60
+ CMI_P_COLNAME_ID = 0x00000026
61
+ CMI_P_COLTYPE_ID = 0x00000027
62
+ CMI_P_DDF_ID = 0x00000028
63
+ CMI_P_PARAMTYPE_ID = 0x00000029
64
+
65
+ CMI_E_BIND_ID = 0x00000030
66
+ CMI_E_PARAM_ID = 0x00000031
67
+ CMI_E_OUTPARAM_ID = 0x00000032
68
+ CMI_E_ENDIAN_ID = 0x00000034
69
+ CMI_E_EXECARRAY_RESULT_ID = 0x00000035
70
+
71
+ CMI_D_STATEMENT_ID = 0x00000040
72
+
73
+ CMI_F_ID_ID = 0x00000050
74
+ CMI_F_ROWS_ID = 0x00000051
75
+ CMI_F_VALUE_ID = 0x00000052
76
+
77
+ CMI_X_ID_ID = 0x00000060
78
+ CMI_X_APPEND_SUCCESS_ID = 0x00000061
79
+ CMI_X_APPEND_FAILURE_ID = 0x00000062
80
+ CMI_L_ERROR_ROWS_ID = 0x00000063
81
+
82
+ CMI_STRING_TYPE = 0x00000002
83
+ CMI_BINARY_TYPE = 0x00000003
84
+ CMI_SCHAR_TYPE = 0x00000004
85
+ CMI_UCHAR_TYPE = 0x00000005
86
+ CMI_SSHORT_TYPE = 0x00000006
87
+ CMI_USHORT_TYPE = 0x00000007
88
+ CMI_SINT_TYPE = 0x00000008
89
+ CMI_UINT_TYPE = 0x00000009
90
+ CMI_SLONG_TYPE = 0x0000000A
91
+ CMI_ULONG_TYPE = 0x0000000B
92
+ CMI_DATE_TYPE = 0x0000000C
93
+ CMI_ROWS_TYPE = 0x0000000D
94
+ CMI_TNUMERIC_TYPE = 0x000000F1
95
+ CMI_NUMBER_TYPE = 0x000000F2
96
+
97
+ CMI_OK_RESULT = 0x724F4B5F00000000
98
+ CMI_CM_ERROR_RESULT = 0x72434D5F00000000
99
+ CMI_LAST_RESULT = 0x724C535400000000
100
+ CMI_TIMEOUT_RESULT = 0x7254494D00000000
101
+ CMI_LARGE_RESULT = 0x724C524700000000
102
+ CMI_INVALID_RESULT = 0x72494E5600000000
103
+
104
+ CMD_FIX_FLAG = 0x0000
105
+ CMD_VAR_FLAG = 0x0001
106
+ CMD_TIME_FLAG = 0x0002
107
+
108
+ CMD_VARCHAR_TYPE = (0x0001 << 2) | CMD_VAR_FLAG
109
+ CMD_DATE_TYPE = (0x0001 << 2) | CMD_TIME_FLAG
110
+ CMD_INT16_TYPE = (0x0001 << 2) | CMD_FIX_FLAG
111
+ CMD_INT32_TYPE = (0x0002 << 2) | CMD_FIX_FLAG
112
+ CMD_INT64_TYPE = (0x0003 << 2) | CMD_FIX_FLAG
113
+ CMD_FLT32_TYPE = (0x0004 << 2) | CMD_FIX_FLAG
114
+ CMD_FLT64_TYPE = (0x0005 << 2) | CMD_FIX_FLAG
115
+ CMD_NUL_TYPE = (0x0006 << 2) | CMD_FIX_FLAG
116
+ CMD_IPV4_TYPE = (0x0008 << 2) | CMD_FIX_FLAG
117
+ CMD_IPV6_TYPE = (0x0009 << 2) | CMD_FIX_FLAG
118
+ CMD_BOOL_TYPE = (0x000A << 2) | CMD_FIX_FLAG
119
+ CMD_CHAR_TYPE = (0x000B << 2) | CMD_VAR_FLAG
120
+ CMD_TEXT_TYPE = (0x000C << 2) | CMD_VAR_FLAG
121
+ CMD_CLOB_TYPE = (0x000D << 2) | CMD_VAR_FLAG
122
+ CMD_BLOB_TYPE = (0x000E << 2) | CMD_VAR_FLAG
123
+ CMD_JSON_TYPE = (0x000F << 2) | CMD_VAR_FLAG
124
+ CMD_BINARY_TYPE = (0x0018 << 2) | CMD_VAR_FLAG
125
+ CMD_IPNET_TYPE = (0x0019 << 2) | CMD_VAR_FLAG
126
+ CMD_UINT16_TYPE = (0x001A << 2) | CMD_FIX_FLAG
127
+ CMD_UINT32_TYPE = (0x001B << 2) | CMD_FIX_FLAG
128
+ CMD_UINT64_TYPE = (0x001C << 2) | CMD_FIX_FLAG
129
+
130
+ SQL_APPEND_TYPE_NULL = 0
131
+ SQL_APPEND_TYPE_INT16 = 1
132
+ SQL_APPEND_TYPE_INT32 = 2
133
+ SQL_APPEND_TYPE_INT64 = 3
134
+ SQL_APPEND_TYPE_UINT16 = 4
135
+ SQL_APPEND_TYPE_UINT32 = 5
136
+ SQL_APPEND_TYPE_UINT64 = 6
137
+ SQL_APPEND_TYPE_FLT32 = 7
138
+ SQL_APPEND_TYPE_FLT64 = 8
139
+ SQL_APPEND_TYPE_IPV4 = 9
140
+ SQL_APPEND_TYPE_IPV6 = 10
141
+ SQL_APPEND_TYPE_DATE = 11
142
+ SQL_APPEND_TYPE_VARCHAR = 12
143
+ SQL_APPEND_TYPE_CLOB = 13
144
+ SQL_APPEND_TYPE_BLOB = 14
145
+ SQL_APPEND_TYPE_JSON = 15
146
+
147
+ CMI_APPEND_TYPE_MAP = {
148
+ SQL_APPEND_TYPE_NULL: CMD_NUL_TYPE,
149
+ SQL_APPEND_TYPE_INT16: CMD_INT16_TYPE,
150
+ SQL_APPEND_TYPE_INT32: CMD_INT32_TYPE,
151
+ SQL_APPEND_TYPE_INT64: CMD_INT64_TYPE,
152
+ SQL_APPEND_TYPE_UINT16: CMD_UINT16_TYPE,
153
+ SQL_APPEND_TYPE_UINT32: CMD_UINT32_TYPE,
154
+ SQL_APPEND_TYPE_UINT64: CMD_UINT64_TYPE,
155
+ SQL_APPEND_TYPE_FLT32: CMD_FLT32_TYPE,
156
+ SQL_APPEND_TYPE_FLT64: CMD_FLT64_TYPE,
157
+ SQL_APPEND_TYPE_IPV4: CMD_IPV4_TYPE,
158
+ SQL_APPEND_TYPE_IPV6: CMD_IPV6_TYPE,
159
+ SQL_APPEND_TYPE_DATE: CMD_DATE_TYPE,
160
+ SQL_APPEND_TYPE_VARCHAR: CMD_VARCHAR_TYPE,
161
+ SQL_APPEND_TYPE_CLOB: CMD_CLOB_TYPE,
162
+ SQL_APPEND_TYPE_BLOB: CMD_BLOB_TYPE,
163
+ SQL_APPEND_TYPE_JSON: CMD_JSON_TYPE,
164
+ 4: CMD_INT16_TYPE,
165
+ 8: CMD_INT32_TYPE,
166
+ 12: CMD_INT64_TYPE,
167
+ 16: CMD_FLT32_TYPE,
168
+ 20: CMD_FLT64_TYPE,
169
+ 32: CMD_DATE_TYPE,
170
+ 36: CMD_UINT64_TYPE,
171
+ 49: CMD_TEXT_TYPE,
172
+ 61: CMD_DATE_TYPE,
173
+ 97: CMD_BINARY_TYPE,
174
+ 104: CMD_UINT16_TYPE,
175
+ 108: CMD_UINT32_TYPE,
176
+ 112: CMD_UINT64_TYPE,
177
+ 2104: CMD_IPV4_TYPE,
178
+ 2106: CMD_IPV6_TYPE,
179
+ 2110: CMD_JSON_TYPE,
180
+ 2111: CMD_BINARY_TYPE,
181
+ }
182
+
183
+
184
+ def is_variable_type(spiner_type: int) -> bool:
185
+ return (spiner_type & CMD_VAR_FLAG) == CMD_VAR_FLAG
186
+
187
+
188
+ DEFAULT_CONNECT_TIMEOUT_MS = 5000
189
+ DEFAULT_QUERY_TIMEOUT_MS = 60000
machbaseAPI/errors.py ADDED
@@ -0,0 +1,38 @@
1
+ """Error hierarchy for the pure-Python Machbase connector."""
2
+
3
+
4
+ class Error(Exception):
5
+ """Base class for all public connector errors."""
6
+
7
+
8
+ class Warning(Error):
9
+ """Warning is kept for compatibility with DB-API style naming."""
10
+
11
+
12
+ class InterfaceError(Error):
13
+ """Invalid public interface usage."""
14
+
15
+
16
+ class DatabaseError(Error):
17
+ """Server-side or protocol error."""
18
+
19
+
20
+ class OperationalError(DatabaseError):
21
+ """Connection / network errors."""
22
+
23
+
24
+ class IntegrityError(DatabaseError):
25
+ """Data integrity violations."""
26
+
27
+
28
+ class DataError(DatabaseError):
29
+ """Data conversion / encoding errors."""
30
+
31
+
32
+ class ProgrammingError(DatabaseError):
33
+ """Invalid arguments or method usage."""
34
+
35
+
36
+ class NotSupportedError(DatabaseError):
37
+ """Unsupported feature requested by caller."""
38
+