MindsDB 25.5.3.0__py3-none-any.whl → 25.5.4.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.

Files changed (313) hide show
  1. mindsdb/__about__.py +8 -8
  2. mindsdb/__main__.py +127 -79
  3. mindsdb/api/a2a/__init__.py +0 -0
  4. mindsdb/api/a2a/__main__.py +144 -0
  5. mindsdb/api/a2a/agent.py +308 -0
  6. mindsdb/api/a2a/common/__init__.py +0 -0
  7. mindsdb/api/a2a/common/server/__init__.py +4 -0
  8. mindsdb/api/a2a/common/server/server.py +164 -0
  9. mindsdb/api/a2a/common/server/task_manager.py +287 -0
  10. mindsdb/api/a2a/common/server/utils.py +28 -0
  11. mindsdb/api/a2a/common/types.py +365 -0
  12. mindsdb/api/a2a/constants.py +9 -0
  13. mindsdb/api/a2a/run_a2a.py +86 -0
  14. mindsdb/api/a2a/task_manager.py +560 -0
  15. mindsdb/api/executor/command_executor.py +185 -309
  16. mindsdb/api/executor/datahub/classes/response.py +5 -2
  17. mindsdb/api/executor/datahub/datanodes/integration_datanode.py +39 -72
  18. mindsdb/api/executor/planner/query_planner.py +10 -1
  19. mindsdb/api/executor/sql_query/result_set.py +185 -52
  20. mindsdb/api/executor/sql_query/sql_query.py +1 -1
  21. mindsdb/api/executor/sql_query/steps/apply_predictor_step.py +9 -12
  22. mindsdb/api/executor/sql_query/steps/fetch_dataframe.py +8 -10
  23. mindsdb/api/executor/sql_query/steps/fetch_dataframe_partition.py +5 -44
  24. mindsdb/api/executor/sql_query/steps/insert_step.py +24 -15
  25. mindsdb/api/executor/sql_query/steps/join_step.py +1 -1
  26. mindsdb/api/executor/sql_query/steps/project_step.py +1 -1
  27. mindsdb/api/executor/sql_query/steps/sql_steps.py +1 -1
  28. mindsdb/api/executor/sql_query/steps/subselect_step.py +4 -8
  29. mindsdb/api/executor/sql_query/steps/union_step.py +1 -3
  30. mindsdb/api/http/initialize.py +99 -83
  31. mindsdb/api/http/namespaces/analysis.py +3 -3
  32. mindsdb/api/http/namespaces/config.py +61 -86
  33. mindsdb/api/http/namespaces/file.py +8 -2
  34. mindsdb/api/http/namespaces/sql.py +13 -27
  35. mindsdb/api/mcp/start.py +42 -5
  36. mindsdb/api/mysql/mysql_proxy/data_types/mysql_packet.py +0 -1
  37. mindsdb/api/mysql/mysql_proxy/data_types/mysql_packets/binary_resultset_row_package.py +52 -19
  38. mindsdb/api/mysql/mysql_proxy/executor/mysql_executor.py +8 -10
  39. mindsdb/api/mysql/mysql_proxy/libs/constants/mysql.py +54 -38
  40. mindsdb/api/mysql/mysql_proxy/mysql_proxy.py +82 -115
  41. mindsdb/api/mysql/mysql_proxy/utilities/dump.py +351 -0
  42. mindsdb/api/postgres/postgres_proxy/executor/executor.py +1 -1
  43. mindsdb/api/postgres/postgres_proxy/postgres_proxy.py +5 -6
  44. mindsdb/integrations/handlers/altibase_handler/altibase_handler.py +26 -27
  45. mindsdb/integrations/handlers/altibase_handler/connection_args.py +13 -13
  46. mindsdb/integrations/handlers/altibase_handler/tests/test_altibase_handler.py +8 -8
  47. mindsdb/integrations/handlers/altibase_handler/tests/test_altibase_handler_dsn.py +13 -13
  48. mindsdb/integrations/handlers/anthropic_handler/__init__.py +2 -2
  49. mindsdb/integrations/handlers/anthropic_handler/anthropic_handler.py +1 -3
  50. mindsdb/integrations/handlers/aurora_handler/aurora_handler.py +1 -0
  51. mindsdb/integrations/handlers/autosklearn_handler/autosklearn_handler.py +1 -1
  52. mindsdb/integrations/handlers/autosklearn_handler/config.py +0 -1
  53. mindsdb/integrations/handlers/bigquery_handler/bigquery_handler.py +1 -1
  54. mindsdb/integrations/handlers/bigquery_handler/tests/test_bigquery_handler.py +1 -1
  55. mindsdb/integrations/handlers/binance_handler/binance_handler.py +1 -0
  56. mindsdb/integrations/handlers/binance_handler/binance_tables.py +3 -4
  57. mindsdb/integrations/handlers/byom_handler/__init__.py +0 -1
  58. mindsdb/integrations/handlers/byom_handler/requirements.txt +1 -2
  59. mindsdb/integrations/handlers/ckan_handler/ckan_handler.py +3 -0
  60. mindsdb/integrations/handlers/clickhouse_handler/__init__.py +1 -1
  61. mindsdb/integrations/handlers/cloud_spanner_handler/tests/test_cloud_spanner_handler.py +0 -2
  62. mindsdb/integrations/handlers/cloud_sql_handler/cloud_sql_handler.py +0 -1
  63. mindsdb/integrations/handlers/cohere_handler/__init__.py +1 -1
  64. mindsdb/integrations/handlers/cohere_handler/cohere_handler.py +11 -13
  65. mindsdb/integrations/handlers/confluence_handler/confluence_tables.py +6 -0
  66. mindsdb/integrations/handlers/databend_handler/connection_args.py +1 -1
  67. mindsdb/integrations/handlers/databend_handler/databend_handler.py +4 -4
  68. mindsdb/integrations/handlers/databend_handler/tests/__init__.py +0 -1
  69. mindsdb/integrations/handlers/databend_handler/tests/test_databend_handler.py +1 -1
  70. mindsdb/integrations/handlers/derby_handler/connection_args.py +1 -1
  71. mindsdb/integrations/handlers/derby_handler/derby_handler.py +14 -22
  72. mindsdb/integrations/handlers/derby_handler/tests/test_derby_handler.py +6 -6
  73. mindsdb/integrations/handlers/discord_handler/discord_handler.py +5 -5
  74. mindsdb/integrations/handlers/discord_handler/discord_tables.py +3 -3
  75. mindsdb/integrations/handlers/discord_handler/tests/test_discord.py +5 -3
  76. mindsdb/integrations/handlers/dockerhub_handler/dockerhub.py +3 -3
  77. mindsdb/integrations/handlers/dockerhub_handler/dockerhub_handler.py +2 -2
  78. mindsdb/integrations/handlers/dockerhub_handler/dockerhub_tables.py +57 -54
  79. mindsdb/integrations/handlers/dremio_handler/__init__.py +2 -2
  80. mindsdb/integrations/handlers/druid_handler/__init__.py +1 -1
  81. mindsdb/integrations/handlers/druid_handler/druid_handler.py +2 -2
  82. mindsdb/integrations/handlers/edgelessdb_handler/tests/test_edgelessdb_handler.py +9 -9
  83. mindsdb/integrations/handlers/email_handler/email_client.py +1 -1
  84. mindsdb/integrations/handlers/email_handler/email_ingestor.py +1 -1
  85. mindsdb/integrations/handlers/email_handler/email_tables.py +0 -1
  86. mindsdb/integrations/handlers/email_handler/settings.py +0 -1
  87. mindsdb/integrations/handlers/eventstoredb_handler/eventstoredb_handler.py +2 -1
  88. mindsdb/integrations/handlers/firebird_handler/firebird_handler.py +1 -1
  89. mindsdb/integrations/handlers/flaml_handler/flaml_handler.py +9 -9
  90. mindsdb/integrations/handlers/frappe_handler/frappe_client.py +5 -5
  91. mindsdb/integrations/handlers/frappe_handler/frappe_handler.py +6 -5
  92. mindsdb/integrations/handlers/frappe_handler/frappe_tables.py +2 -2
  93. mindsdb/integrations/handlers/github_handler/connection_args.py +2 -2
  94. mindsdb/integrations/handlers/github_handler/github_handler.py +1 -8
  95. mindsdb/integrations/handlers/github_handler/github_tables.py +13 -24
  96. mindsdb/integrations/handlers/gitlab_handler/gitlab_handler.py +2 -1
  97. mindsdb/integrations/handlers/gitlab_handler/gitlab_tables.py +1 -4
  98. mindsdb/integrations/handlers/gmail_handler/gmail_handler.py +6 -13
  99. mindsdb/integrations/handlers/google_books_handler/google_books_handler.py +2 -1
  100. mindsdb/integrations/handlers/google_books_handler/google_books_tables.py +0 -3
  101. mindsdb/integrations/handlers/google_calendar_handler/google_calendar_handler.py +4 -4
  102. mindsdb/integrations/handlers/google_calendar_handler/google_calendar_tables.py +2 -6
  103. mindsdb/integrations/handlers/google_content_shopping_handler/google_content_shopping_handler.py +3 -2
  104. mindsdb/integrations/handlers/google_content_shopping_handler/google_content_shopping_tables.py +0 -3
  105. mindsdb/integrations/handlers/google_fit_handler/google_fit_handler.py +10 -12
  106. mindsdb/integrations/handlers/google_fit_handler/google_fit_tables.py +11 -13
  107. mindsdb/integrations/handlers/google_search_handler/google_search_handler.py +2 -1
  108. mindsdb/integrations/handlers/google_search_handler/google_search_tables.py +0 -3
  109. mindsdb/integrations/handlers/groq_handler/__init__.py +3 -3
  110. mindsdb/integrations/handlers/hackernews_handler/hn_handler.py +5 -7
  111. mindsdb/integrations/handlers/hackernews_handler/hn_table.py +6 -7
  112. mindsdb/integrations/handlers/hive_handler/tests/test_hive_handler.py +1 -1
  113. mindsdb/integrations/handlers/hsqldb_handler/connection_args.py +6 -6
  114. mindsdb/integrations/handlers/hsqldb_handler/hsqldb_handler.py +4 -3
  115. mindsdb/integrations/handlers/huggingface_api_handler/exceptions.py +1 -1
  116. mindsdb/integrations/handlers/huggingface_api_handler/huggingface_api_handler.py +1 -8
  117. mindsdb/integrations/handlers/huggingface_handler/huggingface_handler.py +6 -6
  118. mindsdb/integrations/handlers/huggingface_handler/requirements.txt +1 -1
  119. mindsdb/integrations/handlers/huggingface_handler/requirements_cpu.txt +1 -1
  120. mindsdb/integrations/handlers/ignite_handler/ignite_handler.py +2 -1
  121. mindsdb/integrations/handlers/impala_handler/impala_handler.py +9 -12
  122. mindsdb/integrations/handlers/impala_handler/tests/test_impala_handler.py +11 -11
  123. mindsdb/integrations/handlers/influxdb_handler/influxdb_handler.py +10 -13
  124. mindsdb/integrations/handlers/influxdb_handler/influxdb_tables.py +20 -20
  125. mindsdb/integrations/handlers/informix_handler/__about__.py +8 -8
  126. mindsdb/integrations/handlers/informix_handler/__init__.py +12 -5
  127. mindsdb/integrations/handlers/informix_handler/informix_handler.py +99 -133
  128. mindsdb/integrations/handlers/informix_handler/tests/test_informix_handler.py +13 -11
  129. mindsdb/integrations/handlers/ingres_handler/__about__.py +0 -1
  130. mindsdb/integrations/handlers/ingres_handler/ingres_handler.py +1 -0
  131. mindsdb/integrations/handlers/jira_handler/jira_handler.py +4 -4
  132. mindsdb/integrations/handlers/jira_handler/jira_tables.py +9 -9
  133. mindsdb/integrations/handlers/kinetica_handler/__init__.py +0 -1
  134. mindsdb/integrations/handlers/lancedb_handler/requirements.txt +0 -1
  135. mindsdb/integrations/handlers/langchain_handler/langchain_handler.py +4 -4
  136. mindsdb/integrations/handlers/langchain_handler/tools.py +9 -10
  137. mindsdb/integrations/handlers/leonardoai_handler/__init__.py +1 -1
  138. mindsdb/integrations/handlers/lightwood_handler/functions.py +2 -2
  139. mindsdb/integrations/handlers/lightwood_handler/lightwood_handler.py +0 -1
  140. mindsdb/integrations/handlers/lightwood_handler/tests/test_lightwood_handler.py +11 -11
  141. mindsdb/integrations/handlers/litellm_handler/litellm_handler.py +37 -20
  142. mindsdb/integrations/handlers/llama_index_handler/llama_index_handler.py +4 -4
  143. mindsdb/integrations/handlers/llama_index_handler/settings.py +10 -9
  144. mindsdb/integrations/handlers/materialize_handler/tests/test_materialize_handler.py +8 -10
  145. mindsdb/integrations/handlers/matrixone_handler/matrixone_handler.py +4 -4
  146. mindsdb/integrations/handlers/matrixone_handler/tests/test_matrixone_handler.py +8 -9
  147. mindsdb/integrations/handlers/maxdb_handler/connection_args.py +25 -25
  148. mindsdb/integrations/handlers/maxdb_handler/maxdb_handler.py +1 -0
  149. mindsdb/integrations/handlers/mediawiki_handler/mediawiki_handler.py +3 -2
  150. mindsdb/integrations/handlers/mediawiki_handler/mediawiki_tables.py +1 -1
  151. mindsdb/integrations/handlers/mendeley_handler/__about__.py +1 -1
  152. mindsdb/integrations/handlers/mendeley_handler/__init__.py +2 -2
  153. mindsdb/integrations/handlers/mendeley_handler/mendeley_handler.py +48 -56
  154. mindsdb/integrations/handlers/mendeley_handler/mendeley_tables.py +24 -29
  155. mindsdb/integrations/handlers/mendeley_handler/tests/test_mendeley_handler.py +19 -17
  156. mindsdb/integrations/handlers/merlion_handler/merlion_handler.py +5 -4
  157. mindsdb/integrations/handlers/minds_endpoint_handler/__init__.py +3 -3
  158. mindsdb/integrations/handlers/mlflow_handler/mlflow_handler.py +58 -36
  159. mindsdb/integrations/handlers/monetdb_handler/__about__.py +8 -8
  160. mindsdb/integrations/handlers/monetdb_handler/__init__.py +15 -5
  161. mindsdb/integrations/handlers/monetdb_handler/connection_args.py +17 -18
  162. mindsdb/integrations/handlers/monetdb_handler/monetdb_handler.py +40 -57
  163. mindsdb/integrations/handlers/monetdb_handler/tests/test_monetdb_handler.py +7 -8
  164. mindsdb/integrations/handlers/monetdb_handler/utils/monet_get_id.py +13 -14
  165. mindsdb/integrations/handlers/monkeylearn_handler/__about__.py +1 -1
  166. mindsdb/integrations/handlers/monkeylearn_handler/__init__.py +1 -1
  167. mindsdb/integrations/handlers/monkeylearn_handler/monkeylearn_handler.py +2 -5
  168. mindsdb/integrations/handlers/ms_one_drive_handler/ms_graph_api_one_drive_client.py +1 -0
  169. mindsdb/integrations/handlers/ms_one_drive_handler/ms_one_drive_handler.py +1 -1
  170. mindsdb/integrations/handlers/ms_teams_handler/ms_graph_api_teams_client.py +23 -23
  171. mindsdb/integrations/handlers/ms_teams_handler/ms_teams_handler.py +3 -3
  172. mindsdb/integrations/handlers/ms_teams_handler/ms_teams_tables.py +10 -5
  173. mindsdb/integrations/handlers/mssql_handler/mssql_handler.py +73 -8
  174. mindsdb/integrations/handlers/mysql_handler/__about__.py +8 -8
  175. mindsdb/integrations/handlers/mysql_handler/__init__.py +15 -5
  176. mindsdb/integrations/handlers/mysql_handler/connection_args.py +43 -47
  177. mindsdb/integrations/handlers/mysql_handler/mysql_handler.py +101 -34
  178. mindsdb/integrations/handlers/mysql_handler/settings.py +15 -13
  179. mindsdb/integrations/handlers/neuralforecast_handler/neuralforecast_handler.py +1 -1
  180. mindsdb/integrations/handlers/newsapi_handler/newsapi_handler.py +1 -1
  181. mindsdb/integrations/handlers/newsapi_handler/tests/test_newsapi_handler.py +4 -4
  182. mindsdb/integrations/handlers/nuo_jdbc_handler/connection_args.py +2 -2
  183. mindsdb/integrations/handlers/nuo_jdbc_handler/nuo_jdbc_handler.py +28 -36
  184. mindsdb/integrations/handlers/nuo_jdbc_handler/tests/test_nuo_handler.py +5 -5
  185. mindsdb/integrations/handlers/oceanbase_handler/oceanbase_handler.py +0 -1
  186. mindsdb/integrations/handlers/oceanbase_handler/tests/test_oceanbase_handler.py +8 -10
  187. mindsdb/integrations/handlers/ollama_handler/ollama_handler.py +3 -3
  188. mindsdb/integrations/handlers/opengauss_handler/tests/test_opengauss_handler.py +1 -2
  189. mindsdb/integrations/handlers/openstreetmap_handler/__init__.py +7 -7
  190. mindsdb/integrations/handlers/oracle_handler/connection_args.py +6 -0
  191. mindsdb/integrations/handlers/oracle_handler/oracle_handler.py +77 -11
  192. mindsdb/integrations/handlers/orioledb_handler/tests/test_orioledb_handler.py +8 -10
  193. mindsdb/integrations/handlers/palm_handler/__about__.py +1 -1
  194. mindsdb/integrations/handlers/palm_handler/__init__.py +1 -1
  195. mindsdb/integrations/handlers/palm_handler/palm_handler.py +1 -3
  196. mindsdb/integrations/handlers/paypal_handler/paypal_handler.py +2 -2
  197. mindsdb/integrations/handlers/paypal_handler/paypal_tables.py +15 -14
  198. mindsdb/integrations/handlers/pgvector_handler/pgvector_handler.py +53 -10
  199. mindsdb/integrations/handlers/phoenix_handler/__init__.py +1 -1
  200. mindsdb/integrations/handlers/phoenix_handler/phoenix_handler.py +1 -0
  201. mindsdb/integrations/handlers/pinot_handler/__init__.py +1 -1
  202. mindsdb/integrations/handlers/pinot_handler/pinot_handler.py +3 -2
  203. mindsdb/integrations/handlers/plaid_handler/plaid_handler.py +13 -13
  204. mindsdb/integrations/handlers/plaid_handler/plaid_tables.py +10 -12
  205. mindsdb/integrations/handlers/plaid_handler/utils.py +4 -6
  206. mindsdb/integrations/handlers/planetscale_handler/planetscale_handler.py +1 -4
  207. mindsdb/integrations/handlers/portkey_handler/__init__.py +2 -2
  208. mindsdb/integrations/handlers/postgres_handler/postgres_handler.py +105 -24
  209. mindsdb/integrations/handlers/postgres_handler/tests/test_postgres_handler.py +11 -6
  210. mindsdb/integrations/handlers/questdb_handler/questdb_handler.py +1 -2
  211. mindsdb/integrations/handlers/questdb_handler/tests/test_questdb_handler.py +2 -3
  212. mindsdb/integrations/handlers/quickbooks_handler/quickbooks_handler.py +6 -8
  213. mindsdb/integrations/handlers/quickbooks_handler/quickbooks_table.py +10 -10
  214. mindsdb/integrations/handlers/rag_handler/ingest.py +2 -2
  215. mindsdb/integrations/handlers/rag_handler/rag_handler.py +1 -1
  216. mindsdb/integrations/handlers/rag_handler/settings.py +1 -1
  217. mindsdb/integrations/handlers/reddit_handler/reddit_handler.py +2 -7
  218. mindsdb/integrations/handlers/reddit_handler/reddit_tables.py +2 -3
  219. mindsdb/integrations/handlers/replicate_handler/replicate_handler.py +6 -6
  220. mindsdb/integrations/handlers/rocket_chat_handler/rocket_chat_handler.py +1 -2
  221. mindsdb/integrations/handlers/rocket_chat_handler/rocket_chat_tables.py +0 -3
  222. mindsdb/integrations/handlers/rockset_handler/connection_args.py +14 -14
  223. mindsdb/integrations/handlers/rockset_handler/tests/test_rockset_handler.py +1 -0
  224. mindsdb/integrations/handlers/scylla_handler/scylla_handler.py +6 -5
  225. mindsdb/integrations/handlers/sendinblue_handler/sendinblue_handler.py +2 -1
  226. mindsdb/integrations/handlers/sendinblue_handler/sendinblue_tables.py +16 -16
  227. mindsdb/integrations/handlers/sentence_transformers_handler/__init__.py +1 -1
  228. mindsdb/integrations/handlers/sheets_handler/connection_args.py +1 -1
  229. mindsdb/integrations/handlers/shopify_handler/shopify_handler.py +7 -6
  230. mindsdb/integrations/handlers/shopify_handler/shopify_tables.py +38 -41
  231. mindsdb/integrations/handlers/singlestore_handler/__about__.py +1 -1
  232. mindsdb/integrations/handlers/singlestore_handler/__init__.py +0 -1
  233. mindsdb/integrations/handlers/singlestore_handler/singlestore_handler.py +1 -0
  234. mindsdb/integrations/handlers/singlestore_handler/tests/test_singlestore_handler.py +3 -3
  235. mindsdb/integrations/handlers/slack_handler/__init__.py +3 -3
  236. mindsdb/integrations/handlers/snowflake_handler/snowflake_handler.py +100 -6
  237. mindsdb/integrations/handlers/solr_handler/connection_args.py +7 -7
  238. mindsdb/integrations/handlers/solr_handler/solr_handler.py +2 -1
  239. mindsdb/integrations/handlers/solr_handler/tests/test_solr_handler.py +2 -1
  240. mindsdb/integrations/handlers/sqlany_handler/sqlany_handler.py +3 -2
  241. mindsdb/integrations/handlers/sqlite_handler/sqlite_handler.py +1 -0
  242. mindsdb/integrations/handlers/sqreamdb_handler/connection_args.py +1 -1
  243. mindsdb/integrations/handlers/sqreamdb_handler/sqreamdb_handler.py +15 -20
  244. mindsdb/integrations/handlers/sqreamdb_handler/tests/test_sqreamdb_handler.py +4 -4
  245. mindsdb/integrations/handlers/stabilityai_handler/__init__.py +1 -1
  246. mindsdb/integrations/handlers/starrocks_handler/starrocks_handler.py +0 -1
  247. mindsdb/integrations/handlers/starrocks_handler/tests/test_starrocks_handler.py +8 -10
  248. mindsdb/integrations/handlers/statsforecast_handler/statsforecast_handler.py +2 -2
  249. mindsdb/integrations/handlers/strava_handler/strava_handler.py +4 -8
  250. mindsdb/integrations/handlers/strava_handler/strava_tables.py +22 -30
  251. mindsdb/integrations/handlers/stripe_handler/stripe_handler.py +3 -2
  252. mindsdb/integrations/handlers/stripe_handler/stripe_tables.py +11 -27
  253. mindsdb/integrations/handlers/supabase_handler/tests/test_supabase_handler.py +1 -1
  254. mindsdb/integrations/handlers/surrealdb_handler/surrealdb_handler.py +4 -4
  255. mindsdb/integrations/handlers/tdengine_handler/tdengine_handler.py +25 -27
  256. mindsdb/integrations/handlers/tdengine_handler/tests/test_tdengine_handler.py +8 -8
  257. mindsdb/integrations/handlers/tidb_handler/tests/test_tidb_handler.py +1 -2
  258. mindsdb/integrations/handlers/timegpt_handler/timegpt_handler.py +5 -5
  259. mindsdb/integrations/handlers/tpot_handler/tpot_handler.py +21 -26
  260. mindsdb/integrations/handlers/trino_handler/trino_handler.py +14 -14
  261. mindsdb/integrations/handlers/twitter_handler/twitter_handler.py +2 -4
  262. mindsdb/integrations/handlers/unify_handler/tests/test_unify_handler.py +7 -8
  263. mindsdb/integrations/handlers/unify_handler/unify_handler.py +9 -9
  264. mindsdb/integrations/handlers/vertex_handler/vertex_client.py +1 -1
  265. mindsdb/integrations/handlers/vertica_handler/tests/test_vertica_handler.py +11 -11
  266. mindsdb/integrations/handlers/vertica_handler/vertica_handler.py +11 -14
  267. mindsdb/integrations/handlers/vitess_handler/tests/test_vitess_handler.py +9 -11
  268. mindsdb/integrations/handlers/vitess_handler/vitess_handler.py +0 -1
  269. mindsdb/integrations/handlers/web_handler/web_handler.py +1 -0
  270. mindsdb/integrations/handlers/whatsapp_handler/__init__.py +3 -3
  271. mindsdb/integrations/handlers/writer_handler/evaluate.py +1 -1
  272. mindsdb/integrations/handlers/writer_handler/settings.py +0 -1
  273. mindsdb/integrations/handlers/writer_handler/writer_handler.py +1 -0
  274. mindsdb/integrations/handlers/youtube_handler/youtube_handler.py +5 -5
  275. mindsdb/integrations/handlers/youtube_handler/youtube_tables.py +26 -27
  276. mindsdb/integrations/handlers/yugabyte_handler/tests/test_yugabyte_handler.py +3 -3
  277. mindsdb/integrations/handlers/yugabyte_handler/yugabyte_handler.py +0 -6
  278. mindsdb/integrations/libs/llm/config.py +13 -0
  279. mindsdb/integrations/libs/llm/utils.py +37 -65
  280. mindsdb/integrations/libs/response.py +67 -52
  281. mindsdb/integrations/libs/vectordatabase_handler.py +6 -0
  282. mindsdb/integrations/utilities/handler_utils.py +15 -3
  283. mindsdb/integrations/utilities/handlers/api_utilities/__init__.py +0 -1
  284. mindsdb/integrations/utilities/handlers/auth_utilities/__init__.py +0 -2
  285. mindsdb/integrations/utilities/rag/rerankers/base_reranker.py +230 -227
  286. mindsdb/integrations/utilities/utils.py +3 -3
  287. mindsdb/interfaces/agents/agents_controller.py +164 -1
  288. mindsdb/interfaces/agents/constants.py +32 -13
  289. mindsdb/interfaces/agents/langchain_agent.py +106 -95
  290. mindsdb/interfaces/agents/mindsdb_database_agent.py +101 -2
  291. mindsdb/interfaces/knowledge_base/controller.py +250 -216
  292. mindsdb/interfaces/knowledge_base/preprocessing/document_preprocessor.py +13 -10
  293. mindsdb/interfaces/knowledge_base/preprocessing/json_chunker.py +434 -0
  294. mindsdb/interfaces/knowledge_base/preprocessing/models.py +54 -0
  295. mindsdb/interfaces/query_context/context_controller.py +66 -10
  296. mindsdb/interfaces/skills/custom/text2sql/mindsdb_kb_tools.py +190 -0
  297. mindsdb/interfaces/skills/custom/text2sql/mindsdb_sql_toolkit.py +92 -0
  298. mindsdb/interfaces/skills/skill_tool.py +202 -57
  299. mindsdb/interfaces/skills/sql_agent.py +205 -17
  300. mindsdb/interfaces/storage/fs.py +1 -0
  301. mindsdb/interfaces/variables/__init__.py +0 -0
  302. mindsdb/interfaces/variables/variables_controller.py +97 -0
  303. mindsdb/migrations/env.py +5 -7
  304. mindsdb/migrations/migrate.py +47 -7
  305. mindsdb/migrations/versions/2025-05-21_9f150e4f9a05_checkpoint_1.py +360 -0
  306. mindsdb/utilities/config.py +287 -216
  307. mindsdb/utilities/starters.py +13 -0
  308. {mindsdb-25.5.3.0.dist-info → mindsdb-25.5.4.1.dist-info}/METADATA +646 -698
  309. {mindsdb-25.5.3.0.dist-info → mindsdb-25.5.4.1.dist-info}/RECORD +312 -295
  310. {mindsdb-25.5.3.0.dist-info → mindsdb-25.5.4.1.dist-info}/WHEEL +1 -1
  311. mindsdb/integrations/handlers/monkeylearn_handler/requirements.txt +0 -1
  312. {mindsdb-25.5.3.0.dist-info → mindsdb-25.5.4.1.dist-info}/licenses/LICENSE +0 -0
  313. {mindsdb-25.5.3.0.dist-info → mindsdb-25.5.4.1.dist-info}/top_level.txt +0 -0
