prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Crash with web-history-max-items and no items in the history
  When running `qutebrowser --debug --temp-basedir --backend webengine -s completion web-history-max-items 1000` and immediately pressing `o`, this happens:
  
  ```
  12:21:36 DEBUG    sql        sql:__init__:80 Preparing SQL query: "SELECT min(last_atime) FROM (SELECT last_atime FROM CompletionHistory ORDER BY last_atime DESC LIMIT :limit)"
  12:21:36 DEBUG    sql        sql:run:99 Running SQL query: "SELECT min(last_atime) FROM (SELECT last_atime FROM CompletionHistory ORDER BY last_atime DESC LIMIT :limit)"
  12:21:36 DEBUG    sql        sql:run:102 query bindings: {':limit': 1000}
  12:21:36 DEBUG    sql        sql:__init__:80 Preparing SQL query: "SELECT url, title, strftime('%Y-%m-%d', last_atime, 'unixepoch', 'localtime') FROM CompletionHistory WHERE (url LIKE :pat escape '\' or title LIKE :pat escape '\') AND last_atime >=  ORDER BY last_atime DESC"
  12:21:36 DEBUG    completion debug:__exit__:264 Starting url completion took 0.003652 seconds.
  12:21:36 ERROR    misc       crashsignal:exception_hook:205 Uncaught exception
  Traceback (most recent call last):
    File "/home/florian/proj/qutebrowser/git/qutebrowser/completion/completer.py", line 236, in _update_completion
      model = func(*args)
    File "/home/florian/proj/qutebrowser/git/qutebrowser/completion/models/urlmodel.py", line 70, in url
      hist_cat = histcategory.HistoryCategory(delete_func=_delete_history)
    File "/home/florian/proj/qutebrowser/git/qutebrowser/completion/models/histcategory.py", line 54, in __init__
      ]), forward_only=False)
    File "/home/florian/proj/qutebrowser/git/qutebrowser/misc/sql.py", line 83, in __init__
      querystr, self.lastError().text()))
  qutebrowser.misc.sql.SqlException: Failed to prepare query "SELECT url, title, strftime('%Y-%m-%d', last_atime, 'unixepoch', 'localtime') FROM CompletionHistory WHERE (url LIKE :pat escape '\' or title LIKE :pat escape '\') AND last_atime >=  ORDER BY last_atime DESC": "near "ORDER": syntax error Unable to execute statement"
  ```
  
  cc @rcorre 
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `qutebrowser/completion/models/histcategory.py`
  Content:
  ```
  1 # vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
  2 
  3 # Copyright 2017 Ryan Roden-Corrent (rcorre) <ryan@rcorre.net>
  4 #
  5 # This file is part of qutebrowser.
  6 #
  7 # qutebrowser is free software: you can redistribute it and/or modify
  8 # it under the terms of the GNU General Public License as published by
  9 # the Free Software Foundation, either version 3 of the License, or
  10 # (at your option) any later version.
  11 #
  12 # qutebrowser is distributed in the hope that it will be useful,
  13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15 # GNU General Public License for more details.
  16 #
  17 # You should have received a copy of the GNU General Public License
  18 # along with qutebrowser.  If not, see <http://www.gnu.org/licenses/>.
  19 
  20 """A completion category that queries the SQL History store."""
  21 
  22 import re
  23 
  24 from PyQt5.QtSql import QSqlQueryModel
  25 
  26 from qutebrowser.misc import sql
  27 from qutebrowser.utils import debug
  28 from qutebrowser.commands import cmdexc
  29 from qutebrowser.config import config
  30 
  31 
  32 class HistoryCategory(QSqlQueryModel):
  33 
  34     """A completion category that queries the SQL History store."""
  35 
  36     def __init__(self, *, delete_func=None, parent=None):
  37         """Create a new History completion category."""
  38         super().__init__(parent=parent)
  39         self.name = "History"
  40 
  41         # replace ' in timestamp-format to avoid breaking the query
  42         timefmt = ("strftime('{}', last_atime, 'unixepoch', 'localtime')"
  43                    .format(config.get('completion', 'timestamp-format')
  44                            .replace("'", "`")))
  45 
  46         self._query = sql.Query(' '.join([
  47             "SELECT url, title, {}".format(timefmt),
  48             "FROM CompletionHistory",
  49             # the incoming pattern will have literal % and _ escaped with '\'
  50             # we need to tell sql to treat '\' as an escape character
  51             "WHERE (url LIKE :pat escape '\\' or title LIKE :pat escape '\\')",
  52             self._atime_expr(),
  53             "ORDER BY last_atime DESC",
  54         ]), forward_only=False)
  55 
  56         # advertise that this model filters by URL and title
  57         self.columns_to_filter = [0, 1]
  58         self.delete_func = delete_func
  59 
  60     def _atime_expr(self):
  61         """If max_items is set, return an expression to limit the query."""
  62         max_items = config.get('completion', 'web-history-max-items')
  63         # HistoryCategory should not be added to the completion in that case.
  64         assert max_items != 0
  65 
  66         if max_items < 0:
  67             return ''
  68 
  69         min_atime = sql.Query(' '.join([
  70             'SELECT min(last_atime) FROM',
  71             '(SELECT last_atime FROM CompletionHistory',
  72             'ORDER BY last_atime DESC LIMIT :limit)',
  73         ])).run(limit=max_items).value()
  74 
  75         return "AND last_atime >= {}".format(min_atime)
  76 
  77     def set_pattern(self, pattern):
  78         """Set the pattern used to filter results.
  79 
  80         Args:
  81             pattern: string pattern to filter by.
  82         """
  83         # escape to treat a user input % or _ as a literal, not a wildcard
  84         pattern = pattern.replace('%', '\\%')
  85         pattern = pattern.replace('_', '\\_')
  86         # treat spaces as wildcards to match any of the typed words
  87         pattern = re.sub(r' +', '%', pattern)
  88         pattern = '%{}%'.format(pattern)
  89         with debug.log_time('sql', 'Running completion query'):
  90             self._query.run(pat=pattern)
  91         self.setQuery(self._query)
  92 
  93     def delete_cur_item(self, index):
  94         """Delete the row at the given index."""
  95         if not self.delete_func:
  96             raise cmdexc.CommandError("Cannot delete this item.")
  97         data = [self.data(index.sibling(index.row(), i))
  98                 for i in range(self.columnCount())]
  99         self.delete_func(data)
  100         # re-run query to reload updated table
  101         with debug.log_time('sql', 'Re-running completion query post-delete'):
  102             self._query.run()
  103         self.setQuery(self._query)
  104
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/qutebrowser/completion/models/histcategory.py b/qutebrowser/completion/models/histcategory.py
  --- a/qutebrowser/completion/models/histcategory.py
  +++ b/qutebrowser/completion/models/histcategory.py
  @@ -72,6 +72,10 @@
               'ORDER BY last_atime DESC LIMIT :limit)',
           ])).run(limit=max_items).value()
   
  +        if not min_atime:
  +            # if there are no history items, min_atime may be '' (issue #2849)
  +            return ''
  +
           return "AND last_atime >= {}".format(min_atime)
   
       def set_pattern(self, pattern):
  
