MindsDB 25.8.3.0__py3-none-any.whl → 25.9.1.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.
Potentially problematic release.
This version of MindsDB might be problematic. Click here for more details.
- mindsdb/__about__.py +1 -1
- mindsdb/__main__.py +2 -44
- mindsdb/api/a2a/__init__.py +52 -0
- mindsdb/api/a2a/agent.py +11 -12
- mindsdb/api/a2a/common/server/server.py +17 -36
- mindsdb/api/a2a/common/server/task_manager.py +14 -28
- mindsdb/api/a2a/task_manager.py +20 -21
- mindsdb/api/a2a/utils.py +1 -1
- mindsdb/api/common/middleware.py +106 -0
- mindsdb/api/http/initialize.py +13 -15
- mindsdb/api/http/namespaces/auth.py +6 -14
- mindsdb/api/http/namespaces/config.py +0 -2
- mindsdb/api/http/namespaces/default.py +74 -106
- mindsdb/api/http/start.py +25 -44
- mindsdb/api/litellm/start.py +11 -10
- mindsdb/api/mcp/__init__.py +165 -0
- mindsdb/api/mysql/mysql_proxy/mysql_proxy.py +33 -64
- mindsdb/api/postgres/postgres_proxy/postgres_proxy.py +86 -85
- mindsdb/integrations/handlers/crate_handler/crate_handler.py +3 -7
- mindsdb/integrations/handlers/derby_handler/derby_handler.py +32 -34
- mindsdb/integrations/handlers/documentdb_handler/requirements.txt +1 -0
- mindsdb/integrations/handlers/dummy_data_handler/dummy_data_handler.py +12 -13
- mindsdb/integrations/handlers/google_books_handler/google_books_handler.py +45 -44
- mindsdb/integrations/handlers/google_calendar_handler/google_calendar_handler.py +101 -95
- mindsdb/integrations/handlers/google_content_shopping_handler/google_content_shopping_handler.py +129 -129
- mindsdb/integrations/handlers/google_fit_handler/google_fit_handler.py +59 -43
- mindsdb/integrations/handlers/google_search_handler/google_search_handler.py +38 -39
- mindsdb/integrations/handlers/informix_handler/informix_handler.py +5 -18
- mindsdb/integrations/handlers/maxdb_handler/maxdb_handler.py +22 -28
- mindsdb/integrations/handlers/monetdb_handler/monetdb_handler.py +3 -7
- mindsdb/integrations/handlers/mongodb_handler/mongodb_handler.py +53 -67
- mindsdb/integrations/handlers/mongodb_handler/requirements.txt +1 -0
- mindsdb/{api/mongo/utilities → integrations/handlers/mongodb_handler/utils}/mongodb_ast.py +43 -68
- mindsdb/{api/mongo/utilities → integrations/handlers/mongodb_handler/utils}/mongodb_parser.py +17 -25
- mindsdb/{api/mongo/utilities → integrations/handlers/mongodb_handler/utils}/mongodb_query.py +10 -16
- mindsdb/integrations/handlers/mongodb_handler/utils/mongodb_render.py +43 -69
- mindsdb/integrations/libs/base.py +1 -1
- mindsdb/interfaces/agents/constants.py +1 -0
- mindsdb/interfaces/knowledge_base/controller.py +3 -1
- mindsdb/utilities/config.py +3 -155
- mindsdb/utilities/log.py +0 -25
- mindsdb/utilities/starters.py +0 -39
- {mindsdb-25.8.3.0.dist-info → mindsdb-25.9.1.0.dist-info}/METADATA +263 -261
- {mindsdb-25.8.3.0.dist-info → mindsdb-25.9.1.0.dist-info}/RECORD +47 -91
- mindsdb/api/a2a/__main__.py +0 -144
- mindsdb/api/a2a/run_a2a.py +0 -86
- mindsdb/api/common/check_auth.py +0 -42
- mindsdb/api/http/gunicorn_wrapper.py +0 -17
- mindsdb/api/mcp/start.py +0 -205
- mindsdb/api/mongo/__init__.py +0 -0
- mindsdb/api/mongo/classes/__init__.py +0 -5
- mindsdb/api/mongo/classes/query_sql.py +0 -19
- mindsdb/api/mongo/classes/responder.py +0 -45
- mindsdb/api/mongo/classes/responder_collection.py +0 -34
- mindsdb/api/mongo/classes/scram.py +0 -86
- mindsdb/api/mongo/classes/session.py +0 -23
- mindsdb/api/mongo/functions/__init__.py +0 -19
- mindsdb/api/mongo/responders/__init__.py +0 -73
- mindsdb/api/mongo/responders/add_shard.py +0 -13
- mindsdb/api/mongo/responders/aggregate.py +0 -90
- mindsdb/api/mongo/responders/buildinfo.py +0 -17
- mindsdb/api/mongo/responders/coll_stats.py +0 -63
- mindsdb/api/mongo/responders/company_id.py +0 -25
- mindsdb/api/mongo/responders/connection_status.py +0 -22
- mindsdb/api/mongo/responders/count.py +0 -21
- mindsdb/api/mongo/responders/db_stats.py +0 -32
- mindsdb/api/mongo/responders/delete.py +0 -105
- mindsdb/api/mongo/responders/describe.py +0 -23
- mindsdb/api/mongo/responders/end_sessions.py +0 -13
- mindsdb/api/mongo/responders/find.py +0 -175
- mindsdb/api/mongo/responders/get_cmd_line_opts.py +0 -18
- mindsdb/api/mongo/responders/get_free_monitoring_status.py +0 -14
- mindsdb/api/mongo/responders/get_parameter.py +0 -23
- mindsdb/api/mongo/responders/getlog.py +0 -14
- mindsdb/api/mongo/responders/host_info.py +0 -28
- mindsdb/api/mongo/responders/insert.py +0 -270
- mindsdb/api/mongo/responders/is_master.py +0 -20
- mindsdb/api/mongo/responders/is_master_lower.py +0 -13
- mindsdb/api/mongo/responders/list_collections.py +0 -55
- mindsdb/api/mongo/responders/list_databases.py +0 -37
- mindsdb/api/mongo/responders/list_indexes.py +0 -22
- mindsdb/api/mongo/responders/ping.py +0 -13
- mindsdb/api/mongo/responders/recv_chunk_start.py +0 -13
- mindsdb/api/mongo/responders/replsetgetstatus.py +0 -13
- mindsdb/api/mongo/responders/sasl_continue.py +0 -34
- mindsdb/api/mongo/responders/sasl_start.py +0 -33
- mindsdb/api/mongo/responders/update_range_deletions.py +0 -12
- mindsdb/api/mongo/responders/whatsmyuri.py +0 -18
- mindsdb/api/mongo/server.py +0 -388
- mindsdb/api/mongo/start.py +0 -15
- mindsdb/api/mongo/utilities/__init__.py +0 -0
- {mindsdb-25.8.3.0.dist-info → mindsdb-25.9.1.0.dist-info}/WHEEL +0 -0
- {mindsdb-25.8.3.0.dist-info → mindsdb-25.9.1.0.dist-info}/licenses/LICENSE +0 -0
- {mindsdb-25.8.3.0.dist-info → mindsdb-25.9.1.0.dist-info}/top_level.txt +0 -0
|
@@ -14,17 +14,38 @@ from mindsdb.api.executor.controllers import SessionController
|
|
|
14
14
|
from mindsdb.api.postgres.postgres_proxy.executor import Executor
|
|
15
15
|
from mindsdb.api.mysql.mysql_proxy.libs.constants.mysql import CHARSET_NUMBERS
|
|
16
16
|
from mindsdb.api.executor.data_types.response_type import RESPONSE_TYPE
|
|
17
|
-
from mindsdb.api.common.
|
|
17
|
+
from mindsdb.api.common.middleware import check_auth
|
|
18
18
|
from mindsdb.api.mysql.mysql_proxy.mysql_proxy import SQLAnswer
|
|
19
19
|
from mindsdb.api.postgres.postgres_proxy.postgres_packets.errors import POSTGRES_SYNTAX_ERROR_CODE
|
|
20
20
|
from mindsdb.api.postgres.postgres_proxy.postgres_packets.postgres_fields import GenericField, PostgresField
|
|
21
|
-
from mindsdb.api.postgres.postgres_proxy.postgres_packets.postgres_message_formats import
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
from mindsdb.api.postgres.postgres_proxy.postgres_packets.postgres_message_formats import (
|
|
22
|
+
Terminate,
|
|
23
|
+
Query,
|
|
24
|
+
AuthenticationClearTextPassword,
|
|
25
|
+
AuthenticationOk,
|
|
26
|
+
RowDescriptions,
|
|
27
|
+
DataRow,
|
|
28
|
+
CommandComplete,
|
|
29
|
+
ReadyForQuery,
|
|
30
|
+
ConnectionFailure,
|
|
31
|
+
ParameterStatus,
|
|
32
|
+
Error,
|
|
33
|
+
Execute,
|
|
34
|
+
Bind,
|
|
35
|
+
Parse,
|
|
36
|
+
Sync,
|
|
37
|
+
ParseComplete,
|
|
38
|
+
InvalidSQLStatementName,
|
|
39
|
+
BindComplete,
|
|
40
|
+
Describe,
|
|
41
|
+
DataException,
|
|
42
|
+
ParameterDescription,
|
|
43
|
+
)
|
|
25
44
|
from mindsdb.api.postgres.postgres_proxy.postgres_packets.postgres_message import PostgresMessage
|
|
26
|
-
from mindsdb.api.postgres.postgres_proxy.postgres_packets.postgres_packets import
|
|
27
|
-
|
|
45
|
+
from mindsdb.api.postgres.postgres_proxy.postgres_packets.postgres_packets import (
|
|
46
|
+
PostgresPacketReader,
|
|
47
|
+
PostgresPacketBuilder,
|
|
48
|
+
)
|
|
28
49
|
from mindsdb.api.postgres.postgres_proxy.utilities import strip_null_byte
|
|
29
50
|
from mindsdb.utilities.config import config
|
|
30
51
|
from mindsdb.utilities.context import context as ctx
|
|
@@ -38,8 +59,8 @@ class PostgresProxyHandler(socketserver.StreamRequestHandler):
|
|
|
38
59
|
|
|
39
60
|
def __init__(self, request, client_address, server):
|
|
40
61
|
self.logger = log.getLogger(__name__)
|
|
41
|
-
self.charset =
|
|
42
|
-
self.charset_text_type = CHARSET_NUMBERS[
|
|
62
|
+
self.charset = "utf8"
|
|
63
|
+
self.charset_text_type = CHARSET_NUMBERS["utf8_general_ci"]
|
|
43
64
|
self.session = None
|
|
44
65
|
self.client_capabilities = None
|
|
45
66
|
self.user_parameters = None
|
|
@@ -48,17 +69,16 @@ class PostgresProxyHandler(socketserver.StreamRequestHandler):
|
|
|
48
69
|
self.is_cloud = False
|
|
49
70
|
self.named_portals = {}
|
|
50
71
|
self.unnamed_portal = None
|
|
51
|
-
self.transaction_status = b
|
|
72
|
+
self.transaction_status = b"I" # I: Idle, T: Transaction Block, E: Failed Transaction Block
|
|
52
73
|
super().__init__(request, client_address, server)
|
|
53
74
|
|
|
54
75
|
def handle(self) -> None:
|
|
55
|
-
|
|
56
76
|
ctx.set_default()
|
|
57
77
|
self.init_session()
|
|
58
|
-
self.logger.debug(
|
|
78
|
+
self.logger.debug("handle new incoming connection")
|
|
59
79
|
cloud_connection = self.is_cloud_connection()
|
|
60
80
|
if cloud_connection["is_cloud"]:
|
|
61
|
-
ctx.company_id = cloud_connection.get(
|
|
81
|
+
ctx.company_id = cloud_connection.get("company_id")
|
|
62
82
|
self.is_cloud = True
|
|
63
83
|
|
|
64
84
|
self.message_map: Dict[Type[PostgresMessage], Callable[[Any], bool]] = {
|
|
@@ -68,7 +88,7 @@ class PostgresProxyHandler(socketserver.StreamRequestHandler):
|
|
|
68
88
|
Bind: self.bind,
|
|
69
89
|
Execute: self.execute,
|
|
70
90
|
Describe: self.describe,
|
|
71
|
-
Sync: self.sync
|
|
91
|
+
Sync: self.sync,
|
|
72
92
|
}
|
|
73
93
|
self.client_buffer = PostgresPacketReader(self.rfile)
|
|
74
94
|
if self.is_cloud:
|
|
@@ -83,69 +103,59 @@ class PostgresProxyHandler(socketserver.StreamRequestHandler):
|
|
|
83
103
|
self.main_loop()
|
|
84
104
|
|
|
85
105
|
def is_cloud_connection(self):
|
|
86
|
-
"""
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
is_cloud = config.get(
|
|
96
|
-
|
|
97
|
-
if sys.platform !=
|
|
98
|
-
return {
|
|
99
|
-
'is_cloud': False
|
|
100
|
-
}
|
|
106
|
+
"""Determine source of connection. Must be call before handshake.
|
|
107
|
+
Idea based on: real mysql connection does not send anything before server handshake, so
|
|
108
|
+
socket should be in 'out' state. In opposite, clout connection sends '0000' right after
|
|
109
|
+
connection. '0000' selected because in real mysql connection it should be length of package,
|
|
110
|
+
and it can not be 0.
|
|
111
|
+
|
|
112
|
+
Copied from mysql_proxy
|
|
113
|
+
TODO: Extract method into common
|
|
114
|
+
"""
|
|
115
|
+
is_cloud = config.get("cloud", False)
|
|
116
|
+
|
|
117
|
+
if sys.platform != "linux" or is_cloud is False:
|
|
118
|
+
return {"is_cloud": False}
|
|
101
119
|
|
|
102
120
|
read_poller = select.poll()
|
|
103
121
|
read_poller.register(self.request, select.POLLIN)
|
|
104
122
|
events = read_poller.poll(30)
|
|
105
123
|
|
|
106
124
|
if len(events) == 0:
|
|
107
|
-
return {
|
|
108
|
-
'is_cloud': False
|
|
109
|
-
}
|
|
125
|
+
return {"is_cloud": False}
|
|
110
126
|
|
|
111
127
|
first_byte = self.request.recv(4, socket.MSG_PEEK)
|
|
112
|
-
if first_byte == b
|
|
128
|
+
if first_byte == b"\x00\x00\x00\x00":
|
|
113
129
|
self.request.recv(4)
|
|
114
130
|
client_capabilities = self.request.recv(8)
|
|
115
|
-
client_capabilities = struct.unpack(
|
|
131
|
+
client_capabilities = struct.unpack("L", client_capabilities)[0]
|
|
116
132
|
|
|
117
133
|
company_id = self.request.recv(4)
|
|
118
|
-
company_id = struct.unpack(
|
|
134
|
+
company_id = struct.unpack("I", company_id)[0]
|
|
119
135
|
|
|
120
136
|
user_class = self.request.recv(1)
|
|
121
|
-
user_class = struct.unpack(
|
|
137
|
+
user_class = struct.unpack("B", user_class)[0]
|
|
122
138
|
|
|
123
139
|
database_name_len = self.request.recv(2)
|
|
124
|
-
database_name_len = struct.unpack(
|
|
140
|
+
database_name_len = struct.unpack("H", database_name_len)[0]
|
|
125
141
|
|
|
126
|
-
database_name =
|
|
142
|
+
database_name = ""
|
|
127
143
|
if database_name_len > 0:
|
|
128
144
|
database_name = self.request.recv(database_name_len).decode()
|
|
129
145
|
|
|
130
146
|
return {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
147
|
+
"is_cloud": True,
|
|
148
|
+
"client_capabilities": client_capabilities,
|
|
149
|
+
"company_id": company_id,
|
|
150
|
+
"user_class": user_class,
|
|
151
|
+
"database": database_name,
|
|
136
152
|
}
|
|
137
153
|
|
|
138
|
-
return {
|
|
139
|
-
'is_cloud': False
|
|
140
|
-
}
|
|
154
|
+
return {"is_cloud": False}
|
|
141
155
|
|
|
142
156
|
def parse(self, message: Parse):
|
|
143
157
|
self.logger.info("Postgres_Proxy: Parsing")
|
|
144
|
-
executor = Executor(
|
|
145
|
-
session=self.session,
|
|
146
|
-
proxy_server=self,
|
|
147
|
-
charset=self.charset
|
|
148
|
-
)
|
|
158
|
+
executor = Executor(session=self.session, proxy_server=self, charset=self.charset)
|
|
149
159
|
# TODO: Remove comment if unneeded ot use session since we're storing in this proxy class per session anyway
|
|
150
160
|
# stmt_id = self.session.register_stmt(executor)
|
|
151
161
|
executor.stmt_prepare(sql=message.query)
|
|
@@ -179,7 +189,7 @@ class PostgresProxyHandler(socketserver.StreamRequestHandler):
|
|
|
179
189
|
|
|
180
190
|
def describe(self, message: Describe):
|
|
181
191
|
self.logger.info("Postgres_Proxy: Describing")
|
|
182
|
-
if message.describe_type == b
|
|
192
|
+
if message.describe_type == b"P":
|
|
183
193
|
if message.name:
|
|
184
194
|
describing = self.named_portals[message.name]
|
|
185
195
|
elif self.unnamed_statement:
|
|
@@ -187,7 +197,7 @@ class PostgresProxyHandler(socketserver.StreamRequestHandler):
|
|
|
187
197
|
else:
|
|
188
198
|
self.send(InvalidSQLStatementName("Portal Does not Exist"))
|
|
189
199
|
return True
|
|
190
|
-
elif message.describe_type == b
|
|
200
|
+
elif message.describe_type == b"S":
|
|
191
201
|
if message.name:
|
|
192
202
|
describing = self.named_statements[message.name]
|
|
193
203
|
elif self.unnamed_statement:
|
|
@@ -227,8 +237,7 @@ class PostgresProxyHandler(socketserver.StreamRequestHandler):
|
|
|
227
237
|
return True
|
|
228
238
|
|
|
229
239
|
def init_session(self):
|
|
230
|
-
self.logger.info(
|
|
231
|
-
ip=self.client_address[0], port=self.client_address[1]))
|
|
240
|
+
self.logger.info("New connection [{ip}:{port}]".format(ip=self.client_address[0], port=self.client_address[1]))
|
|
232
241
|
self.logger.debug(self.__dict__)
|
|
233
242
|
|
|
234
243
|
if self.server.connection_id >= 65025:
|
|
@@ -236,9 +245,9 @@ class PostgresProxyHandler(socketserver.StreamRequestHandler):
|
|
|
236
245
|
self.server.connection_id += 1
|
|
237
246
|
self.connection_id = self.server.connection_id
|
|
238
247
|
self.session = SessionController()
|
|
239
|
-
self.session.database = config.get(
|
|
248
|
+
self.session.database = config.get("default_project")
|
|
240
249
|
|
|
241
|
-
if hasattr(self.server,
|
|
250
|
+
if hasattr(self.server, "salt") and isinstance(self.server.salt, str):
|
|
242
251
|
self.salt = self.server.salt
|
|
243
252
|
else:
|
|
244
253
|
self.salt = base64.b64encode(os.urandom(15)).decode()
|
|
@@ -247,14 +256,10 @@ class PostgresProxyHandler(socketserver.StreamRequestHandler):
|
|
|
247
256
|
|
|
248
257
|
self.current_transaction = None
|
|
249
258
|
|
|
250
|
-
self.logger.debug(
|
|
259
|
+
self.logger.debug("session salt: {salt}".format(salt=self.salt))
|
|
251
260
|
|
|
252
261
|
def process_query(self, sql):
|
|
253
|
-
executor = Executor(
|
|
254
|
-
session=self.session,
|
|
255
|
-
proxy_server=self,
|
|
256
|
-
charset=self.charset
|
|
257
|
-
)
|
|
262
|
+
executor = Executor(session=self.session, proxy_server=self, charset=self.charset)
|
|
258
263
|
self.logger.debug("processing query\n%s", sql)
|
|
259
264
|
try:
|
|
260
265
|
executor.query_execute(sql)
|
|
@@ -262,7 +267,7 @@ class PostgresProxyHandler(socketserver.StreamRequestHandler):
|
|
|
262
267
|
return SQLAnswer(
|
|
263
268
|
resp_type=RESPONSE_TYPE.ERROR,
|
|
264
269
|
error_message=str(e).encode(self.get_encoding()),
|
|
265
|
-
error_code=POSTGRES_SYNTAX_ERROR_CODE.encode(self.get_encoding())
|
|
270
|
+
error_code=POSTGRES_SYNTAX_ERROR_CODE.encode(self.get_encoding()),
|
|
266
271
|
)
|
|
267
272
|
return self.return_executor_data(executor)
|
|
268
273
|
|
|
@@ -277,7 +282,7 @@ class PostgresProxyHandler(socketserver.StreamRequestHandler):
|
|
|
277
282
|
resp_type=RESPONSE_TYPE.TABLE,
|
|
278
283
|
state_track=executor.state_track,
|
|
279
284
|
result_set=executor.data,
|
|
280
|
-
status=executor.server_status
|
|
285
|
+
status=executor.server_status,
|
|
281
286
|
)
|
|
282
287
|
return resp
|
|
283
288
|
|
|
@@ -295,7 +300,7 @@ class PostgresProxyHandler(socketserver.StreamRequestHandler):
|
|
|
295
300
|
self.client_buffer.read_verify_ssl_request()
|
|
296
301
|
# self.send(NoticeResponse()) -- Should Probably not send. Looks in protocol manual to be sent for warning
|
|
297
302
|
self.logger.debug("Sending No to SSL Request")
|
|
298
|
-
PostgresPacketBuilder().write_char(b
|
|
303
|
+
PostgresPacketBuilder().write_char(b"N", self.wfile)
|
|
299
304
|
self.user_parameters = self.client_buffer.read_startup_message()
|
|
300
305
|
|
|
301
306
|
def authenticate(self, ask_for_password=False):
|
|
@@ -303,12 +308,12 @@ class PostgresProxyHandler(socketserver.StreamRequestHandler):
|
|
|
303
308
|
self.send(AuthenticationClearTextPassword())
|
|
304
309
|
password = self.client_buffer.read_authentication(encoding=self.charset)
|
|
305
310
|
else:
|
|
306
|
-
password =
|
|
307
|
-
username = self.user_parameters[b
|
|
311
|
+
password = ""
|
|
312
|
+
username = self.user_parameters[b"user"].decode(encoding=self.charset)
|
|
308
313
|
auth_data = self.server.check_auth(username, password, scramble_func, self.salt, ctx.company_id)
|
|
309
|
-
if auth_data[
|
|
314
|
+
if auth_data["success"]:
|
|
310
315
|
self.logger.debug("Authentication succeeded")
|
|
311
|
-
self.session.username = auth_data[
|
|
316
|
+
self.session.username = auth_data["username"]
|
|
312
317
|
self.session.auth = True
|
|
313
318
|
self.send(AuthenticationOk())
|
|
314
319
|
return True
|
|
@@ -329,9 +334,9 @@ class PostgresProxyHandler(socketserver.StreamRequestHandler):
|
|
|
329
334
|
def return_ok(self, sql, rows: int = 0):
|
|
330
335
|
command = self.get_command(sql)
|
|
331
336
|
if command == "BEGIN":
|
|
332
|
-
self.transaction_status = b
|
|
337
|
+
self.transaction_status = b"T"
|
|
333
338
|
if command == "COMMIT":
|
|
334
|
-
self.transaction_status = b
|
|
339
|
+
self.transaction_status = b"I"
|
|
335
340
|
if command == "CREATE":
|
|
336
341
|
command = "SELECT"
|
|
337
342
|
if command in ("INSERT", "DELETE", "UPDATE", "SELECT", "MOVE", "FETCH", "COPY"):
|
|
@@ -347,7 +352,7 @@ class PostgresProxyHandler(socketserver.StreamRequestHandler):
|
|
|
347
352
|
if type(sql) == bytes:
|
|
348
353
|
encoding = self.get_encoding()
|
|
349
354
|
sql: str = sql.decode(encoding)
|
|
350
|
-
return strip_null_byte(sql).strip(
|
|
355
|
+
return strip_null_byte(sql).strip(";")
|
|
351
356
|
|
|
352
357
|
def return_table(self, sql_answer: SQLAnswer, row_descs=True):
|
|
353
358
|
fields = self.to_postgres_fields(sql_answer.result_set.columns)
|
|
@@ -356,7 +361,7 @@ class PostgresProxyHandler(socketserver.StreamRequestHandler):
|
|
|
356
361
|
self.send(RowDescriptions(fields=fields))
|
|
357
362
|
self.send(DataRow(rows=rows))
|
|
358
363
|
encoding = self.get_encoding()
|
|
359
|
-
tag = (
|
|
364
|
+
tag = ("SELECT %s" % str(len(rows))).encode(encoding)
|
|
360
365
|
self.send(CommandComplete(tag=tag))
|
|
361
366
|
return True
|
|
362
367
|
|
|
@@ -389,11 +394,7 @@ class PostgresProxyHandler(socketserver.StreamRequestHandler):
|
|
|
389
394
|
fields = []
|
|
390
395
|
i = 0
|
|
391
396
|
for column in columns:
|
|
392
|
-
fields.append(GenericField(
|
|
393
|
-
name=column['name'],
|
|
394
|
-
object_id=column['type'].value,
|
|
395
|
-
column_id=i
|
|
396
|
-
))
|
|
397
|
+
fields.append(GenericField(name=column["name"], object_id=column["type"].value, column_id=i))
|
|
397
398
|
i += 1
|
|
398
399
|
return fields
|
|
399
400
|
|
|
@@ -410,12 +411,12 @@ class PostgresProxyHandler(socketserver.StreamRequestHandler):
|
|
|
410
411
|
column = json.dumps(column)
|
|
411
412
|
if isinstance(column, datetime.date) or isinstance(column, datetime.datetime):
|
|
412
413
|
try:
|
|
413
|
-
column = datetime.datetime.strftime(column,
|
|
414
|
+
column = datetime.datetime.strftime(column, "%Y-%m-%d")
|
|
414
415
|
except ValueError:
|
|
415
416
|
try:
|
|
416
|
-
column = datetime.datetime.strftime(column,
|
|
417
|
+
column = datetime.datetime.strftime(column, "%Y-%m-%dT%H:%M:%S")
|
|
417
418
|
except ValueError:
|
|
418
|
-
column = datetime.datetime.strptime(column,
|
|
419
|
+
column = datetime.datetime.strptime(column, "%Y-%m-%dT%H:%M:%S.%f")
|
|
419
420
|
if isinstance(column, bool):
|
|
420
421
|
if column:
|
|
421
422
|
column = "true"
|
|
@@ -427,7 +428,7 @@ class PostgresProxyHandler(socketserver.StreamRequestHandler):
|
|
|
427
428
|
|
|
428
429
|
def send_initial_data(self):
|
|
429
430
|
server_encoding = self.charset.encode(self.charset)
|
|
430
|
-
client_encoding = self.user_parameters.get(b
|
|
431
|
+
client_encoding = self.user_parameters.get(b"client_encoding", server_encoding)
|
|
431
432
|
# TODO: Send BackendKeyData Here (55.2.1)
|
|
432
433
|
self.send(ParameterStatus(name=b"server_version", value=b"14.6"))
|
|
433
434
|
self.send(ParameterStatus(name=b"server_encoding", value=server_encoding))
|
|
@@ -459,8 +460,8 @@ class PostgresProxyHandler(socketserver.StreamRequestHandler):
|
|
|
459
460
|
|
|
460
461
|
@staticmethod
|
|
461
462
|
def startProxy():
|
|
462
|
-
host = config[
|
|
463
|
-
port = int(config[
|
|
463
|
+
host = config["api"]["postgres"]["host"]
|
|
464
|
+
port = int(config["api"]["postgres"]["port"])
|
|
464
465
|
server = TcpServer((host, port), PostgresProxyHandler)
|
|
465
466
|
server.connection_id = 0
|
|
466
467
|
server.mindsdb_config = config
|
|
@@ -56,9 +56,7 @@ class CrateHandler(DatabaseHandler):
|
|
|
56
56
|
if self.is_connected:
|
|
57
57
|
return self.connection
|
|
58
58
|
|
|
59
|
-
is_local = (
|
|
60
|
-
self.host.startswith("localhost") or self.host == "127.0.0.1"
|
|
61
|
-
)
|
|
59
|
+
is_local = self.host.startswith("localhost") or self.host == "127.0.0.1"
|
|
62
60
|
|
|
63
61
|
try:
|
|
64
62
|
# Build URL based on connection type
|
|
@@ -121,7 +119,7 @@ class CrateHandler(DatabaseHandler):
|
|
|
121
119
|
"""Receive raw query and act upon it somehow.
|
|
122
120
|
Args:
|
|
123
121
|
query (Any): query in native format (str for sql databases,
|
|
124
|
-
|
|
122
|
+
etc)
|
|
125
123
|
Returns:
|
|
126
124
|
HandlerResponse
|
|
127
125
|
"""
|
|
@@ -136,9 +134,7 @@ class CrateHandler(DatabaseHandler):
|
|
|
136
134
|
result = cur.fetchall()
|
|
137
135
|
response = Response(
|
|
138
136
|
RESPONSE_TYPE.TABLE,
|
|
139
|
-
data_frame=pd.DataFrame(
|
|
140
|
-
result, columns=[x[0] for x in cur.description]
|
|
141
|
-
),
|
|
137
|
+
data_frame=pd.DataFrame(result, columns=[x[0] for x in cur.description]),
|
|
142
138
|
)
|
|
143
139
|
else:
|
|
144
140
|
response = Response(RESPONSE_TYPE.OK)
|
|
@@ -6,7 +6,7 @@ from mindsdb_sql_parser import parse_sql
|
|
|
6
6
|
from mindsdb.integrations.libs.response import (
|
|
7
7
|
HandlerStatusResponse as StatusResponse,
|
|
8
8
|
HandlerResponse as Response,
|
|
9
|
-
RESPONSE_TYPE
|
|
9
|
+
RESPONSE_TYPE,
|
|
10
10
|
)
|
|
11
11
|
import pandas as pd
|
|
12
12
|
import jaydebeapi as jdbcconnector
|
|
@@ -15,11 +15,10 @@ logger = log.getLogger(__name__)
|
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
class DerbyHandler(DatabaseHandler):
|
|
18
|
-
|
|
19
|
-
name = 'derby'
|
|
18
|
+
name = "derby"
|
|
20
19
|
|
|
21
20
|
def __init__(self, name: str, connection_data: Optional[dict], **kwargs):
|
|
22
|
-
"""
|
|
21
|
+
"""Initialize the handler
|
|
23
22
|
Args:
|
|
24
23
|
name (str): name of particular handler instance
|
|
25
24
|
connection_data (dict): parameters for connecting to the database
|
|
@@ -29,16 +28,16 @@ class DerbyHandler(DatabaseHandler):
|
|
|
29
28
|
|
|
30
29
|
self.kwargs = kwargs
|
|
31
30
|
self.parser = parse_sql
|
|
32
|
-
self.database = connection_data[
|
|
31
|
+
self.database = connection_data["database"]
|
|
33
32
|
self.connection_config = connection_data
|
|
34
|
-
self.host = connection_data[
|
|
35
|
-
self.port = connection_data[
|
|
36
|
-
self.schema =
|
|
33
|
+
self.host = connection_data["host"]
|
|
34
|
+
self.port = connection_data["port"]
|
|
35
|
+
self.schema = "APP"
|
|
37
36
|
self.connection = None
|
|
38
37
|
self.is_connected = False
|
|
39
38
|
|
|
40
39
|
def connect(self):
|
|
41
|
-
"""
|
|
40
|
+
"""Set up any connections required by the handler
|
|
42
41
|
Should return output of check_connection() method after attempting
|
|
43
42
|
connection. Should switch self.is_connected.
|
|
44
43
|
Returns:
|
|
@@ -47,10 +46,10 @@ class DerbyHandler(DatabaseHandler):
|
|
|
47
46
|
if self.is_connected is True:
|
|
48
47
|
return self.connection
|
|
49
48
|
|
|
50
|
-
user = self.connection_config.get(
|
|
51
|
-
password = self.connection_config.get(
|
|
52
|
-
jdbc_class = self.connection_config.get(
|
|
53
|
-
jar_location = self.connection_config.get(
|
|
49
|
+
user = self.connection_config.get("user")
|
|
50
|
+
password = self.connection_config.get("password")
|
|
51
|
+
jdbc_class = self.connection_config.get("jdbcClass")
|
|
52
|
+
jar_location = self.connection_config.get("jdbcJarLocation")
|
|
54
53
|
|
|
55
54
|
jdbc_url = "jdbc:derby://" + self.host + ":" + self.port + "/" + self.database + ";"
|
|
56
55
|
|
|
@@ -62,11 +61,17 @@ class DerbyHandler(DatabaseHandler):
|
|
|
62
61
|
|
|
63
62
|
try:
|
|
64
63
|
if user and password and jar_location:
|
|
65
|
-
self.connection = jdbcconnector.connect(
|
|
64
|
+
self.connection = jdbcconnector.connect(
|
|
65
|
+
jclassname=jdbc_class, url=jdbc_url, driver_args=[user, password], jars=jar_location.split(",")
|
|
66
|
+
)
|
|
66
67
|
elif user and password:
|
|
67
|
-
self.connection = jdbcconnector.connect(
|
|
68
|
+
self.connection = jdbcconnector.connect(
|
|
69
|
+
jclassname=jdbc_class, url=jdbc_url, driver_args=[user, password]
|
|
70
|
+
)
|
|
68
71
|
elif jar_location:
|
|
69
|
-
self.connection = jdbcconnector.connect(
|
|
72
|
+
self.connection = jdbcconnector.connect(
|
|
73
|
+
jclassname=jdbc_class, url=jdbc_url, jars=jar_location.split(",")
|
|
74
|
+
)
|
|
70
75
|
else:
|
|
71
76
|
self.connection = jdbcconnector.connect(jdbc_class, jdbc_url)
|
|
72
77
|
except Exception as e:
|
|
@@ -75,7 +80,7 @@ class DerbyHandler(DatabaseHandler):
|
|
|
75
80
|
return self.connection
|
|
76
81
|
|
|
77
82
|
def disconnect(self):
|
|
78
|
-
"""
|
|
83
|
+
"""Close any existing connections
|
|
79
84
|
Should switch self.is_connected.
|
|
80
85
|
"""
|
|
81
86
|
if self.is_connected is False:
|
|
@@ -89,7 +94,7 @@ class DerbyHandler(DatabaseHandler):
|
|
|
89
94
|
return
|
|
90
95
|
|
|
91
96
|
def check_connection(self) -> StatusResponse:
|
|
92
|
-
"""
|
|
97
|
+
"""Check connection to the handler
|
|
93
98
|
Returns:
|
|
94
99
|
HandlerStatusResponse
|
|
95
100
|
"""
|
|
@@ -100,7 +105,7 @@ class DerbyHandler(DatabaseHandler):
|
|
|
100
105
|
self.connect()
|
|
101
106
|
responseCode.success = True
|
|
102
107
|
except Exception as e:
|
|
103
|
-
logger.error(f
|
|
108
|
+
logger.error(f"Error connecting to database {self.database}, {e}!")
|
|
104
109
|
responseCode.error_message = str(e)
|
|
105
110
|
finally:
|
|
106
111
|
if responseCode.success is True and need_to_close:
|
|
@@ -114,7 +119,7 @@ class DerbyHandler(DatabaseHandler):
|
|
|
114
119
|
"""Receive raw query and act upon it somehow.
|
|
115
120
|
Args:
|
|
116
121
|
query (Any): query in native format (str for sql databases,
|
|
117
|
-
|
|
122
|
+
etc)
|
|
118
123
|
Returns:
|
|
119
124
|
HandlerResponse
|
|
120
125
|
"""
|
|
@@ -126,21 +131,14 @@ class DerbyHandler(DatabaseHandler):
|
|
|
126
131
|
if cur.description:
|
|
127
132
|
result = cur.fetchall()
|
|
128
133
|
response = Response(
|
|
129
|
-
RESPONSE_TYPE.TABLE,
|
|
130
|
-
data_frame=pd.DataFrame(
|
|
131
|
-
result,
|
|
132
|
-
columns=[x[0] for x in cur.description]
|
|
133
|
-
)
|
|
134
|
+
RESPONSE_TYPE.TABLE, data_frame=pd.DataFrame(result, columns=[x[0] for x in cur.description])
|
|
134
135
|
)
|
|
135
136
|
else:
|
|
136
137
|
response = Response(RESPONSE_TYPE.OK)
|
|
137
138
|
self.connection.commit()
|
|
138
139
|
except Exception as e:
|
|
139
|
-
logger.error(f
|
|
140
|
-
response = Response(
|
|
141
|
-
RESPONSE_TYPE.ERROR,
|
|
142
|
-
error_message=str(e)
|
|
143
|
-
)
|
|
140
|
+
logger.error(f"Error running query: {query} on {self.database}!")
|
|
141
|
+
response = Response(RESPONSE_TYPE.ERROR, error_message=str(e))
|
|
144
142
|
self.connection.rollback()
|
|
145
143
|
|
|
146
144
|
if need_to_close is True:
|
|
@@ -173,12 +171,12 @@ class DerbyHandler(DatabaseHandler):
|
|
|
173
171
|
Returns:
|
|
174
172
|
Response: Names of the tables in the database.
|
|
175
173
|
"""
|
|
176
|
-
query = f
|
|
177
|
-
SELECT st.tablename FROM sys.systables st LEFT OUTER JOIN sys.sysschemas ss ON (st.schemaid = ss.schemaid) WHERE ss.schemaname ='{self.schema}'
|
|
174
|
+
query = f"""
|
|
175
|
+
SELECT st.tablename FROM sys.systables st LEFT OUTER JOIN sys.sysschemas ss ON (st.schemaid = ss.schemaid) WHERE ss.schemaname ='{self.schema}' """
|
|
178
176
|
|
|
179
177
|
result = self.native_query(query)
|
|
180
178
|
df = result.data_frame
|
|
181
|
-
result.data_frame = df.rename(columns={df.columns[0]:
|
|
179
|
+
result.data_frame = df.rename(columns={df.columns[0]: "table_name"})
|
|
182
180
|
return result
|
|
183
181
|
|
|
184
182
|
def get_columns(self, table_name: str) -> StatusResponse:
|
|
@@ -191,5 +189,5 @@ class DerbyHandler(DatabaseHandler):
|
|
|
191
189
|
Response: Details of the table.
|
|
192
190
|
"""
|
|
193
191
|
|
|
194
|
-
query = f
|
|
192
|
+
query = f""" SELECT COLUMNNAME FROM SYS.SYSCOLUMNS INNER JOIN SYS.SYSTABLES ON SYS.SYSCOLUMNS.REFERENCEID=SYS.SYSTABLES.TABLEID WHERE TABLENAME='{table_name}' """
|
|
195
193
|
return self.native_query(query)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
-r mindsdb/integrations/handlers/mongodb_handler/requirements.txt
|
|
@@ -11,22 +11,22 @@ from mindsdb.utilities.render.sqlalchemy_render import SqlalchemyRender
|
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
class DummyHandler(DatabaseHandler):
|
|
14
|
-
name =
|
|
14
|
+
name = "dummy_data"
|
|
15
15
|
|
|
16
16
|
def __init__(self, **kwargs):
|
|
17
|
-
super().__init__(
|
|
17
|
+
super().__init__("dummy_data")
|
|
18
18
|
self.db_path = None
|
|
19
19
|
|
|
20
|
-
args = kwargs.get(
|
|
21
|
-
if
|
|
22
|
-
self.db_path = args[
|
|
20
|
+
args = kwargs.get("connection_data", {})
|
|
21
|
+
if "db_path" in args:
|
|
22
|
+
self.db_path = args["db_path"]
|
|
23
23
|
|
|
24
24
|
def connect(self):
|
|
25
25
|
"""Set up any connections required by the handler"""
|
|
26
26
|
return self.db_path is not None
|
|
27
27
|
|
|
28
28
|
def disconnect(self):
|
|
29
|
-
"""
|
|
29
|
+
"""Close any existing connections"""
|
|
30
30
|
return
|
|
31
31
|
|
|
32
32
|
def check_connection(self) -> HandlerStatusResponse:
|
|
@@ -41,7 +41,7 @@ class DummyHandler(DatabaseHandler):
|
|
|
41
41
|
"""Receive raw query and act upon it somehow
|
|
42
42
|
|
|
43
43
|
Args:
|
|
44
|
-
query (Any): query in native format (str for sql databases,
|
|
44
|
+
query (Any): query in native format (str for sql databases, etc)
|
|
45
45
|
params (Optional[List])
|
|
46
46
|
|
|
47
47
|
Returns:
|
|
@@ -49,7 +49,7 @@ class DummyHandler(DatabaseHandler):
|
|
|
49
49
|
"""
|
|
50
50
|
con = duckdb.connect(self.db_path)
|
|
51
51
|
if params is not None:
|
|
52
|
-
query = query.replace(
|
|
52
|
+
query = query.replace("%s", "?")
|
|
53
53
|
cur = con.executemany(query, params)
|
|
54
54
|
if cur.rowcount >= 0:
|
|
55
55
|
result_df = cur.fetchdf()
|
|
@@ -71,7 +71,7 @@ class DummyHandler(DatabaseHandler):
|
|
|
71
71
|
Returns:
|
|
72
72
|
HandlerResponse
|
|
73
73
|
"""
|
|
74
|
-
renderer = SqlalchemyRender(
|
|
74
|
+
renderer = SqlalchemyRender("postgres")
|
|
75
75
|
query_str, params = renderer.get_exec_params(query, with_failback=True)
|
|
76
76
|
return self.native_query(query_str, params)
|
|
77
77
|
|
|
@@ -81,10 +81,10 @@ class DummyHandler(DatabaseHandler):
|
|
|
81
81
|
Returns:
|
|
82
82
|
HandlerResponse: Names of the tables in the database
|
|
83
83
|
"""
|
|
84
|
-
q =
|
|
84
|
+
q = "SHOW TABLES;"
|
|
85
85
|
result = self.native_query(q)
|
|
86
86
|
df = result.data_frame
|
|
87
|
-
result.data_frame = df.rename(columns={df.columns[0]:
|
|
87
|
+
result.data_frame = df.rename(columns={df.columns[0]: "table_name"})
|
|
88
88
|
return result
|
|
89
89
|
|
|
90
90
|
def get_columns(self, table_name: str) -> HandlerResponse:
|
|
@@ -96,11 +96,10 @@ class DummyHandler(DatabaseHandler):
|
|
|
96
96
|
Returns:
|
|
97
97
|
HandlerResponse: Details of the table.
|
|
98
98
|
"""
|
|
99
|
-
query = f
|
|
99
|
+
query = f"DESCRIBE {table_name};"
|
|
100
100
|
return self.native_query(query)
|
|
101
101
|
|
|
102
102
|
def subscribe(self, stop_event, callback, table_name, columns=None, **kwargs):
|
|
103
|
-
|
|
104
103
|
while True:
|
|
105
104
|
if stop_event.is_set():
|
|
106
105
|
return
|