You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iotdb.apache.org by ro...@apache.org on 2023/05/31 13:24:49 UTC
[iotdb] branch master updated: [PyClient] Update SQLAlchemy version to 1.4 (#10006)
This is an automated email from the ASF dual-hosted git repository.
rong pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iotdb.git
The following commit(s) were added to refs/heads/master by this push:
new 24f8c3e0621 [PyClient] Update SQLAlchemy version to 1.4 (#10006)
24f8c3e0621 is described below
commit 24f8c3e062124384473d7caf8d272ec35fdfb528
Author: Chen YZ <43...@users.noreply.github.com>
AuthorDate: Wed May 31 21:24:42 2023 +0800
[PyClient] Update SQLAlchemy version to 1.4 (#10006)
---
.../client-py/iotdb/sqlalchemy/IoTDBSQLCompiler.py | 203 +++++++++++++++------
iotdb-client/client-py/setup.py | 4 +-
2 files changed, 145 insertions(+), 62 deletions(-)
diff --git a/iotdb-client/client-py/iotdb/sqlalchemy/IoTDBSQLCompiler.py b/iotdb-client/client-py/iotdb/sqlalchemy/IoTDBSQLCompiler.py
index 36c4ca0bf76..8d966febd69 100644
--- a/iotdb-client/client-py/iotdb/sqlalchemy/IoTDBSQLCompiler.py
+++ b/iotdb-client/client-py/iotdb/sqlalchemy/IoTDBSQLCompiler.py
@@ -52,35 +52,63 @@ class IoTDBSQLCompiler(SQLCompiler):
1. IoTDB does not support querying Time as a measurement name (e.g. select Time from root.storagegroup.device)
2. IoTDB does not support path.measurement format to determine a column (e.g. select root.storagegroup.device.temperature from root.storagegroup.device)
"""
- needs_nested_translation = (
- select.use_labels
- and not nested_join_translation
- and not self.stack
- and not self.dialect.supports_right_nested_joins
+ assert select_wraps_for is None, (
+ "SQLAlchemy 1.4 requires use of "
+ "the translate_select_structure hook for structural "
+ "translations of SELECT objects"
)
- if needs_nested_translation:
- transformed_select = self._transform_select_for_nested_joins(select)
- text = self.visit_select(
- transformed_select,
- asfrom=asfrom,
- parens=parens,
- fromhints=fromhints,
- compound_index=compound_index,
- nested_join_translation=True,
- **kwargs,
- )
+ # initial setup of SELECT. the compile_state_factory may now
+ # be creating a totally different SELECT from the one that was
+ # passed in. for ORM use this will convert from an ORM-state
+ # SELECT to a regular "Core" SELECT. other composed operations
+ # such as computation of joins will be performed.
+
+ kwargs["within_columns_clause"] = False
+
+ compile_state = select_stmt._compile_state_factory(
+ select_stmt, self, **kwargs
+ )
+ select_stmt = compile_state.statement
toplevel = not self.stack
+
+ if toplevel and not self.compile_state:
+ self.compile_state = compile_state
+
+ is_embedded_select = compound_index is not None or insert_into
+
+ # translate step for Oracle, SQL Server which often need to
+ # restructure the SELECT to allow for LIMIT/OFFSET and possibly
+ # other conditions
+ if self.translate_select_structure:
+ new_select_stmt = self.translate_select_structure(
+ select_stmt, asfrom=asfrom, **kwargs
+ )
+
+ # if SELECT was restructured, maintain a link to the originals
+ # and assemble a new compile state
+ if new_select_stmt is not select_stmt:
+ compile_state_wraps_for = compile_state
+ select_wraps_for = select_stmt
+ select_stmt = new_select_stmt
+
+ compile_state = select_stmt._compile_state_factory(
+ select_stmt, self, **kwargs
+ )
+ select_stmt = compile_state.statement
+
entry = self._default_stack_entry if toplevel else self.stack[-1]
populate_result_map = need_column_expressions = (
- toplevel
- or entry.get("need_result_map_for_compound", False)
- or entry.get("need_result_map_for_nested", False)
+ toplevel
+ or entry.get("need_result_map_for_compound", False)
+ or entry.get("need_result_map_for_nested", False)
)
- if compound_index > 0:
+ # indicates there is a CompoundSelect in play and we are not the
+ # first select
+ if compound_index:
populate_result_map = False
# this was first proposed as part of #3372; however, it is not
@@ -89,12 +117,9 @@ class IoTDBSQLCompiler(SQLCompiler):
if not populate_result_map and "add_to_result_map" in kwargs:
del kwargs["add_to_result_map"]
- if needs_nested_translation:
- if populate_result_map:
- self._transform_result_map_for_nested_joins(select, transformed_select)
- return text
-
- froms = self._setup_select_stack(select, entry, asfrom, lateral)
+ froms = self._setup_select_stack(
+ select_stmt, compile_state, entry, asfrom, lateral, compound_index
+ )
column_clause_args = kwargs.copy()
column_clause_args.update(
@@ -103,43 +128,76 @@ class IoTDBSQLCompiler(SQLCompiler):
text = "SELECT " # we're off to a good start !
- if select._hints:
- hint_text, byfrom = self._setup_select_hints(select)
+ if select_stmt._hints:
+ hint_text, byfrom = self._setup_select_hints(select_stmt)
if hint_text:
text += hint_text + " "
else:
byfrom = None
- if select._prefixes:
- text += self._generate_prefixes(select, select._prefixes, **kwargs)
+ if select_stmt._independent_ctes:
+ for cte in select_stmt._independent_ctes:
+ cte._compiler_dispatch(self, **kwargs)
- text += self.get_select_precolumns(select, **kwargs)
+ if select_stmt._prefixes:
+ text += self._generate_prefixes(
+ select_stmt, select_stmt._prefixes, **kwargs
+ )
+
+ text += self.get_select_precolumns(select_stmt, **kwargs)
# the actual list of columns to print in the SELECT column list.
- # IoTDB does not support querying Time as a measurement name (e.g. select Time from root.storagegroup.device)
- columns = []
- for name, column in select._columns_plus_names:
- column.table = None
- columns.append(
+ inner_columns = [
+ c
+ for c in [
self._label_select_column(
- select,
+ select_stmt,
column,
populate_result_map,
asfrom,
column_clause_args,
name=name,
+ proxy_name=proxy_name,
+ fallback_label_name=fallback_label_name,
+ column_is_repeated=repeated,
need_column_expressions=need_column_expressions,
)
- )
- inner_columns = [c for c in columns if c is not None]
+ for (
+ name,
+ proxy_name,
+ fallback_label_name,
+ column,
+ repeated,
+ ) in compile_state.columns_plus_names
+ ]
+ if c is not None
+ ]
if populate_result_map and select_wraps_for is not None:
- # if this select is a compiler-generated wrapper,
+ # if this select was generated from translate_select,
# rewrite the targeted columns in the result map
translate = dict(
zip(
- [name for (key, name) in select._columns_plus_names],
- [name for (key, name) in select_wraps_for._columns_plus_names],
+ [
+ name
+ for (
+ key,
+ proxy_name,
+ fallback_label_name,
+ name,
+ repeated,
+ ) in compile_state.columns_plus_names
+ ],
+ [
+ name
+ for (
+ key,
+ proxy_name,
+ fallback_label_name,
+ name,
+ repeated,
+ ) in compile_state_wraps_for.columns_plus_names
+ ],
)
)
@@ -147,6 +205,17 @@ class IoTDBSQLCompiler(SQLCompiler):
(key, name, tuple(translate.get(o, o) for o in obj), type_)
for key, name, obj, type_ in self._result_columns
]
+
+ # change the superset aggregate function name into iotdb aggregate function name
+ # by matching the head of aggregate function name and replace it.
+ for i in range(len(inner_columns)):
+ if inner_columns[i].startswith("max("):
+ inner_columns[i] = inner_columns[i].replace("max(", "max_value(")
+ if inner_columns[i].startswith("min("):
+ inner_columns[i] = inner_columns[i].replace("min(", "min_value(")
+ if inner_columns[i].startswith("count(DISTINCT"):
+ inner_columns[i] = inner_columns[i].replace("count(DISTINCT", "count(")
+
# IoTDB does not allow to query Time as column,
# need to filter out Time and pass Time and Time's alias to DBAPI separately
# to achieve the query of Time by encoding.
@@ -167,44 +236,58 @@ class IoTDBSQLCompiler(SQLCompiler):
inner_columns = list(
filter(
lambda x: "Time"
- not in x.replace(self.preparer.initial_quote, "").split(),
+ not in x.replace(self.preparer.initial_quote, "").split(),
inner_columns,
)
)
+
if inner_columns and time_column_index:
inner_columns[-1] = (
- inner_columns[-1]
- + " \n FROM Time Index "
- + " ".join(time_column_index)
- + "\n FROM Time Name "
- + " ".join(time_column_names)
+ inner_columns[-1]
+ + " \n FROM Time Index "
+ + " ".join(time_column_index)
+ + " \n FROM Time Name "
+ + " ".join(time_column_names)
)
text = self._compose_select_body(
- text, select, inner_columns, froms, byfrom, kwargs
+ text,
+ select_stmt,
+ compile_state,
+ inner_columns,
+ froms,
+ byfrom,
+ toplevel,
+ kwargs,
)
- if select._statement_hints:
+ if select_stmt._statement_hints:
per_dialect = [
ht
- for (dialect_name, ht) in select._statement_hints
+ for (dialect_name, ht) in select_stmt._statement_hints
if dialect_name in ("*", self.dialect.name)
]
if per_dialect:
text += " " + self.get_statement_hint_text(per_dialect)
- if self.ctes and toplevel:
- text = self._render_cte_clause() + text
+ # In compound query, CTEs are shared at the compound level
+ if self.ctes and (not is_embedded_select or toplevel):
+ nesting_level = len(self.stack) if not toplevel else None
+ text = (
+ self._render_cte_clause(
+ nesting_level=nesting_level,
+ visiting_cte=kwargs.get("visiting_cte"),
+ )
+ + text
+ )
- if select._suffixes:
- text += " " + self._generate_prefixes(select, select._suffixes, **kwargs)
+ if select_stmt._suffixes:
+ text += " " + self._generate_prefixes(
+ select_stmt, select_stmt._suffixes, **kwargs
+ )
self.stack.pop(-1)
-
- if (asfrom or lateral) and parens:
- return "(" + text + ")"
- else:
- return text
+ return text
def visit_table(
self,
diff --git a/iotdb-client/client-py/setup.py b/iotdb-client/client-py/setup.py
index 6cbdf12c1c8..364f42e5ae6 100644
--- a/iotdb-client/client-py/setup.py
+++ b/iotdb-client/client-py/setup.py
@@ -44,8 +44,8 @@ setuptools.setup(
"pandas>=1.0.0,<1.99.99",
"numpy>=1.0.0",
"testcontainers>=2.0.0",
- "sqlalchemy>=1.3.16, <1.4, !=1.3.21",
- "sqlalchemy-utils>=0.37.8, <0.38",
+ "sqlalchemy<1.5,>=1.4",
+ "sqlalchemy-utils>=0.37.8",
],
classifiers=[
"Programming Language :: Python :: 3",