verification_info: {"golden_diff": "diff --git a/qutebrowser/completion/models/histcategory.py b/qutebrowser/completion/models/histcategory.py\n--- a/qutebrowser/completion/models/histcategory.py\n+++ b/qutebrowser/completion/models/histcategory.py\n@@ -72,6 +72,10 @@\n             'ORDER BY last_atime DESC LIMIT :limit)',\n         ])).run(limit=max_items).value()\n \n+        if not min_atime:\n+            # if there are no history items, min_atime may be '' (issue #2849)\n+            return ''\n+\n         return \"AND last_atime >= {}\".format(min_atime)\n \n     def set_pattern(self, pattern):\n", "issue": "Crash with web-history-max-items and no items in the history\nWhen running `qutebrowser --debug --temp-basedir --backend webengine -s completion web-history-max-items 1000` and immediately pressing `o`, this happens:\r\n\r\n```\r\n12:21:36 DEBUG    sql        sql:__init__:80 Preparing SQL query: \"SELECT min(last_atime) FROM (SELECT last_atime FROM CompletionHistory ORDER BY last_atime DESC LIMIT :limit)\"\r\n12:21:36 DEBUG    sql        sql:run:99 Running SQL query: \"SELECT min(last_atime) FROM (SELECT last_atime FROM CompletionHistory ORDER BY last_atime DESC LIMIT :limit)\"\r\n12:21:36 DEBUG    sql        sql:run:102 query bindings: {':limit': 1000}\r\n12:21:36 DEBUG    sql        sql:__init__:80 Preparing SQL query: \"SELECT url, title, strftime('%Y-%m-%d', last_atime, 'unixepoch', 'localtime') FROM CompletionHistory WHERE (url LIKE :pat escape '\\' or title LIKE :pat escape '\\') AND last_atime >=  ORDER BY last_atime DESC\"\r\n12:21:36 DEBUG    completion debug:__exit__:264 Starting url completion took 0.003652 seconds.\r\n12:21:36 ERROR    misc       crashsignal:exception_hook:205 Uncaught exception\r\nTraceback (most recent call last):\r\n  File \"/home/florian/proj/qutebrowser/git/qutebrowser/completion/completer.py\", line 236, in _update_completion\r\n    model = func(*args)\r\n  File \"/home/florian/proj/qutebrowser/git/qutebrowser/completion/models/urlmodel.py\", line 70, in url\r\n    hist_cat = histcategory.HistoryCategory(delete_func=_delete_history)\r\n  File \"/home/florian/proj/qutebrowser/git/qutebrowser/completion/models/histcategory.py\", line 54, in __init__\r\n    ]), forward_only=False)\r\n  File \"/home/florian/proj/qutebrowser/git/qutebrowser/misc/sql.py\", line 83, in __init__\r\n    querystr, self.lastError().text()))\r\nqutebrowser.misc.sql.SqlException: Failed to prepare query \"SELECT url, title, strftime('%Y-%m-%d', last_atime, 'unixepoch', 'localtime') FROM CompletionHistory WHERE (url LIKE :pat escape '\\' or title LIKE :pat escape '\\') AND last_atime >=  ORDER BY last_atime DESC\": \"near \"ORDER\": syntax error Unable to execute statement\"\r\n```\r\n\r\ncc @rcorre \n", "before_files": [{"content": "# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:\n\n# Copyright 2017 Ryan Roden-Corrent (rcorre) <ryan@rcorre.net>\n#\n# This file is part of qutebrowser.\n#\n# qutebrowser is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# qutebrowser is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with qutebrowser.  If not, see <http://www.gnu.org/licenses/>.\n\n\"\"\"A completion category that queries the SQL History store.\"\"\"\n\nimport re\n\nfrom PyQt5.QtSql import QSqlQueryModel\n\nfrom qutebrowser.misc import sql\nfrom qutebrowser.utils import debug\nfrom qutebrowser.commands import cmdexc\nfrom qutebrowser.config import config\n\n\nclass HistoryCategory(QSqlQueryModel):\n\n    \"\"\"A completion category that queries the SQL History store.\"\"\"\n\n    def __init__(self, *, delete_func=None, parent=None):\n        \"\"\"Create a new History completion category.\"\"\"\n        super().__init__(parent=parent)\n        self.name = \"History\"\n\n        # replace ' in timestamp-format to avoid breaking the query\n        timefmt = (\"strftime('{}', last_atime, 'unixepoch', 'localtime')\"\n                   .format(config.get('completion', 'timestamp-format')\n                           .replace(\"'\", \"`\")))\n\n        self._query = sql.Query(' '.join([\n            \"SELECT url, title, {}\".format(timefmt),\n            \"FROM CompletionHistory\",\n            # the incoming pattern will have literal % and _ escaped with '\\'\n            # we need to tell sql to treat '\\' as an escape character\n            \"WHERE (url LIKE :pat escape '\\\\' or title LIKE :pat escape '\\\\')\",\n            self._atime_expr(),\n            \"ORDER BY last_atime DESC\",\n        ]), forward_only=False)\n\n        # advertise that this model filters by URL and title\n        self.columns_to_filter = [0, 1]\n        self.delete_func = delete_func\n\n    def _atime_expr(self):\n        \"\"\"If max_items is set, return an expression to limit the query.\"\"\"\n        max_items = config.get('completion', 'web-history-max-items')\n        # HistoryCategory should not be added to the completion in that case.\n        assert max_items != 0\n\n        if max_items < 0:\n            return ''\n\n        min_atime = sql.Query(' '.join([\n            'SELECT min(last_atime) FROM',\n            '(SELECT last_atime FROM CompletionHistory',\n            'ORDER BY last_atime DESC LIMIT :limit)',\n        ])).run(limit=max_items).value()\n\n        return \"AND last_atime >= {}\".format(min_atime)\n\n    def set_pattern(self, pattern):\n        \"\"\"Set the pattern used to filter results.\n\n        Args:\n            pattern: string pattern to filter by.\n        \"\"\"\n        # escape to treat a user input % or _ as a literal, not a wildcard\n        pattern = pattern.replace('%', '\\\\%')\n        pattern = pattern.replace('_', '\\\\_')\n        # treat spaces as wildcards to match any of the typed words\n        pattern = re.sub(r' +', '%', pattern)\n        pattern = '%{}%'.format(pattern)\n        with debug.log_time('sql', 'Running completion query'):\n            self._query.run(pat=pattern)\n        self.setQuery(self._query)\n\n    def delete_cur_item(self, index):\n        \"\"\"Delete the row at the given index.\"\"\"\n        if not self.delete_func:\n            raise cmdexc.CommandError(\"Cannot delete this item.\")\n        data = [self.data(index.sibling(index.row(), i))\n                for i in range(self.columnCount())]\n        self.delete_func(data)\n        # re-run query to reload updated table\n        with debug.log_time('sql', 'Re-running completion query post-delete'):\n            self._query.run()\n        self.setQuery(self._query)\n", "path": "qutebrowser/completion/models/histcategory.py"}], "after_files": [{"content": "# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:\n\n# Copyright 2017 Ryan Roden-Corrent (rcorre) <ryan@rcorre.net>\n#\n# This file is part of qutebrowser.\n#\n# qutebrowser is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# qutebrowser is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with qutebrowser.  If not, see <http://www.gnu.org/licenses/>.\n\n\"\"\"A completion category that queries the SQL History store.\"\"\"\n\nimport re\n\nfrom PyQt5.QtSql import QSqlQueryModel\n\nfrom qutebrowser.misc import sql\nfrom qutebrowser.utils import debug\nfrom qutebrowser.commands import cmdexc\nfrom qutebrowser.config import config\n\n\nclass HistoryCategory(QSqlQueryModel):\n\n    \"\"\"A completion category that queries the SQL History store.\"\"\"\n\n    def __init__(self, *, delete_func=None, parent=None):\n        \"\"\"Create a new History completion category.\"\"\"\n        super().__init__(parent=parent)\n        self.name = \"History\"\n\n        # replace ' in timestamp-format to avoid breaking the query\n        timefmt = (\"strftime('{}', last_atime, 'unixepoch', 'localtime')\"\n                   .format(config.get('completion', 'timestamp-format')\n                           .replace(\"'\", \"`\")))\n\n        self._query = sql.Query(' '.join([\n            \"SELECT url, title, {}\".format(timefmt),\n            \"FROM CompletionHistory\",\n            # the incoming pattern will have literal % and _ escaped with '\\'\n            # we need to tell sql to treat '\\' as an escape character\n            \"WHERE (url LIKE :pat escape '\\\\' or title LIKE :pat escape '\\\\')\",\n            self._atime_expr(),\n            \"ORDER BY last_atime DESC\",\n        ]), forward_only=False)\n\n        # advertise that this model filters by URL and title\n        self.columns_to_filter = [0, 1]\n        self.delete_func = delete_func\n\n    def _atime_expr(self):\n        \"\"\"If max_items is set, return an expression to limit the query.\"\"\"\n        max_items = config.get('completion', 'web-history-max-items')\n        # HistoryCategory should not be added to the completion in that case.\n        assert max_items != 0\n\n        if max_items < 0:\n            return ''\n\n        min_atime = sql.Query(' '.join([\n            'SELECT min(last_atime) FROM',\n            '(SELECT last_atime FROM CompletionHistory',\n            'ORDER BY last_atime DESC LIMIT :limit)',\n        ])).run(limit=max_items).value()\n\n        if not min_atime:\n            # if there are no history items, min_atime may be '' (issue #2849)\n            return ''\n\n        return \"AND last_atime >= {}\".format(min_atime)\n\n    def set_pattern(self, pattern):\n        \"\"\"Set the pattern used to filter results.\n\n        Args:\n            pattern: string pattern to filter by.\n        \"\"\"\n        # escape to treat a user input % or _ as a literal, not a wildcard\n        pattern = pattern.replace('%', '\\\\%')\n        pattern = pattern.replace('_', '\\\\_')\n        # treat spaces as wildcards to match any of the typed words\n        pattern = re.sub(r' +', '%', pattern)\n        pattern = '%{}%'.format(pattern)\n        with debug.log_time('sql', 'Running completion query'):\n            self._query.run(pat=pattern)\n        self.setQuery(self._query)\n\n    def delete_cur_item(self, index):\n        \"\"\"Delete the row at the given index.\"\"\"\n        if not self.delete_func:\n            raise cmdexc.CommandError(\"Cannot delete this item.\")\n        data = [self.data(index.sibling(index.row(), i))\n                for i in range(self.columnCount())]\n        self.delete_func(data)\n        # re-run query to reload updated table\n        with debug.log_time('sql', 'Re-running completion query post-delete'):\n            self._query.run()\n        self.setQuery(self._query)\n", "path": "qutebrowser/completion/models/histcategory.py"}]}