chdb 2.1.1__cp311-cp311-macosx_10_15_x86_64.whl → 2.2.0b1__cp311-cp311-macosx_10_15_x86_64.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.
Potentially problematic release.
This version of chdb might be problematic. Click here for more details.
- chdb/__init__.py +4 -1
- chdb/_chdb.cpython-311-darwin.so +0 -0
- chdb/dbapi/connections.py +36 -153
- chdb/dbapi/cursors.py +28 -90
- chdb/state/__init__.py +3 -0
- chdb/state/sqlitelike.py +132 -0
- chdb/utils/__init__.py +1 -0
- chdb/utils/trace.py +74 -0
- {chdb-2.1.1.dist-info → chdb-2.2.0b1.dist-info}/METADATA +16 -3
- {chdb-2.1.1.dist-info → chdb-2.2.0b1.dist-info}/RECORD +13 -10
- {chdb-2.1.1.dist-info → chdb-2.2.0b1.dist-info}/WHEEL +1 -1
- {chdb-2.1.1.dist-info → chdb-2.2.0b1.dist-info}/LICENSE.txt +0 -0
- {chdb-2.1.1.dist-info → chdb-2.2.0b1.dist-info}/top_level.txt +0 -0
chdb/__init__.py
CHANGED
|
@@ -18,7 +18,7 @@ _process_result_format_funs = {
|
|
|
18
18
|
# UDF script path will be f"{g_udf_path}/{func_name}.py"
|
|
19
19
|
g_udf_path = ""
|
|
20
20
|
|
|
21
|
-
chdb_version = ('2', '
|
|
21
|
+
chdb_version = ('2', '2', '0b1')
|
|
22
22
|
if sys.version_info[:2] >= (3, 7):
|
|
23
23
|
# get the path of the current file
|
|
24
24
|
current_path = os.path.dirname(os.path.abspath(__file__))
|
|
@@ -85,8 +85,10 @@ sql = query
|
|
|
85
85
|
PyReader = _chdb.PyReader
|
|
86
86
|
|
|
87
87
|
from . import dbapi, session, udf, utils # noqa: E402
|
|
88
|
+
from .state import connect # noqa: E402
|
|
88
89
|
|
|
89
90
|
__all__ = [
|
|
91
|
+
"_chdb",
|
|
90
92
|
"PyReader",
|
|
91
93
|
"ChdbError",
|
|
92
94
|
"query",
|
|
@@ -99,4 +101,5 @@ __all__ = [
|
|
|
99
101
|
"session",
|
|
100
102
|
"udf",
|
|
101
103
|
"utils",
|
|
104
|
+
"connect",
|
|
102
105
|
]
|
chdb/_chdb.cpython-311-darwin.so
CHANGED
|
Binary file
|
chdb/dbapi/connections.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import json
|
|
2
1
|
from . import err
|
|
3
2
|
from .cursors import Cursor
|
|
4
3
|
from . import converters
|
|
4
|
+
from ..state import sqlitelike as chdb_stateful
|
|
5
5
|
|
|
6
6
|
DEBUG = False
|
|
7
7
|
VERBOSE = False
|
|
@@ -10,56 +10,29 @@ VERBOSE = False
|
|
|
10
10
|
class Connection(object):
|
|
11
11
|
"""
|
|
12
12
|
Representation of a connection with chdb.
|
|
13
|
-
|
|
14
|
-
The proper way to get an instance of this class is to call
|
|
15
|
-
connect().
|
|
16
|
-
|
|
17
|
-
Accepts several arguments:
|
|
18
|
-
|
|
19
|
-
:param cursorclass: Custom cursor class to use.
|
|
20
|
-
:param path: Optional folder path to store database files on disk.
|
|
21
|
-
|
|
22
|
-
See `Connection <https://www.python.org/dev/peps/pep-0249/#connection-objects>`_ in the
|
|
23
|
-
specification.
|
|
24
13
|
"""
|
|
25
14
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
def __init__(self, cursorclass=Cursor, path=None):
|
|
30
|
-
|
|
31
|
-
self._resp = None
|
|
32
|
-
|
|
33
|
-
# 1. pre-process params in init
|
|
34
|
-
self.encoding = 'utf8'
|
|
35
|
-
|
|
36
|
-
self.cursorclass = cursorclass
|
|
37
|
-
|
|
38
|
-
self._result = None
|
|
15
|
+
def __init__(self, path=None):
|
|
16
|
+
self._closed = False
|
|
17
|
+
self.encoding = "utf8"
|
|
39
18
|
self._affected_rows = 0
|
|
19
|
+
self._resp = None
|
|
40
20
|
|
|
41
|
-
|
|
21
|
+
# Initialize sqlitelike connection
|
|
22
|
+
connection_string = ":memory:" if path is None else f"file:{path}"
|
|
23
|
+
self._conn = chdb_stateful.Connection(connection_string)
|
|
42
24
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
self._execute_command("select 1;")
|
|
48
|
-
self._read_query_result()
|
|
25
|
+
# Test connection with a simple query
|
|
26
|
+
cursor = self._conn.cursor()
|
|
27
|
+
cursor.execute("SELECT 1")
|
|
28
|
+
cursor.close()
|
|
49
29
|
|
|
50
30
|
def close(self):
|
|
51
|
-
"""
|
|
52
|
-
Send the quit message and close the socket.
|
|
53
|
-
|
|
54
|
-
See `Connection.close() <https://www.python.org/dev/peps/pep-0249/#Connection.close>`_
|
|
55
|
-
in the specification.
|
|
56
|
-
|
|
57
|
-
:raise Error: If the connection is already closed.
|
|
58
|
-
"""
|
|
31
|
+
"""Send the quit message and close the socket."""
|
|
59
32
|
if self._closed:
|
|
60
33
|
raise err.Error("Already closed")
|
|
61
34
|
self._closed = True
|
|
62
|
-
self.
|
|
35
|
+
self._conn.close()
|
|
63
36
|
|
|
64
37
|
@property
|
|
65
38
|
def open(self):
|
|
@@ -67,81 +40,41 @@ class Connection(object):
|
|
|
67
40
|
return not self._closed
|
|
68
41
|
|
|
69
42
|
def commit(self):
|
|
70
|
-
"""
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
See `Connection.commit() <https://www.python.org/dev/peps/pep-0249/#commit>`_
|
|
74
|
-
in the specification.
|
|
75
|
-
"""
|
|
76
|
-
return
|
|
43
|
+
"""Commit changes to stable storage."""
|
|
44
|
+
# No-op for ClickHouse
|
|
45
|
+
pass
|
|
77
46
|
|
|
78
47
|
def rollback(self):
|
|
79
|
-
"""
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
See `Connection.rollback() <https://www.python.org/dev/peps/pep-0249/#rollback>`_
|
|
83
|
-
in the specification.
|
|
84
|
-
"""
|
|
85
|
-
return
|
|
48
|
+
"""Roll back the current transaction."""
|
|
49
|
+
# No-op for ClickHouse
|
|
50
|
+
pass
|
|
86
51
|
|
|
87
52
|
def cursor(self, cursor=None):
|
|
88
|
-
"""
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
:param cursor: The type of cursor to create; current only :py:class:`Cursor`
|
|
92
|
-
None means use Cursor.
|
|
93
|
-
"""
|
|
53
|
+
"""Create a new cursor to execute queries with."""
|
|
54
|
+
if self._closed:
|
|
55
|
+
raise err.Error("Connection closed")
|
|
94
56
|
if cursor:
|
|
95
|
-
return
|
|
96
|
-
return
|
|
57
|
+
return Cursor(self)
|
|
58
|
+
return Cursor(self)
|
|
97
59
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
if isinstance(sql, str):
|
|
101
|
-
sql = sql.encode(self.encoding, 'surrogateescape')
|
|
102
|
-
self._execute_command(sql)
|
|
103
|
-
self._affected_rows = self._read_query_result()
|
|
104
|
-
return self._affected_rows
|
|
105
|
-
|
|
106
|
-
def _execute_command(self, sql):
|
|
107
|
-
"""
|
|
108
|
-
:raise InterfaceError: If the connection is closed.
|
|
109
|
-
:raise ValueError: If no username was specified.
|
|
110
|
-
"""
|
|
60
|
+
def query(self, sql, fmt="ArrowStream"):
|
|
61
|
+
"""Execute a query and return the raw result."""
|
|
111
62
|
if self._closed:
|
|
112
63
|
raise err.InterfaceError("Connection closed")
|
|
113
64
|
|
|
114
65
|
if isinstance(sql, str):
|
|
115
|
-
sql = sql.encode(self.encoding)
|
|
66
|
+
sql = sql.encode(self.encoding, "surrogateescape")
|
|
116
67
|
|
|
117
|
-
if isinstance(sql, bytearray):
|
|
118
|
-
sql = bytes(sql)
|
|
119
|
-
|
|
120
|
-
# drop last command return
|
|
121
|
-
if self._resp is not None:
|
|
122
|
-
self._resp = None
|
|
123
|
-
|
|
124
|
-
if DEBUG:
|
|
125
|
-
print("DEBUG: query:", sql)
|
|
126
68
|
try:
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
self._resp = res.data()
|
|
69
|
+
result = self._conn.query(sql.decode(), fmt)
|
|
70
|
+
self._resp = result
|
|
71
|
+
return result
|
|
131
72
|
except Exception as error:
|
|
132
|
-
raise err.InterfaceError("
|
|
73
|
+
raise err.InterfaceError(f"Query error: {error}")
|
|
133
74
|
|
|
134
75
|
def escape(self, obj, mapping=None):
|
|
135
|
-
"""Escape whatever value you pass to it.
|
|
136
|
-
|
|
137
|
-
Non-standard, for internal use; do not use this in your applications.
|
|
138
|
-
"""
|
|
139
|
-
if isinstance(obj, str):
|
|
140
|
-
return "'" + self.escape_string(obj) + "'"
|
|
141
|
-
if isinstance(obj, (bytes, bytearray)):
|
|
142
|
-
ret = self._quote_bytes(obj)
|
|
143
|
-
return ret
|
|
144
|
-
return converters.escape_item(obj, mapping=mapping)
|
|
76
|
+
"""Escape whatever value you pass to it."""
|
|
77
|
+
return converters.escape_item(obj, mapping)
|
|
145
78
|
|
|
146
79
|
def escape_string(self, s):
|
|
147
80
|
return converters.escape_string(s)
|
|
@@ -149,13 +82,6 @@ class Connection(object):
|
|
|
149
82
|
def _quote_bytes(self, s):
|
|
150
83
|
return converters.escape_bytes(s)
|
|
151
84
|
|
|
152
|
-
def _read_query_result(self):
|
|
153
|
-
self._result = None
|
|
154
|
-
result = CHDBResult(self)
|
|
155
|
-
result.read()
|
|
156
|
-
self._result = result
|
|
157
|
-
return result.affected_rows
|
|
158
|
-
|
|
159
85
|
def __enter__(self):
|
|
160
86
|
"""Context manager that returns a Cursor"""
|
|
161
87
|
return self.cursor()
|
|
@@ -166,52 +92,9 @@ class Connection(object):
|
|
|
166
92
|
self.rollback()
|
|
167
93
|
else:
|
|
168
94
|
self.commit()
|
|
95
|
+
self.close()
|
|
169
96
|
|
|
170
97
|
@property
|
|
171
98
|
def resp(self):
|
|
99
|
+
"""Return the last query response"""
|
|
172
100
|
return self._resp
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
class CHDBResult(object):
|
|
176
|
-
def __init__(self, connection):
|
|
177
|
-
"""
|
|
178
|
-
:type connection: Connection
|
|
179
|
-
"""
|
|
180
|
-
self.connection = connection
|
|
181
|
-
self.affected_rows = 0
|
|
182
|
-
self.insert_id = None
|
|
183
|
-
self.warning_count = 0
|
|
184
|
-
self.message = None
|
|
185
|
-
self.field_count = 0
|
|
186
|
-
self.description = None
|
|
187
|
-
self.rows = None
|
|
188
|
-
self.has_next = None
|
|
189
|
-
|
|
190
|
-
def read(self):
|
|
191
|
-
# Handle empty responses (for instance from CREATE TABLE)
|
|
192
|
-
if self.connection.resp is None:
|
|
193
|
-
return
|
|
194
|
-
|
|
195
|
-
try:
|
|
196
|
-
data = json.loads(self.connection.resp)
|
|
197
|
-
except Exception as error:
|
|
198
|
-
raise err.InterfaceError("Unsupported response format:" % error)
|
|
199
|
-
|
|
200
|
-
try:
|
|
201
|
-
self.field_count = len(data["meta"])
|
|
202
|
-
description = []
|
|
203
|
-
for meta in data["meta"]:
|
|
204
|
-
fields = [meta["name"], meta["type"]]
|
|
205
|
-
description.append(tuple(fields))
|
|
206
|
-
self.description = tuple(description)
|
|
207
|
-
|
|
208
|
-
rows = []
|
|
209
|
-
for line in data["data"]:
|
|
210
|
-
row = []
|
|
211
|
-
for i in range(self.field_count):
|
|
212
|
-
column_data = converters.convert_column_data(self.description[i][1], line[self.description[i][0]])
|
|
213
|
-
row.append(column_data)
|
|
214
|
-
rows.append(tuple(row))
|
|
215
|
-
self.rows = tuple(rows)
|
|
216
|
-
except Exception as error:
|
|
217
|
-
raise err.InterfaceError("Read return data err:" % error)
|
chdb/dbapi/cursors.py
CHANGED
|
@@ -29,13 +29,11 @@ class Cursor(object):
|
|
|
29
29
|
|
|
30
30
|
def __init__(self, connection):
|
|
31
31
|
self.connection = connection
|
|
32
|
+
self._cursor = connection._conn.cursor()
|
|
32
33
|
self.description = None
|
|
33
34
|
self.rowcount = -1
|
|
34
|
-
self.rownumber = 0
|
|
35
35
|
self.arraysize = 1
|
|
36
36
|
self.lastrowid = None
|
|
37
|
-
self._result = None
|
|
38
|
-
self._rows = None
|
|
39
37
|
self._executed = None
|
|
40
38
|
|
|
41
39
|
def __enter__(self):
|
|
@@ -83,14 +81,7 @@ class Cursor(object):
|
|
|
83
81
|
"""
|
|
84
82
|
Closing a cursor just exhausts all remaining data.
|
|
85
83
|
"""
|
|
86
|
-
|
|
87
|
-
if conn is None:
|
|
88
|
-
return
|
|
89
|
-
try:
|
|
90
|
-
while self.nextset():
|
|
91
|
-
pass
|
|
92
|
-
finally:
|
|
93
|
-
self.connection = None
|
|
84
|
+
self._cursor.close()
|
|
94
85
|
|
|
95
86
|
def _get_db(self):
|
|
96
87
|
if not self.connection:
|
|
@@ -121,33 +112,6 @@ class Cursor(object):
|
|
|
121
112
|
|
|
122
113
|
return query
|
|
123
114
|
|
|
124
|
-
def _clear_result(self):
|
|
125
|
-
self.rownumber = 0
|
|
126
|
-
self._result = None
|
|
127
|
-
|
|
128
|
-
self.rowcount = 0
|
|
129
|
-
self.description = None
|
|
130
|
-
self.lastrowid = None
|
|
131
|
-
self._rows = None
|
|
132
|
-
|
|
133
|
-
def _do_get_result(self):
|
|
134
|
-
conn = self._get_db()
|
|
135
|
-
|
|
136
|
-
self._result = result = conn._result
|
|
137
|
-
|
|
138
|
-
self.rowcount = result.affected_rows
|
|
139
|
-
self.description = result.description
|
|
140
|
-
self.lastrowid = result.insert_id
|
|
141
|
-
self._rows = result.rows
|
|
142
|
-
|
|
143
|
-
def _query(self, q):
|
|
144
|
-
conn = self._get_db()
|
|
145
|
-
self._last_executed = q
|
|
146
|
-
self._clear_result()
|
|
147
|
-
conn.query(q)
|
|
148
|
-
self._do_get_result()
|
|
149
|
-
return self.rowcount
|
|
150
|
-
|
|
151
115
|
def execute(self, query, args=None):
|
|
152
116
|
"""Execute a query
|
|
153
117
|
|
|
@@ -162,14 +126,24 @@ class Cursor(object):
|
|
|
162
126
|
If args is a list or tuple, %s can be used as a placeholder in the query.
|
|
163
127
|
If args is a dict, %(name)s can be used as a placeholder in the query.
|
|
164
128
|
"""
|
|
165
|
-
|
|
166
|
-
|
|
129
|
+
if args is not None:
|
|
130
|
+
query = query % self._escape_args(args, self.connection)
|
|
131
|
+
|
|
132
|
+
self._cursor.execute(query)
|
|
167
133
|
|
|
168
|
-
|
|
134
|
+
# Get description from Arrow schema
|
|
135
|
+
if self._cursor._current_table is not None:
|
|
136
|
+
self.description = [
|
|
137
|
+
(field.name, field.type.to_pandas_dtype(), None, None, None, None, None)
|
|
138
|
+
for field in self._cursor._current_table.schema
|
|
139
|
+
]
|
|
140
|
+
self.rowcount = self._cursor._current_table.num_rows
|
|
141
|
+
else:
|
|
142
|
+
self.description = None
|
|
143
|
+
self.rowcount = -1
|
|
169
144
|
|
|
170
|
-
result = self._query(query)
|
|
171
145
|
self._executed = query
|
|
172
|
-
return
|
|
146
|
+
return self.rowcount
|
|
173
147
|
|
|
174
148
|
def executemany(self, query, args):
|
|
175
149
|
# type: (str, list) -> int
|
|
@@ -233,34 +207,21 @@ class Cursor(object):
|
|
|
233
207
|
|
|
234
208
|
def fetchone(self):
|
|
235
209
|
"""Fetch the next row"""
|
|
236
|
-
self.
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
return result
|
|
242
|
-
|
|
243
|
-
def fetchmany(self, size=None):
|
|
210
|
+
if not self._executed:
|
|
211
|
+
raise err.ProgrammingError("execute() first")
|
|
212
|
+
return self._cursor.fetchone()
|
|
213
|
+
|
|
214
|
+
def fetchmany(self, size=1):
|
|
244
215
|
"""Fetch several rows"""
|
|
245
|
-
self.
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
end = self.rownumber + (size or self.arraysize)
|
|
249
|
-
result = self._rows[self.rownumber:end]
|
|
250
|
-
self.rownumber = min(end, len(self._rows))
|
|
251
|
-
return result
|
|
216
|
+
if not self._executed:
|
|
217
|
+
raise err.ProgrammingError("execute() first")
|
|
218
|
+
return self._cursor.fetchmany(size)
|
|
252
219
|
|
|
253
220
|
def fetchall(self):
|
|
254
221
|
"""Fetch all the rows"""
|
|
255
|
-
self.
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
if self.rownumber:
|
|
259
|
-
result = self._rows[self.rownumber:]
|
|
260
|
-
else:
|
|
261
|
-
result = self._rows
|
|
262
|
-
self.rownumber = len(self._rows)
|
|
263
|
-
return result
|
|
222
|
+
if not self._executed:
|
|
223
|
+
raise err.ProgrammingError("execute() first")
|
|
224
|
+
return self._cursor.fetchall()
|
|
264
225
|
|
|
265
226
|
def nextset(self):
|
|
266
227
|
"""Get the next query set"""
|
|
@@ -272,26 +233,3 @@ class Cursor(object):
|
|
|
272
233
|
|
|
273
234
|
def setoutputsizes(self, *args):
|
|
274
235
|
"""Does nothing, required by DB API."""
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
class DictCursor(Cursor):
|
|
278
|
-
"""A cursor which returns results as a dictionary"""
|
|
279
|
-
# You can override this to use OrderedDict or other dict-like types.
|
|
280
|
-
dict_type = dict
|
|
281
|
-
|
|
282
|
-
def _do_get_result(self):
|
|
283
|
-
super()._do_get_result()
|
|
284
|
-
fields = []
|
|
285
|
-
if self.description:
|
|
286
|
-
for f in self.description:
|
|
287
|
-
name = f[0]
|
|
288
|
-
fields.append(name)
|
|
289
|
-
self._fields = fields
|
|
290
|
-
|
|
291
|
-
if fields and self._rows:
|
|
292
|
-
self._rows = [self._conv_row(r) for r in self._rows]
|
|
293
|
-
|
|
294
|
-
def _conv_row(self, row):
|
|
295
|
-
if row is None:
|
|
296
|
-
return None
|
|
297
|
-
return self.dict_type(zip(self._fields, row))
|
chdb/state/__init__.py
ADDED
chdb/state/sqlitelike.py
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import io
|
|
2
|
+
from typing import Optional, Any
|
|
3
|
+
from chdb import _chdb
|
|
4
|
+
|
|
5
|
+
# try import pyarrow if failed, raise ImportError with suggestion
|
|
6
|
+
try:
|
|
7
|
+
import pyarrow as pa # noqa
|
|
8
|
+
except ImportError as e:
|
|
9
|
+
print(f"ImportError: {e}")
|
|
10
|
+
print('Please install pyarrow via "pip install pyarrow"')
|
|
11
|
+
raise ImportError("Failed to import pyarrow") from None
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Connection:
|
|
15
|
+
def __init__(self, connection_string: str):
|
|
16
|
+
# print("Connection", connection_string)
|
|
17
|
+
self._cursor: Optional[Cursor] = None
|
|
18
|
+
self._conn = _chdb.connect(connection_string)
|
|
19
|
+
|
|
20
|
+
def cursor(self) -> "Cursor":
|
|
21
|
+
self._cursor = Cursor(self._conn)
|
|
22
|
+
return self._cursor
|
|
23
|
+
|
|
24
|
+
def query(self, query: str, format: str = "ArrowStream") -> Any:
|
|
25
|
+
return self._conn.query(query, format)
|
|
26
|
+
|
|
27
|
+
def close(self) -> None:
|
|
28
|
+
# print("close")
|
|
29
|
+
if self._cursor:
|
|
30
|
+
self._cursor.close()
|
|
31
|
+
self._conn.close()
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class Cursor:
|
|
35
|
+
def __init__(self, connection):
|
|
36
|
+
self._conn = connection
|
|
37
|
+
self._cursor = self._conn.cursor()
|
|
38
|
+
self._current_table: Optional[pa.Table] = None
|
|
39
|
+
self._current_row: int = 0
|
|
40
|
+
|
|
41
|
+
def execute(self, query: str) -> None:
|
|
42
|
+
self._cursor.execute(query)
|
|
43
|
+
result_mv = self._cursor.get_memview()
|
|
44
|
+
# print("get_result", result_mv)
|
|
45
|
+
if self._cursor.has_error():
|
|
46
|
+
raise Exception(self._cursor.error_message())
|
|
47
|
+
if self._cursor.data_size() == 0:
|
|
48
|
+
self._current_table = None
|
|
49
|
+
self._current_row = 0
|
|
50
|
+
return
|
|
51
|
+
arrow_data = result_mv.tobytes()
|
|
52
|
+
reader = pa.ipc.open_stream(io.BytesIO(arrow_data))
|
|
53
|
+
self._current_table = reader.read_all()
|
|
54
|
+
self._current_row = 0
|
|
55
|
+
|
|
56
|
+
def commit(self) -> None:
|
|
57
|
+
self._cursor.commit()
|
|
58
|
+
|
|
59
|
+
def fetchone(self) -> Optional[tuple]:
|
|
60
|
+
if not self._current_table or self._current_row >= len(self._current_table):
|
|
61
|
+
return None
|
|
62
|
+
|
|
63
|
+
row_dict = {
|
|
64
|
+
col: self._current_table.column(col)[self._current_row].as_py()
|
|
65
|
+
for col in self._current_table.column_names
|
|
66
|
+
}
|
|
67
|
+
self._current_row += 1
|
|
68
|
+
return tuple(row_dict.values())
|
|
69
|
+
|
|
70
|
+
def fetchmany(self, size: int = 1) -> tuple:
|
|
71
|
+
if not self._current_table:
|
|
72
|
+
return tuple()
|
|
73
|
+
|
|
74
|
+
rows = []
|
|
75
|
+
for _ in range(size):
|
|
76
|
+
if (row := self.fetchone()) is None:
|
|
77
|
+
break
|
|
78
|
+
rows.append(row)
|
|
79
|
+
return tuple(rows)
|
|
80
|
+
|
|
81
|
+
def fetchall(self) -> tuple:
|
|
82
|
+
if not self._current_table:
|
|
83
|
+
return tuple()
|
|
84
|
+
|
|
85
|
+
remaining_rows = []
|
|
86
|
+
while (row := self.fetchone()) is not None:
|
|
87
|
+
remaining_rows.append(row)
|
|
88
|
+
return tuple(remaining_rows)
|
|
89
|
+
|
|
90
|
+
def close(self) -> None:
|
|
91
|
+
self._cursor.close()
|
|
92
|
+
|
|
93
|
+
def __iter__(self):
|
|
94
|
+
return self
|
|
95
|
+
|
|
96
|
+
def __next__(self) -> tuple:
|
|
97
|
+
row = self.fetchone()
|
|
98
|
+
if row is None:
|
|
99
|
+
raise StopIteration
|
|
100
|
+
return row
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def connect(connection_string: str = ":memory:") -> Connection:
|
|
104
|
+
"""
|
|
105
|
+
Create a connection to chDB backgroud server.
|
|
106
|
+
Only one open connection is allowed per process. Use `close` to close the connection.
|
|
107
|
+
If called with the same connection string, the same connection object will be returned.
|
|
108
|
+
You can use the connection object to create cursor object. `cursor` method will return a cursor object.
|
|
109
|
+
|
|
110
|
+
Args:
|
|
111
|
+
connection_string (str, optional): Connection string. Defaults to ":memory:".
|
|
112
|
+
Aslo support file path like:
|
|
113
|
+
- ":memory:" (for in-memory database)
|
|
114
|
+
- "test.db" (for relative path)
|
|
115
|
+
- "file:test.db" (same as above)
|
|
116
|
+
- "/path/to/test.db" (for absolute path)
|
|
117
|
+
- "file:/path/to/test.db" (same as above)
|
|
118
|
+
- "file:test.db?param1=value1¶m2=value2" (for relative path with query params)
|
|
119
|
+
- "///path/to/test.db?param1=value1¶m2=value2" (for absolute path)
|
|
120
|
+
|
|
121
|
+
Connection string args handling:
|
|
122
|
+
Connection string can contain query params like "file:test.db?param1=value1¶m2=value2"
|
|
123
|
+
"param1=value1" will be passed to ClickHouse engine as start up args.
|
|
124
|
+
|
|
125
|
+
For more details, see `clickhouse local --help --verbose`
|
|
126
|
+
Some special args handling:
|
|
127
|
+
- "mode=ro" would be "--readonly=1" for clickhouse (read-only mode)
|
|
128
|
+
|
|
129
|
+
Returns:
|
|
130
|
+
Connection: Connection object
|
|
131
|
+
"""
|
|
132
|
+
return Connection(connection_string)
|
chdb/utils/__init__.py
CHANGED
chdb/utils/trace.py
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import functools
|
|
2
|
+
import inspect
|
|
3
|
+
import sys
|
|
4
|
+
import linecache
|
|
5
|
+
from datetime import datetime
|
|
6
|
+
|
|
7
|
+
enable_print = False
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def print_lines(func):
|
|
11
|
+
if not enable_print:
|
|
12
|
+
return func
|
|
13
|
+
|
|
14
|
+
@functools.wraps(func)
|
|
15
|
+
def wrapper(*args, **kwargs):
|
|
16
|
+
# Get function name and determine if it's a method
|
|
17
|
+
is_method = inspect.ismethod(func) or (
|
|
18
|
+
len(args) > 0 and hasattr(args[0].__class__, func.__name__)
|
|
19
|
+
)
|
|
20
|
+
class_name = args[0].__class__.__name__ if is_method else None # type: ignore
|
|
21
|
+
|
|
22
|
+
# Get the source code of the function
|
|
23
|
+
try:
|
|
24
|
+
source_lines, start_line = inspect.getsourcelines(func)
|
|
25
|
+
except OSError:
|
|
26
|
+
# Handle cases where source might not be available
|
|
27
|
+
print(f"Warning: Could not get source for {func.__name__}")
|
|
28
|
+
return func(*args, **kwargs)
|
|
29
|
+
|
|
30
|
+
def trace(frame, event, arg):
|
|
31
|
+
if event == "line":
|
|
32
|
+
# Get the current line number and code
|
|
33
|
+
line_no = frame.f_lineno
|
|
34
|
+
line = linecache.getline(frame.f_code.co_filename, line_no).strip()
|
|
35
|
+
|
|
36
|
+
# Don't print decorator lines or empty lines
|
|
37
|
+
if line and not line.startswith("@"):
|
|
38
|
+
# Get local variables
|
|
39
|
+
local_vars = frame.f_locals.copy()
|
|
40
|
+
if is_method:
|
|
41
|
+
# Remove 'self' from local variables for clarity
|
|
42
|
+
local_vars.pop("self", None)
|
|
43
|
+
|
|
44
|
+
# Format timestamp
|
|
45
|
+
timestamp = datetime.now().strftime("%H:%M:%S.%f")[:-3]
|
|
46
|
+
|
|
47
|
+
# Create context string (class.method or function)
|
|
48
|
+
context = (
|
|
49
|
+
f"{class_name}.{func.__name__}" if class_name else func.__name__
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
# Print execution information
|
|
53
|
+
print(f"[{timestamp}] {context} line {line_no}: {line}")
|
|
54
|
+
|
|
55
|
+
# Print local variables if they exist and have changed
|
|
56
|
+
if local_vars:
|
|
57
|
+
vars_str = ", ".join(
|
|
58
|
+
f"{k}={repr(v)}" for k, v in local_vars.items()
|
|
59
|
+
)
|
|
60
|
+
print(f" Variables: {vars_str}")
|
|
61
|
+
return trace
|
|
62
|
+
|
|
63
|
+
# Set the trace function
|
|
64
|
+
sys.settrace(trace)
|
|
65
|
+
|
|
66
|
+
# Call the original function
|
|
67
|
+
result = func(*args, **kwargs)
|
|
68
|
+
|
|
69
|
+
# Disable tracing
|
|
70
|
+
sys.settrace(None)
|
|
71
|
+
|
|
72
|
+
return result
|
|
73
|
+
|
|
74
|
+
return wrapper
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: chdb
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.2.0b1
|
|
4
4
|
Summary: chDB is an in-process SQL OLAP Engine powered by ClickHouse
|
|
5
5
|
Home-page: https://github.com/chdb-io/chdb
|
|
6
6
|
Author: auxten
|
|
7
7
|
Author-email: auxten@clickhouse.com
|
|
8
8
|
License: Apache-2.0
|
|
9
|
-
Project-URL:
|
|
9
|
+
Project-URL: Homepage, https://clickhouse.com/chdb
|
|
10
|
+
Project-URL: Documentation, https://clickhouse.com/docs/en/chdb
|
|
11
|
+
Project-URL: Source, https://github.com/chdb-io/chdb
|
|
12
|
+
Project-URL: Download, https://pypi.org/project/chdb/#files
|
|
10
13
|
Project-URL: Twitter, https://twitter.com/chdb_io
|
|
11
14
|
Platform: Mac
|
|
12
15
|
Platform: Linux
|
|
@@ -19,11 +22,14 @@ Classifier: Programming Language :: Python :: 3.8
|
|
|
19
22
|
Classifier: Programming Language :: Python :: 3.9
|
|
20
23
|
Classifier: Programming Language :: Python :: 3.10
|
|
21
24
|
Classifier: Programming Language :: Python :: 3.11
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
26
|
Classifier: Topic :: Database
|
|
23
27
|
Classifier: Topic :: Scientific/Engineering :: Information Analysis
|
|
24
28
|
Requires-Python: >=3.8
|
|
25
29
|
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
26
30
|
License-File: LICENSE.txt
|
|
31
|
+
Requires-Dist: pyarrow>=13.0.0
|
|
32
|
+
Requires-Dist: pandas>=2.0.0
|
|
27
33
|
|
|
28
34
|
<div align="center">
|
|
29
35
|
<a href="https://clickhouse.com/blog/chdb-joins-clickhouse-family">📢 chDB joins the ClickHouse family 🐍+🚀</a>
|
|
@@ -312,8 +318,11 @@ For more examples, see [examples](examples) and [tests](tests).
|
|
|
312
318
|
|
|
313
319
|
- [chDB vs Pandas](https://colab.research.google.com/drive/1FogLujJ_-ds7RGurDrUnK-U0IW8a8Qd0)
|
|
314
320
|
|
|
321
|
+
- [Benchmark on DataFrame: chDB Pandas DuckDB Polars](https://benchmark.clickhouse.com/#eyJzeXN0ZW0iOnsiQWxsb3lEQiI6dHJ1ZSwiQWxsb3lEQiAodHVuZWQpIjp0cnVlLCJBdGhlbmEgKHBhcnRpdGlvbmVkKSI6dHJ1ZSwiQXRoZW5hIChzaW5nbGUpIjp0cnVlLCJBdXJvcmEgZm9yIE15U1FMIjp0cnVlLCJBdXJvcmEgZm9yIFBvc3RncmVTUUwiOnRydWUsIkJ5Q29uaXR5Ijp0cnVlLCJCeXRlSG91c2UiOnRydWUsImNoREIgKERhdGFGcmFtZSkiOnRydWUsImNoREIgKFBhcnF1ZXQsIHBhcnRpdGlvbmVkKSI6dHJ1ZSwiY2hEQiI6dHJ1ZSwiQ2l0dXMiOnRydWUsIkNsaWNrSG91c2UgQ2xvdWQgKGF3cykiOnRydWUsIkNsaWNrSG91c2UgQ2xvdWQgKGF6dXJlKSI6dHJ1ZSwiQ2xpY2tIb3VzZSBDbG91ZCAoZ2NwKSI6dHJ1ZSwiQ2xpY2tIb3VzZSAoZGF0YSBsYWtlLCBwYXJ0aXRpb25lZCkiOnRydWUsIkNsaWNrSG91c2UgKGRhdGEgbGFrZSwgc2luZ2xlKSI6dHJ1ZSwiQ2xpY2tIb3VzZSAoUGFycXVldCwgcGFydGl0aW9uZWQpIjp0cnVlLCJDbGlja0hvdXNlIChQYXJxdWV0LCBzaW5nbGUpIjp0cnVlLCJDbGlja0hvdXNlICh3ZWIpIjp0cnVlLCJDbGlja0hvdXNlIjp0cnVlLCJDbGlja0hvdXNlICh0dW5lZCkiOnRydWUsIkNsaWNrSG91c2UgKHR1bmVkLCBtZW1vcnkpIjp0cnVlLCJDbG91ZGJlcnJ5Ijp0cnVlLCJDcmF0ZURCIjp0cnVlLCJDcnVuY2h5IEJyaWRnZSBmb3IgQW5hbHl0aWNzIChQYXJxdWV0KSI6dHJ1ZSwiRGF0YWJlbmQiOnRydWUsIkRhdGFGdXNpb24gKFBhcnF1ZXQsIHBhcnRpdGlvbmVkKSI6dHJ1ZSwiRGF0YUZ1c2lvbiAoUGFycXVldCwgc2luZ2xlKSI6dHJ1ZSwiQXBhY2hlIERvcmlzIjp0cnVlLCJEcnVpZCI6dHJ1ZSwiRHVja0RCIChEYXRhRnJhbWUpIjp0cnVlLCJEdWNrREIgKFBhcnF1ZXQsIHBhcnRpdGlvbmVkKSI6dHJ1ZSwiRHVja0RCIjp0cnVlLCJFbGFzdGljc2VhcmNoIjp0cnVlLCJFbGFzdGljc2VhcmNoICh0dW5lZCkiOmZhbHNlLCJHbGFyZURCIjp0cnVlLCJHcmVlbnBsdW0iOnRydWUsIkhlYXZ5QUkiOnRydWUsIkh5ZHJhIjp0cnVlLCJJbmZvYnJpZ2h0Ijp0cnVlLCJLaW5ldGljYSI6dHJ1ZSwiTWFyaWFEQiBDb2x1bW5TdG9yZSI6dHJ1ZSwiTWFyaWFEQiI6ZmFsc2UsIk1vbmV0REIiOnRydWUsIk1vbmdvREIiOnRydWUsIk1vdGhlcmR1Y2siOnRydWUsIk15U1FMIChNeUlTQU0pIjp0cnVlLCJNeVNRTCI6dHJ1ZSwiT3hsYSI6dHJ1ZSwiUGFuZGFzIChEYXRhRnJhbWUpIjp0cnVlLCJQYXJhZGVEQiAoUGFycXVldCwgcGFydGl0aW9uZWQpIjp0cnVlLCJQYXJhZGVEQiAoUGFycXVldCwgc2luZ2xlKSI6dHJ1ZSwiUGlub3QiOnRydWUsIlBvbGFycyAoRGF0YUZyYW1lKSI6dHJ1ZSwiUG9zdGdyZVNRTCAodHVuZWQpIjpmYWxzZSwiUG9zdGdyZVNRTCI6dHJ1ZSwiUXVlc3REQiAocGFydGl0aW9uZWQpIjp0cnVlLCJRdWVzdERCIjp0cnVlLCJSZWRzaGlmdCI6dHJ1ZSwiU2luZ2xlU3RvcmUiOnRydWUsIlNub3dmbGFrZSI6dHJ1ZSwiU1FMaXRlIjp0cnVlLCJTdGFyUm9ja3MiOnRydWUsIlRhYmxlc3BhY2UiOnRydWUsIlRlbWJvIE9MQVAgKGNvbHVtbmFyKSI6dHJ1ZSwiVGltZXNjYWxlREIgKGNvbXByZXNzaW9uKSI6dHJ1ZSwiVGltZXNjYWxlREIiOnRydWUsIlVtYnJhIjp0cnVlfSwidHlwZSI6eyJDIjpmYWxzZSwiY29sdW1uLW9yaWVudGVkIjpmYWxzZSwiUG9zdGdyZVNRTCBjb21wYXRpYmxlIjpmYWxzZSwibWFuYWdlZCI6ZmFsc2UsImdjcCI6ZmFsc2UsInN0YXRlbGVzcyI6ZmFsc2UsIkphdmEiOmZhbHNlLCJDKysiOmZhbHNlLCJNeVNRTCBjb21wYXRpYmxlIjpmYWxzZSwicm93LW9yaWVudGVkIjpmYWxzZSwiQ2xpY2tIb3VzZSBkZXJpdmF0aXZlIjpmYWxzZSwiZW1iZWRkZWQiOmZhbHNlLCJzZXJ2ZXJsZXNzIjpmYWxzZSwiZGF0YWZyYW1lIjp0cnVlLCJhd3MiOmZhbHNlLCJhenVyZSI6ZmFsc2UsImFuYWx5dGljYWwiOmZhbHNlLCJSdXN0IjpmYWxzZSwic2VhcmNoIjpmYWxzZSwiZG9jdW1lbnQiOmZhbHNlLCJzb21ld2hhdCBQb3N0Z3JlU1FMIGNvbXBhdGlibGUiOmZhbHNlLCJ0aW1lLXNlcmllcyI6ZmFsc2V9LCJtYWNoaW5lIjp7IjE2IHZDUFUgMTI4R0IiOnRydWUsIjggdkNQVSA2NEdCIjp0cnVlLCJzZXJ2ZXJsZXNzIjp0cnVlLCIxNmFjdSI6dHJ1ZSwiYzZhLjR4bGFyZ2UsIDUwMGdiIGdwMiI6dHJ1ZSwiTCI6dHJ1ZSwiTSI6dHJ1ZSwiUyI6dHJ1ZSwiWFMiOnRydWUsImM2YS5tZXRhbCwgNTAwZ2IgZ3AyIjp0cnVlLCIxOTJHQiI6dHJ1ZSwiMjRHQiI6dHJ1ZSwiMzYwR0IiOnRydWUsIjQ4R0IiOnRydWUsIjcyMEdCIjp0cnVlLCI5NkdCIjp0cnVlLCJkZXYiOnRydWUsIjcwOEdCIjp0cnVlLCJjNW4uNHhsYXJnZSwgNTAwZ2IgZ3AyIjp0cnVlLCJBbmFseXRpY3MtMjU2R0IgKDY0IHZDb3JlcywgMjU2IEdCKSI6dHJ1ZSwiYzUuNHhsYXJnZSwgNTAwZ2IgZ3AyIjp0cnVlLCJjNmEuNHhsYXJnZSwgMTUwMGdiIGdwMiI6dHJ1ZSwiY2xvdWQiOnRydWUsImRjMi44eGxhcmdlIjp0cnVlLCJyYTMuMTZ4bGFyZ2UiOnRydWUsInJhMy40eGxhcmdlIjp0cnVlLCJyYTMueGxwbHVzIjp0cnVlLCJTMiI6dHJ1ZSwiUzI0Ijp0cnVlLCIyWEwiOnRydWUsIjNYTCI6dHJ1ZSwiNFhMIjp0cnVlLCJYTCI6dHJ1ZSwiTDEgLSAxNkNQVSAzMkdCIjp0cnVlLCJjNmEuNHhsYXJnZSwgNTAwZ2IgZ3AzIjp0cnVlfSwiY2x1c3Rlcl9zaXplIjp7IjEiOnRydWUsIjIiOnRydWUsIjQiOnRydWUsIjgiOnRydWUsIjE2Ijp0cnVlLCIzMiI6dHJ1ZSwiNjQiOnRydWUsIjEyOCI6dHJ1ZSwic2VydmVybGVzcyI6dHJ1ZX0sIm1ldHJpYyI6ImhvdCIsInF1ZXJpZXMiOlt0cnVlLHRydWUsdHJ1ZSx0cnVlLHRydWUsdHJ1ZSx0cnVlLHRydWUsdHJ1ZSx0cnVlLHRydWUsdHJ1ZSx0cnVlLHRydWUsdHJ1ZSx0cnVlLHRydWUsdHJ1ZSx0cnVlLHRydWUsdHJ1ZSx0cnVlLHRydWUsdHJ1ZSx0cnVlLHRydWUsdHJ1ZSx0cnVlLHRydWUsdHJ1ZSx0cnVlLHRydWUsdHJ1ZSx0cnVlLHRydWUsdHJ1ZSx0cnVlLHRydWUsdHJ1ZSx0cnVlLHRydWUsdHJ1ZSx0cnVlXX0=)
|
|
322
|
+
|
|
323
|
+
|
|
315
324
|
<div align="center">
|
|
316
|
-
<img src="https://github.com/chdb-io/chdb/raw/main/docs/_static/
|
|
325
|
+
<img src="https://github.com/chdb-io/chdb/raw/main/docs/_static/df_bench.png" width="800">
|
|
317
326
|
</div>
|
|
318
327
|
|
|
319
328
|
|
|
@@ -337,6 +346,10 @@ There are something you can help:
|
|
|
337
346
|
|
|
338
347
|
We welcome bindings for other languages, please refer to [bindings](bindings.md) for more details.
|
|
339
348
|
|
|
349
|
+
## Paper
|
|
350
|
+
|
|
351
|
+
- [ClickHouse - Lightning Fast Analytics for Everyone](https://www.vldb.org/pvldb/vol17/p3731-schulze.pdf)
|
|
352
|
+
|
|
340
353
|
## License
|
|
341
354
|
Apache 2.0, see [LICENSE](LICENSE.txt) for more information.
|
|
342
355
|
|
|
@@ -1,25 +1,28 @@
|
|
|
1
|
-
chdb/__init__.py,sha256=
|
|
1
|
+
chdb/__init__.py,sha256=li1sCjhLx7HmRBbWtekahee1iQtJl5p69oGYIaVVplk,2994
|
|
2
2
|
chdb/__main__.py,sha256=xNNtDY38d973YM5dlxiIazcqqKhXJSpNb7JflyyrXGE,1185
|
|
3
|
-
chdb/_chdb.cpython-311-darwin.so,sha256
|
|
3
|
+
chdb/_chdb.cpython-311-darwin.so,sha256=yqHmUmgmvIEPTrJqDZTItRPACVX-0vspgwB30TB8amk,421948804
|
|
4
4
|
chdb/rwabc.py,sha256=tbiwCrXirfrfx46wCJxS64yvFe6pVWIPGdSuvrAL5Ys,2102
|
|
5
5
|
chdb/dataframe/__init__.py,sha256=1_mrZZiJwqBTnH_P8_FCbbYXIWWY5sxnaFpe3-tDLF4,680
|
|
6
6
|
chdb/dataframe/query.py,sha256=ggvE8A5vtabFg9gSTp99S7LCrnIEwbWtb-PtJVT8Ct0,12759
|
|
7
7
|
chdb/dbapi/__init__.py,sha256=aaNhxXNBC1ZkFr260cbGR8msOinTp0VoNTT_j8AXGUc,2205
|
|
8
|
-
chdb/dbapi/connections.py,sha256=
|
|
8
|
+
chdb/dbapi/connections.py,sha256=4RBO0h-B149xEicE8cXSSJl9wpXa4FQMY_4SghgEvCw,2762
|
|
9
9
|
chdb/dbapi/converters.py,sha256=qS9k0Kzo_vDQxnFtsJ_3pLjlTrBK09SfdWcXdxzIrtI,7413
|
|
10
|
-
chdb/dbapi/cursors.py,sha256=
|
|
10
|
+
chdb/dbapi/cursors.py,sha256=OXF36raoyI3MIC5SCQ5IvnCtbOnppga4Q1IKOt2EIsk,7920
|
|
11
11
|
chdb/dbapi/err.py,sha256=kUI9-A8LNqBoMoo4jh2NFsLCOLoPEwh9YIuz_qMoLoM,2017
|
|
12
12
|
chdb/dbapi/times.py,sha256=_qXgDaYwsHntvpIKSKXp1rrYIgtq6Z9pLyLnO2XNoL0,360
|
|
13
13
|
chdb/dbapi/constants/FIELD_TYPE.py,sha256=ytFzgAnGmb9hvdsBlnK68qdZv_a6jYFIXT6VSAb60z8,370
|
|
14
14
|
chdb/dbapi/constants/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
15
15
|
chdb/session/__init__.py,sha256=fCUROZ5L1-92o2lcASiWJpFu-80-kDoSrNfouLEmLg8,50
|
|
16
16
|
chdb/session/state.py,sha256=Hc9lJGLZ97Un7ElBbeWeCZoc9p_m1k_ojQbzJMPBPKg,1341
|
|
17
|
+
chdb/state/__init__.py,sha256=RVUIWDqDi7gte4Os7Mz1wPXFyFpdHT_p1klJC7QtluI,55
|
|
18
|
+
chdb/state/sqlitelike.py,sha256=RSVJW5M3hH_TUBcXiH7zna21WTSGbqkOccyEiFFd8PI,4425
|
|
17
19
|
chdb/udf/__init__.py,sha256=qSMaPEre7w1pYz8uJ-iZtuu8wYOUNRcI_8UNuaOymGE,80
|
|
18
20
|
chdb/udf/udf.py,sha256=z0A1RmyZrx55bykpvvS-LpVt1lMrQOexjvU5zxCdCSA,3935
|
|
19
|
-
chdb/utils/__init__.py,sha256=
|
|
21
|
+
chdb/utils/__init__.py,sha256=tXRcwBRGW2YQNBZWV4Mitw5QlCu_qlSRCjllw15XHbs,171
|
|
22
|
+
chdb/utils/trace.py,sha256=W-pvDoKlnzq6H_7FiWjr5_teN40UNE4E5--zbUrjOIc,2511
|
|
20
23
|
chdb/utils/types.py,sha256=MGLFIjoDvu7Uc2Wy8EDY60jjue66HmMPxbhrujjrZxQ,7530
|
|
21
|
-
chdb-2.
|
|
22
|
-
chdb-2.
|
|
23
|
-
chdb-2.
|
|
24
|
-
chdb-2.
|
|
25
|
-
chdb-2.
|
|
24
|
+
chdb-2.2.0b1.dist-info/LICENSE.txt,sha256=isYVtNCO5910aj6e9bJJ6kQceivkLqsMlFSNYwzGGKI,11366
|
|
25
|
+
chdb-2.2.0b1.dist-info/METADATA,sha256=cjvQmdOiS1pll_E2ohhXF2DVb7wdbVndY00xLuCnVi8,19444
|
|
26
|
+
chdb-2.2.0b1.dist-info/WHEEL,sha256=VWvw4oRwn4xDjG7Gswu4E1gGHduxi4uHa_PavRsTDGU,111
|
|
27
|
+
chdb-2.2.0b1.dist-info/top_level.txt,sha256=se0Jj0A2-ijfMW51hIjiuNyDJPqy5xJU1G8a_IEdllI,11
|
|
28
|
+
chdb-2.2.0b1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|