# Buggy code
def cache_key(self, query_obj, **extra):
    """
    The cache key is made out of the key/values in `query_obj`, plus any
    other key/values in `extra`.

    We remove datetime bounds that are hard values, and replace them with
    the use-provided inputs to bounds, which may be time-relative (as in
    "5 days ago" or "now").

    The `extra` arguments are currently used by time shift queries, since
    different time shifts wil differ only in the `from_dttm` and `to_dttm`
    values which are stripped.
    """
    cache_dict = copy.copy(query_obj)
    cache_dict.update(extra)

    for k in ["from_dttm", "to_dttm"]:
        del cache_dict[k]

    cache_dict["time_range"] = self.form_data.get("time_range")
    cache_dict["datasource"] = self.datasource.uid
    cache_dict["extra_cache_keys"] = self.datasource.get_extra_cache_keys(query_obj)
    cache_dict["rls"] = security_manager.get_rls_ids(self.datasource)
    cache_dict["changed_on"] = self.datasource.changed_on
    json_data = self.json_dumps(cache_dict, sort_keys=True)
    return hashlib.md5(json_data.encode("utf-8")).hexdigest()


# Traceback (sqlalchemy.exc.CompileError)
| INFO:werkzeug:172.18.0.1 - - [15/Apr/2020 14:37:29] "GET /superset/annotation_json/3?form_data=%7B%22time_range%22%3A%22No+filter%22%7D HTTP/1.1" 500 -
superset_1         | 172.18.0.1 - - [15/Apr/2020 14:37:48] "GET /annotationlayermodelview/api/read HTTP/1.1" 200 -
superset_1         | INFO:werkzeug:172.18.0.1 - - [15/Apr/2020 14:37:48] "GET /annotationlayermodelview/api/read HTTP/1.1" 200 -
superset_1         | 127.0.0.1 - - [15/Apr/2020 14:37:50] "GET /health HTTP/1.1" 200 -
superset_1         | INFO:werkzeug:127.0.0.1 - - [15/Apr/2020 14:37:50] "GET /health HTTP/1.1" 200 -
superset_1         | DEBUG:superset.stats_logger:[stats_logger] (incr) annotation_json
superset_1         | DEBUG:parsedatetime:eval - with context - False, False
superset_1         | ERROR:superset.views.base:Cannot compile Column object until its 'name' is assigned.
superset_1         | Traceback (most recent call last):
superset_1         |   File "/app/superset/views/base.py", line 120, in wraps
superset_1         |     return f(self, *args, **kwargs)
superset_1         |   File "/usr/local/lib/python3.6/site-packages/flask_appbuilder/security/decorators.py", line 151, in wraps
superset_1         |     return f(self, *args, **kwargs)
superset_1         |   File "/app/superset/views/core.py", line 674, in annotation_json
superset_1         |     payload = viz_obj.get_payload()
superset_1         |   File "/app/superset/viz.py", line 404, in get_payload
superset_1         |     payload = self.get_df_payload(query_obj)
superset_1         |   File "/app/superset/viz.py", line 417, in get_df_payload
superset_1         |     cache_key = self.cache_key(query_obj, **kwargs) if query_obj else None
superset_1         |   File "/app/superset/viz.py", line 396, in cache_key
superset_1         |     cache_dict["rls"] = security_manager.get_rls_ids(self.datasource)
superset_1         |   File "/app/superset/security/manager.py", line 943, in get_rls_ids
superset_1         |     ids = [f.id for f in self.get_rls_filters(table)]
superset_1         |   File "/app/superset/security/manager.py", line 933, in get_rls_filters
superset_1         |     return query.all()
superset_1         |   File "/usr/local/lib/python3.6/site-packages/sqlalchemy/orm/query.py", line 3246, in all
superset_1         |     return list(self)
superset_1         |   File "/usr/local/lib/python3.6/site-packages/sqlalchemy/orm/query.py", line 3405, in __iter__
superset_1         |     return self._execute_and_instances(context)
superset_1         |   File "/usr/local/lib/python3.6/site-packages/sqlalchemy/orm/query.py", line 3430, in _execute_and_instances
superset_1         |     result = conn.execute(querycontext.statement, self._params)
superset_1         |   File "/usr/local/lib/python3.6/site-packages/sqlalchemy/engine/base.py", line 984, in execute
superset_1         |     return meth(self, multiparams, params)
superset_1         |   File "/usr/local/lib/python3.6/site-packages/sqlalchemy/sql/elements.py", line 293, in _execute_on_connection
superset_1         |     return connection._execute_clauseelement(self, multiparams, params)
superset_1         |   File "/usr/local/lib/python3.6/site-packages/sqlalchemy/engine/base.py", line 1094, in _execute_clauseelement
superset_1         |     else None,
superset_1         |   File "<string>", line 1, in <lambda>
superset_1         |   File "/usr/local/lib/python3.6/site-packages/sqlalchemy/sql/elements.py", line 468, in compile
superset_1         |     return self._compiler(dialect, bind=bind, **kw)
superset_1         |   File "/usr/local/lib/python3.6/site-packages/sqlalchemy/sql/elements.py", line 474, in _compiler
superset_1         |     return dialect.statement_compiler(dialect, self, **kw)
superset_1         |   File "/usr/local/lib/python3.6/site-packages/sqlalchemy/sql/compiler.py", line 590, in __init__
superset_1         |     Compiled.__init__(self, dialect, statement, **kwargs)
superset_1         |   File "/usr/local/lib/python3.6/site-packages/sqlalchemy/sql/compiler.py", line 319, in __init__
superset_1         |     self.string = self.process(self.statement, **compile_kwargs)
superset_1         |   File "/usr/local/lib/python3.6/site-packages/sqlalchemy/sql/compiler.py", line 350, in process
superset_1         |     return obj._compiler_dispatch(self, **kwargs)
superset_1         |   File "/usr/local/lib/python3.6/site-packages/sqlalchemy/sql/visitors.py", line 95, in _compiler_dispatch
superset_1         |     return meth(self, **kw)
superset_1         |   File "/usr/local/lib/python3.6/site-packages/sqlalchemy/sql/compiler.py", line 2162, in visit_select
superset_1         |     text, select, inner_columns, froms, byfrom, kwargs
superset_1         |   File "/usr/local/lib/python3.6/site-packages/sqlalchemy/sql/compiler.py", line 2261, in _compose_select_body
superset_1         |     t = select._whereclause._compiler_dispatch(self, **kwargs)
superset_1         |   File "/usr/local/lib/python3.6/site-packages/sqlalchemy/sql/visitors.py", line 95, in _compiler_dispatch
superset_1         |     return meth(self, **kw)
superset_1         |   File "/usr/local/lib/python3.6/site-packages/sqlalchemy/sql/compiler.py", line 1003, in visit_clauselist
superset_1         |     c._compiler_dispatch(self, **kw) for c in clauselist.clauses
superset_1         |   File "/usr/local/lib/python3.6/site-packages/sqlalchemy/sql/compiler.py", line 1001, in <genexpr>
superset_1         |     s
superset_1         |   File "/usr/local/lib/python3.6/site-packages/sqlalchemy/sql/compiler.py", line 1003, in <genexpr>
superset_1         |     c._compiler_dispatch(self, **kw) for c in clauselist.clauses
superset_1         |   File "/usr/local/lib/python3.6/site-packages/sqlalchemy/sql/visitors.py", line 95, in _compiler_dispatch
superset_1         |     return meth(self, **kw)
superset_1         |   File "/usr/local/lib/python3.6/site-packages/sqlalchemy/sql/compiler.py", line 1324, in visit_binary
superset_1         |     return self._generate_generic_binary(binary, opstring, **kw)
superset_1         |   File "/usr/local/lib/python3.6/site-packages/sqlalchemy/sql/compiler.py", line 1372, in _generate_generic_binary
superset_1         |     self, eager_grouping=eager_grouping, **kw
superset_1         |   File "/usr/local/lib/python3.6/site-packages/sqlalchemy/sql/visitors.py", line 95, in _compiler_dispatch
superset_1         |     return meth(self, **kw)
superset_1         |   File "/usr/local/lib/python3.6/site-packages/sqlalchemy/sql/compiler.py", line 869, in visit_column
superset_1         |     name = self._fallback_column_name(column)
superset_1         |   File "/usr/local/lib/python3.6/site-packages/sqlalchemy/sql/compiler.py", line 861, in _fallback_column_name
superset_1         |     "Cannot compile Column object until " "its 'name' is assigned."
superset_1         | sqlalchemy.exc.CompileError: Cannot compile Column object until its 'name' is assigned.

# Fixed code
def cache_key(self, query_obj, **extra):
    """
    The cache key is made out of the key/values in `query_obj`, plus any
    other key/values in `extra`.

    We remove datetime bounds that are hard values, and replace them with
    the use-provided inputs to bounds, which may be time-relative (as in
    "5 days ago" or "now").

    The `extra` arguments are currently used by time shift queries, since
    different time shifts wil differ only in the `from_dttm` and `to_dttm`
    values which are stripped.
    """
    cache_dict = copy.copy(query_obj)
    cache_dict.update(extra)

    for k in ["from_dttm", "to_dttm"]:
        del cache_dict[k]

    cache_dict["time_range"] = self.form_data.get("time_range")
    cache_dict["datasource"] = self.datasource.uid
    cache_dict["extra_cache_keys"] = self.datasource.get_extra_cache_keys(query_obj)
    if config["ENABLE_ROW_LEVEL_SECURITY"]:
        cache_dict["rls"] = security_manager.get_rls_ids(self.datasource)
    cache_dict["changed_on"] = self.datasource.changed_on
    json_data = self.json_dumps(cache_dict, sort_keys=True)
    return hashlib.md5(json_data.encode("utf-8")).hexdigest()