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

Superset SQL parser does not recognize FETCH FIRST clause causing syntax error when appending LIMIT clause #27427

Open
3 tasks done
hab6 opened this issue Mar 7, 2024 · 1 comment

Comments

@hab6
Copy link

hab6 commented Mar 7, 2024

Bug description

In sql_parse.py, the Superset SQL parser is able to recognize and handle row limiting clauses that use keywords LIMIT and TOP but does not handle the FETCH FIRST clause, which is used by some databases, including Ingres and PostgreSQL. With Ingres, the FETCH FIRST clause is required if using the OFFSET keyword in a SQL SELECT statement.

If an [OFFSET] FETCH FIRST clause is used in a SQL statement, the Superset parser still appends a LIMIT clause, which makes the SQL syntactically invalid.

The problem can be worked around by setting SQL_MAX_ROW=0 in superset_config.py, but this requires restarting Superset and doesn't fit well if SQL_MAX_ROW needs to be set to a value greater than zero for other reasons.

I found the following two older issues that reported similar problems using DB2 and Teradata, but they don't seem to have addressed the issue that still exists when using a FETCH FIRST clause.

#5063 and #9600

How to reproduce the bug

The problem can be reproduced using Superset SQL Lab with an Ingres or Postgres database by trying to execute an adhoc SQL statement such as SELECT * FROM myschema.people OFFSET 5 FETCH FIRST 3 ROWS ONLY in SQL Lab. Superset reports an error because the SQL parser appends a LIMIT clause, which makes the SQL syntactically invalid:

SELECT * FROM myschema.people OFFSET 5 FETCH FIRST 3 ROWS ONLY LIMIT 11
SupersetErrorsException
[42000] [Actian][Actian ODBC Driver][INGRES]line 2,
Syntax error on \'LIMIT\' at or near \' fetch first 3 rows only\\nLIMIT\' ...

Screenshots/recordings

No response

Superset version

master / latest-dev

Python version

3.10

Node version

I don't know

Browser

Not applicable

Additional context

Stack trace