@@ -20,121 +20,109 @@ from mindsdb.integrations.libs.response import HandlerStatusResponse
20
20
  logger = log.getLogger(__name__)
21
21
 
22
22
 
23
- @ns_conf.route('/')
24
- @ns_conf.param('name', 'Get config')
23
+ @ns_conf.route("/")
24
+ @ns_conf.param("name", "Get config")
25
25
  class GetConfig(Resource):
26
- @ns_conf.doc('get_config')
27
- @api_endpoint_metrics('GET', '/config')
26
+ @ns_conf.doc("get_config")
27
+ @api_endpoint_metrics("GET", "/config")
28
28
  def get(self):
29
29
  config = Config()
30
- resp = {
31
- 'auth': {
32
- 'http_auth_enabled': config['auth']['http_auth_enabled']
33
- }
34
- }
35
- for key in ['default_llm', 'default_embedding_model']:
30
+ resp = {"auth": {"http_auth_enabled": config["auth"]["http_auth_enabled"]}}
31
+ for key in ["default_llm", "default_embedding_model", "default_reranking_model"]:
36
32
  value = config.get(key)
37
33
  if value is not None:
38
34
  resp[key] = value
39
35
  return resp
40
36
 
41
- @ns_conf.doc('put_config')
42
- @api_endpoint_metrics('PUT', '/config')
37
+ @ns_conf.doc("put_config")
38
+ @api_endpoint_metrics("PUT", "/config")
43
39
  def put(self):
