MindsDB 25.9.3rc1__py3-none-any.whl → 25.10.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.

Files changed (90) hide show
  1. mindsdb/__about__.py +1 -1
  2. mindsdb/__main__.py +1 -9
  3. mindsdb/api/a2a/__init__.py +1 -1
  4. mindsdb/api/a2a/agent.py +9 -1
  5. mindsdb/api/a2a/common/server/server.py +4 -0
  6. mindsdb/api/a2a/common/server/task_manager.py +8 -1
  7. mindsdb/api/a2a/common/types.py +66 -0
  8. mindsdb/api/a2a/task_manager.py +50 -0
  9. mindsdb/api/common/middleware.py +1 -1
  10. mindsdb/api/executor/command_executor.py +49 -36
  11. mindsdb/api/executor/datahub/datanodes/information_schema_datanode.py +7 -13
  12. mindsdb/api/executor/datahub/datanodes/integration_datanode.py +2 -2
  13. mindsdb/api/executor/datahub/datanodes/system_tables.py +2 -1
  14. mindsdb/api/executor/planner/query_prepare.py +2 -20
  15. mindsdb/api/executor/utilities/sql.py +5 -4
  16. mindsdb/api/http/initialize.py +76 -60
  17. mindsdb/api/http/namespaces/agents.py +0 -3
  18. mindsdb/api/http/namespaces/chatbots.py +0 -5
  19. mindsdb/api/http/namespaces/file.py +2 -0
  20. mindsdb/api/http/namespaces/handlers.py +10 -5
  21. mindsdb/api/http/namespaces/knowledge_bases.py +20 -0
  22. mindsdb/api/http/namespaces/sql.py +2 -2
  23. mindsdb/api/http/start.py +2 -2
  24. mindsdb/api/mysql/mysql_proxy/utilities/dump.py +8 -2
  25. mindsdb/integrations/handlers/byom_handler/byom_handler.py +2 -10
  26. mindsdb/integrations/handlers/databricks_handler/databricks_handler.py +98 -46
  27. mindsdb/integrations/handlers/druid_handler/druid_handler.py +32 -40
  28. mindsdb/integrations/handlers/gitlab_handler/gitlab_handler.py +5 -2
  29. mindsdb/integrations/handlers/mssql_handler/mssql_handler.py +438 -100
  30. mindsdb/integrations/handlers/mssql_handler/requirements_odbc.txt +3 -0
  31. mindsdb/integrations/handlers/mysql_handler/mysql_handler.py +235 -3
  32. mindsdb/integrations/handlers/oracle_handler/__init__.py +2 -0
  33. mindsdb/integrations/handlers/oracle_handler/connection_args.py +7 -1
  34. mindsdb/integrations/handlers/oracle_handler/oracle_handler.py +321 -16
  35. mindsdb/integrations/handlers/oracle_handler/requirements.txt +1 -1
  36. mindsdb/integrations/handlers/postgres_handler/postgres_handler.py +2 -2
  37. mindsdb/integrations/handlers/shopify_handler/requirements.txt +1 -0
  38. mindsdb/integrations/handlers/shopify_handler/shopify_handler.py +57 -3
  39. mindsdb/integrations/handlers/zendesk_handler/zendesk_tables.py +144 -111
  40. mindsdb/integrations/libs/response.py +2 -2
  41. mindsdb/integrations/utilities/handlers/auth_utilities/snowflake/__init__.py +1 -0
  42. mindsdb/integrations/utilities/handlers/auth_utilities/snowflake/snowflake_jwt_gen.py +151 -0
  43. mindsdb/integrations/utilities/rag/rerankers/base_reranker.py +24 -21
  44. mindsdb/interfaces/agents/agents_controller.py +0 -2
  45. mindsdb/interfaces/data_catalog/data_catalog_loader.py +6 -7
  46. mindsdb/interfaces/data_catalog/data_catalog_reader.py +15 -4
  47. mindsdb/interfaces/database/data_handlers_cache.py +190 -0
  48. mindsdb/interfaces/database/database.py +3 -3
  49. mindsdb/interfaces/database/integrations.py +1 -121
  50. mindsdb/interfaces/database/projects.py +2 -6
  51. mindsdb/interfaces/database/views.py +1 -4
  52. mindsdb/interfaces/jobs/jobs_controller.py +0 -4
  53. mindsdb/interfaces/jobs/scheduler.py +0 -1
  54. mindsdb/interfaces/knowledge_base/controller.py +197 -108
  55. mindsdb/interfaces/knowledge_base/evaluate.py +36 -41
  56. mindsdb/interfaces/knowledge_base/executor.py +11 -0
  57. mindsdb/interfaces/knowledge_base/llm_client.py +51 -17
  58. mindsdb/interfaces/model/model_controller.py +4 -4
  59. mindsdb/interfaces/skills/custom/text2sql/mindsdb_sql_toolkit.py +4 -10
  60. mindsdb/interfaces/skills/skills_controller.py +1 -4
  61. mindsdb/interfaces/storage/db.py +16 -6
  62. mindsdb/interfaces/triggers/triggers_controller.py +1 -3
  63. mindsdb/utilities/config.py +19 -2
  64. mindsdb/utilities/exception.py +2 -2
  65. mindsdb/utilities/json_encoder.py +24 -10
  66. mindsdb/utilities/render/sqlalchemy_render.py +15 -14
  67. mindsdb/utilities/starters.py +0 -10
  68. {mindsdb-25.9.3rc1.dist-info → mindsdb-25.10.0.dist-info}/METADATA +278 -264
  69. {mindsdb-25.9.3rc1.dist-info → mindsdb-25.10.0.dist-info}/RECORD +72 -86
  70. mindsdb/api/postgres/__init__.py +0 -0
  71. mindsdb/api/postgres/postgres_proxy/__init__.py +0 -0
  72. mindsdb/api/postgres/postgres_proxy/executor/__init__.py +0 -1
  73. mindsdb/api/postgres/postgres_proxy/executor/executor.py +0 -182
  74. mindsdb/api/postgres/postgres_proxy/postgres_packets/__init__.py +0 -0
  75. mindsdb/api/postgres/postgres_proxy/postgres_packets/errors.py +0 -322
  76. mindsdb/api/postgres/postgres_proxy/postgres_packets/postgres_fields.py +0 -34
  77. mindsdb/api/postgres/postgres_proxy/postgres_packets/postgres_message.py +0 -31
  78. mindsdb/api/postgres/postgres_proxy/postgres_packets/postgres_message_formats.py +0 -1265
  79. mindsdb/api/postgres/postgres_proxy/postgres_packets/postgres_message_identifiers.py +0 -31
  80. mindsdb/api/postgres/postgres_proxy/postgres_packets/postgres_packets.py +0 -265
  81. mindsdb/api/postgres/postgres_proxy/postgres_proxy.py +0 -477
  82. mindsdb/api/postgres/postgres_proxy/utilities/__init__.py +0 -10
  83. mindsdb/api/postgres/start.py +0 -11
  84. mindsdb/integrations/handlers/mssql_handler/tests/__init__.py +0 -0
  85. mindsdb/integrations/handlers/mssql_handler/tests/test_mssql_handler.py +0 -169
  86. mindsdb/integrations/handlers/oracle_handler/tests/__init__.py +0 -0
  87. mindsdb/integrations/handlers/oracle_handler/tests/test_oracle_handler.py +0 -32
  88. {mindsdb-25.9.3rc1.dist-info → mindsdb-25.10.0.dist-info}/WHEEL +0 -0
  89. {mindsdb-25.9.3rc1.dist-info → mindsdb-25.10.0.dist-info}/licenses/LICENSE +0 -0
  90. {mindsdb-25.9.3rc1.dist-info → mindsdb-25.10.0.dist-info}/top_level.txt +0 -0