2024-03-07 16:33:34,277:INFO:werkzeug:10.250.88.252 - - [07/Mar/2024 16:33:34] "PUT /tabstateview/1 HTTP/1.1" 200 -
Triggering query_id: 209
2024-03-07 16:33:35,185:INFO:superset.commands.sql_lab.execute:Triggering query_id: 209
SQLite Database support for metadata databases will be removed             in a future version of Superset.
2024-03-07 16:33:35,200:WARNING:superset.utils.celery:SQLite Database support for metadata databases will be removed             in a future version of Superset.
Query 209: Executing 1 statement(s)
2024-03-07 16:33:35,207:INFO:superset.sql_lab:Query 209: Executing 1 statement(s)
Query 209: Set query to 'running'
2024-03-07 16:33:35,207:INFO:superset.sql_lab:Query 209: Set query to 'running'
Query 209: Running statement 1 out of 1
2024-03-07 16:33:35,292:INFO:superset.sql_lab:Query 209: Running statement 1 out of 1
2024-03-07 16:33:35,311:DEBUG:root:Query 209: Running query: SELECT * from actian.people offset 5 fetch first 3 rows only
LIMIT 11
SupersetErrorsException
Traceback (most recent call last):
  File "/home/test13536/.venv/lib/python3.10/site-packages/flask/app.py", line 1484, in full_dispatch_request
    rv = self.dispatch_request()
  File "/home/test13536/.venv/lib/python3.10/site-packages/flask/app.py", line 1469, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
  File "/home/test13536/.venv/lib/python3.10/site-packages/flask_appbuilder/security/decorators.py", line 95, in wraps
    return f(self, *args, **kwargs)
  File "/home/test13536/apache-superset-3.1.1/superset/views/base_api.py", line 127, in wraps
    raise ex
  File "/home/test13536/apache-superset-3.1.1/superset/views/base_api.py", line 121, in wraps
    duration, response = time_function(f, self, *args, **kwargs)
  File "/home/test13536/apache-superset-3.1.1/superset/utils/core.py", line 1463, in time_function
    response = func(*args, **kwargs)
  File "/home/test13536/apache-superset-3.1.1/superset/views/base_api.py", line 93, in wraps
    return f(self, *args, **kwargs)
  File "/home/test13536/apache-superset-3.1.1/superset/utils/log.py", line 255, in wrapper
    value = f(*args, **kwargs)
  File "/home/test13536/apache-superset-3.1.1/superset/sqllab/api.py", line 407, in execute_sql_query
    command_result: CommandResult = command.run()
  File "/home/test13536/apache-superset-3.1.1/superset/commands/sql_lab/execute.py", line 121, in run
    raise ex
  File "/home/test13536/apache-superset-3.1.1/superset/commands/sql_lab/execute.py", line 103, in run
    status = self._run_sql_json_exec_from_scratch()
  File "/home/test13536/apache-superset-3.1.1/superset/commands/sql_lab/execute.py", line 161, in _run_sql_json_exec_from_scratch
    raise ex
  File "/home/test13536/apache-superset-3.1.1/superset/commands/sql_lab/execute.py", line 156, in _run_sql_json_exec_from_scratch
    return self._sql_json_executor.execute(
  File "/home/test13536/apache-superset-3.1.1/superset/sqllab/sql_json_executer.py", line 111, in execute
    raise SupersetErrorsException(
superset.exceptions.SupersetErrorsException: [SupersetError(message='base error: (\'42000\', "[42000] [Actian][Actian ODBC Driver][INGRES]line 2, Syntax error on \'LIMIT\' at or near \' fetch first 3 rows only\\nLIMIT\'.  The correct syntax is: \\n SELECT [ALL|DISTINCT] target_list \\n  FROM table(s) \\n  [WHERE search_cond] \\n  [GROUP BY col(s)] \\n  [HAVING search_cond] \\n  [WINDOW window_defn] \\n [UNION subselect] \\n [ORDER BY col(s)] (2501) (SQLExecDirectW)")', error_type=<SupersetErrorType.GENERIC_DB_ENGINE_ERROR: 'GENERIC_DB_ENGINE_ERROR'>, level=<ErrorLevel.ERROR: 'error'>, extra={'engine_name': None, 'issue_codes': [{'code': 1002, 'message': 'Issue 1002 - The database returned an unexpected error.'}]})]
2024-03-07 16:33:35,329:WARNING:superset.views.base:SupersetErrorsException
Traceback (most recent call last):
  File "/home/test13536/.venv/lib/python3.10/site-packages/flask/app.py", line 1484, in full_dispatch_request
    rv = self.dispatch_request()
  File "/home/test13536/.venv/lib/python3.10/site-packages/flask/app.py", line 1469, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
  File "/home/test13536/.venv/lib/python3.10/site-packages/flask_appbuilder/security/decorators.py", line 95, in wraps
    return f(self, *args, **kwargs)
  File "/home/test13536/apache-superset-3.1.1/superset/views/base_api.py", line 127, in wraps
    raise ex
  File "/home/test13536/apache-superset-3.1.1/superset/views/base_api.py", line 121, in wraps
    duration, response = time_function(f, self, *args, **kwargs)
  File "/home/test13536/apache-superset-3.1.1/superset/utils/core.py", line 1463, in time_function
    response = func(*args, **kwargs)
  File "/home/test13536/apache-superset-3.1.1/superset/views/base_api.py", line 93, in wraps
    return f(self, *args, **kwargs)
  File "/home/test13536/apache-superset-3.1.1/superset/utils/log.py", line 255, in wrapper
    value = f(*args, **kwargs)
  File "/home/test13536/apache-superset-3.1.1/superset/sqllab/api.py", line 407, in execute_sql_query
    command_result: CommandResult = command.run()
  File "/home/test13536/apache-superset-3.1.1/superset/commands/sql_lab/execute.py", line 121, in run
    raise ex
  File "/home/test13536/apache-superset-3.1.1/superset/commands/sql_lab/execute.py", line 103, in run
    status = self._run_sql_json_exec_from_scratch()
  File "/home/test13536/apache-superset-3.1.1/superset/commands/sql_lab/execute.py", line 161, in _run_sql_json_exec_from_scratch
    raise ex
  File "/home/test13536/apache-superset-3.1.1/superset/commands/sql_lab/execute.py", line 156, in _run_sql_json_exec_from_scratch
    return self._sql_json_executor.execute(
  File "/home/test13536/apache-superset-3.1.1/superset/sqllab/sql_json_executer.py", line 111, in execute
    raise SupersetErrorsException(
superset.exceptions.SupersetErrorsException: [SupersetError(message='base error: (\'42000\', "[42000] [Actian][Actian ODBC Driver][INGRES]line 2, Syntax error on \'LIMIT\' at or near \' fetch first 3 rows only\\nLIMIT\'.  The correct syntax is: \\n SELECT [ALL|DISTINCT] target_list \\n  FROM table(s) \\n  [WHERE search_cond] \\n  [GROUP BY col(s)] \\n  [HAVING search_cond] \\n  [WINDOW window_defn] \\n [UNION subselect] \\n [ORDER BY col(s)] (2501) (SQLExecDirectW)")', error_type=<SupersetErrorType.GENERIC_DB_ENGINE_ERROR: 'GENERIC_DB_ENGINE_ERROR'>, level=<ErrorLevel.ERROR: 'error'>, extra={'engine_name': None, 'issue_codes': [{'code': 1002, 'message': 'Issue 1002 - The database returned an unexpected error.'}]})]

Checklist

  • I have searched Superset docs and Slack and didn't find a solution to my problem.
  • I have searched the GitHub issue tracker and didn't find a similar bug report.
  • I have checked Superset's logs for errors and if I found a relevant Python stacktrace, I included it here as text in the "additional context" section.
@rusackas
Copy link
Member

I see a couple linked/merged PRs here. Is this still an issue? If so, maybe @betodealmeida can weigh in here, since this might be resolved by the SQLParse/SQLGlot migration.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants