Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add more SIP-40 errors to SQL Lab #15436

Merged
merged 1 commit into from Jun 30, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
26 changes: 24 additions & 2 deletions docs/src/pages/docs/Miscellaneous/issue_codes.mdx
Expand Up @@ -271,8 +271,6 @@ One or more parameters specified in the query are malformatted.
```

The query contains one or more malformed template parameters. Please check your query and confirm that all template parameters are surround by double braces, for example, "{{ ds }}". Then, try running your query again.
The object does not exist in this database.
```

## Issue 1029

Expand All @@ -289,3 +287,27 @@ The query potentially has a syntax error.
```

The query might have a syntax error. Please check and run again.

## Issue 1031

```
The results backend no longer has the data from the query.
```

The results from the query might have been deleted from the results backend after some period. Please re-run your query.

## Issue 1032

```
The query associated with the results was deleted.
```

The query associated with the stored results no longer exists. Please re-run your query.

## Issue 1033

```
The results stored in the backend were stored in a different format, and no longer can be deserialized.
```

The query results were stored in a format that is no longer supported. Please re-run your query.
2 changes: 2 additions & 0 deletions superset-frontend/src/components/ErrorMessage/types.ts
Expand Up @@ -52,6 +52,7 @@ export const ErrorTypeEnum = {
TABLE_SECURITY_ACCESS_ERROR: 'TABLE_SECURITY_ACCESS_ERROR',
DATASOURCE_SECURITY_ACCESS_ERROR: 'DATASOURCE_SECURITY_ACCESS_ERROR',
DATABASE_SECURITY_ACCESS_ERROR: 'DATABASE_SECURITY_ACCESS_ERROR',
QUERY_SECURITY_ACCESS_ERROR: 'QUERY_SECURITY_ACCESS_ERROR',
MISSING_OWNERSHIP_ERROR: 'MISSING_OWNERSHIP_ERROR',

// Other errors
Expand All @@ -65,6 +66,7 @@ export const ErrorTypeEnum = {
INVALID_CTAS_QUERY_ERROR: 'INVALID_CTAS_QUERY_ERROR',
INVALID_CVAS_QUERY_ERROR: 'INVALID_CVAS_QUERY_ERROR',
SQLLAB_TIMEOUT_ERROR: 'SQLLAB_TIMEOUT_ERROR',
RESULTS_BACKEND_ERROR: 'RESULTS_BACKEND_ERROR',

// Generic errors
GENERIC_COMMAND_ERROR: 'GENERIC_COMMAND_ERROR',
Expand Down
8 changes: 8 additions & 0 deletions superset-frontend/src/setup/setupErrorMessages.ts
Expand Up @@ -71,10 +71,18 @@ export default function setupErrorMessages() {
ErrorTypeEnum.INVALID_CVAS_QUERY_ERROR,
DatabaseErrorMessage,
);
errorMessageComponentRegistry.registerValue(
ErrorTypeEnum.QUERY_SECURITY_ACCESS_ERROR,
DatabaseErrorMessage,
);
errorMessageComponentRegistry.registerValue(
ErrorTypeEnum.CONNECTION_INVALID_HOSTNAME_ERROR,
DatabaseErrorMessage,
);
errorMessageComponentRegistry.registerValue(
ErrorTypeEnum.RESULTS_BACKEND_ERROR,
DatabaseErrorMessage,
);
errorMessageComponentRegistry.registerValue(
ErrorTypeEnum.SQLLAB_TIMEOUT_ERROR,
DatabaseErrorMessage,
Expand Down
26 changes: 25 additions & 1 deletion superset/errors.py
Expand Up @@ -61,6 +61,7 @@ class SupersetErrorType(str, Enum):
TABLE_SECURITY_ACCESS_ERROR = "TABLE_SECURITY_ACCESS_ERROR"
DATASOURCE_SECURITY_ACCESS_ERROR = "DATASOURCE_SECURITY_ACCESS_ERROR"
DATABASE_SECURITY_ACCESS_ERROR = "DATABASE_SECURITY_ACCESS_ERROR"
QUERY_SECURITY_ACCESS_ERROR = "QUERY_SECURITY_ACCESS_ERROR"
MISSING_OWNERSHIP_ERROR = "MISSING_OWNERSHIP_ERROR"

# Other errors
Expand All @@ -74,6 +75,7 @@ class SupersetErrorType(str, Enum):
INVALID_CTAS_QUERY_ERROR = "INVALID_CTAS_QUERY_ERROR"
INVALID_CVAS_QUERY_ERROR = "INVALID_CVAS_QUERY_ERROR"
SQLLAB_TIMEOUT_ERROR = "SQLLAB_TIMEOUT_ERROR"
RESULTS_BACKEND_ERROR = "RESULTS_BACKEND_ERROR"

# Generic errors
GENERIC_COMMAND_ERROR = "GENERIC_COMMAND_ERROR"
Expand Down Expand Up @@ -331,7 +333,29 @@ class SupersetErrorType(str, Enum):
},
],
SupersetErrorType.SYNTAX_ERROR: [
{"code": 1030, "message": _("Issue 1029 - The query has a syntax error."),},
{"code": 1030, "message": _("Issue 1030 - The query has a syntax error.")},
],
SupersetErrorType.RESULTS_BACKEND_ERROR: [
{
"code": 1031,
"message": _(
"Issue 1031 - The results backend no longer has the data from the "
"query."
),
},
{
"code": 1032,
"message": _(
"Issue 1032 - The query associated with the results was deleted."
),
},
{
"code": 1033,
"message": _(
"Issue 1033 - The results stored in the backend were stored in a "
"different format, and no longer can be deserialized."
),
},
],
}

Expand Down
10 changes: 8 additions & 2 deletions superset/exceptions.py
Expand Up @@ -43,9 +43,11 @@ def exception(self) -> Optional[Exception]:
class SupersetErrorException(SupersetException):
"""Exceptions with a single SupersetErrorType associated with them"""

def __init__(self, error: SupersetError) -> None:
def __init__(self, error: SupersetError, status: Optional[int] = None) -> None:
super().__init__(error.message)
self.error = error
if status is not None:
self.status = status


class SupersetGenericErrorException(SupersetErrorException):
Expand Down Expand Up @@ -81,9 +83,13 @@ def __init__(
class SupersetErrorsException(SupersetException):
"""Exceptions with multiple SupersetErrorType associated with them"""

def __init__(self, errors: List[SupersetError]) -> None:
def __init__(
self, errors: List[SupersetError], status: Optional[int] = None
) -> None:
super().__init__(str(errors))
self.errors = errors
if status is not None:
self.status = status


class SupersetTimeoutException(SupersetErrorFromParamsException):
Expand Down
64 changes: 53 additions & 11 deletions superset/views/core.py
Expand Up @@ -2196,39 +2196,81 @@ def results_exec( # pylint: disable=too-many-return-statements
now_as_float() - read_from_results_backend_start,
)
if not blob:
return json_error_response(
"Data could not be retrieved. " "You may want to re-run the query.",
raise SupersetErrorException(
SupersetError(
message=__(
"Data could not be retrieved from the results backend. You "
"need to re-run the original query."
),
error_type=SupersetErrorType.RESULTS_BACKEND_ERROR,
level=ErrorLevel.ERROR,
),
status=410,
)

query = db.session.query(Query).filter_by(results_key=key).one_or_none()
if query is None:
return json_error_response(
"Data could not be retrieved. You may want to re-run the query.",
raise SupersetErrorException(
SupersetError(
message=__(
"The query associated with these results could not be find. "
"You need to re-run the original query."
),
error_type=SupersetErrorType.RESULTS_BACKEND_ERROR,
level=ErrorLevel.ERROR,
),
status=404,
)

try:
query.raise_for_access()
except SupersetSecurityException as ex:
return json_errors_response([ex.error], status=403)
raise SupersetErrorException(
SupersetError(
message=__(
"You are not authorized to see this query. If you think this "
"is an error, please reach out to your administrator."
),
error_type=SupersetErrorType.QUERY_SECURITY_ACCESS_ERROR,
level=ErrorLevel.ERROR,
),
status=403,
) from ex

payload = utils.zlib_decompress(blob, decode=not results_backend_use_msgpack)
try:
obj = _deserialize_results_payload(
payload, query, cast(bool, results_backend_use_msgpack)
)
except SerializationError:
return json_error_response(
__("Data could not be deserialized. You may want to re-run the query."),
except SerializationError as ex:
raise SupersetErrorException(
SupersetError(
message=__(
"Data could not be deserialized from the results backend. The "
"storage format might have changed, rendering the old data "
"stake. You need to re-run the original query."
),
error_type=SupersetErrorType.RESULTS_BACKEND_ERROR,
level=ErrorLevel.ERROR,
),
status=404,
)
) from ex

if "rows" in request.args:
try:
rows = int(request.args["rows"])
except ValueError:
return json_error_response("Invalid `rows` argument", status=400)
except ValueError as ex:
raise SupersetErrorException(
SupersetError(
message=__(
"The provided `rows` argument is not a valid integer."
),
error_type=SupersetErrorType.INVALID_PAYLOAD_SCHEMA_ERROR,
level=ErrorLevel.ERROR,
),
status=400,
) from ex

obj = apply_display_max_row_limit(obj, rows)

return json_success(
Expand Down