44
40
  data = request.json
45
41
 
46
- allowed_arguments = {'auth', 'default_llm', 'default_embedding_model'}
42
+ allowed_arguments = {"auth", "default_llm", "default_embedding_model", "default_reranking_model"}
47
43
  unknown_arguments = list(set(data.keys()) - allowed_arguments)
48
44
  if len(unknown_arguments) > 0:
49
- return http_error(
50
- HTTPStatus.BAD_REQUEST, 'Wrong arguments',
51
- f'Unknown argumens: {unknown_arguments}'
52
- )
45
+ return http_error(HTTPStatus.BAD_REQUEST, "Wrong arguments", f"Unknown argumens: {unknown_arguments}")
53
46
 
54
- nested_keys_to_validate = {'auth'}
47
+ nested_keys_to_validate = {"auth"}
55
48
  for key in data.keys():
56
49
  if key in nested_keys_to_validate:
57
- unknown_arguments = list(
58
- set(data[key].keys()) - set(Config()[key].keys())
59
- )
50
+ unknown_arguments = list(set(data[key].keys()) - set(Config()[key].keys()))
60
51
  if len(unknown_arguments) > 0:
61
52
  return http_error(
62
- HTTPStatus.BAD_REQUEST, 'Wrong arguments',
63
- f'Unknown argumens: {unknown_arguments}'
53
+ HTTPStatus.BAD_REQUEST, "Wrong arguments", f"Unknown argumens: {unknown_arguments}"
64
54
  )