@@ -1,11 +1,23 @@
1
- import copy
2
1
  import os
3
2
  from typing import List
4
3
 
5
4
  from openai import OpenAI, AzureOpenAI
6
5
 
7
6
  from mindsdb.integrations.utilities.handler_utils import get_api_key
8
- from mindsdb.utilities.config import config
7
+
8
+ try:
9
+ from mindsdb.integrations.handlers.openai_handler.helpers import retry_with_exponential_backoff
10
+ except ImportError:
11
+
12
+ def retry_with_exponential_backoff(func):
13
+ """
14
+ An empty decorator
15
+ """
16
+
17
+ def wrapper(*args, **kwargs):
18
+ return func(*args, **kwargs)
19
+
20
+ return wrapper
9
21
 
10
22
 
11
23
  class LLMClient:
@@ -14,12 +26,8 @@ class LLMClient:
14
26
  It chooses openai client or litellm handler depending on the config
15
27
  """
16
28
 
17
- def __init__(self, llm_params: dict = None):
18
- params = copy.deepcopy(config.get("default_llm", {}))
19
-
20
- if llm_params:
21
- params.update(llm_params)
22
-
29
+ def __init__(self, params: dict = None, session=None):
30
+ self._session = session
23
31
  self.params = params
24
32
 
25
33
  self.provider = params.get("provider", "openai")
@@ -27,11 +35,13 @@ class LLMClient:
27
35
  if "api_key" not in params:
28
36
  params["api_key"] = get_api_key(self.provider, params, strict=False)
29
37
 
38
+ self.engine = "openai"
39
+
30
40
  if self.provider == "azure_openai":
31
41
  azure_api_key = params.get("api_key") or os.getenv("AZURE_OPENAI_API_KEY")
32
42
  azure_api_endpoint = params.get("base_url") or os.environ.get("AZURE_OPENAI_ENDPOINT")
33
43
  azure_api_version = params.get("api_version") or os.environ.get("AZURE_OPENAI_API_VERSION")
34
- self._llm_client = AzureOpenAI(
44
+ self.client = AzureOpenAI(
35
45
  api_key=azure_api_key, azure_endpoint=azure_api_endpoint, api_version=azure_api_version, max_retries=2
36
46
  )
37
47
  elif self.provider == "openai":
@@ -41,34 +51,58 @@ class LLMClient:
41
51
  if base_url:
42
52
  kwargs["base_url"] = base_url
43
53
  self.client = OpenAI(**kwargs)
44
-
54
+ elif self.provider == "ollama":
55
+ kwargs = params.copy()
56
+ kwargs.pop("model_name")
57
+ kwargs.pop("provider", None)
58
+ if kwargs["api_key"] is None:
59
+ kwargs["api_key"] = "n/a"
60
+ self.client = OpenAI(**kwargs)
45
61
  else:
46
62
  # try to use litellm
47
- from mindsdb.api.executor.controllers.session_controller import SessionController
63
+ if self._session is None:
64
+ from mindsdb.api.executor.controllers.session_controller import SessionController
48
65
 
49
- session = SessionController()
50
- module = session.integration_controller.get_handler_module("litellm")
66
+ self._session = SessionController()
67
+ module = self._session.integration_controller.get_handler_module("litellm")
51
68
 
52
69
  if module is None or module.Handler is None:
53
70
  raise ValueError(f'Unable to use "{self.provider}" provider. Litellm handler is not installed')
54
71
 
55
72
  self.client = module.Handler
73
+ self.engine = "litellm"
74
+
75
+ @retry_with_exponential_backoff()
76
+ def embeddings(self, messages: List[str]):
77
+ params = self.params
78
+ if self.engine == "openai":
79
+ response = self.client.embeddings.create(
80
+ model=params["model_name"],
81
+ input=messages,
82
+ )
83
+ return [item.embedding for item in response.data]
84
+ else:
85
+ kwargs = params.copy()
86
+ model = kwargs.pop("model_name")
87
+ kwargs.pop("provider", None)
88
+
89
+ return self.client.embeddings(self.provider, model=model, messages=messages, args=kwargs)
56
90
 
57
- def completion(self, messages: List[dict], json_output: bool = False) -> str:
91
+ def completion(self, messages: List[dict], json_output: bool = False) -> List[str]:
58
92
  """
59
93
  Call LLM completion and get response
60
94
  """
61
95
  params = self.params
62
96
  params["json_output"] = json_output
63
- if self.provider in ("azure_openai", "openai"):
97
+ if self.engine == "openai":
64
98
  response = self.client.chat.completions.create(
65
99
  model=params["model_name"],
66
100
  messages=messages,
67
101
  )
68
- return response.choices[0].message.content
102
+ return [item.message.content for item in response.choices]
69
103
  else:
70
104
  kwargs = params.copy()
71
105
  model = kwargs.pop("model_name")
72
106
  kwargs.pop("provider", None)
73
107
  response = self.client.completion(self.provider, model=model, messages=messages, args=kwargs)
74
- return response.choices[0].message.content
108
+ return [item.message.content for item in response.choices]
@@ -246,8 +246,8 @@ class ModelController:
246
246
 
247
247
  def prepare_create_statement(self, statement, database_controller):
248
248
  # extract data from Create model or Retrain statement and prepare it for using in crate and retrain functions
249
- project_name = statement.name.parts[0].lower()
250
- model_name = statement.name.parts[1].lower()
249
+ project_name = statement.name.parts[0]
250
+ model_name = statement.name.parts[1]
251
251
 
252
252
  sql_task = None
253
253
  if statement.task is not None:
@@ -294,11 +294,11 @@ class ModelController:
294
294
  def create_model(self, statement, ml_handler):
295
295
  params = self.prepare_create_statement(statement, ml_handler.database_controller)
296
296
 
297
- existing_projects_meta = ml_handler.database_controller.get_dict(filter_type="project")
297
+ existing_projects_meta = ml_handler.database_controller.get_dict(filter_type="project", lowercase=False)
298
298
  if params["project_name"] not in existing_projects_meta:
299
299
  raise EntityNotExistsError("Project does not exist", params["project_name"])
300
300
 
301
- project = ml_handler.database_controller.get_project(name=params["project_name"])
301
+ project = ml_handler.database_controller.get_project(name=params["project_name"], strict_case=True)
302
302
  project_tables = project.get_tables()
303
303
  if params["model_name"] in project_tables:
304
304
  raise EntityExistsError("Model already exists", f"{params['project_name']}.{params['model_name']}")
@@ -177,29 +177,23 @@ class MindsDBSQLToolkit(SQLDatabaseToolkit):
177
177
 
178
178
  Query Types and Examples:
179
179
  1. Basic semantic search:
180
- kb_query_tool("SELECT * FROM kb_name WHERE content = 'your search query';")
180
+ kb_query_tool("SELECT * FROM kb_name WHERE chunk_content = 'your search query';")
181
181
 
182
182
  2. Metadata filtering:
183
183
  kb_query_tool("SELECT * FROM kb_name WHERE metadata_field = 'value';")
184
184
 
185
185
  3. Combined search:
186
- kb_query_tool("SELECT * FROM kb_name WHERE content = 'query' AND metadata_field = 'value';")
186
+ kb_query_tool("SELECT * FROM kb_name WHERE chunk_content = 'query' AND metadata_field = 'value';")
187
187
 
188
188
  4. Setting relevance threshold:
189
- kb_query_tool("SELECT * FROM kb_name WHERE content = 'query' AND relevance_threshold = 0.7;")
189
+ kb_query_tool("SELECT * FROM kb_name WHERE chunk_content = 'query' AND relevance_threshold = 0.7;")
190
190
 
191
191
  5. Limiting results:
192
- kb_query_tool("SELECT * FROM kb_name WHERE content = 'query' LIMIT 5;")
192
+ kb_query_tool("SELECT * FROM kb_name WHERE chunk_content = 'query' LIMIT 5;")
193
193
 
194
194
  6. Getting sample data:
195
195
  kb_query_tool("SELECT * FROM kb_name LIMIT 3;")
196
196
 
197
- 7. Don't use LIKE operator on content filter ie semantic search:
198
- SELECT * FROM `test_kb` WHERE content LIKE '%population of New York%' $STOP$
199
-
200
- Like is not supported, use the following instead:
201
- SELECT * FROM `test_kb` WHERE content = 'population of New York'
202
-
203
197
  Result Format:
204
198
  - Results include: id, chunk_id, chunk_content, metadata, distance, and relevance columns
205
199
  - The metadata column contains a JSON object with all metadata fields
@@ -100,10 +100,7 @@ class SkillsController:
100
100
  project_name = default_project
101
101
  project = self.project_controller.get(name=project_name)
102
102
 
103
- if not name.islower():
104
- raise ValueError(f"The name must be in lower case: {name}")
105
-
106
- skill = self.get_skill(name, project_name)
103
+ skill = self.get_skill(name, project_name, strict_case=True)
107
104
 
108
105
  if skill is not None:
109
106
  raise ValueError(f"Skill with name already exists: {name}")
@@ -1,4 +1,5 @@
1
1
  import json
2
+ import orjson
2
3
  import datetime
3
4
  from typing import Dict, List, Optional
4
5
 
@@ -47,10 +48,20 @@ def init(connection_str: str = None):
47
48
  global Base, session, engine
48
49
  if connection_str is None:
49
50
  connection_str = config["storage_db"]
51
+ # Use orjson with our CustomJSONEncoder.default for JSON serialization
52
+ _default_json = CustomJSONEncoder().default
53
+
54
+ def _json_serializer(value):
55
+ return orjson.dumps(
56
+ value,
57
+ default=_default_json,
58
+ option=orjson.OPT_SERIALIZE_NUMPY | orjson.OPT_PASSTHROUGH_DATETIME,
59
+ ).decode("utf-8")
60
+
50
61
  base_args = {
51
62
  "pool_size": 30,
52
63
  "max_overflow": 200,
53
- "json_serializer": CustomJSONEncoder().encode,
64
+ "json_serializer": _json_serializer,
54
65
  }
55
66
  engine = create_engine(connection_str, echo=False, **base_args)
56
67
  session = scoped_session(sessionmaker(bind=engine, autoflush=True))
@@ -534,11 +545,10 @@ class KnowledgeBase(Base):
534
545
  reranking_model = params.pop("reranking_model", None)
535
546
 
536
547
  if not with_secrets:
537
- if embedding_model and "api_key" in embedding_model:
538
- embedding_model["api_key"] = "******"
539
-
540
- if reranking_model and "api_key" in reranking_model:
541
- reranking_model["api_key"] = "******"
548
+ for key in ("api_key", "private_key"):
549
+ for el in (embedding_model, reranking_model):
550
+ if el and key in el:
551
+ el[key] = "******"
542
552
 
543
553
  return {
544
554
  "id": self.id,
@@ -14,8 +14,6 @@ class TriggersController:
14
14
  OBJECT_TYPE = "trigger"
15
15
 
16
16
  def add(self, name, project_name, table, query_str, columns=None):
17
- name = name.lower()
18
-
19
17
  if project_name is None:
20
18
  project_name = config.get("default_project")
21
19
  project_controller = ProjectController()
@@ -155,7 +153,7 @@ class TriggersController:
155
153
  {
156
154
  "id": record.object_id,
157
155
  "project": project_names[record.project_id],
158
- "name": record.name.lower(),
156
+ "name": record.name,
159
157
  "database": database_names.get(record.database_id, "?"),
160
158
  "table": record.table_name,
161
159
  "query": record.query_str,
@@ -181,7 +181,6 @@ class Config:
181
181
  "max_restart_count": 1,
182
182
  "max_restart_interval_seconds": 60,
183
183
  },
184
- "postgres": {"host": api_host, "port": "55432", "database": "mindsdb"},
185
184
  "litellm": {
186
185
  "host": "0.0.0.0", # API server binds to all interfaces by default
187
186
  "port": "8000",
@@ -234,7 +233,17 @@ class Config:
234
233
 
235
234
  # region storage root path
236
235
  if os.environ.get("MINDSDB_STORAGE_DIR", "") != "":
237
- self._env_config["paths"] = {"root": Path(os.environ["MINDSDB_STORAGE_DIR"])}
236
+ storage_root_path = Path(os.environ["MINDSDB_STORAGE_DIR"])
237
+ self._env_config["paths"] = {
238
+ "root": storage_root_path,
239
+ "content": storage_root_path / "content",
240
+ "storage": storage_root_path / "storage",
241
+ "static": storage_root_path / "static",
242
+ "tmp": storage_root_path / "tmp",
243
+ "log": storage_root_path / "log",
244
+ "cache": storage_root_path / "cache",
245
+ "locks": storage_root_path / "locks",
246
+ }
238
247
  # endregion
239
248
 
240
249
  # region vars: permanent storage disabled?
@@ -356,6 +365,14 @@ class Config:
356
365
  self._env_config["gui"]["open_on_start"] = False
357
366
  self._env_config["gui"]["autoupdate"] = False
358
367
 
368
+ mindsdb_gui_autoupdate = os.environ.get("MINDSDB_GUI_AUTOUPDATE", "").lower()
369
+ if mindsdb_gui_autoupdate in ("0", "false"):
370
+ self._env_config["gui"]["autoupdate"] = False
371
+ elif mindsdb_gui_autoupdate in ("1", "true"):
372
+ self._env_config["gui"]["autoupdate"] = True
373
+ elif mindsdb_gui_autoupdate != "":
374
+ raise ValueError(f"Wrong value of env var MINDSDB_GUI_AUTOUPDATE={mindsdb_gui_autoupdate}")
375
+
359
376
  def fetch_auto_config(self) -> bool:
360
377
  """Load dict readed from config.auto.json to `auto_config`.
361
378
  Do it only if `auto_config` was not loaded before or config.auto.json been changed.
@@ -54,7 +54,7 @@ class QueryError(MindsDBError):
54
54
  db_error_msg: str | None = None,
55
55
  failed_query: str | None = None,
56
56
  is_external: bool = True,
57
- is_acceptable: bool = False,
57
+ is_expected: bool = False,
58
58
  ) -> None:
59
59
  self.mysql_error_code = ERR.ER_UNKNOWN_ERROR
60
60
  self.db_name = db_name
@@ -62,7 +62,7 @@ class QueryError(MindsDBError):
62
62
  self.db_error_msg = db_error_msg
63
63
  self.failed_query = failed_query
64
64
  self.is_external = is_external
65
- self.is_acceptable = is_acceptable
65
+ self.is_expected = is_expected
66
66
 
67
67
  def __str__(self) -> str:
68
68
  return format_db_error_message(
@@ -1,13 +1,12 @@
1
1
  from datetime import datetime, date, timedelta
2
2
  from decimal import Decimal
3
- import numpy as np
4
3
  import pandas as pd
5
- import json
6
-
4
+ import numpy as np
5
+ import orjson
7
6
  from flask.json.provider import DefaultJSONProvider
8
7
 
9
8
 
10
- class CustomJSONEncoder(json.JSONEncoder):
9
+ class CustomJSONEncoder:
11
10
  def default(self, obj):
12
11
  if isinstance(obj, timedelta):
13
12
  return str(obj)
@@ -15,12 +14,10 @@ class CustomJSONEncoder(json.JSONEncoder):
15
14
  return obj.strftime("%Y-%m-%d %H:%M:%S.%f")
16
15
  if isinstance(obj, date):
17
16
  return obj.strftime("%Y-%m-%d")
17
+ if isinstance(obj, Decimal):
18
+ return float(obj)
18
19
  if isinstance(obj, np.bool_):
19
20
  return bool(obj)
20
- if isinstance(obj, np.int8) or isinstance(obj, np.int16) or isinstance(obj, np.int32) or isinstance(obj, np.int64):
21
- return int(obj)
22
- if isinstance(obj, np.float16) or isinstance(obj, np.float32) or isinstance(obj, np.float64) or isinstance(obj, Decimal):
23
- return float(obj)
24
21
  if isinstance(obj, np.ndarray):
25
22
  return obj.tolist()
26
23
  if pd.isnull(obj):
@@ -29,5 +26,22 @@ class CustomJSONEncoder(json.JSONEncoder):
29
26
  return str(obj)
30
27
 
31
28
 
32
- class CustomJSONProvider(CustomJSONEncoder, DefaultJSONProvider):
33
- ...
29
+ class ORJSONProvider(DefaultJSONProvider):
30
+ """
31
+ Use orjson to serialize data instead of flask json provider.
32
+ """
33
+
34
+ def dumps(self, obj, **kwargs):
35
+ return orjson.dumps(
36
+ obj,
37
+ option=(
38
+ orjson.OPT_SERIALIZE_NUMPY
39
+ | orjson.OPT_NON_STR_KEYS
40
+ # keep this for using CustomJSON encoder
41
+ | orjson.OPT_PASSTHROUGH_DATETIME
42
+ ),
43
+ default=CustomJSONEncoder().default,
44
+ ).decode("utf-8")
45
+
46
+ def loads(self, s, **kwargs):
47
+ return orjson.loads(s)
@@ -10,6 +10,7 @@ from sqlalchemy.dialects import mysql, postgresql, sqlite, mssql, oracle
10
10
  from sqlalchemy.schema import CreateTable, DropTable
11
11
  from sqlalchemy.sql import ColumnElement
12
12
  from sqlalchemy.sql import functions as sa_fnc
13
+ from sqlalchemy.engine.interfaces import Dialect
13
14
 
14
15
  from mindsdb_sql_parser import ast
15
16
 
@@ -80,27 +81,27 @@ def get_is_quoted(identifier: ast.Identifier):
80
81
  return quoted
81
82
 
82
83
 
83
- class SqlalchemyRender:
84
- def __init__(self, dialect_name):
85
- dialects = {
86
- "mysql": mysql,
87
- "postgresql": postgresql,
88
- "postgres": postgresql,
89
- "sqlite": sqlite,
90
- "mssql": mssql,
91
- "oracle": oracle,
92
- "Snowflake": oracle,
93
- }
84
+ dialects = {
85
+ "mysql": mysql,
86
+ "postgresql": postgresql,
87
+ "postgres": postgresql,
88
+ "sqlite": sqlite,
89
+ "mssql": mssql,
90
+ "oracle": oracle,
91
+ }
92
+
94
93
 
94
+ class SqlalchemyRender:
95
+ def __init__(self, dialect_name: str | Dialect):
95
96
  if isinstance(dialect_name, str):
96
97
  dialect = dialects[dialect_name].dialect
97
98
  else:
98
99
  dialect = dialect_name
99
100
 
100
101
  # override dialect's preparer
101
- if hasattr(dialect, "preparer"):
102
+ if hasattr(dialect, "preparer") and dialect.preparer.__name__ != "MDBPreparer":
102
103
 
103
- class Preparer(dialect.preparer):
104
+ class MDBPreparer(dialect.preparer):
104
105
  def _requires_quotes(self, value: str) -> bool:
105
106
  # check force-quote flag
106
107
  if isinstance(value, AttributedStr):
@@ -116,7 +117,7 @@ class SqlalchemyRender:
116
117
  # or (lc_value != value)
117
118
  )
118
119
 
119
- dialect.preparer = Preparer
120
+ dialect.preparer = MDBPreparer
120
121
 
121
122
  # remove double percent signs
122
123
  # https://docs.sqlalchemy.org/en/14/faq/sqlexpressions.html#why-are-percent-signs-being-doubled-up-when-stringifying-sql-statements
@@ -18,16 +18,6 @@ def start_mysql(*args, **kwargs):
18
18
  start(*args, **kwargs)
19
19
 
20
20
 
21
- def start_postgres(*args, **kwargs):
22
- from mindsdb.utilities.log import initialize_logging
23
-
24
- initialize_logging("postgres")
25
-
26
- from mindsdb.api.postgres.start import start
27
-
28
- start(*args, **kwargs)
29
-
30
-
31
21
  def start_tasks(*args, **kwargs):
32
22
  from mindsdb.utilities.log import initialize_logging
33
23