MindsDB 25.2.1.2__py3-none-any.whl → 25.2.2.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of MindsDB might be problematic. Click here for more details.
- {MindsDB-25.2.1.2.dist-info → MindsDB-25.2.2.1.dist-info}/METADATA +234 -230
- {MindsDB-25.2.1.2.dist-info → MindsDB-25.2.2.1.dist-info}/RECORD +33 -33
- mindsdb/__about__.py +1 -1
- mindsdb/api/executor/command_executor.py +1 -57
- mindsdb/api/executor/datahub/datanodes/system_tables.py +34 -33
- mindsdb/api/executor/planner/query_planner.py +7 -2
- mindsdb/api/executor/sql_query/steps/fetch_dataframe.py +19 -11
- mindsdb/api/executor/sql_query/steps/subselect_step.py +44 -2
- mindsdb/integrations/handlers/byom_handler/byom_handler.py +1 -1
- mindsdb/integrations/handlers/byom_handler/requirements.txt +1 -1
- mindsdb/integrations/handlers/file_handler/file_handler.py +13 -320
- mindsdb/integrations/handlers/file_handler/tests/test_file_handler.py +60 -156
- mindsdb/integrations/handlers/huggingface_handler/requirements.txt +1 -1
- mindsdb/integrations/handlers/huggingface_handler/requirements_cpu.txt +1 -1
- mindsdb/integrations/handlers/lancedb_handler/requirements.txt +1 -1
- mindsdb/integrations/handlers/lightwood_handler/requirements.txt +3 -3
- mindsdb/integrations/handlers/ms_one_drive_handler/ms_graph_api_one_drive_client.py +3 -3
- mindsdb/integrations/handlers/ms_one_drive_handler/ms_one_drive_tables.py +2 -20
- mindsdb/integrations/handlers/salesforce_handler/connection_args.py +9 -1
- mindsdb/integrations/handlers/salesforce_handler/salesforce_handler.py +2 -1
- mindsdb/integrations/handlers/snowflake_handler/snowflake_handler.py +1 -1
- mindsdb/integrations/handlers/writer_handler/requirements.txt +1 -1
- mindsdb/integrations/utilities/files/file_reader.py +120 -61
- mindsdb/integrations/utilities/handlers/api_utilities/microsoft/ms_graph_api_utilities.py +1 -8
- mindsdb/integrations/utilities/query_traversal.py +42 -37
- mindsdb/interfaces/agents/langfuse_callback_handler.py +205 -27
- mindsdb/interfaces/file/file_controller.py +1 -1
- mindsdb/interfaces/skills/custom/text2sql/mindsdb_sql_toolkit.py +12 -2
- mindsdb/utilities/config.py +2 -2
- mindsdb/utilities/render/sqlalchemy_render.py +52 -19
- {MindsDB-25.2.1.2.dist-info → MindsDB-25.2.2.1.dist-info}/LICENSE +0 -0
- {MindsDB-25.2.1.2.dist-info → MindsDB-25.2.2.1.dist-info}/WHEEL +0 -0
- {MindsDB-25.2.1.2.dist-info → MindsDB-25.2.2.1.dist-info}/top_level.txt +0 -0
|
@@ -54,6 +54,23 @@ def _compile_interval(element, compiler, **kw):
|
|
|
54
54
|
return "INTERVAL " + args
|
|
55
55
|
|
|
56
56
|
|
|
57
|
+
class AttributedStr(str):
|
|
58
|
+
"""
|
|
59
|
+
Custom str-like object to pass it to `_requires_quotes` method with `is_quoted` flag
|
|
60
|
+
"""
|
|
61
|
+
def __new__(cls, string, is_quoted: bool):
|
|
62
|
+
obj = str.__new__(cls, string)
|
|
63
|
+
obj.is_quoted = is_quoted
|
|
64
|
+
return obj
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def get_is_quoted(identifier: ast.Identifier):
|
|
68
|
+
quoted = getattr(identifier, 'is_quoted', [])
|
|
69
|
+
# len can be different
|
|
70
|
+
quoted = quoted + [None] * (len(identifier.parts) - len(quoted))
|
|
71
|
+
return quoted
|
|
72
|
+
|
|
73
|
+
|
|
57
74
|
class SqlalchemyRender:
|
|
58
75
|
|
|
59
76
|
def __init__(self, dialect_name):
|
|
@@ -72,6 +89,29 @@ class SqlalchemyRender:
|
|
|
72
89
|
else:
|
|
73
90
|
dialect = dialect_name
|
|
74
91
|
|
|
92
|
+
# override dialect's preparer
|
|
93
|
+
if hasattr(dialect, 'preparer'):
|
|
94
|
+
class Preparer(dialect.preparer):
|
|
95
|
+
|
|
96
|
+
def __init__(self, *args, **kwargs):
|
|
97
|
+
super().__init__(*args, **kwargs)
|
|
98
|
+
|
|
99
|
+
def _requires_quotes(self, value: str) -> bool:
|
|
100
|
+
# check force-quote flag
|
|
101
|
+
if isinstance(value, AttributedStr):
|
|
102
|
+
if value.is_quoted:
|
|
103
|
+
return True
|
|
104
|
+
|
|
105
|
+
lc_value = value.lower()
|
|
106
|
+
return (
|
|
107
|
+
lc_value in self.reserved_words
|
|
108
|
+
or value[0] in self.illegal_initial_characters
|
|
109
|
+
or not self.legal_characters.match(str(value))
|
|
110
|
+
# Override sqlalchemy behavior: don't require to quote mixed- or upper-case
|
|
111
|
+
# or (lc_value != value)
|
|
112
|
+
)
|
|
113
|
+
dialect.preparer = Preparer
|
|
114
|
+
|
|
75
115
|
# remove double percent signs
|
|
76
116
|
# https://docs.sqlalchemy.org/en/14/faq/sqlexpressions.html#why-are-percent-signs-being-doubled-up-when-stringifying-sql-statements
|
|
77
117
|
self.dialect = dialect(paramstyle="named")
|
|
@@ -90,26 +130,16 @@ class SqlalchemyRender:
|
|
|
90
130
|
|
|
91
131
|
parts2 = []
|
|
92
132
|
|
|
93
|
-
quoted =
|
|
94
|
-
# len can be different
|
|
95
|
-
quoted = quoted + [None] * (len(identifier.parts) - len(quoted))
|
|
96
|
-
|
|
133
|
+
quoted = get_is_quoted(identifier)
|
|
97
134
|
for i, is_quoted in zip(identifier.parts, quoted):
|
|
98
135
|
if isinstance(i, ast.Star):
|
|
99
136
|
part = '*'
|
|
100
|
-
elif is_quoted:
|
|
101
|
-
|
|
137
|
+
elif is_quoted or i.lower() in RESERVED_WORDS:
|
|
138
|
+
# quote anyway
|
|
139
|
+
part = self.dialect.identifier_preparer.quote_identifier(i)
|
|
102
140
|
else:
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
if not i.islower():
|
|
106
|
-
# if lower value is not quoted
|
|
107
|
-
# then it is quoted only because of mixed case
|
|
108
|
-
# in that case use origin string
|
|
109
|
-
|
|
110
|
-
part_lower = str(sa.column(i.lower()).compile(dialect=self.dialect))
|
|
111
|
-
if part.lower() != part_lower and i.lower() not in RESERVED_WORDS:
|
|
112
|
-
part = i
|
|
141
|
+
# quote if required
|
|
142
|
+
part = self.dialect.identifier_preparer.quote(i)
|
|
113
143
|
|
|
114
144
|
parts2.append(part)
|
|
115
145
|
|
|
@@ -120,7 +150,9 @@ class SqlalchemyRender:
|
|
|
120
150
|
return None
|
|
121
151
|
if len(alias.parts) > 1:
|
|
122
152
|
raise NotImplementedError(f'Multiple alias {alias.parts}')
|
|
123
|
-
|
|
153
|
+
|
|
154
|
+
is_quoted = get_is_quoted(alias)[0]
|
|
155
|
+
return AttributedStr(alias.parts[0], is_quoted)
|
|
124
156
|
|
|
125
157
|
def to_expression(self, t):
|
|
126
158
|
|
|
@@ -435,15 +467,16 @@ class SqlalchemyRender:
|
|
|
435
467
|
schema = None
|
|
436
468
|
if isinstance(table_name, ast.Identifier):
|
|
437
469
|
parts = table_name.parts
|
|
470
|
+
quoted = get_is_quoted(table_name)
|
|
438
471
|
|
|
439
472
|
if len(parts) > 2:
|
|
440
473
|
# TODO tests is failing
|
|
441
474
|
raise NotImplementedError(f'Path to long: {table_name.parts}')
|
|
442
475
|
|
|
443
476
|
if len(parts) == 2:
|
|
444
|
-
schema = parts[-2]
|
|
477
|
+
schema = AttributedStr(parts[-2], quoted[-2])
|
|
445
478
|
|
|
446
|
-
table_name = parts[-1]
|
|
479
|
+
table_name = AttributedStr(parts[-1], quoted[-1])
|
|
447
480
|
|
|
448
481
|
return schema, table_name
|
|
449
482
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|