65
55
 
66
56
  Config().update(data)
67
57
 
68
- return '', 200
58
+ return "", 200
69
59
 
70
60
 
71
- @ns_conf.route('/integrations')
72
- @ns_conf.param('name', 'List all database integration')
61
+ @ns_conf.route("/integrations")
62
+ @ns_conf.param("name", "List all database integration")
73
63
  class ListIntegration(Resource):
74
- @api_endpoint_metrics('GET', '/config/integrations')
64
+ @api_endpoint_metrics("GET", "/config/integrations")
75
65
  def get(self):
76
- return {
77
- 'integrations': [k for k in ca.integration_controller.get_all(show_secrets=False)]
78
- }
66
+ return {"integrations": [k for k in ca.integration_controller.get_all(show_secrets=False)]}
79
67
 
80
68
 
81
- @ns_conf.route('/all_integrations')
82
- @ns_conf.param('name', 'List all database integration')
69
+ @ns_conf.route("/all_integrations")
70
+ @ns_conf.param("name", "List all database integration")
83
71
  class AllIntegration(Resource):
84
- @ns_conf.doc('get_all_integrations')
85
- @api_endpoint_metrics('GET', '/config/all_integrations')
72
+ @ns_conf.doc("get_all_integrations")
73
+ @api_endpoint_metrics("GET", "/config/all_integrations")
86
74
  def get(self):
