MindsDB 25.5.3.0__py3-none-any.whl → 25.5.4.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 +127 -79
- mindsdb/api/a2a/__init__.py +0 -0
- mindsdb/api/a2a/__main__.py +114 -0
- mindsdb/api/a2a/a2a_client.py +439 -0
- mindsdb/api/a2a/agent.py +308 -0
- mindsdb/api/a2a/common/__init__.py +0 -0
- mindsdb/api/a2a/common/client/__init__.py +4 -0
- mindsdb/api/a2a/common/client/card_resolver.py +21 -0
- mindsdb/api/a2a/common/client/client.py +86 -0
- mindsdb/api/a2a/common/server/__init__.py +4 -0
- mindsdb/api/a2a/common/server/server.py +164 -0
- mindsdb/api/a2a/common/server/task_manager.py +287 -0
- mindsdb/api/a2a/common/server/utils.py +28 -0
- mindsdb/api/a2a/common/types.py +365 -0
- mindsdb/api/a2a/constants.py +9 -0
- mindsdb/api/a2a/run_a2a.py +129 -0
- mindsdb/api/a2a/task_manager.py +594 -0
- mindsdb/api/executor/command_executor.py +47 -27
- mindsdb/api/executor/datahub/classes/response.py +5 -2
- mindsdb/api/executor/datahub/datanodes/integration_datanode.py +39 -72
- mindsdb/api/executor/planner/query_planner.py +10 -1
- mindsdb/api/executor/sql_query/result_set.py +185 -52
- mindsdb/api/executor/sql_query/sql_query.py +1 -1
- mindsdb/api/executor/sql_query/steps/apply_predictor_step.py +9 -12
- mindsdb/api/executor/sql_query/steps/fetch_dataframe.py +8 -10
- mindsdb/api/executor/sql_query/steps/fetch_dataframe_partition.py +5 -44
- mindsdb/api/executor/sql_query/steps/insert_step.py +24 -15
- mindsdb/api/executor/sql_query/steps/join_step.py +1 -1
- mindsdb/api/executor/sql_query/steps/project_step.py +1 -1
- mindsdb/api/executor/sql_query/steps/sql_steps.py +1 -1
- mindsdb/api/executor/sql_query/steps/subselect_step.py +4 -8
- mindsdb/api/executor/sql_query/steps/union_step.py +1 -3
- mindsdb/api/http/initialize.py +99 -83
- mindsdb/api/http/namespaces/analysis.py +3 -3
- mindsdb/api/http/namespaces/file.py +8 -2
- mindsdb/api/http/namespaces/sql.py +13 -27
- mindsdb/api/mcp/start.py +42 -5
- mindsdb/api/mysql/mysql_proxy/data_types/mysql_packet.py +0 -1
- mindsdb/api/mysql/mysql_proxy/data_types/mysql_packets/binary_resultset_row_package.py +52 -19
- mindsdb/api/mysql/mysql_proxy/executor/mysql_executor.py +8 -10
- mindsdb/api/mysql/mysql_proxy/libs/constants/mysql.py +54 -38
- mindsdb/api/mysql/mysql_proxy/mysql_proxy.py +82 -115
- mindsdb/api/mysql/mysql_proxy/utilities/dump.py +351 -0
- mindsdb/api/postgres/postgres_proxy/executor/executor.py +1 -1
- mindsdb/api/postgres/postgres_proxy/postgres_proxy.py +5 -6
- mindsdb/integrations/handlers/altibase_handler/altibase_handler.py +26 -27
- mindsdb/integrations/handlers/altibase_handler/connection_args.py +13 -13
- mindsdb/integrations/handlers/altibase_handler/tests/test_altibase_handler.py +8 -8
- mindsdb/integrations/handlers/altibase_handler/tests/test_altibase_handler_dsn.py +13 -13
- mindsdb/integrations/handlers/anthropic_handler/__init__.py +2 -2
- mindsdb/integrations/handlers/anthropic_handler/anthropic_handler.py +1 -3
- mindsdb/integrations/handlers/aurora_handler/aurora_handler.py +1 -0
- mindsdb/integrations/handlers/autosklearn_handler/autosklearn_handler.py +1 -1
- mindsdb/integrations/handlers/autosklearn_handler/config.py +0 -1
- mindsdb/integrations/handlers/bigquery_handler/bigquery_handler.py +1 -1
- mindsdb/integrations/handlers/bigquery_handler/tests/test_bigquery_handler.py +1 -1
- mindsdb/integrations/handlers/binance_handler/binance_handler.py +1 -0
- mindsdb/integrations/handlers/binance_handler/binance_tables.py +3 -4
- mindsdb/integrations/handlers/byom_handler/__init__.py +0 -1
- mindsdb/integrations/handlers/ckan_handler/ckan_handler.py +3 -0
- mindsdb/integrations/handlers/clickhouse_handler/__init__.py +1 -1
- mindsdb/integrations/handlers/cloud_spanner_handler/tests/test_cloud_spanner_handler.py +0 -2
- mindsdb/integrations/handlers/cloud_sql_handler/cloud_sql_handler.py +0 -1
- mindsdb/integrations/handlers/cohere_handler/__init__.py +1 -1
- mindsdb/integrations/handlers/cohere_handler/cohere_handler.py +11 -13
- mindsdb/integrations/handlers/confluence_handler/confluence_tables.py +6 -0
- mindsdb/integrations/handlers/databend_handler/connection_args.py +1 -1
- mindsdb/integrations/handlers/databend_handler/databend_handler.py +4 -4
- mindsdb/integrations/handlers/databend_handler/tests/__init__.py +0 -1
- mindsdb/integrations/handlers/databend_handler/tests/test_databend_handler.py +1 -1
- mindsdb/integrations/handlers/derby_handler/connection_args.py +1 -1
- mindsdb/integrations/handlers/derby_handler/derby_handler.py +14 -22
- mindsdb/integrations/handlers/derby_handler/tests/test_derby_handler.py +6 -6
- mindsdb/integrations/handlers/discord_handler/discord_handler.py +5 -5
- mindsdb/integrations/handlers/discord_handler/discord_tables.py +3 -3
- mindsdb/integrations/handlers/discord_handler/tests/test_discord.py +5 -3
- mindsdb/integrations/handlers/dockerhub_handler/dockerhub.py +3 -3
- mindsdb/integrations/handlers/dockerhub_handler/dockerhub_handler.py +2 -2
- mindsdb/integrations/handlers/dockerhub_handler/dockerhub_tables.py +57 -54
- mindsdb/integrations/handlers/dremio_handler/__init__.py +2 -2
- mindsdb/integrations/handlers/druid_handler/__init__.py +1 -1
- mindsdb/integrations/handlers/druid_handler/druid_handler.py +2 -2
- mindsdb/integrations/handlers/edgelessdb_handler/tests/test_edgelessdb_handler.py +9 -9
- mindsdb/integrations/handlers/email_handler/email_client.py +1 -1
- mindsdb/integrations/handlers/email_handler/email_ingestor.py +1 -1
- mindsdb/integrations/handlers/email_handler/email_tables.py +0 -1
- mindsdb/integrations/handlers/email_handler/settings.py +0 -1
- mindsdb/integrations/handlers/eventstoredb_handler/eventstoredb_handler.py +2 -1
- mindsdb/integrations/handlers/firebird_handler/firebird_handler.py +1 -1
- mindsdb/integrations/handlers/flaml_handler/flaml_handler.py +9 -9
- mindsdb/integrations/handlers/frappe_handler/frappe_client.py +5 -5
- mindsdb/integrations/handlers/frappe_handler/frappe_handler.py +6 -5
- mindsdb/integrations/handlers/frappe_handler/frappe_tables.py +2 -2
- mindsdb/integrations/handlers/github_handler/connection_args.py +2 -2
- mindsdb/integrations/handlers/github_handler/github_handler.py +1 -8
- mindsdb/integrations/handlers/github_handler/github_tables.py +13 -24
- mindsdb/integrations/handlers/gitlab_handler/gitlab_handler.py +2 -1
- mindsdb/integrations/handlers/gitlab_handler/gitlab_tables.py +1 -4
- mindsdb/integrations/handlers/gmail_handler/gmail_handler.py +6 -13
- mindsdb/integrations/handlers/google_books_handler/google_books_handler.py +2 -1
- mindsdb/integrations/handlers/google_books_handler/google_books_tables.py +0 -3
- mindsdb/integrations/handlers/google_calendar_handler/google_calendar_handler.py +4 -4
- mindsdb/integrations/handlers/google_calendar_handler/google_calendar_tables.py +2 -6
- mindsdb/integrations/handlers/google_content_shopping_handler/google_content_shopping_handler.py +3 -2
- mindsdb/integrations/handlers/google_content_shopping_handler/google_content_shopping_tables.py +0 -3
- mindsdb/integrations/handlers/google_fit_handler/google_fit_handler.py +10 -12
- mindsdb/integrations/handlers/google_fit_handler/google_fit_tables.py +11 -13
- mindsdb/integrations/handlers/google_search_handler/google_search_handler.py +2 -1
- mindsdb/integrations/handlers/google_search_handler/google_search_tables.py +0 -3
- mindsdb/integrations/handlers/groq_handler/__init__.py +3 -3
- mindsdb/integrations/handlers/hackernews_handler/hn_handler.py +5 -7
- mindsdb/integrations/handlers/hackernews_handler/hn_table.py +6 -7
- mindsdb/integrations/handlers/hive_handler/tests/test_hive_handler.py +1 -1
- mindsdb/integrations/handlers/hsqldb_handler/connection_args.py +6 -6
- mindsdb/integrations/handlers/hsqldb_handler/hsqldb_handler.py +4 -3
- mindsdb/integrations/handlers/huggingface_api_handler/exceptions.py +1 -1
- mindsdb/integrations/handlers/huggingface_api_handler/huggingface_api_handler.py +1 -8
- mindsdb/integrations/handlers/huggingface_handler/huggingface_handler.py +6 -6
- mindsdb/integrations/handlers/huggingface_handler/requirements.txt +1 -1
- mindsdb/integrations/handlers/huggingface_handler/requirements_cpu.txt +1 -1
- mindsdb/integrations/handlers/ignite_handler/ignite_handler.py +2 -1
- mindsdb/integrations/handlers/impala_handler/impala_handler.py +9 -12
- mindsdb/integrations/handlers/impala_handler/tests/test_impala_handler.py +11 -11
- mindsdb/integrations/handlers/influxdb_handler/influxdb_handler.py +10 -13
- mindsdb/integrations/handlers/influxdb_handler/influxdb_tables.py +20 -20
- mindsdb/integrations/handlers/informix_handler/__about__.py +8 -8
- mindsdb/integrations/handlers/informix_handler/__init__.py +12 -5
- mindsdb/integrations/handlers/informix_handler/informix_handler.py +99 -133
- mindsdb/integrations/handlers/informix_handler/tests/test_informix_handler.py +13 -11
- mindsdb/integrations/handlers/ingres_handler/__about__.py +0 -1
- mindsdb/integrations/handlers/ingres_handler/ingres_handler.py +1 -0
- mindsdb/integrations/handlers/jira_handler/jira_handler.py +4 -4
- mindsdb/integrations/handlers/jira_handler/jira_tables.py +9 -9
- mindsdb/integrations/handlers/kinetica_handler/__init__.py +0 -1
- mindsdb/integrations/handlers/langchain_handler/langchain_handler.py +4 -4
- mindsdb/integrations/handlers/langchain_handler/tools.py +9 -10
- mindsdb/integrations/handlers/leonardoai_handler/__init__.py +1 -1
- mindsdb/integrations/handlers/lightwood_handler/functions.py +2 -2
- mindsdb/integrations/handlers/lightwood_handler/lightwood_handler.py +0 -1
- mindsdb/integrations/handlers/lightwood_handler/tests/test_lightwood_handler.py +11 -11
- mindsdb/integrations/handlers/llama_index_handler/llama_index_handler.py +4 -4
- mindsdb/integrations/handlers/llama_index_handler/settings.py +10 -9
- mindsdb/integrations/handlers/materialize_handler/tests/test_materialize_handler.py +8 -10
- mindsdb/integrations/handlers/matrixone_handler/matrixone_handler.py +4 -4
- mindsdb/integrations/handlers/matrixone_handler/tests/test_matrixone_handler.py +8 -9
- mindsdb/integrations/handlers/maxdb_handler/connection_args.py +25 -25
- mindsdb/integrations/handlers/maxdb_handler/maxdb_handler.py +1 -0
- mindsdb/integrations/handlers/mediawiki_handler/mediawiki_handler.py +3 -2
- mindsdb/integrations/handlers/mediawiki_handler/mediawiki_tables.py +1 -1
- mindsdb/integrations/handlers/mendeley_handler/__about__.py +1 -1
- mindsdb/integrations/handlers/mendeley_handler/__init__.py +2 -2
- mindsdb/integrations/handlers/mendeley_handler/mendeley_handler.py +48 -56
- mindsdb/integrations/handlers/mendeley_handler/mendeley_tables.py +24 -29
- mindsdb/integrations/handlers/mendeley_handler/tests/test_mendeley_handler.py +19 -17
- mindsdb/integrations/handlers/merlion_handler/merlion_handler.py +5 -4
- mindsdb/integrations/handlers/minds_endpoint_handler/__init__.py +3 -3
- mindsdb/integrations/handlers/mlflow_handler/mlflow_handler.py +58 -36
- mindsdb/integrations/handlers/monetdb_handler/__about__.py +8 -8
- mindsdb/integrations/handlers/monetdb_handler/__init__.py +15 -5
- mindsdb/integrations/handlers/monetdb_handler/connection_args.py +17 -18
- mindsdb/integrations/handlers/monetdb_handler/monetdb_handler.py +40 -57
- mindsdb/integrations/handlers/monetdb_handler/tests/test_monetdb_handler.py +7 -8
- mindsdb/integrations/handlers/monetdb_handler/utils/monet_get_id.py +13 -14
- mindsdb/integrations/handlers/monkeylearn_handler/__about__.py +1 -1
- mindsdb/integrations/handlers/monkeylearn_handler/__init__.py +1 -1
- mindsdb/integrations/handlers/monkeylearn_handler/monkeylearn_handler.py +2 -5
- mindsdb/integrations/handlers/ms_one_drive_handler/ms_graph_api_one_drive_client.py +1 -0
- mindsdb/integrations/handlers/ms_one_drive_handler/ms_one_drive_handler.py +1 -1
- mindsdb/integrations/handlers/ms_teams_handler/ms_graph_api_teams_client.py +23 -23
- mindsdb/integrations/handlers/ms_teams_handler/ms_teams_handler.py +3 -3
- mindsdb/integrations/handlers/ms_teams_handler/ms_teams_tables.py +10 -5
- mindsdb/integrations/handlers/mssql_handler/mssql_handler.py +73 -8
- mindsdb/integrations/handlers/mysql_handler/__about__.py +8 -8
- mindsdb/integrations/handlers/mysql_handler/__init__.py +15 -5
- mindsdb/integrations/handlers/mysql_handler/connection_args.py +43 -47
- mindsdb/integrations/handlers/mysql_handler/mysql_handler.py +101 -34
- mindsdb/integrations/handlers/mysql_handler/settings.py +15 -13
- mindsdb/integrations/handlers/neuralforecast_handler/neuralforecast_handler.py +1 -1
- mindsdb/integrations/handlers/newsapi_handler/newsapi_handler.py +1 -1
- mindsdb/integrations/handlers/newsapi_handler/tests/test_newsapi_handler.py +4 -4
- mindsdb/integrations/handlers/nuo_jdbc_handler/connection_args.py +2 -2
- mindsdb/integrations/handlers/nuo_jdbc_handler/nuo_jdbc_handler.py +28 -36
- mindsdb/integrations/handlers/nuo_jdbc_handler/tests/test_nuo_handler.py +5 -5
- mindsdb/integrations/handlers/oceanbase_handler/oceanbase_handler.py +0 -1
- mindsdb/integrations/handlers/oceanbase_handler/tests/test_oceanbase_handler.py +8 -10
- mindsdb/integrations/handlers/ollama_handler/ollama_handler.py +3 -3
- mindsdb/integrations/handlers/opengauss_handler/tests/test_opengauss_handler.py +1 -2
- mindsdb/integrations/handlers/openstreetmap_handler/__init__.py +7 -7
- mindsdb/integrations/handlers/oracle_handler/connection_args.py +6 -0
- mindsdb/integrations/handlers/oracle_handler/oracle_handler.py +77 -11
- mindsdb/integrations/handlers/orioledb_handler/tests/test_orioledb_handler.py +8 -10
- mindsdb/integrations/handlers/palm_handler/__about__.py +1 -1
- mindsdb/integrations/handlers/palm_handler/__init__.py +1 -1
- mindsdb/integrations/handlers/palm_handler/palm_handler.py +1 -3
- mindsdb/integrations/handlers/paypal_handler/paypal_handler.py +2 -2
- mindsdb/integrations/handlers/paypal_handler/paypal_tables.py +15 -14
- mindsdb/integrations/handlers/pgvector_handler/pgvector_handler.py +53 -10
- mindsdb/integrations/handlers/phoenix_handler/__init__.py +1 -1
- mindsdb/integrations/handlers/phoenix_handler/phoenix_handler.py +1 -0
- mindsdb/integrations/handlers/pinot_handler/__init__.py +1 -1
- mindsdb/integrations/handlers/pinot_handler/pinot_handler.py +3 -2
- mindsdb/integrations/handlers/plaid_handler/plaid_handler.py +13 -13
- mindsdb/integrations/handlers/plaid_handler/plaid_tables.py +10 -12
- mindsdb/integrations/handlers/plaid_handler/utils.py +4 -6
- mindsdb/integrations/handlers/planetscale_handler/planetscale_handler.py +1 -4
- mindsdb/integrations/handlers/portkey_handler/__init__.py +2 -2
- mindsdb/integrations/handlers/postgres_handler/postgres_handler.py +105 -24
- mindsdb/integrations/handlers/postgres_handler/tests/test_postgres_handler.py +11 -6
- mindsdb/integrations/handlers/questdb_handler/questdb_handler.py +1 -2
- mindsdb/integrations/handlers/questdb_handler/tests/test_questdb_handler.py +2 -3
- mindsdb/integrations/handlers/quickbooks_handler/quickbooks_handler.py +6 -8
- mindsdb/integrations/handlers/quickbooks_handler/quickbooks_table.py +10 -10
- mindsdb/integrations/handlers/rag_handler/ingest.py +2 -2
- mindsdb/integrations/handlers/rag_handler/rag_handler.py +1 -1
- mindsdb/integrations/handlers/rag_handler/settings.py +1 -1
- mindsdb/integrations/handlers/reddit_handler/reddit_handler.py +2 -7
- mindsdb/integrations/handlers/reddit_handler/reddit_tables.py +2 -3
- mindsdb/integrations/handlers/replicate_handler/replicate_handler.py +6 -6
- mindsdb/integrations/handlers/rocket_chat_handler/rocket_chat_handler.py +1 -2
- mindsdb/integrations/handlers/rocket_chat_handler/rocket_chat_tables.py +0 -3
- mindsdb/integrations/handlers/rockset_handler/connection_args.py +14 -14
- mindsdb/integrations/handlers/rockset_handler/tests/test_rockset_handler.py +1 -0
- mindsdb/integrations/handlers/scylla_handler/scylla_handler.py +6 -5
- mindsdb/integrations/handlers/sendinblue_handler/sendinblue_handler.py +2 -1
- mindsdb/integrations/handlers/sendinblue_handler/sendinblue_tables.py +16 -16
- mindsdb/integrations/handlers/sentence_transformers_handler/__init__.py +1 -1
- mindsdb/integrations/handlers/sheets_handler/connection_args.py +1 -1
- mindsdb/integrations/handlers/shopify_handler/shopify_handler.py +7 -6
- mindsdb/integrations/handlers/shopify_handler/shopify_tables.py +38 -41
- mindsdb/integrations/handlers/singlestore_handler/__about__.py +1 -1
- mindsdb/integrations/handlers/singlestore_handler/__init__.py +0 -1
- mindsdb/integrations/handlers/singlestore_handler/singlestore_handler.py +1 -0
- mindsdb/integrations/handlers/singlestore_handler/tests/test_singlestore_handler.py +3 -3
- mindsdb/integrations/handlers/slack_handler/__init__.py +3 -3
- mindsdb/integrations/handlers/snowflake_handler/snowflake_handler.py +100 -6
- mindsdb/integrations/handlers/solr_handler/connection_args.py +7 -7
- mindsdb/integrations/handlers/solr_handler/solr_handler.py +2 -1
- mindsdb/integrations/handlers/solr_handler/tests/test_solr_handler.py +2 -1
- mindsdb/integrations/handlers/sqlany_handler/sqlany_handler.py +3 -2
- mindsdb/integrations/handlers/sqlite_handler/sqlite_handler.py +1 -0
- mindsdb/integrations/handlers/sqreamdb_handler/connection_args.py +1 -1
- mindsdb/integrations/handlers/sqreamdb_handler/sqreamdb_handler.py +15 -20
- mindsdb/integrations/handlers/sqreamdb_handler/tests/test_sqreamdb_handler.py +4 -4
- mindsdb/integrations/handlers/stabilityai_handler/__init__.py +1 -1
- mindsdb/integrations/handlers/starrocks_handler/starrocks_handler.py +0 -1
- mindsdb/integrations/handlers/starrocks_handler/tests/test_starrocks_handler.py +8 -10
- mindsdb/integrations/handlers/statsforecast_handler/statsforecast_handler.py +2 -2
- mindsdb/integrations/handlers/strava_handler/strava_handler.py +4 -8
- mindsdb/integrations/handlers/strava_handler/strava_tables.py +22 -30
- mindsdb/integrations/handlers/stripe_handler/stripe_handler.py +3 -2
- mindsdb/integrations/handlers/stripe_handler/stripe_tables.py +11 -27
- mindsdb/integrations/handlers/supabase_handler/tests/test_supabase_handler.py +1 -1
- mindsdb/integrations/handlers/surrealdb_handler/surrealdb_handler.py +4 -4
- mindsdb/integrations/handlers/tdengine_handler/tdengine_handler.py +25 -27
- mindsdb/integrations/handlers/tdengine_handler/tests/test_tdengine_handler.py +8 -8
- mindsdb/integrations/handlers/tidb_handler/tests/test_tidb_handler.py +1 -2
- mindsdb/integrations/handlers/timegpt_handler/timegpt_handler.py +5 -5
- mindsdb/integrations/handlers/tpot_handler/tpot_handler.py +21 -26
- mindsdb/integrations/handlers/trino_handler/trino_handler.py +14 -14
- mindsdb/integrations/handlers/twitter_handler/twitter_handler.py +2 -4
- mindsdb/integrations/handlers/unify_handler/tests/test_unify_handler.py +7 -8
- mindsdb/integrations/handlers/unify_handler/unify_handler.py +9 -9
- mindsdb/integrations/handlers/vertex_handler/vertex_client.py +1 -1
- mindsdb/integrations/handlers/vertica_handler/tests/test_vertica_handler.py +11 -11
- mindsdb/integrations/handlers/vertica_handler/vertica_handler.py +11 -14
- mindsdb/integrations/handlers/vitess_handler/tests/test_vitess_handler.py +9 -11
- mindsdb/integrations/handlers/vitess_handler/vitess_handler.py +0 -1
- mindsdb/integrations/handlers/web_handler/web_handler.py +1 -0
- mindsdb/integrations/handlers/whatsapp_handler/__init__.py +3 -3
- mindsdb/integrations/handlers/writer_handler/evaluate.py +1 -1
- mindsdb/integrations/handlers/writer_handler/settings.py +0 -1
- mindsdb/integrations/handlers/writer_handler/writer_handler.py +1 -0
- mindsdb/integrations/handlers/youtube_handler/youtube_handler.py +5 -5
- mindsdb/integrations/handlers/youtube_handler/youtube_tables.py +26 -27
- mindsdb/integrations/handlers/yugabyte_handler/tests/test_yugabyte_handler.py +3 -3
- mindsdb/integrations/handlers/yugabyte_handler/yugabyte_handler.py +0 -6
- mindsdb/integrations/libs/response.py +67 -52
- mindsdb/integrations/libs/vectordatabase_handler.py +6 -0
- mindsdb/integrations/utilities/handler_utils.py +15 -3
- mindsdb/integrations/utilities/handlers/api_utilities/__init__.py +0 -1
- mindsdb/integrations/utilities/handlers/auth_utilities/__init__.py +0 -2
- mindsdb/integrations/utilities/utils.py +3 -3
- mindsdb/interfaces/agents/agents_controller.py +164 -1
- mindsdb/interfaces/agents/constants.py +15 -0
- mindsdb/interfaces/agents/langchain_agent.py +16 -4
- mindsdb/interfaces/agents/mindsdb_database_agent.py +101 -2
- mindsdb/interfaces/knowledge_base/controller.py +25 -0
- mindsdb/interfaces/knowledge_base/preprocessing/document_preprocessor.py +13 -10
- mindsdb/interfaces/knowledge_base/preprocessing/json_chunker.py +434 -0
- mindsdb/interfaces/knowledge_base/preprocessing/models.py +54 -0
- mindsdb/interfaces/query_context/context_controller.py +66 -10
- mindsdb/interfaces/skills/custom/text2sql/mindsdb_kb_tools.py +190 -0
- mindsdb/interfaces/skills/custom/text2sql/mindsdb_sql_toolkit.py +92 -0
- mindsdb/interfaces/skills/skill_tool.py +202 -57
- mindsdb/interfaces/skills/sql_agent.py +205 -17
- mindsdb/interfaces/storage/fs.py +1 -0
- mindsdb/interfaces/variables/__init__.py +0 -0
- mindsdb/interfaces/variables/variables_controller.py +97 -0
- mindsdb/migrations/env.py +5 -7
- mindsdb/migrations/migrate.py +47 -7
- mindsdb/migrations/versions/2025-05-21_9f150e4f9a05_checkpoint_1.py +360 -0
- mindsdb/utilities/config.py +331 -219
- mindsdb/utilities/starters.py +13 -0
- {mindsdb-25.5.3.0.dist-info → mindsdb-25.5.4.0.dist-info}/METADATA +641 -695
- {mindsdb-25.5.3.0.dist-info → mindsdb-25.5.4.0.dist-info}/RECORD +309 -288
- {mindsdb-25.5.3.0.dist-info → mindsdb-25.5.4.0.dist-info}/WHEEL +1 -1
- mindsdb/integrations/handlers/monkeylearn_handler/requirements.txt +0 -1
- {mindsdb-25.5.3.0.dist-info → mindsdb-25.5.4.0.dist-info}/licenses/LICENSE +0 -0
- {mindsdb-25.5.3.0.dist-info → mindsdb-25.5.4.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import datetime
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
from numpy import dtype as np_dtype
|
|
7
|
+
import pandas as pd
|
|
8
|
+
from pandas.api import types as pd_types
|
|
9
|
+
|
|
10
|
+
from mindsdb.api.executor.sql_query.result_set import ResultSet, get_mysql_data_type_from_series, Column
|
|
11
|
+
from mindsdb.api.mysql.mysql_proxy.utilities.lightwood_dtype import dtype as lightwood_dtype
|
|
12
|
+
from mindsdb.api.mysql.mysql_proxy.libs.constants.mysql import MYSQL_DATA_TYPE, DATA_C_TYPE_MAP, CTypeProperties
|
|
13
|
+
from mindsdb.utilities import log
|
|
14
|
+
|
|
15
|
+
logger = log.getLogger(__name__)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def column_to_mysql_column_dict(column: Column, database_name: str | None = None) -> dict[str, str | int]:
|
|
19
|
+
"""Convert Column object to dict with column properties.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
column (Column): Column object to convert.
|
|
23
|
+
database_name (str | None): Name of the database.
|
|
24
|
+
|
|
25
|
+
Returns:
|
|
26
|
+
dict[str, str | int]: Dictionary with mysql column properties.
|
|
27
|
+
"""
|
|
28
|
+
# region infer type. Should not happen, but what if it is dtype of lightwood type?
|
|
29
|
+
if isinstance(column.type, str):
|
|
30
|
+
try:
|
|
31
|
+
column.type = MYSQL_DATA_TYPE(column.type)
|
|
32
|
+
except ValueError:
|
|
33
|
+
if column.type == lightwood_dtype.date:
|
|
34
|
+
column.type = MYSQL_DATA_TYPE.DATE
|
|
35
|
+
elif column.type == lightwood_dtype.datetime:
|
|
36
|
+
column.type = MYSQL_DATA_TYPE.DATETIME
|
|
37
|
+
elif column.type == lightwood_dtype.float:
|
|
38
|
+
column.type = MYSQL_DATA_TYPE.FLOAT
|
|
39
|
+
elif column.type == lightwood_dtype.integer:
|
|
40
|
+
column.type = MYSQL_DATA_TYPE.INT
|
|
41
|
+
else:
|
|
42
|
+
column.type = MYSQL_DATA_TYPE.TEXT
|
|
43
|
+
elif isinstance(column.type, np_dtype):
|
|
44
|
+
if pd_types.is_integer_dtype(column.type):
|
|
45
|
+
column.type = MYSQL_DATA_TYPE.INT
|
|
46
|
+
elif pd_types.is_numeric_dtype(column.type):
|
|
47
|
+
column.type = MYSQL_DATA_TYPE.FLOAT
|
|
48
|
+
elif pd_types.is_datetime64_any_dtype(column.type):
|
|
49
|
+
column.type = MYSQL_DATA_TYPE.DATETIME
|
|
50
|
+
else:
|
|
51
|
+
column.type = MYSQL_DATA_TYPE.TEXT
|
|
52
|
+
# endregion
|
|
53
|
+
|
|
54
|
+
if isinstance(column.type, MYSQL_DATA_TYPE) is False:
|
|
55
|
+
logger.warning(f'Unexpected column type: {column.type}. Use TEXT as fallback.')
|
|
56
|
+
column.type = MYSQL_DATA_TYPE.TEXT
|
|
57
|
+
|
|
58
|
+
type_properties: CTypeProperties = DATA_C_TYPE_MAP[column.type]
|
|
59
|
+
|
|
60
|
+
result = {
|
|
61
|
+
"database": column.database or database_name,
|
|
62
|
+
# TODO add 'original_table'
|
|
63
|
+
"table_name": column.table_name,
|
|
64
|
+
"name": column.name,
|
|
65
|
+
"alias": column.alias or column.name,
|
|
66
|
+
"size": type_properties.size,
|
|
67
|
+
"flags": type_properties.flags,
|
|
68
|
+
"type": type_properties.code,
|
|
69
|
+
}
|
|
70
|
+
return result
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def _dump_bool(var: Any) -> int | None:
|
|
74
|
+
"""Dumps a boolean value to an integer, as in MySQL boolean type is tinyint with values 0 and 1.
|
|
75
|
+
NOTE: None consider as True in dataframe with dtype=bool, we can't change it
|
|
76
|
+
|
|
77
|
+
Args:
|
|
78
|
+
var (Any): The boolean value to dump
|
|
79
|
+
|
|
80
|
+
Returns:
|
|
81
|
+
int | None: 1 or 0 or None
|
|
82
|
+
"""
|
|
83
|
+
if pd.isna(var):
|
|
84
|
+
return None
|
|
85
|
+
return '1' if var else '0'
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def _dump_str(var: Any) -> str | None:
|
|
89
|
+
"""Dumps a value to a string.
|
|
90
|
+
|
|
91
|
+
Args:
|
|
92
|
+
var (Any): The value to dump
|
|
93
|
+
|
|
94
|
+
Returns:
|
|
95
|
+
str | None: The string representation of the value or None if the value is None
|
|
96
|
+
"""
|
|
97
|
+
if pd.isna(var):
|
|
98
|
+
return None
|
|
99
|
+
if isinstance(var, bytes):
|
|
100
|
+
try:
|
|
101
|
+
return var.decode('utf-8')
|
|
102
|
+
except Exception:
|
|
103
|
+
return str(var)[2:-1]
|
|
104
|
+
if isinstance(var, dict):
|
|
105
|
+
try:
|
|
106
|
+
return json.dumps(var)
|
|
107
|
+
except Exception:
|
|
108
|
+
return str(var)
|
|
109
|
+
return str(var)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def _dump_int_or_str(var: Any) -> str | None:
|
|
113
|
+
"""Dumps a value to a string.
|
|
114
|
+
If the value is numeric - then cast it to int to avoid float representation.
|
|
115
|
+
|
|
116
|
+
Args:
|
|
117
|
+
var (Any): The value to dump.
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
str | None: The string representation of the value or None if the value is None
|
|
121
|
+
"""
|
|
122
|
+
if pd.isna(var):
|
|
123
|
+
return None
|
|
124
|
+
try:
|
|
125
|
+
return str(int(var))
|
|
126
|
+
except ValueError:
|
|
127
|
+
return str(var)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def _dump_date(var: datetime.date | str | None) -> str | None:
|
|
131
|
+
"""Dumps a date value to a string.
|
|
132
|
+
|
|
133
|
+
Args:
|
|
134
|
+
var (datetime.date | str | None): The date value to dump
|
|
135
|
+
|
|
136
|
+
Returns:
|
|
137
|
+
str | None: The string representation of the date value or None if the value is None
|
|
138
|
+
"""
|
|
139
|
+
if isinstance(var, (datetime.date, pd.Timestamp)): # it is also True for datetime.datetime
|
|
140
|
+
return var.strftime("%Y-%m-%d")
|
|
141
|
+
elif isinstance(var, str):
|
|
142
|
+
return var
|
|
143
|
+
elif pd.isna(var):
|
|
144
|
+
return None
|
|
145
|
+
logger.warning(f'Unexpected value type for DATE: {type(var)}, {var}')
|
|
146
|
+
return _dump_str(var)
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def _dump_datetime(var: datetime.datetime | str | None) -> str | None:
|
|
150
|
+
"""Dumps a datetime value to a string.
|
|
151
|
+
# NOTE mysql may display only %Y-%m-%d %H:%M:%S format for datetime column
|
|
152
|
+
|
|
153
|
+
Args:
|
|
154
|
+
var (datetime.datetime | str | None): The datetime value to dump
|
|
155
|
+
|
|
156
|
+
Returns:
|
|
157
|
+
str | None: The string representation of the datetime value or None if the value is None
|
|
158
|
+
"""
|
|
159
|
+
if isinstance(var, datetime.date): # it is also datetime.datetime
|
|
160
|
+
if hasattr(var, 'tzinfo') and var.tzinfo is not None:
|
|
161
|
+
return var.astimezone(datetime.timezone.utc).strftime("%Y-%m-%d %H:%M:%S")
|
|
162
|
+
return var.strftime("%Y-%m-%d %H:%M:%S")
|
|
163
|
+
elif isinstance(var, pd.Timestamp):
|
|
164
|
+
if var.tzinfo is not None:
|
|
165
|
+
return var.tz_convert('UTC').strftime("%Y-%m-%d %H:%M:%S")
|
|
166
|
+
return var.strftime("%Y-%m-%d %H:%M:%S")
|
|
167
|
+
elif isinstance(var, str):
|
|
168
|
+
return var
|
|
169
|
+
elif pd.isna(var):
|
|
170
|
+
return None
|
|
171
|
+
logger.warning(f'Unexpected value type for DATETIME: {type(var)}, {var}')
|
|
172
|
+
return _dump_str(var)
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def _dump_time(var: datetime.time | str | None) -> str | None:
|
|
176
|
+
"""Dumps a time value to a string.
|
|
177
|
+
|
|
178
|
+
Args:
|
|
179
|
+
var (datetime.time | str | None): The time value to dump
|
|
180
|
+
|
|
181
|
+
Returns:
|
|
182
|
+
str | None: The string representation of the time value or None if the value is None
|
|
183
|
+
"""
|
|
184
|
+
if isinstance(var, datetime.time):
|
|
185
|
+
if var.tzinfo is not None:
|
|
186
|
+
# NOTE strftime does not support timezone, so we need to convert to UTC
|
|
187
|
+
offset_seconds = var.tzinfo.utcoffset(None).total_seconds()
|
|
188
|
+
time_seconds = var.hour * 3600 + var.minute * 60 + var.second
|
|
189
|
+
utc_seconds = (time_seconds - offset_seconds) % (24 * 3600)
|
|
190
|
+
hours = int(utc_seconds // 3600)
|
|
191
|
+
minutes = int((utc_seconds % 3600) // 60)
|
|
192
|
+
seconds = int(utc_seconds % 60)
|
|
193
|
+
var = datetime.time(hours, minutes, seconds, var.microsecond)
|
|
194
|
+
return var.strftime("%H:%M:%S")
|
|
195
|
+
elif isinstance(var, datetime.datetime):
|
|
196
|
+
if var.tzinfo is not None:
|
|
197
|
+
return var.astimezone(datetime.timezone.utc).strftime("%H:%M:%S")
|
|
198
|
+
return var.strftime("%H:%M:%S")
|
|
199
|
+
elif isinstance(var, pd.Timestamp):
|
|
200
|
+
if var.tzinfo is not None:
|
|
201
|
+
return var.tz_convert('UTC').strftime("%H:%M:%S")
|
|
202
|
+
return var.strftime("%H:%M:%S")
|
|
203
|
+
elif isinstance(var, str):
|
|
204
|
+
return var
|
|
205
|
+
elif pd.isna(var):
|
|
206
|
+
return None
|
|
207
|
+
logger.warning(f'Unexpected value type for TIME: {type(var)}, {var}')
|
|
208
|
+
return _dump_str(var)
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def _handle_series_as_date(series: pd.Series) -> pd.Series:
|
|
212
|
+
"""Convert values in a series to a string representation of a date.
|
|
213
|
+
NOTE: MySQL require exactly %Y-%m-%d for DATE type.
|
|
214
|
+
|
|
215
|
+
Args:
|
|
216
|
+
series (pd.Series): The series to handle
|
|
217
|
+
|
|
218
|
+
Returns:
|
|
219
|
+
pd.Series: The series with the date values as strings
|
|
220
|
+
"""
|
|
221
|
+
if pd_types.is_datetime64_any_dtype(series.dtype):
|
|
222
|
+
return series.dt.strftime('%Y-%m-%d')
|
|
223
|
+
elif pd_types.is_object_dtype(series.dtype):
|
|
224
|
+
return series.apply(_dump_date)
|
|
225
|
+
logger.info(f'Unexpected dtype: {series.dtype} for column with type DATE')
|
|
226
|
+
return series.apply(_dump_str)
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def _handle_series_as_datetime(series: pd.Series) -> pd.Series:
|
|
230
|
+
"""Convert values in a series to a string representation of a datetime.
|
|
231
|
+
NOTE: MySQL's DATETIME type require exactly %Y-%m-%d %H:%M:%S format.
|
|
232
|
+
|
|
233
|
+
Args:
|
|
234
|
+
series (pd.Series): The series to handle
|
|
235
|
+
|
|
236
|
+
Returns:
|
|
237
|
+
pd.Series: The series with the datetime values as strings
|
|
238
|
+
"""
|
|
239
|
+
if pd_types.is_datetime64_any_dtype(series.dtype):
|
|
240
|
+
return series.dt.strftime('%Y-%m-%d %H:%M:%S')
|
|
241
|
+
elif pd_types.is_object_dtype(series.dtype):
|
|
242
|
+
return series.apply(_dump_datetime)
|
|
243
|
+
logger.info(f'Unexpected dtype: {series.dtype} for column with type DATETIME')
|
|
244
|
+
return series.apply(_dump_str)
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
def _handle_series_as_time(series: pd.Series) -> pd.Series:
|
|
248
|
+
"""Convert values in a series to a string representation of a time.
|
|
249
|
+
NOTE: MySQL's TIME type require exactly %H:%M:%S format.
|
|
250
|
+
|
|
251
|
+
Args:
|
|
252
|
+
series (pd.Series): The series to handle
|
|
253
|
+
|
|
254
|
+
Returns:
|
|
255
|
+
pd.Series: The series with the time values as strings
|
|
256
|
+
"""
|
|
257
|
+
if pd_types.is_timedelta64_ns_dtype(series.dtype):
|
|
258
|
+
base_time = pd.Timestamp('2000-01-01')
|
|
259
|
+
series = ((base_time + series).dt.strftime('%H:%M:%S'))
|
|
260
|
+
elif pd_types.is_datetime64_dtype(series.dtype):
|
|
261
|
+
series = series.dt.strftime('%H:%M:%S')
|
|
262
|
+
elif pd_types.is_object_dtype(series.dtype):
|
|
263
|
+
series = series.apply(_dump_time)
|
|
264
|
+
else:
|
|
265
|
+
logger.info(f'Unexpected dtype: {series.dtype} for column with type TIME')
|
|
266
|
+
series = series.apply(_dump_str)
|
|
267
|
+
return series
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
def _handle_series_as_int(series: pd.Series) -> pd.Series:
|
|
271
|
+
"""Dump series to str(int) (or just str, of can't case to int). This need because of DataFrame store imput int as
|
|
272
|
+
float if dtype is object: pd.DataFrame([None, 1], dtype='object') -> [NaN, 1.0]
|
|
273
|
+
|
|
274
|
+
Args:
|
|
275
|
+
series (pd.Series): The series to handle
|
|
276
|
+
|
|
277
|
+
Returns:
|
|
278
|
+
pd.Series: The series with the int values as strings
|
|
279
|
+
"""
|
|
280
|
+
if pd_types.is_integer_dtype(series.dtype):
|
|
281
|
+
if series.dtype == 'Int64':
|
|
282
|
+
# NOTE: 'apply' converts values to python floats
|
|
283
|
+
return series.astype(object).apply(_dump_str)
|
|
284
|
+
return series.apply(_dump_str)
|
|
285
|
+
return series.apply(_dump_int_or_str)
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
def dump_result_set_to_mysql(result_set: ResultSet, infer_column_size: bool = False) -> tuple[pd.DataFrame, list[dict[str, str | int]]]:
|
|
289
|
+
"""
|
|
290
|
+
Dumps the ResultSet to a format that can be used to send as MySQL response packet.
|
|
291
|
+
NOTE: This method modifies the original DataFrame and columns.
|
|
292
|
+
|
|
293
|
+
Args:
|
|
294
|
+
result_set (ResultSet): result set to dump
|
|
295
|
+
infer_column_size (bool): If True, infer the 'size' attribute of the column from the data.
|
|
296
|
+
Exact size is not necessary, approximate is enough.
|
|
297
|
+
|
|
298
|
+
Returns:
|
|
299
|
+
tuple[pd.DataFrame, list[dict[str, str | int]]]: A tuple containing the modified DataFrame and a list
|
|
300
|
+
of MySQL column dictionaries. The dataframe values are
|
|
301
|
+
str or None, dtype=object
|
|
302
|
+
"""
|
|
303
|
+
df = result_set.get_raw_df()
|
|
304
|
+
|
|
305
|
+
for i, column in enumerate(result_set.columns):
|
|
306
|
+
series = df[i]
|
|
307
|
+
if isinstance(column.type, MYSQL_DATA_TYPE) is False:
|
|
308
|
+
column.type = get_mysql_data_type_from_series(series)
|
|
309
|
+
|
|
310
|
+
column_type: MYSQL_DATA_TYPE = column.type
|
|
311
|
+
|
|
312
|
+
match column_type:
|
|
313
|
+
case MYSQL_DATA_TYPE.BOOL | MYSQL_DATA_TYPE.BOOLEAN:
|
|
314
|
+
series = series.apply(_dump_bool)
|
|
315
|
+
case MYSQL_DATA_TYPE.DATE:
|
|
316
|
+
series = _handle_series_as_date(series)
|
|
317
|
+
case MYSQL_DATA_TYPE.DATETIME:
|
|
318
|
+
series = _handle_series_as_datetime(series)
|
|
319
|
+
case MYSQL_DATA_TYPE.TIME:
|
|
320
|
+
series = _handle_series_as_time(series)
|
|
321
|
+
case (
|
|
322
|
+
MYSQL_DATA_TYPE.INT | MYSQL_DATA_TYPE.TINYINT | MYSQL_DATA_TYPE.SMALLINT
|
|
323
|
+
| MYSQL_DATA_TYPE.MEDIUMINT | MYSQL_DATA_TYPE.BIGINT | MYSQL_DATA_TYPE.YEAR
|
|
324
|
+
):
|
|
325
|
+
series = _handle_series_as_int(series)
|
|
326
|
+
case _:
|
|
327
|
+
series = series.apply(_dump_str)
|
|
328
|
+
|
|
329
|
+
# inplace modification of dt types raise SettingWithCopyWarning, so do regular replace
|
|
330
|
+
# we may split this operation for dt and other types for optimisation
|
|
331
|
+
df[i] = series.replace([np.NaN, pd.NA, pd.NaT], None)
|
|
332
|
+
|
|
333
|
+
columns_dicts = [
|
|
334
|
+
column_to_mysql_column_dict(column)
|
|
335
|
+
for column in result_set.columns
|
|
336
|
+
]
|
|
337
|
+
|
|
338
|
+
if infer_column_size and any(column_info.get('size') is None for column_info in columns_dicts):
|
|
339
|
+
if len(df) == 0:
|
|
340
|
+
for column_info in columns_dicts:
|
|
341
|
+
if column_info['size'] is None:
|
|
342
|
+
column_info['size'] = 1
|
|
343
|
+
else:
|
|
344
|
+
sample = df.head(100)
|
|
345
|
+
for i, column_info in enumerate(columns_dicts):
|
|
346
|
+
try:
|
|
347
|
+
column_info['size'] = sample[sample.columns[i]].astype(str).str.len().max()
|
|
348
|
+
except Exception:
|
|
349
|
+
column_info['size'] = 1
|
|
350
|
+
|
|
351
|
+
return df, columns_dicts
|
|
@@ -276,8 +276,7 @@ class PostgresProxyHandler(socketserver.StreamRequestHandler):
|
|
|
276
276
|
resp = SQLAnswer(
|
|
277
277
|
resp_type=RESPONSE_TYPE.TABLE,
|
|
278
278
|
state_track=executor.state_track,
|
|
279
|
-
|
|
280
|
-
data=executor.data,
|
|
279
|
+
result_set=executor.data,
|
|
281
280
|
status=executor.server_status
|
|
282
281
|
)
|
|
283
282
|
return resp
|
|
@@ -351,8 +350,8 @@ class PostgresProxyHandler(socketserver.StreamRequestHandler):
|
|
|
351
350
|
return strip_null_byte(sql).strip(';')
|
|
352
351
|
|
|
353
352
|
def return_table(self, sql_answer: SQLAnswer, row_descs=True):
|
|
354
|
-
fields = self.to_postgres_fields(sql_answer.columns)
|
|
355
|
-
rows = self.to_postgres_rows(sql_answer.
|
|
353
|
+
fields = self.to_postgres_fields(sql_answer.result_set.columns)
|
|
354
|
+
rows = self.to_postgres_rows(sql_answer.result_set)
|
|
356
355
|
if row_descs:
|
|
357
356
|
self.send(RowDescriptions(fields=fields))
|
|
358
357
|
self.send(DataRow(rows=rows))
|
|
@@ -376,8 +375,8 @@ class PostgresProxyHandler(socketserver.StreamRequestHandler):
|
|
|
376
375
|
def respond_from_sql_answer(self, sql, sql_answer: SQLAnswer, row_descs=True) -> bool:
|
|
377
376
|
# TODO Add command complete passthrough for Complex Queries that exceed row limit in one go
|
|
378
377
|
rows = 0
|
|
379
|
-
if sql_answer.
|
|
380
|
-
rows = len(sql_answer.
|
|
378
|
+
if sql_answer.result_set:
|
|
379
|
+
rows = len(sql_answer.result_set)
|
|
381
380
|
if RESPONSE_TYPE.OK == sql_answer.type:
|
|
382
381
|
return self.return_ok(sql, rows=rows)
|
|
383
382
|
elif RESPONSE_TYPE.TABLE == sql_answer.type:
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
from typing import
|
|
1
|
+
from typing import Optional
|
|
2
2
|
|
|
3
3
|
import jaydebeapi as jdbcconnector
|
|
4
4
|
from mindsdb_sql_parser import parse_sql
|
|
5
5
|
from mindsdb_sql_parser.ast.base import ASTNode
|
|
6
6
|
import pandas as pd
|
|
7
7
|
import pyodbc
|
|
8
|
-
import pyodbc
|
|
9
8
|
import numpy as np
|
|
10
9
|
|
|
11
10
|
from mindsdb.integrations.libs.base import DatabaseHandler
|
|
@@ -33,7 +32,7 @@ class AltibaseHandler(DatabaseHandler):
|
|
|
33
32
|
connection_data (dict): parameters for connecting to the database
|
|
34
33
|
"""
|
|
35
34
|
super().__init__(name)
|
|
36
|
-
|
|
35
|
+
|
|
37
36
|
self.parser = parse_sql
|
|
38
37
|
|
|
39
38
|
self.connection_args = connection_data
|
|
@@ -87,7 +86,7 @@ class AltibaseHandler(DatabaseHandler):
|
|
|
87
86
|
self.is_connected = True
|
|
88
87
|
except Exception as e:
|
|
89
88
|
logger.error(f"Error while connecting to {self.database}, {e}")
|
|
90
|
-
|
|
89
|
+
|
|
91
90
|
return self.connection
|
|
92
91
|
|
|
93
92
|
def connect_with_jdbc(self):
|
|
@@ -103,11 +102,11 @@ class AltibaseHandler(DatabaseHandler):
|
|
|
103
102
|
jdbc_url = f"jdbc:Altibase://{self.host}:{self.port}/{self.database}"
|
|
104
103
|
|
|
105
104
|
try:
|
|
106
|
-
if self.user and self.password and jar_location:
|
|
105
|
+
if self.user and self.password and jar_location:
|
|
107
106
|
connection = jdbcconnector.connect(jclassname=jdbc_class, url=jdbc_url, driver_args=[self.user, self.password], jars=str(jar_location).split(","))
|
|
108
|
-
elif self.user and self.password:
|
|
107
|
+
elif self.user and self.password:
|
|
109
108
|
connection = jdbcconnector.connect(jclassname=jdbc_class, url=jdbc_url, driver_args=[self.user, self.password])
|
|
110
|
-
elif jar_location:
|
|
109
|
+
elif jar_location:
|
|
111
110
|
connection = jdbcconnector.connect(jclassname=jdbc_class, url=jdbc_url, jars=jar_location.split(","))
|
|
112
111
|
else:
|
|
113
112
|
connection = jdbcconnector.connect(jclassname=jdbc_class, url=jdbc_url)
|
|
@@ -117,7 +116,7 @@ class AltibaseHandler(DatabaseHandler):
|
|
|
117
116
|
except Exception as e:
|
|
118
117
|
logger.error(f"Error while connecting to {self.database}, {e}")
|
|
119
118
|
raise e
|
|
120
|
-
|
|
119
|
+
|
|
121
120
|
return self.connection
|
|
122
121
|
|
|
123
122
|
def disconnect(self):
|
|
@@ -131,7 +130,7 @@ class AltibaseHandler(DatabaseHandler):
|
|
|
131
130
|
except Exception as e:
|
|
132
131
|
logger.error(f"Error while disconnecting to {self.database}, {e}")
|
|
133
132
|
return False
|
|
134
|
-
return True
|
|
133
|
+
return True
|
|
135
134
|
|
|
136
135
|
def check_connection(self) -> StatusResponse:
|
|
137
136
|
""" Check connection to the handler
|
|
@@ -168,7 +167,7 @@ class AltibaseHandler(DatabaseHandler):
|
|
|
168
167
|
try:
|
|
169
168
|
cur.execute(query)
|
|
170
169
|
if cur.description:
|
|
171
|
-
result = cur.fetchall()
|
|
170
|
+
result = cur.fetchall()
|
|
172
171
|
|
|
173
172
|
if self.dsn:
|
|
174
173
|
if len(result) > 0:
|
|
@@ -218,13 +217,13 @@ class AltibaseHandler(DatabaseHandler):
|
|
|
218
217
|
HandlerResponse
|
|
219
218
|
"""
|
|
220
219
|
query = '''
|
|
221
|
-
SELECT
|
|
222
|
-
TABLE_NAME,
|
|
223
|
-
TABLE_ID,
|
|
224
|
-
TABLE_TYPE
|
|
225
|
-
FROM
|
|
226
|
-
system_.sys_tables_
|
|
227
|
-
WHERE
|
|
220
|
+
SELECT
|
|
221
|
+
TABLE_NAME,
|
|
222
|
+
TABLE_ID,
|
|
223
|
+
TABLE_TYPE
|
|
224
|
+
FROM
|
|
225
|
+
system_.sys_tables_
|
|
226
|
+
WHERE
|
|
228
227
|
user_id = USER_ID();
|
|
229
228
|
'''
|
|
230
229
|
|
|
@@ -238,16 +237,16 @@ class AltibaseHandler(DatabaseHandler):
|
|
|
238
237
|
HandlerResponse
|
|
239
238
|
"""
|
|
240
239
|
query = f"""
|
|
241
|
-
SELECT
|
|
242
|
-
COLUMN_NAME,
|
|
243
|
-
DATA_TYPE
|
|
244
|
-
FROM
|
|
245
|
-
system_.sys_columns_ ct
|
|
246
|
-
inner join
|
|
247
|
-
system_.sys_tables_ tt
|
|
248
|
-
on ct.table_id=tt.table_id
|
|
249
|
-
where
|
|
240
|
+
SELECT
|
|
241
|
+
COLUMN_NAME,
|
|
242
|
+
DATA_TYPE
|
|
243
|
+
FROM
|
|
244
|
+
system_.sys_columns_ ct
|
|
245
|
+
inner join
|
|
246
|
+
system_.sys_tables_ tt
|
|
247
|
+
on ct.table_id=tt.table_id
|
|
248
|
+
where
|
|
250
249
|
tt.table_name = '{table_name.capitalize()}';
|
|
251
250
|
"""
|
|
252
|
-
|
|
251
|
+
|
|
253
252
|
return self.native_query(query)
|
|
@@ -4,47 +4,47 @@ from mindsdb.integrations.libs.const import HANDLER_CONNECTION_ARG_TYPE as ARG_T
|
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
connection_args = OrderedDict(
|
|
7
|
-
host
|
|
7
|
+
host={
|
|
8
8
|
'type': ARG_TYPE.STR,
|
|
9
9
|
'description': 'The host name or IP address of the Altibase server. NOTE: use \'127.0.0.1\' instead of \'localhost\' to connect to local server.'
|
|
10
10
|
},
|
|
11
|
-
port
|
|
11
|
+
port={
|
|
12
12
|
'type': ARG_TYPE.INT,
|
|
13
13
|
'description': 'The TCP/IP port of the Altibase server. Must be an integer.'
|
|
14
14
|
},
|
|
15
|
-
user
|
|
15
|
+
user={
|
|
16
16
|
'type': ARG_TYPE.STR,
|
|
17
17
|
'description': 'The user name used to authenticate with the Altibase server.'
|
|
18
18
|
},
|
|
19
|
-
password
|
|
19
|
+
password={
|
|
20
20
|
'type': ARG_TYPE.STR,
|
|
21
21
|
'description': 'The password to authenticate the user with the Altibase server.',
|
|
22
22
|
'secret': True
|
|
23
23
|
},
|
|
24
|
-
database
|
|
24
|
+
database={
|
|
25
25
|
'type': ARG_TYPE.STR,
|
|
26
26
|
'description': 'The database name to use when connecting with the Altibase server.'
|
|
27
27
|
},
|
|
28
|
-
jdbc_class
|
|
28
|
+
jdbc_class={
|
|
29
29
|
'type': ARG_TYPE.STR,
|
|
30
30
|
'description': 'The driver class of the Altibase JDBC driver'
|
|
31
31
|
},
|
|
32
|
-
jar_location
|
|
32
|
+
jar_location={
|
|
33
33
|
'type': ARG_TYPE.PATH,
|
|
34
34
|
'description': 'The location of the Altibase JDBC driver jar file'
|
|
35
35
|
},
|
|
36
|
-
dsn
|
|
36
|
+
dsn={
|
|
37
37
|
'type': ARG_TYPE.STR,
|
|
38
38
|
'description': 'Datasource name of the Altibase server. NOTE: use dsn if you want to use an ODBC connection.'
|
|
39
39
|
}
|
|
40
40
|
)
|
|
41
41
|
|
|
42
42
|
connection_args_example = OrderedDict(
|
|
43
|
-
host
|
|
44
|
-
port
|
|
45
|
-
user
|
|
46
|
-
password
|
|
47
|
-
database
|
|
43
|
+
host='127.0.0.1',
|
|
44
|
+
port=20300,
|
|
45
|
+
user='sys',
|
|
46
|
+
password='manager',
|
|
47
|
+
database='mydb',
|
|
48
48
|
jdbc_class='Altibase.jdbc.driver.AltibaseDriver',
|
|
49
49
|
jar_location='/data/altibase_home/lib/Altibase.jar'
|
|
50
50
|
)
|
|
@@ -2,6 +2,7 @@ import unittest
|
|
|
2
2
|
from mindsdb.integrations.handlers.altibase_handler.altibase_handler import AltibaseHandler
|
|
3
3
|
from mindsdb.api.executor.data_types.response_type import RESPONSE_TYPE
|
|
4
4
|
|
|
5
|
+
|
|
5
6
|
class AltibaseHandlerTest(unittest.TestCase):
|
|
6
7
|
@classmethod
|
|
7
8
|
def setUpClass(cls):
|
|
@@ -18,7 +19,7 @@ class AltibaseHandlerTest(unittest.TestCase):
|
|
|
18
19
|
|
|
19
20
|
def test_0_connect(self):
|
|
20
21
|
assert self.handler.connect()
|
|
21
|
-
|
|
22
|
+
|
|
22
23
|
def test_1_drop_table(self):
|
|
23
24
|
# Not supported 'IF EXISTS' syntax
|
|
24
25
|
res = self.handler.query("DROP TABLE TEST_TABLE")
|
|
@@ -27,20 +28,20 @@ class AltibaseHandlerTest(unittest.TestCase):
|
|
|
27
28
|
def test_2_create_table(self):
|
|
28
29
|
res = self.handler.query(
|
|
29
30
|
'''CREATE TABLE TEST_TABLE (
|
|
30
|
-
ID INT PRIMARY KEY,
|
|
31
|
+
ID INT PRIMARY KEY,
|
|
31
32
|
NAME VARCHAR(14)
|
|
32
33
|
)'''
|
|
33
|
-
|
|
34
|
+
)
|
|
34
35
|
assert res.type is RESPONSE_TYPE.OK
|
|
35
36
|
|
|
36
37
|
def test_3_insert(self):
|
|
37
38
|
res = self.handler.query(
|
|
38
|
-
"""INSERT INTO TEST_TABLE
|
|
39
|
-
VALUES
|
|
39
|
+
"""INSERT INTO TEST_TABLE
|
|
40
|
+
VALUES
|
|
40
41
|
(100,'ONE HUNDRED'),
|
|
41
42
|
(200,'TWO HUNDRED'),
|
|
42
43
|
(300,'THREE HUNDRED')"""
|
|
43
|
-
|
|
44
|
+
)
|
|
44
45
|
assert res.type is RESPONSE_TYPE.OK
|
|
45
46
|
|
|
46
47
|
def test_4_select(self):
|
|
@@ -60,8 +61,7 @@ class AltibaseHandlerTest(unittest.TestCase):
|
|
|
60
61
|
|
|
61
62
|
def test_8_disconnect(self):
|
|
62
63
|
assert self.handler.disconnect()
|
|
63
|
-
|
|
64
64
|
|
|
65
|
-
|
|
65
|
+
|
|
66
66
|
if __name__ == '__main__':
|
|
67
67
|
unittest.main()
|