From 41afb84bfd56e7947b1227bb4b4b22280a9d1db1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alja=C5=BE=20Mur=20Er=C5=BEen?= Date: Thu, 21 Nov 2024 14:13:02 +0100 Subject: [PATCH] Improve unsupported error message over SQL adapter (#7995) --- edb/pgsql/parser/ast_builder.py | 6 ++++-- edb/pgsql/parser/exceptions.py | 17 ++++++++++++++--- edb/pgsql/resolver/command.py | 6 +----- edb/pgsql/resolver/dispatch.py | 21 +++++++++++++++++++-- edb/pgsql/resolver/static.py | 5 ++++- edb/server/compiler/sql.py | 5 ++--- tests/test_sql_dml.py | 4 ++-- tests/test_sql_query.py | 24 ++++++++++++++++++++++++ 8 files changed, 70 insertions(+), 18 deletions(-) diff --git a/edb/pgsql/parser/ast_builder.py b/edb/pgsql/parser/ast_builder.py index b7688634497..1b62b424cc4 100644 --- a/edb/pgsql/parser/ast_builder.py +++ b/edb/pgsql/parser/ast_builder.py @@ -36,7 +36,7 @@ from edb.pgsql import ast as pgast from edb.edgeql import ast as qlast -from edb.pgsql.parser.exceptions import PSqlUnsupportedError +from edb.pgsql.parser.exceptions import PSqlUnsupportedError, get_node_name @dataclasses.dataclass(kw_only=True) @@ -134,7 +134,9 @@ def _enum( if outer_fallback: return None # type: ignore - raise PSqlUnsupportedError(node, ", ".join(node.keys())) + raise PSqlUnsupportedError( + node, ", ".join(get_node_name(k) for k in node.keys()) + ) finally: ctx.has_fallback = outer_fallback diff --git a/edb/pgsql/parser/exceptions.py b/edb/pgsql/parser/exceptions.py index 207f485f577..82053a8f364 100644 --- a/edb/pgsql/parser/exceptions.py +++ b/edb/pgsql/parser/exceptions.py @@ -16,7 +16,7 @@ # limitations under the License. # - +import re from typing import Any, Optional @@ -34,9 +34,20 @@ class PSqlUnsupportedError(Exception): def __init__(self, node: Optional[Any] = None, feat: Optional[str] = None): self.node = node self.location = None - self.message = "unsupported SQL feature" + self.message = "not supported" if feat: - self.message += f" `{feat}`" + self.message += f": {feat}" def __str__(self): return self.message + + +def get_node_name(name: str) -> str: + """ + Given a node name (CreateTableStmt), this function tries to guess the SQL + command text (CREATE TABLE). + """ + + name = name.removesuffix('Stmt').removesuffix('Expr') + name = re.sub(r'(? pgast.Base: - raise ValueError(f'no SQL resolve handler for {expr.__class__}') + expr.dump() + _raise_unsupported(expr) def resolve(expr: Base_T, *, ctx: context.ResolverContextLevel) -> Base_T: @@ -85,7 +89,7 @@ def _resolve_relation( include_inherited: bool, ctx: context.ResolverContextLevel, ) -> typing.Tuple[pgast.BaseRelation, context.Table]: - raise ValueError(f'no SQL resolve handler for {rel.__class__}') + _raise_unsupported(rel) @_resolve.register @@ -96,3 +100,16 @@ def _resolve_BaseRelation( rel, _ = resolve_relation(rel, ctx=ctx) return rel + + +def _raise_unsupported(expr: pgast.Base) -> typing.Never: + pretty_name = expr.__class__.__name__ + pretty_name = pretty_name.removesuffix('Stmt') + # title case to spaces + pretty_name = re.sub(r'(?