87
75
  integrations = ca.integration_controller.get_all(show_secrets=False)
88
76
  return integrations
89
77
 
90
78
 
91
- @ns_conf.route('/integrations/<name>')
92
- @ns_conf.param('name', 'Database integration')
79
+ @ns_conf.route("/integrations/<name>")
80
+ @ns_conf.param("name", "Database integration")
93
81
  class Integration(Resource):
94
- @ns_conf.doc('get_integration')
95
- @api_endpoint_metrics('GET', '/config/integrations/integration')
82
+ @ns_conf.doc("get_integration")
83
+ @api_endpoint_metrics("GET", "/config/integrations/integration")
96
84
  def get(self, name):
97
85
  integration = ca.integration_controller.get(name, show_secrets=False)
98
86
  if integration is None:
99
- return http_error(HTTPStatus.NOT_FOUND, 'Not found', f'Can\'t find integration: {name}')
87
+ return http_error(HTTPStatus.NOT_FOUND, "Not found", f"Can't find integration: {name}")
100
88
  integration = copy.deepcopy(integration)
101
89
  return integration
102
90
 
103
- @ns_conf.doc('put_integration')
104
- @api_endpoint_metrics('PUT', '/config/integrations/integration')
91
+ @ns_conf.doc("put_integration")
92
+ @api_endpoint_metrics("PUT", "/config/integrations/integration")
105
93
  def put(self, name):
106
94
  params = {}
107
95
  if request.is_json:
108
- params.update((request.json or {}).get('params', {}))
96
+ params.update((request.json or {}).get("params", {}))
109
97
  else:
110
98
  params.update(request.form or {})
111
99
 
112
100
  if len(params) == 0:
113
- return http_error(HTTPStatus.BAD_REQUEST, 'Wrong argument', "type of 'params' must be dict")
101
+ return http_error(HTTPStatus.BAD_REQUEST, "Wrong argument", "type of 'params' must be dict")
114
102
 
115
103
  files = request.files
116
104
  temp_dir = None
117
105
  if files is not None and len(files) > 0:
118
- temp_dir = tempfile.mkdtemp(prefix='integration_files_')
106
+ temp_dir = tempfile.mkdtemp(prefix="integration_files_")
119
107
  for key, file in files.items():
120
108
  temp_dir_path = Path(temp_dir)
121
109
  file_name = Path(file.filename)
122
110
  file_path = temp_dir_path.joinpath(file_name).resolve()
123
111
  if temp_dir_path not in file_path.parents:
124
- raise Exception(f'Can not save file at path: {file_path}')
112
+ raise Exception(f"Can not save file at path: {file_path}")
125
113
  file.save(file_path)
126
114
  params[key] = str(file_path)
127
115
 
128
- is_test = params.get('test', False)
116
+ is_test = params.get("test", False)
129
117
  # TODO: Move this to new Endpoint
130
118
 
131
119
  config = Config()
132
- secret_key = config.get('secret_key', 'dummy-key')
120
+ secret_key = config.get("secret_key", "dummy-key")
133
121
 
134
122
  if is_test:
135
- del params['test']
136
- handler_type = params.pop('type', None)
137
- params.pop('publish', None)
123
+ del params["test"]
124
+ handler_type = params.pop("type", None)
125
+ params.pop("publish", None)
138
126
  try:
139
127
  handler = ca.integration_controller.create_tmp_handler(name, handler_type, params)
140
128
  status = handler.check_connection()
@@ -145,33 +133,32 @@ class Integration(Resource):
145
133
 
146
134
  resp = status.to_json()
147
135
 
148
- if status.success and 'code' in params:
149
- if hasattr(handler, 'handler_storage'):
136
+ if status.success and "code" in params:
137
+ if hasattr(handler, "handler_storage"):
150
138
  # attach storage if exists
151
139
  export = handler.handler_storage.export_files()
152
140
  if export:
153
141
  # encrypt with flask secret key
154
142
  encrypted = encrypt(export, secret_key)
155
- resp['storage'] = encrypted.decode()
143
+ resp["storage"] = encrypted.decode()
156
144
 
157
145
  return resp, 200
158
146
 
159
147
  config = Config()
160
- secret_key = config.get('secret_key', 'dummy-key')
148
+ secret_key = config.get("secret_key", "dummy-key")
161
149
 
162
150
  integration = ca.integration_controller.get(name, show_secrets=False)
163
151
  if integration is not None:
164
152
  return http_error(
165
- HTTPStatus.BAD_REQUEST, 'Wrong argument',
166
- f"Integration with name '{name}' already exists"
153
+ HTTPStatus.BAD_REQUEST, "Wrong argument", f"Integration with name '{name}' already exists"
167
154
  )
168
155
 
169
156
  try:
170
- engine = params['type']
157
+ engine = params["type"]
171
158
  if engine is not None:
172
- del params['type']
173
- params.pop('publish', False)
174
- storage = params.pop('storage', None)
159
+ del params["type"]
160
+ params.pop("publish", False)
161
+ storage = params.pop("storage", None)
175
162
  ca.integration_controller.add(name, engine, params)
176
163
 
177
164
  # copy storage
@@ -185,62 +172,50 @@ class Integration(Resource):
185
172
  logger.error(str(e))
186
173
  if temp_dir is not None:
187
174
  shutil.rmtree(temp_dir)
188
- return http_error(
189
- HTTPStatus.INTERNAL_SERVER_ERROR, 'Error',
190
- f'Error during config update: {str(e)}'
191
- )
175
+ return http_error(HTTPStatus.INTERNAL_SERVER_ERROR, "Error", f"Error during config update: {str(e)}")
192
176
 
193
177
  if temp_dir is not None:
194
178
  shutil.rmtree(temp_dir)
195
179
  return {}, 200
196
180
 
197
- @ns_conf.doc('delete_integration')
198
- @api_endpoint_metrics('DELETE', '/config/integrations/integration')
181
+ @ns_conf.doc("delete_integration")
182
+ @api_endpoint_metrics("DELETE", "/config/integrations/integration")
199
183
  def delete(self, name):
200
184
  integration = ca.integration_controller.get(name)
201
185
  if integration is None:
202
186
  return http_error(
203
- HTTPStatus.BAD_REQUEST, 'Integration does not exists',
204
- f"Nothing to delete. '{name}' not exists."
187
+ HTTPStatus.BAD_REQUEST, "Integration does not exists", f"Nothing to delete. '{name}' not exists."
205
188
  )
206
189
  try:
207
190
  ca.integration_controller.delete(name)
208
191
  except Exception as e:
209
192
  logger.error(str(e))
210
- return http_error(
211
- HTTPStatus.INTERNAL_SERVER_ERROR, 'Error',
212
- f"Error during integration delete: {str(e)}"
213
- )
193
+ return http_error(HTTPStatus.INTERNAL_SERVER_ERROR, "Error", f"Error during integration delete: {str(e)}")
214
194
  return "", 200
215
195
 
216
- @ns_conf.doc('modify_integration')
217
- @api_endpoint_metrics('POST', '/config/integrations/integration')
196
+ @ns_conf.doc("modify_integration")
197
+ @api_endpoint_metrics("POST", "/config/integrations/integration")
218
198
  def post(self, name):
219
199
  params = {}
220
- params.update((request.json or {}).get('params', {}))
200
+ params.update((request.json or {}).get("params", {}))
221
201
  params.update(request.form or {})
222
202
 
223
203
  if not isinstance(params, dict):
224
- return http_error(
225
- HTTPStatus.BAD_REQUEST, 'Wrong argument',
226
- "type of 'params' must be dict"
227
- )
204
+ return http_error(HTTPStatus.BAD_REQUEST, "Wrong argument", "type of 'params' must be dict")
228
205
  integration = ca.integration_controller.get(name)
229
206
  if integration is None:
230
207
  return http_error(
231
- HTTPStatus.BAD_REQUEST, 'Integration does not exists',
232
- f"Nothin to modify. '{name}' not exists."
208
+ HTTPStatus.BAD_REQUEST, "Integration does not exists", f"Nothin to modify. '{name}' not exists."
233
209
  )
234
210
  try:
235
- if 'enabled' in params:
236
- params['publish'] = params['enabled']
237
- del params['enabled']
211
+ if "enabled" in params:
212
+ params["publish"] = params["enabled"]
213
+ del params["enabled"]
238
214
  ca.integration_controller.modify(name, params)
239
215
 
240
216
  except Exception as e:
241
217
  logger.error(str(e))
242
218
  return http_error(
243
- HTTPStatus.INTERNAL_SERVER_ERROR, 'Error',
244
- f"Error during integration modification: {str(e)}"
219
+ HTTPStatus.INTERNAL_SERVER_ERROR, "Error", f"Error during integration modification: {str(e)}"
245
220
  )
246
221
  return "", 200
@@ -84,8 +84,14 @@ class File(Resource):
84
84
  parser.finalize()
85
85
  parser.close()
86
86
 
87
- if file_object is not None and not file_object.closed:
88
- file_object.close()
87
+ if file_object is not None:
88
+ if not file_object.closed:
89
+ try:
90
+ file_object.flush()
91
+ except (AttributeError, ValueError, OSError):
92
+ logger.debug("Failed to flush file_object before closing.", exc_info=True)
93
+ file_object.close()
94
+ file_object = None
89
95
  else:
