MindsDB 25.4.1.0__py3-none-any.whl → 25.4.2.1__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/api/executor/command_executor.py +91 -61
- mindsdb/api/executor/data_types/answer.py +9 -12
- mindsdb/api/executor/datahub/classes/response.py +11 -0
- mindsdb/api/executor/datahub/datanodes/datanode.py +4 -4
- mindsdb/api/executor/datahub/datanodes/information_schema_datanode.py +10 -11
- mindsdb/api/executor/datahub/datanodes/integration_datanode.py +22 -16
- mindsdb/api/executor/datahub/datanodes/mindsdb_tables.py +43 -1
- mindsdb/api/executor/datahub/datanodes/project_datanode.py +20 -20
- mindsdb/api/executor/planner/plan_join.py +2 -2
- mindsdb/api/executor/planner/query_plan.py +1 -0
- mindsdb/api/executor/planner/query_planner.py +86 -14
- mindsdb/api/executor/planner/steps.py +11 -2
- mindsdb/api/executor/sql_query/result_set.py +10 -7
- mindsdb/api/executor/sql_query/sql_query.py +69 -84
- mindsdb/api/executor/sql_query/steps/__init__.py +1 -0
- mindsdb/api/executor/sql_query/steps/delete_step.py +2 -3
- mindsdb/api/executor/sql_query/steps/fetch_dataframe.py +5 -3
- mindsdb/api/executor/sql_query/steps/fetch_dataframe_partition.py +288 -0
- mindsdb/api/executor/sql_query/steps/insert_step.py +2 -2
- mindsdb/api/executor/sql_query/steps/prepare_steps.py +2 -2
- mindsdb/api/executor/sql_query/steps/subselect_step.py +20 -8
- mindsdb/api/executor/sql_query/steps/update_step.py +4 -6
- mindsdb/api/http/namespaces/sql.py +4 -1
- mindsdb/api/mysql/mysql_proxy/data_types/mysql_packets/ok_packet.py +1 -1
- mindsdb/api/mysql/mysql_proxy/executor/mysql_executor.py +4 -27
- mindsdb/api/mysql/mysql_proxy/libs/constants/mysql.py +1 -0
- mindsdb/api/mysql/mysql_proxy/mysql_proxy.py +38 -37
- mindsdb/integrations/handlers/chromadb_handler/chromadb_handler.py +23 -13
- mindsdb/integrations/handlers/langchain_embedding_handler/langchain_embedding_handler.py +17 -16
- mindsdb/integrations/handlers/langchain_handler/langchain_handler.py +1 -0
- mindsdb/integrations/handlers/mssql_handler/mssql_handler.py +1 -1
- mindsdb/integrations/handlers/mysql_handler/mysql_handler.py +3 -2
- mindsdb/integrations/handlers/oracle_handler/oracle_handler.py +4 -4
- mindsdb/integrations/handlers/pgvector_handler/pgvector_handler.py +26 -16
- mindsdb/integrations/handlers/postgres_handler/postgres_handler.py +36 -7
- mindsdb/integrations/handlers/redshift_handler/redshift_handler.py +1 -1
- mindsdb/integrations/handlers/snowflake_handler/snowflake_handler.py +18 -11
- mindsdb/integrations/libs/llm/config.py +11 -1
- mindsdb/integrations/libs/llm/utils.py +12 -0
- mindsdb/integrations/libs/ml_handler_process/learn_process.py +1 -2
- mindsdb/integrations/libs/response.py +9 -4
- mindsdb/integrations/libs/vectordatabase_handler.py +17 -5
- mindsdb/integrations/utilities/rag/rerankers/reranker_compressor.py +8 -98
- mindsdb/interfaces/agents/constants.py +12 -1
- mindsdb/interfaces/agents/langchain_agent.py +6 -0
- mindsdb/interfaces/database/log.py +8 -9
- mindsdb/interfaces/database/projects.py +1 -5
- mindsdb/interfaces/functions/controller.py +59 -17
- mindsdb/interfaces/functions/to_markdown.py +194 -0
- mindsdb/interfaces/jobs/jobs_controller.py +3 -3
- mindsdb/interfaces/knowledge_base/controller.py +223 -97
- mindsdb/interfaces/knowledge_base/preprocessing/document_preprocessor.py +3 -14
- mindsdb/interfaces/query_context/context_controller.py +224 -1
- mindsdb/interfaces/storage/db.py +23 -0
- mindsdb/migrations/versions/2025-03-21_fda503400e43_queries.py +45 -0
- mindsdb/utilities/context_executor.py +1 -1
- mindsdb/utilities/partitioning.py +35 -20
- {mindsdb-25.4.1.0.dist-info → mindsdb-25.4.2.1.dist-info}/METADATA +227 -224
- {mindsdb-25.4.1.0.dist-info → mindsdb-25.4.2.1.dist-info}/RECORD +63 -59
- {mindsdb-25.4.1.0.dist-info → mindsdb-25.4.2.1.dist-info}/WHEEL +0 -0
- {mindsdb-25.4.1.0.dist-info → mindsdb-25.4.2.1.dist-info}/licenses/LICENSE +0 -0
- {mindsdb-25.4.1.0.dist-info → mindsdb-25.4.2.1.dist-info}/top_level.txt +0 -0
mindsdb/__about__.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
__title__ = 'MindsDB'
|
|
2
2
|
__package_name__ = 'mindsdb'
|
|
3
|
-
__version__ = '25.4.1
|
|
3
|
+
__version__ = '25.4.2.1'
|
|
4
4
|
__description__ = "MindsDB's AI SQL Server enables developers to build AI tools that need access to real-time data to perform their tasks"
|
|
5
5
|
__email__ = "jorge@mindsdb.com"
|
|
6
6
|
__author__ = 'MindsDB Inc'
|
|
@@ -34,6 +34,7 @@ from mindsdb_sql_parser.ast import (
|
|
|
34
34
|
Update,
|
|
35
35
|
Use,
|
|
36
36
|
Tuple,
|
|
37
|
+
Function,
|
|
37
38
|
)
|
|
38
39
|
|
|
39
40
|
# typed models
|
|
@@ -164,18 +165,17 @@ class ExecuteCommands:
|
|
|
164
165
|
self.datahub = session.datahub
|
|
165
166
|
|
|
166
167
|
@profiler.profile()
|
|
167
|
-
def execute_command(self, statement, database_name: str = None) -> ExecuteAnswer:
|
|
168
|
-
sql =
|
|
169
|
-
|
|
170
|
-
sql = statement.to_string()
|
|
171
|
-
sql_lower = sql.lower()
|
|
168
|
+
def execute_command(self, statement: ASTNode, database_name: str = None) -> ExecuteAnswer:
|
|
169
|
+
sql: str = statement.to_string()
|
|
170
|
+
sql_lower: str = sql.lower()
|
|
172
171
|
|
|
173
172
|
if database_name is None:
|
|
174
173
|
database_name = self.session.database
|
|
175
174
|
|
|
176
|
-
|
|
175
|
+
statement_type = type(statement)
|
|
176
|
+
if statement_type is CreateDatabase:
|
|
177
177
|
return self.answer_create_database(statement)
|
|
178
|
-
elif
|
|
178
|
+
elif statement_type is CreateMLEngine:
|
|
179
179
|
name = statement.name.parts[-1]
|
|
180
180
|
|
|
181
181
|
return self.answer_create_ml_engine(
|
|
@@ -184,16 +184,16 @@ class ExecuteCommands:
|
|
|
184
184
|
params=statement.params,
|
|
185
185
|
if_not_exists=getattr(statement, "if_not_exists", False)
|
|
186
186
|
)
|
|
187
|
-
elif
|
|
187
|
+
elif statement_type is DropMLEngine:
|
|
188
188
|
return self.answer_drop_ml_engine(statement)
|
|
189
|
-
elif
|
|
189
|
+
elif statement_type is DropPredictor:
|
|
190
190
|
return self.answer_drop_model(statement, database_name)
|
|
191
191
|
|
|
192
|
-
elif
|
|
192
|
+
elif statement_type is DropTables:
|
|
193
193
|
return self.answer_drop_tables(statement, database_name)
|
|
194
|
-
elif
|
|
194
|
+
elif statement_type is DropDatasource or statement_type is DropDatabase:
|
|
195
195
|
return self.answer_drop_database(statement)
|
|
196
|
-
elif
|
|
196
|
+
elif statement_type is Describe:
|
|
197
197
|
# NOTE in sql 'describe table' is same as 'show columns'
|
|
198
198
|
obj_type = statement.type
|
|
199
199
|
|
|
@@ -202,11 +202,11 @@ class ExecuteCommands:
|
|
|
202
202
|
else:
|
|
203
203
|
return self.answer_describe_object(obj_type.upper(), statement.value, database_name)
|
|
204
204
|
|
|
205
|
-
elif
|
|
205
|
+
elif statement_type is RetrainPredictor:
|
|
206
206
|
return self.answer_retrain_predictor(statement, database_name)
|
|
207
|
-
elif
|
|
207
|
+
elif statement_type is FinetunePredictor:
|
|
208
208
|
return self.answer_finetune_predictor(statement, database_name)
|
|
209
|
-
elif
|
|
209
|
+
elif statement_type is Show:
|
|
210
210
|
sql_category = statement.category.lower()
|
|
211
211
|
if hasattr(statement, "modes"):
|
|
212
212
|
if isinstance(statement.modes, list) is False:
|
|
@@ -504,13 +504,13 @@ class ExecuteCommands:
|
|
|
504
504
|
return self.answer_select(query)
|
|
505
505
|
else:
|
|
506
506
|
raise NotSupportedYet(f"Statement not implemented: {sql}")
|
|
507
|
-
elif
|
|
507
|
+
elif statement_type in (
|
|
508
508
|
StartTransaction,
|
|
509
509
|
CommitTransaction,
|
|
510
510
|
RollbackTransaction,
|
|
511
511
|
):
|
|
512
512
|
return ExecuteAnswer()
|
|
513
|
-
elif
|
|
513
|
+
elif statement_type is Set:
|
|
514
514
|
category = (statement.category or "").lower()
|
|
515
515
|
if category == "" and isinstance(statement.name, Identifier):
|
|
516
516
|
param = statement.name.parts[0].lower()
|
|
@@ -565,85 +565,118 @@ class ExecuteCommands:
|
|
|
565
565
|
f"SQL statement is not processable, return OK package: {sql}"
|
|
566
566
|
)
|
|
567
567
|
return ExecuteAnswer()
|
|
568
|
-
elif
|
|
568
|
+
elif statement_type is Use:
|
|
569
569
|
db_name = statement.value.parts[-1]
|
|
570
570
|
self.change_default_db(db_name)
|
|
571
571
|
return ExecuteAnswer()
|
|
572
|
-
elif
|
|
572
|
+
elif statement_type in (
|
|
573
573
|
CreatePredictor,
|
|
574
574
|
CreateAnomalyDetectionModel, # we may want to specialize these in the future
|
|
575
575
|
):
|
|
576
576
|
return self.answer_create_predictor(statement, database_name)
|
|
577
|
-
elif
|
|
577
|
+
elif statement_type is CreateView:
|
|
578
578
|
return self.answer_create_view(statement, database_name)
|
|
579
|
-
elif
|
|
579
|
+
elif statement_type is DropView:
|
|
580
580
|
return self.answer_drop_view(statement, database_name)
|
|
581
|
-
elif
|
|
582
|
-
SQLQuery(statement, session=self.session,
|
|
583
|
-
return ExecuteAnswer(
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
581
|
+
elif statement_type is Delete:
|
|
582
|
+
query = SQLQuery(statement, session=self.session, database=database_name)
|
|
583
|
+
return ExecuteAnswer(
|
|
584
|
+
affected_rows=query.fetched_data.affected_rows
|
|
585
|
+
)
|
|
586
|
+
elif statement_type is Insert:
|
|
587
|
+
query = SQLQuery(statement, session=self.session, database=database_name)
|
|
588
|
+
return ExecuteAnswer(
|
|
589
|
+
affected_rows=query.fetched_data.affected_rows
|
|
590
|
+
)
|
|
591
|
+
elif statement_type is Update:
|
|
592
|
+
query = SQLQuery(statement, session=self.session, database=database_name)
|
|
593
|
+
return ExecuteAnswer(
|
|
594
|
+
affected_rows=query.fetched_data.affected_rows
|
|
595
|
+
)
|
|
591
596
|
elif (
|
|
592
|
-
|
|
597
|
+
statement_type is Alter
|
|
593
598
|
and ("disable keys" in sql_lower)
|
|
594
599
|
or ("enable keys" in sql_lower)
|
|
595
600
|
):
|
|
596
601
|
return ExecuteAnswer()
|
|
597
|
-
elif
|
|
602
|
+
elif statement_type is Select:
|
|
603
|
+
ret = self.exec_service_function(statement, database_name)
|
|
604
|
+
if ret is not None:
|
|
605
|
+
return ret
|
|
598
606
|
query = SQLQuery(statement, session=self.session, database=database_name)
|
|
599
607
|
return self.answer_select(query)
|
|
600
|
-
elif
|
|
608
|
+
elif statement_type is Union:
|
|
601
609
|
query = SQLQuery(statement, session=self.session, database=database_name)
|
|
602
610
|
return self.answer_select(query)
|
|
603
|
-
elif
|
|
611
|
+
elif statement_type is Explain:
|
|
604
612
|
return self.answer_show_columns(statement.target, database_name=database_name)
|
|
605
|
-
elif
|
|
613
|
+
elif statement_type is CreateTable:
|
|
606
614
|
return self.answer_create_table(statement, database_name)
|
|
607
615
|
# -- jobs --
|
|
608
|
-
elif
|
|
616
|
+
elif statement_type is CreateJob:
|
|
609
617
|
return self.answer_create_job(statement, database_name)
|
|
610
|
-
elif
|
|
618
|
+
elif statement_type is DropJob:
|
|
611
619
|
return self.answer_drop_job(statement, database_name)
|
|
612
620
|
# -- triggers --
|
|
613
|
-
elif
|
|
621
|
+
elif statement_type is CreateTrigger:
|
|
614
622
|
return self.answer_create_trigger(statement, database_name)
|
|
615
|
-
elif
|
|
623
|
+
elif statement_type is DropTrigger:
|
|
616
624
|
return self.answer_drop_trigger(statement, database_name)
|
|
617
625
|
# -- chatbots
|
|
618
|
-
elif
|
|
626
|
+
elif statement_type is CreateChatBot:
|
|
619
627
|
return self.answer_create_chatbot(statement, database_name)
|
|
620
|
-
elif
|
|
628
|
+
elif statement_type is UpdateChatBot:
|
|
621
629
|
return self.answer_update_chatbot(statement, database_name)
|
|
622
|
-
elif
|
|
630
|
+
elif statement_type is DropChatBot:
|
|
623
631
|
return self.answer_drop_chatbot(statement, database_name)
|
|
624
|
-
elif
|
|
632
|
+
elif statement_type is CreateKnowledgeBase:
|
|
625
633
|
return self.answer_create_kb(statement, database_name)
|
|
626
|
-
elif
|
|
634
|
+
elif statement_type is DropKnowledgeBase:
|
|
627
635
|
return self.answer_drop_kb(statement, database_name)
|
|
628
|
-
elif
|
|
636
|
+
elif statement_type is CreateSkill:
|
|
629
637
|
return self.answer_create_skill(statement, database_name)
|
|
630
|
-
elif
|
|
638
|
+
elif statement_type is DropSkill:
|
|
631
639
|
return self.answer_drop_skill(statement, database_name)
|
|
632
|
-
elif
|
|
640
|
+
elif statement_type is UpdateSkill:
|
|
633
641
|
return self.answer_update_skill(statement, database_name)
|
|
634
|
-
elif
|
|
642
|
+
elif statement_type is CreateAgent:
|
|
635
643
|
return self.answer_create_agent(statement, database_name)
|
|
636
|
-
elif
|
|
644
|
+
elif statement_type is DropAgent:
|
|
637
645
|
return self.answer_drop_agent(statement, database_name)
|
|
638
|
-
elif
|
|
646
|
+
elif statement_type is UpdateAgent:
|
|
639
647
|
return self.answer_update_agent(statement, database_name)
|
|
640
|
-
elif
|
|
648
|
+
elif statement_type is Evaluate:
|
|
641
649
|
statement.data = parse_sql(statement.query_str)
|
|
642
650
|
return self.answer_evaluate_metric(statement, database_name)
|
|
643
651
|
else:
|
|
644
652
|
logger.warning(f"Unknown SQL statement: {sql}")
|
|
645
653
|
raise NotSupportedYet(f"Unknown SQL statement: {sql}")
|
|
646
654
|
|
|
655
|
+
def exec_service_function(self, statement: Select, database_name: str) -> Optional[ExecuteAnswer]:
|
|
656
|
+
"""
|
|
657
|
+
If input query is a single line select without FROM
|
|
658
|
+
and has function in targets that matches with one of the mindsdb service functions:
|
|
659
|
+
- execute this function and return response
|
|
660
|
+
Otherwise, return None to allow to continue execution query outside
|
|
661
|
+
"""
|
|
662
|
+
|
|
663
|
+
if statement.from_table is not None or len(statement.targets) != 1:
|
|
664
|
+
return
|
|
665
|
+
|
|
666
|
+
target = statement.targets[0]
|
|
667
|
+
if not isinstance(target, Function):
|
|
668
|
+
return
|
|
669
|
+
|
|
670
|
+
command = target.op.lower()
|
|
671
|
+
args = [arg.value for arg in target.args if isinstance(arg, Constant)]
|
|
672
|
+
if command == 'query_resume':
|
|
673
|
+
ret = SQLQuery(None, session=self.session, database=database_name, query_id=args[0])
|
|
674
|
+
return self.answer_select(ret)
|
|
675
|
+
|
|
676
|
+
elif command == 'query_cancel':
|
|
677
|
+
query_context_controller.cancel_query(*args)
|
|
678
|
+
return ExecuteAnswer()
|
|
679
|
+
|
|
647
680
|
def answer_create_trigger(self, statement, database_name):
|
|
648
681
|
triggers_controller = TriggersController()
|
|
649
682
|
|
|
@@ -785,8 +818,7 @@ class ExecuteCommands:
|
|
|
785
818
|
raise Exception(
|
|
786
819
|
f'Nested query failed to execute with error: "{e}", please check and try again.'
|
|
787
820
|
)
|
|
788
|
-
|
|
789
|
-
df = result["result"]
|
|
821
|
+
df = sqlquery.fetched_data.to_df()
|
|
790
822
|
df.columns = [
|
|
791
823
|
str(t.alias) if hasattr(t, "alias") else str(t.parts[-1])
|
|
792
824
|
for t in statement.data.targets
|
|
@@ -1253,7 +1285,6 @@ class ExecuteCommands:
|
|
|
1253
1285
|
project_name = parts[0]
|
|
1254
1286
|
|
|
1255
1287
|
query_str = statement.query_str
|
|
1256
|
-
query = parse_sql(query_str)
|
|
1257
1288
|
|
|
1258
1289
|
if isinstance(statement.from_table, Identifier):
|
|
1259
1290
|
query = Select(
|
|
@@ -1263,6 +1294,8 @@ class ExecuteCommands:
|
|
|
1263
1294
|
),
|
|
1264
1295
|
)
|
|
1265
1296
|
query_str = str(query)
|
|
1297
|
+
else:
|
|
1298
|
+
query = parse_sql(query_str)
|
|
1266
1299
|
|
|
1267
1300
|
if isinstance(query, Select):
|
|
1268
1301
|
# check create view sql
|
|
@@ -1272,9 +1305,7 @@ class ExecuteCommands:
|
|
|
1272
1305
|
query_context_controller.IGNORE_CONTEXT
|
|
1273
1306
|
)
|
|
1274
1307
|
try:
|
|
1275
|
-
|
|
1276
|
-
if sqlquery.fetch()["success"] is not True:
|
|
1277
|
-
raise ExecutorException("Wrong view query")
|
|
1308
|
+
SQLQuery(query, session=self.session, database=database_name)
|
|
1278
1309
|
finally:
|
|
1279
1310
|
query_context_controller.release_context(
|
|
1280
1311
|
query_context_controller.IGNORE_CONTEXT
|
|
@@ -1920,9 +1951,8 @@ class ExecuteCommands:
|
|
|
1920
1951
|
return ExecuteAnswer()
|
|
1921
1952
|
|
|
1922
1953
|
def answer_select(self, query):
|
|
1923
|
-
data = query.
|
|
1924
|
-
|
|
1925
|
-
return ExecuteAnswer(data=data["result"])
|
|
1954
|
+
data = query.fetched_data
|
|
1955
|
+
return ExecuteAnswer(data=data)
|
|
1926
1956
|
|
|
1927
1957
|
def answer_update_model_version(self, model_version, database_name):
|
|
1928
1958
|
if not isinstance(model_version, Identifier):
|
|
@@ -1,16 +1,13 @@
|
|
|
1
|
-
from
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from typing import List, Optional
|
|
3
|
+
|
|
2
4
|
from mindsdb.api.executor.sql_query.result_set import ResultSet
|
|
3
5
|
|
|
4
6
|
|
|
7
|
+
@dataclass(kw_only=True, slots=True)
|
|
5
8
|
class ExecuteAnswer:
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
error_message: str = None,
|
|
12
|
-
):
|
|
13
|
-
self.data = data
|
|
14
|
-
self.state_track = state_track
|
|
15
|
-
self.error_code = error_code
|
|
16
|
-
self.error_message = error_message
|
|
9
|
+
data: Optional[ResultSet] = None
|
|
10
|
+
state_track: Optional[List[List]] = None
|
|
11
|
+
error_code: Optional[int] = None
|
|
12
|
+
error_message: Optional[str] = None
|
|
13
|
+
affected_rows: Optional[int] = None
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
|
+
from typing import Optional, List, Dict
|
|
3
|
+
|
|
4
|
+
import pandas as pd
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass
|
|
8
|
+
class DataHubResponse:
|
|
9
|
+
data_frame: pd.DataFrame = field(default_factory=pd.DataFrame)
|
|
10
|
+
columns: List[Dict] = field(default_factory=list)
|
|
11
|
+
affected_rows: Optional[int] = None
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
from mindsdb.api.executor.datahub.classes.response import DataHubResponse
|
|
2
|
+
|
|
3
|
+
|
|
1
4
|
class DataNode:
|
|
2
5
|
type = 'meta'
|
|
3
6
|
|
|
@@ -10,11 +13,8 @@ class DataNode:
|
|
|
10
13
|
def get_tables(self):
|
|
11
14
|
pass
|
|
12
15
|
|
|
13
|
-
def has_table(self, tableName):
|
|
14
|
-
pass
|
|
15
|
-
|
|
16
16
|
def get_table_columns(self, tableName, schema_name=None):
|
|
17
17
|
pass
|
|
18
18
|
|
|
19
|
-
def query(self, query=None, native_query=None, session=None):
|
|
19
|
+
def query(self, query=None, native_query=None, session=None) -> DataHubResponse:
|
|
20
20
|
return []
|
|
@@ -9,7 +9,7 @@ from mindsdb.api.executor import exceptions as exc
|
|
|
9
9
|
from mindsdb.api.executor.utilities.sql import query_df
|
|
10
10
|
from mindsdb.api.executor.utilities.sql import get_query_tables
|
|
11
11
|
from mindsdb.interfaces.database.projects import ProjectController
|
|
12
|
-
|
|
12
|
+
from mindsdb.api.executor.datahub.classes.response import DataHubResponse
|
|
13
13
|
from mindsdb.utilities import log
|
|
14
14
|
|
|
15
15
|
from .system_tables import (
|
|
@@ -17,7 +17,7 @@ from .system_tables import (
|
|
|
17
17
|
PluginsTable, EnginesTable, KeyColumnUsageTable, StatisticsTable,
|
|
18
18
|
CharacterSetsTable, CollationsTable)
|
|
19
19
|
from .mindsdb_tables import (
|
|
20
|
-
ModelsTable, DatabasesTable, MLEnginesTable, HandlersTable, JobsTable,
|
|
20
|
+
ModelsTable, DatabasesTable, MLEnginesTable, HandlersTable, JobsTable, QueriesTable,
|
|
21
21
|
ChatbotsTable, KBTable, SkillsTable, AgentsTable, ViewsTable, TriggersTable)
|
|
22
22
|
|
|
23
23
|
|
|
@@ -32,7 +32,8 @@ class InformationSchemaDataNode(DataNode):
|
|
|
32
32
|
PluginsTable, EnginesTable, KeyColumnUsageTable, StatisticsTable,
|
|
33
33
|
CharacterSetsTable, CollationsTable,
|
|
34
34
|
ModelsTable, DatabasesTable, MLEnginesTable, HandlersTable, JobsTable,
|
|
35
|
-
ChatbotsTable, KBTable, SkillsTable, AgentsTable, ViewsTable, TriggersTable
|
|
35
|
+
ChatbotsTable, KBTable, SkillsTable, AgentsTable, ViewsTable, TriggersTable,
|
|
36
|
+
QueriesTable
|
|
36
37
|
]
|
|
37
38
|
|
|
38
39
|
def __init__(self, session):
|
|
@@ -110,12 +111,6 @@ class InformationSchemaDataNode(DataNode):
|
|
|
110
111
|
|
|
111
112
|
return None
|
|
112
113
|
|
|
113
|
-
def has_table(self, tableName):
|
|
114
|
-
tn = tableName.upper()
|
|
115
|
-
if tn in self.tables:
|
|
116
|
-
return True
|
|
117
|
-
return False
|
|
118
|
-
|
|
119
114
|
def get_table_columns(self, tableName, schema_name=None):
|
|
120
115
|
tn = tableName.upper()
|
|
121
116
|
if tn in self.tables:
|
|
@@ -143,7 +138,7 @@ class InformationSchemaDataNode(DataNode):
|
|
|
143
138
|
if table.visible
|
|
144
139
|
}
|
|
145
140
|
|
|
146
|
-
def query(self, query: ASTNode, session=None):
|
|
141
|
+
def query(self, query: ASTNode, session=None) -> DataHubResponse:
|
|
147
142
|
query_tables = [x[1] for x in get_query_tables(query)]
|
|
148
143
|
|
|
149
144
|
if len(query_tables) != 1:
|
|
@@ -166,7 +161,11 @@ class InformationSchemaDataNode(DataNode):
|
|
|
166
161
|
|
|
167
162
|
columns_info = [{"name": k, "type": v} for k, v in data.dtypes.items()]
|
|
168
163
|
|
|
169
|
-
return
|
|
164
|
+
return DataHubResponse(
|
|
165
|
+
data_frame=data,
|
|
166
|
+
columns=columns_info,
|
|
167
|
+
affected_rows=0
|
|
168
|
+
)
|
|
170
169
|
|
|
171
170
|
def _get_empty_table(self, table):
|
|
172
171
|
columns = table.columns
|
|
@@ -10,16 +10,19 @@ from sqlalchemy.types import (
|
|
|
10
10
|
Integer, Float, Text
|
|
11
11
|
)
|
|
12
12
|
|
|
13
|
+
from mindsdb_sql_parser.ast.base import ASTNode
|
|
13
14
|
from mindsdb_sql_parser.ast import Insert, Identifier, CreateTable, TableColumn, DropTables
|
|
14
15
|
|
|
16
|
+
from mindsdb.api.executor.datahub.classes.response import DataHubResponse
|
|
15
17
|
from mindsdb.api.executor.datahub.datanodes.datanode import DataNode
|
|
16
|
-
from mindsdb.api.executor.data_types.response_type import RESPONSE_TYPE
|
|
17
18
|
from mindsdb.api.executor.datahub.classes.tables_row import TablesRow
|
|
19
|
+
from mindsdb.api.executor.data_types.response_type import RESPONSE_TYPE
|
|
18
20
|
from mindsdb.api.executor.sql_query.result_set import ResultSet
|
|
19
21
|
from mindsdb.integrations.utilities.utils import get_class_name
|
|
20
22
|
from mindsdb.metrics import metrics
|
|
21
23
|
from mindsdb.utilities import log
|
|
22
24
|
from mindsdb.utilities.profiler import profiler
|
|
25
|
+
from mindsdb.integrations.libs.response import HandlerResponse
|
|
23
26
|
|
|
24
27
|
logger = log.getLogger(__name__)
|
|
25
28
|
|
|
@@ -52,9 +55,6 @@ class IntegrationDataNode(DataNode):
|
|
|
52
55
|
else:
|
|
53
56
|
raise Exception(f"Can't get tables: {response.error_message}")
|
|
54
57
|
|
|
55
|
-
def has_table(self, tableName):
|
|
56
|
-
return True
|
|
57
|
-
|
|
58
58
|
def get_table_columns(self, table_name: str, schema_name: Optional[str] = None):
|
|
59
59
|
if 'schema_name' in inspect.signature(self.integration_handler.get_columns).parameters:
|
|
60
60
|
response = self.integration_handler.get_columns(table_name, schema_name)
|
|
@@ -107,7 +107,7 @@ class IntegrationDataNode(DataNode):
|
|
|
107
107
|
raise Exception(result.error_message)
|
|
108
108
|
|
|
109
109
|
def create_table(self, table_name: Identifier, result_set: ResultSet = None, columns=None,
|
|
110
|
-
is_replace=False, is_create=False):
|
|
110
|
+
is_replace=False, is_create=False) -> DataHubResponse:
|
|
111
111
|
# is_create - create table
|
|
112
112
|
# is_replace - drop table if exists
|
|
113
113
|
# is_create==False and is_replace==False: just insert
|
|
@@ -164,14 +164,14 @@ class IntegrationDataNode(DataNode):
|
|
|
164
164
|
|
|
165
165
|
if result_set is None:
|
|
166
166
|
# it is just a 'create table'
|
|
167
|
-
return
|
|
167
|
+
return DataHubResponse()
|
|
168
168
|
|
|
169
169
|
# native insert
|
|
170
170
|
if hasattr(self.integration_handler, 'insert'):
|
|
171
171
|
df = result_set.to_df()
|
|
172
172
|
|
|
173
|
-
self.integration_handler.insert(table_name.parts[-1], df)
|
|
174
|
-
return
|
|
173
|
+
result: HandlerResponse = self.integration_handler.insert(table_name.parts[-1], df)
|
|
174
|
+
return DataHubResponse(affected_rows=result.affected_rows)
|
|
175
175
|
|
|
176
176
|
insert_columns = [Identifier(parts=[x.alias]) for x in result_set.columns]
|
|
177
177
|
|
|
@@ -195,7 +195,7 @@ class IntegrationDataNode(DataNode):
|
|
|
195
195
|
|
|
196
196
|
if len(values) == 0:
|
|
197
197
|
# not need to insert
|
|
198
|
-
return
|
|
198
|
+
return DataHubResponse()
|
|
199
199
|
|
|
200
200
|
insert_ast = Insert(
|
|
201
201
|
table=table_name,
|
|
@@ -213,7 +213,9 @@ class IntegrationDataNode(DataNode):
|
|
|
213
213
|
if result.type == RESPONSE_TYPE.ERROR:
|
|
214
214
|
raise Exception(result.error_message)
|
|
215
215
|
|
|
216
|
-
|
|
216
|
+
return DataHubResponse(affected_rows=result.affected_rows)
|
|
217
|
+
|
|
218
|
+
def _query(self, query) -> HandlerResponse:
|
|
217
219
|
time_before_query = time.perf_counter()
|
|
218
220
|
result = self.integration_handler.query(query)
|
|
219
221
|
elapsed_seconds = time.perf_counter() - time_before_query
|
|
@@ -229,7 +231,7 @@ class IntegrationDataNode(DataNode):
|
|
|
229
231
|
response_size_with_labels.observe(num_rows)
|
|
230
232
|
return result
|
|
231
233
|
|
|
232
|
-
def _native_query(self, native_query):
|
|
234
|
+
def _native_query(self, native_query) -> HandlerResponse:
|
|
233
235
|
time_before_query = time.perf_counter()
|
|
234
236
|
result = self.integration_handler.native_query(native_query)
|
|
235
237
|
elapsed_seconds = time.perf_counter() - time_before_query
|
|
@@ -246,13 +248,13 @@ class IntegrationDataNode(DataNode):
|
|
|
246
248
|
return result
|
|
247
249
|
|
|
248
250
|
@profiler.profile()
|
|
249
|
-
def query(self, query=None, native_query=None, session=None):
|
|
251
|
+
def query(self, query: Optional[ASTNode] = None, native_query: Optional[str] = None, session=None) -> DataHubResponse:
|
|
250
252
|
try:
|
|
251
253
|
if query is not None:
|
|
252
|
-
result = self._query(query)
|
|
254
|
+
result: HandlerResponse = self._query(query)
|
|
253
255
|
else:
|
|
254
256
|
# try to fetch native query
|
|
255
|
-
result = self._native_query(native_query)
|
|
257
|
+
result: HandlerResponse = self._native_query(native_query)
|
|
256
258
|
except Exception as e:
|
|
257
259
|
msg = str(e).strip()
|
|
258
260
|
if msg == '':
|
|
@@ -263,7 +265,7 @@ class IntegrationDataNode(DataNode):
|
|
|
263
265
|
if result.type == RESPONSE_TYPE.ERROR:
|
|
264
266
|
raise Exception(f'Error in {self.integration_name}: {result.error_message}')
|
|
265
267
|
if result.type == RESPONSE_TYPE.OK:
|
|
266
|
-
return
|
|
268
|
+
return DataHubResponse(affected_rows=result.affected_rows)
|
|
267
269
|
|
|
268
270
|
df = result.data_frame
|
|
269
271
|
# region clearing df from NaN values
|
|
@@ -286,4 +288,8 @@ class IntegrationDataNode(DataNode):
|
|
|
286
288
|
for k, v in df.dtypes.items()
|
|
287
289
|
]
|
|
288
290
|
|
|
289
|
-
return
|
|
291
|
+
return DataHubResponse(
|
|
292
|
+
data_frame=df,
|
|
293
|
+
columns=columns_info,
|
|
294
|
+
affected_rows=result.affected_rows
|
|
295
|
+
)
|
|
@@ -9,6 +9,7 @@ from mindsdb.interfaces.jobs.jobs_controller import JobsController
|
|
|
9
9
|
from mindsdb.interfaces.skills.skills_controller import SkillsController
|
|
10
10
|
from mindsdb.interfaces.database.views import ViewController
|
|
11
11
|
from mindsdb.interfaces.database.projects import ProjectController
|
|
12
|
+
from mindsdb.interfaces.query_context.context_controller import query_context_controller
|
|
12
13
|
|
|
13
14
|
from mindsdb.api.executor.datahub.datanodes.system_tables import Table
|
|
14
15
|
|
|
@@ -326,7 +327,8 @@ class ChatbotsTable(MdbTable):
|
|
|
326
327
|
|
|
327
328
|
class KBTable(MdbTable):
|
|
328
329
|
name = 'KNOWLEDGE_BASES'
|
|
329
|
-
columns = ["NAME", "PROJECT", "MODEL", "STORAGE", "PARAMS"
|
|
330
|
+
columns = ["NAME", "PROJECT", "MODEL", "STORAGE", "PARAMS",
|
|
331
|
+
"INSERT_STARTED_AT", "INSERT_FINISHED_AT", "PROCESSED_ROWS", "ERROR", "QUERY_ID"]
|
|
330
332
|
|
|
331
333
|
@classmethod
|
|
332
334
|
def get_data(cls, query: ASTNode = None, inf_schema=None, **kwargs):
|
|
@@ -336,17 +338,36 @@ class KBTable(MdbTable):
|
|
|
336
338
|
controller = KnowledgeBaseController(inf_schema.session)
|
|
337
339
|
kb_list = controller.list(project_name)
|
|
338
340
|
|
|
341
|
+
# shouldn't be a lot of queries, we can fetch them all
|
|
342
|
+
queries_data = {
|
|
343
|
+
item['id']: item
|
|
344
|
+
for item in query_context_controller.list_queries()
|
|
345
|
+
}
|
|
346
|
+
|
|
339
347
|
data = []
|
|
340
348
|
|
|
341
349
|
for kb in kb_list:
|
|
342
350
|
vector_database_name = kb['vector_database'] or ''
|
|
343
351
|
|
|
352
|
+
query_item = {}
|
|
353
|
+
query_id = kb['query_id']
|
|
354
|
+
if query_id is not None:
|
|
355
|
+
if query_id in queries_data:
|
|
356
|
+
query_item = queries_data.get(query_id)
|
|
357
|
+
else:
|
|
358
|
+
query_id = None
|
|
359
|
+
|
|
344
360
|
data.append((
|
|
345
361
|
kb['name'],
|
|
346
362
|
kb['project_name'],
|
|
347
363
|
kb['embedding_model'],
|
|
348
364
|
vector_database_name + '.' + kb['vector_database_table'],
|
|
349
365
|
to_json(kb['params']),
|
|
366
|
+
query_item.get('started_at'),
|
|
367
|
+
query_item.get('finished_at'),
|
|
368
|
+
query_item.get('processed_rows'),
|
|
369
|
+
query_item.get('error'),
|
|
370
|
+
query_id,
|
|
350
371
|
))
|
|
351
372
|
|
|
352
373
|
return pd.DataFrame(data, columns=cls.columns)
|
|
@@ -426,3 +447,24 @@ class ViewsTable(MdbTable):
|
|
|
426
447
|
data = [[row[k] for k in columns_lower] for row in data]
|
|
427
448
|
|
|
428
449
|
return pd.DataFrame(data, columns=cls.columns)
|
|
450
|
+
|
|
451
|
+
|
|
452
|
+
class QueriesTable(MdbTable):
|
|
453
|
+
name = 'QUERIES'
|
|
454
|
+
columns = ["ID", "STARTED_AT", "FINISHED_AT", "PROCESSED_ROWS", "ERROR", "SQL", "PARAMETERS", "CONTEXT", "UPDATED_AT"]
|
|
455
|
+
|
|
456
|
+
@classmethod
|
|
457
|
+
def get_data(cls, **kwargs):
|
|
458
|
+
"""
|
|
459
|
+
Returns all queries in progres or recently completed
|
|
460
|
+
Only queries marked as is_resumable by planner are stored in this table
|
|
461
|
+
:param kwargs:
|
|
462
|
+
:return:
|
|
463
|
+
"""
|
|
464
|
+
|
|
465
|
+
data = query_context_controller.list_queries()
|
|
466
|
+
columns_lower = [col.lower() for col in cls.columns]
|
|
467
|
+
|
|
468
|
+
data = [[row[k] for k in columns_lower] for row in data]
|
|
469
|
+
|
|
470
|
+
return pd.DataFrame(data, columns=cls.columns)
|