90
96
  data = request.json
91
97
 
@@ -8,6 +8,7 @@ import mindsdb.utilities.hooks as hooks
8
8
  import mindsdb.utilities.profiler as profiler
9
9
  from mindsdb.api.http.utils import http_error
10
10
  from mindsdb.api.http.namespaces.configs.sql import ns_conf
11
+ from mindsdb.api.mysql.mysql_proxy.mysql_proxy import SQLAnswer
11
12
  from mindsdb.api.mysql.mysql_proxy.classes.fake_mysql_proxy import FakeMysqlProxy
12
13
  from mindsdb.api.executor.data_types.response_type import (
13
14
  RESPONSE_TYPE as SQL_RESPONSE_TYPE,
@@ -56,23 +57,8 @@ class Query(Resource):
56
57
  mysql_proxy = FakeMysqlProxy()
57
58
  mysql_proxy.set_context(context)
58
59
  try:
59
- result = mysql_proxy.process_query(query)
60
-
61
- if result.type == SQL_RESPONSE_TYPE.OK:
62
- query_response = {
63
- "type": SQL_RESPONSE_TYPE.OK,
64
- "affected_rows": result.affected_rows
65
- }
66
- elif result.type == SQL_RESPONSE_TYPE.TABLE:
67
- data = result.data.to_lists(json_types=True)
68
- query_response = {
69
- "type": SQL_RESPONSE_TYPE.TABLE,
70
- "data": data,
71
- "column_names": [
72
- x["alias"] or x["name"] if "alias" in x else x["name"]
73
- for x in result.columns
74
- ],
75
- }
60
+ result: SQLAnswer = mysql_proxy.process_query(query)
61
+ query_response: dict = result.dump_http_response()
76
62
  except ExecutorException as e:
77
63
  # classified error
78
64
  error_type = "expected"
@@ -134,7 +120,7 @@ class ListDatabases(Resource):
134
120
  listing_query = "SHOW DATABASES"
135
121
  mysql_proxy = FakeMysqlProxy()
136
122
  try:
137
- result = mysql_proxy.process_query(listing_query)
123
+ result: SQLAnswer = mysql_proxy.process_query(listing_query)
138
124
 
139
125
  # iterate over result.data and perform a query on each item to get the name of the tables
140
126
  if result.type == SQL_RESPONSE_TYPE.ERROR:
@@ -147,15 +133,15 @@ class ListDatabases(Resource):
147
133
  listing_query_response = {"type": "ok"}
148
134
  elif result.type == SQL_RESPONSE_TYPE.TABLE:
149
135
  listing_query_response = {
150
- "data": [
151
- {
152
- "name": x[0],
153
- "tables": mysql_proxy.process_query(
154
- "SHOW TABLES FROM `{}`".format(x[0])
155
- ).data,
156
- }
157
- for x in result.data
158
- ]
136
+ "data": [{
137
+ "name": db_row[0],
138
+ "tables": [
139
+ table_row[0]
140
+ for table_row in mysql_proxy.process_query(
141
+ "SHOW TABLES FROM `{}`".format(db_row[0])
142
+ ).result_set.to_lists()
143
+ ]
144
+ } for db_row in result.result_set.to_lists()]
159
145
  }
160
146
  except Exception as e:
161
147
  listing_query_response = {
mindsdb/api/mcp/start.py CHANGED
@@ -1,9 +1,16 @@
1
+ import os
1
2
  from contextlib import asynccontextmanager
2
3
  from collections.abc import AsyncIterator
3
4
  from typing import Optional, Dict, Any
4
5
  from dataclasses import dataclass
5
6
 
7
+ import uvicorn
8
+ import anyio
6
9
  from mcp.server.fastmcp import FastMCP
10
+ from starlette.middleware.base import BaseHTTPMiddleware
11
+ from starlette.requests import Request
12
+ from starlette.responses import Response
13
+
7
14
  from mindsdb.api.mysql.mysql_proxy.classes.fake_mysql_proxy import FakeMysqlProxy
8
15
  from mindsdb.api.executor.data_types.response_type import RESPONSE_TYPE as SQL_RESPONSE_TYPE
9
16
  from mindsdb.utilities import log
@@ -70,10 +77,10 @@ def query(query: str, context: Optional[Dict] = None) -> Dict[str, Any]:
70
77
  if result.type == SQL_RESPONSE_TYPE.TABLE:
71
78
  return {
72
79
  "type": SQL_RESPONSE_TYPE.TABLE,
73
- "data": result.data.to_lists(json_types=True),
80
+ "data": result.result_set.to_lists(json_types=True),
74
81
  "column_names": [
75
- x["alias"] or x["name"] if "alias" in x else x["name"]
76
- for x in result.columns
82
+ column.alias or column.name
83
+ for column in result.result_set.columns
77
84
  ],
78
85
  }
79
86
  else:
@@ -116,7 +123,7 @@ def list_databases() -> Dict[str, Any]:
116
123
  return {"type": "ok"}
117
124
 
118
125
  elif result.type == SQL_RESPONSE_TYPE.TABLE:
119
- data = result.data.to_lists(json_types=True)
126
+ data = result.result_set.to_lists(json_types=True)
120
127
  return data
121
128
 
122
129
  except Exception as e:
@@ -127,6 +134,36 @@ def list_databases() -> Dict[str, Any]:
127
134
  }
128
135
 
129
136
 
137
+ class CustomAuthMiddleware(BaseHTTPMiddleware):
138
+ """Custom middleware to handle authentication basing on header 'Authorization'
139
+ """
140
+ async def dispatch(self, request: Request, call_next):
141
+ mcp_access_token = os.environ.get('MINDSDB_MCP_ACCESS_TOKEN')
142
+ if mcp_access_token is not None:
143
+ auth_token = request.headers.get('Authorization', '').partition('Bearer ')[-1]
144
+ if mcp_access_token != auth_token:
145
+ return Response(status_code=401, content="Unauthorized", media_type="text/plain")
146
+
147
+ response = await call_next(request)
148
+
149
+ return response
150
+
151
+
152
+ async def run_sse_async() -> None:
153
+ """Run the server using SSE transport."""
154
+ starlette_app = mcp.sse_app()
155
+ starlette_app.add_middleware(CustomAuthMiddleware)
156
+
157
+ config = uvicorn.Config(
158
+ starlette_app,
159
+ host=mcp.settings.host,
160
+ port=mcp.settings.port,
161
+ log_level=mcp.settings.log_level.lower(),
162
+ )
163
+ server = uvicorn.Server(config)
164
+ await server.serve()
165
+
166
+
130
167
  def start(*args, **kwargs):
131
168
  """Start the MCP server
132
169
  Args:
@@ -142,7 +179,7 @@ def start(*args, **kwargs):
142
179
  mcp.settings.port = port
143
180
 
144
181
  try:
145
- mcp.run(transport="sse") # Use SSE transport instead of stdio
182
+ anyio.run(run_sse_async)
146
183
  except Exception as e:
147
184
  logger.error(f"Error starting MCP server: {str(e)}")
148
185
  raise
@@ -77,7 +77,6 @@ class Packet:
77
77
  f"Packet with less than 4 bytes in length: {packet_string}"
78
78
  )
79
79
  return False
80
- break
81
80
  len_header = struct.unpack("i", packet_string[:3] + b"\x00")[0]
82
81
  count_header = int(packet_string[3])
83
82
  if len_header == 0:
@@ -30,16 +30,18 @@ class BinaryResultsetRowPacket(Packet):
30
30
  columns = self._kwargs.get('columns', {})
31
31
 
32
32
  self.value = [b'\x00']
33
- nulls = [0]
33
+
34
+ # NOTE: according to mysql's doc offset=0 only for COM_STMT_EXECUTE, mariadb's doc does't mention that
35
+ # but in fact it looks like offset=2 everywhere
36
+ offset = 2
37
+ nulls_bitmap = bytearray((len(columns) + offset + 7) // 8)
34
38
  for i, el in enumerate(data):
35
- if i > 0 and (i + 2) % 8 == 0:
36
- nulls.append(0)
37
- if el is None:
38
- if i < 6:
39
- nulls[-1] = nulls[-1] + (1 << ((i + 2) % 8))
40
- else:
41
- nulls[-1] = nulls[-1] + (1 << ((i - 6) % 8))
42
- self.value.append(bytes(nulls))
39
+ if el is not None:
40
+ continue
41
+ byte_index = (i + offset) // 8
42
+ bit_index = (i + offset) % 8
43
+ nulls_bitmap[byte_index] |= (1 << bit_index)
44
+ self.value.append(bytes(nulls_bitmap))
43
45
 
44
46
  for i, col in enumerate(columns):
45
47
  # NOTE at this moment all types sends as strings, and it works
@@ -65,6 +67,12 @@ class BinaryResultsetRowPacket(Packet):
65
67
  elif col_type == TYPES.MYSQL_TYPE_YEAR:
66
68
  enc = '<h'
67
69
  val = int(float(val))
70
+ elif col_type == TYPES.MYSQL_TYPE_SHORT:
71
+ enc = '<h'
72
+ val = int(val)
73
+ elif col_type == TYPES.MYSQL_TYPE_TINY:
74
+ enc = '<B'
75
+ val = int(val)
68
76
  elif col_type == TYPES.MYSQL_TYPE_DATE:
69
77
  env_val = self.encode_date(val)
70
78
  elif col_type == TYPES.MYSQL_TYPE_TIMESTAMP:
@@ -72,9 +80,9 @@ class BinaryResultsetRowPacket(Packet):
72
80
  elif col_type == TYPES.MYSQL_TYPE_DATETIME:
73
81
  env_val = self.encode_date(val)
74
82
  elif col_type == TYPES.MYSQL_TYPE_TIME:
75
- enc = ''
83
+ env_val = self.encode_time(val)
76
84
  elif col_type == TYPES.MYSQL_TYPE_NEWDECIMAL:
77
- enc = ''
85
+ enc = 'string'
78
86
  else:
79
87
  enc = 'string'
80
88
 
@@ -90,21 +98,46 @@ class BinaryResultsetRowPacket(Packet):
90
98
  env_val = struct.pack(enc, val)
91
99
  self.value.append(env_val)
92
100
 
101
+ def encode_time(self, val: dt.time | str) -> bytes:
102
+ """ https://mariadb.com/kb/en/resultset-row/#time-binary-encoding
103
+ """
104
+ if isinstance(val, str):
105
+ try:
106
+ val = dt.datetime.strptime(val, '%H:%M:%S').time()
107
+ except ValueError:
108
+ val = dt.datetime.strptime(val, '%H:%M:%S.%f').time()
109
+ if val == dt.time(0, 0, 0):
110
+ return struct.pack('<B', 0) # special case for 0 time
111
+ out = struct.pack('<B', 0) # positive time
112
+ out += struct.pack('<L', 0) # days
113
+ out += struct.pack('<B', val.hour)
114
+ out += struct.pack('<B', val.minute)
115
+ out += struct.pack('<B', val.second)
116
+ if val.microsecond > 0:
117
+ out += struct.pack('<L', val.microsecond)
118
+ len_bit = struct.pack('<B', 12)
119
+ else:
120
+ len_bit = struct.pack('<B', 8)
121
+ return len_bit + out
122
+
93
123
  def encode_date(self, val):
94
124
  # date_type = None
95
125
  # date_value = None
96
126
 
97
127
  if isinstance(val, str):
98
- try:
99
- date_value = dt.datetime.strptime(val, '%Y-%m-%d')
100
- date_type = 'date'
101
- except ValueError:
128
+ forms = [
129
+ '%Y-%m-%d', '%Y-%m-%d %H:%M:%S', '%Y-%m-%d %H:%M:%S.%f',
130
+ '%Y-%m-%dT%H:%M:%S', '%Y-%m-%dT%H:%M:%S.%f'
131
+ ]
132
+ for f in forms:
102
133
  try:
103
- date_value = dt.datetime.strptime(val, '%Y-%m-%dT%H:%M:%S')
104
- date_type = 'datetime'
134
+ date_value = dt.datetime.strptime(val, f)
135
+ break
105
136
  except ValueError:
106
- date_value = dt.datetime.strptime(val, '%Y-%m-%dT%H:%M:%S.%f')
107
- date_type = 'datetime'
137
+ date_value = None
138
+ if date_value is None:
139
+ raise ValueError(f"Invalid date format: {val}")
140
+ date_type = 'datetime'
108
141
  elif isinstance(val, pd.Timestamp):
109
142
  date_value = val
110
143
  date_type = 'datetime'
@@ -7,6 +7,7 @@ from mindsdb.api.executor.sql_query import SQLQuery
7
7
  from mindsdb.api.executor.data_types.answer import ExecuteAnswer
8
8
  from mindsdb.api.executor.command_executor import ExecuteCommands
9
9
  from mindsdb.api.mysql.mysql_proxy.utilities import ErSqlSyntaxError
10
+ from mindsdb.api.mysql.mysql_proxy.libs.constants.mysql import MYSQL_DATA_TYPE
10
11
  from mindsdb.utilities import log
11
12
 
12
13
  logger = log.getLogger(__name__)
@@ -19,8 +20,8 @@ class Executor:
19
20
 
20
21
  self.query = None
21
22
 
22
- self.columns = []
23
- self.params = []
23
+ self.columns: list[Column] = []
24
+ self.params: list[Column] = []
24
25
  self.data = None
25
26
  self.server_status = None
26
27
  self.is_executed = False
@@ -56,14 +57,11 @@ class Executor:
56
57
 
57
58
  sqlquery.prepare_query()
58
59
 
59
- self.params = [
60
- Column(
61
- alias=p.value,
62
- type="str",
63
- name=p.value,
64
- )
65
- for p in params
66
- ]
60
+ self.params = [Column(
61
+ name=p.value,
62
+ alias=p.value,
63
+ type=MYSQL_DATA_TYPE.TEXT
64
+ ) for p in params]
67
65
 
68
66
  # TODO:
69
67
  # select * from mindsdb.models doesn't invoke prepare_steps and columns_list is empty