prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Clickhouse: password is optional but we try to access it anyway
  For Clickhouse type data sources, we don't require a password. But the code does require it by trying to directly access the value in the options dictionary, instead of using `get`:
  
  https://github.com/getredash/redash/blob/823e4ccdd6fcfee5d0df0d919d87af3100876549/redash/query_runner/clickhouse.py#L77
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `redash/query_runner/clickhouse.py`
  Content:
  ```
  1 import logging
  2 import re
  3 
  4 import requests
  5 
  6 from redash.query_runner import *
  7 from redash.utils import json_dumps, json_loads
  8 
  9 logger = logging.getLogger(__name__)
  10 
  11 
  12 class ClickHouse(BaseSQLQueryRunner):
  13     noop_query = "SELECT 1"
  14 
  15     @classmethod
  16     def configuration_schema(cls):
  17         return {
  18             "type": "object",
  19             "properties": {
  20                 "url": {
  21                     "type": "string",
  22                     "default": "http://127.0.0.1:8123"
  23                 },
  24                 "user": {
  25                     "type": "string",
  26                     "default": "default"
  27                 },
  28                 "password": {
  29                     "type": "string"
  30                 },
  31                 "dbname": {
  32                     "type": "string",
  33                     "title": "Database Name"
  34                 },
  35                 "timeout": {
  36                     "type": "number",
  37                     "title": "Request Timeout",
  38                     "default": 30
  39                 }
  40             },
  41             "required": ["dbname"],
  42             "secret": ["password"]
  43         }
  44 
  45     @classmethod
  46     def type(cls):
  47         return "clickhouse"
  48 
  49     def _get_tables(self, schema):
  50         query = "SELECT database, table, name FROM system.columns WHERE database NOT IN ('system')"
  51 
  52         results, error = self.run_query(query, None)
  53 
  54         if error is not None:
  55             raise Exception("Failed getting schema.")
  56 
  57         results = json_loads(results)
  58 
  59         for row in results['rows']:
  60             table_name = '{}.{}'.format(row['database'], row['table'])
  61 
  62             if table_name not in schema:
  63                 schema[table_name] = {'name': table_name, 'columns': []}
  64 
  65             schema[table_name]['columns'].append(row['name'])
  66 
  67         return schema.values()
  68 
  69     def _send_query(self, data, stream=False):
  70         r = requests.post(
  71             self.configuration['url'],
  72             data=data.encode("utf-8"),
  73             stream=stream,
  74             timeout=self.configuration.get('timeout', 30),
  75             params={
  76                 'user': self.configuration['user'],
  77                 'password':  self.configuration['password'],
  78                 'database': self.configuration['dbname']
  79             }
  80         )
  81         if r.status_code != 200:
  82             raise Exception(r.text)
  83         # logging.warning(r.json())
  84         return r.json()
  85 
  86     @staticmethod
  87     def _define_column_type(column):
  88         c = column.lower()
  89         f = re.search(r'^nullable\((.*)\)$', c)
  90         if f is not None:
  91             c = f.group(1)
  92         if c.startswith('int') or c.startswith('uint'):
  93             return TYPE_INTEGER
  94         elif c.startswith('float'):
  95             return TYPE_FLOAT
  96         elif c == 'datetime':
  97             return TYPE_DATETIME
  98         elif c == 'date':
  99             return TYPE_DATE
  100         else:
  101             return TYPE_STRING
  102 
  103     def _clickhouse_query(self, query):
  104         query += '\nFORMAT JSON'
  105         result = self._send_query(query)
  106         columns = []
  107         columns_int64 = []  # db converts value to string if its type equals UInt64
  108         columns_totals = {}
  109 
  110         for r in result['meta']:
  111             column_name = r['name']
  112             column_type = self._define_column_type(r['type'])
  113 
  114             if r['type'] in ('Int64', 'UInt64', 'Nullable(Int64)', 'Nullable(UInt64)'):
  115                 columns_int64.append(column_name)
  116             else:
  117                 columns_totals[column_name] = 'Total' if column_type == TYPE_STRING else None
  118 
  119             columns.append({'name': column_name, 'friendly_name': column_name, 'type': column_type})
  120 
  121         rows = result['data']
  122         for row in rows:
  123             for column in columns_int64:
  124                 try:
  125                     row[column] = int(row[column])
  126                 except TypeError:
  127                     row[column] = None
  128 
  129         if 'totals' in result:
  130             totals = result['totals']
  131             for column, value in columns_totals.iteritems():
  132                 totals[column] = value
  133             rows.append(totals)
  134 
  135         return {'columns': columns, 'rows': rows}
  136 
  137     def run_query(self, query, user):
  138         logger.debug("Clickhouse is about to execute query: %s", query)
  139         if query == "":
  140             json_data = None
  141             error = "Query is empty"
  142             return json_data, error
  143         try:
  144             q = self._clickhouse_query(query)
  145             data = json_dumps(q)
  146             error = None
  147         except Exception as e:
  148             data = None
  149             logging.exception(e)
  150             error = unicode(e)
  151         return data, error
  152 
  153 register(ClickHouse)
  154
  ```
  --- 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/redash/query_runner/clickhouse.py b/redash/query_runner/clickhouse.py
  --- a/redash/query_runner/clickhouse.py
  +++ b/redash/query_runner/clickhouse.py
  @@ -68,13 +68,13 @@
   
       def _send_query(self, data, stream=False):
           r = requests.post(
  -            self.configuration['url'],
  +            self.configuration.get('url', "http://127.0.0.1:8123"),
               data=data.encode("utf-8"),
               stream=stream,
               timeout=self.configuration.get('timeout', 30),
               params={
  -                'user': self.configuration['user'],
  -                'password':  self.configuration['password'],
  +                'user': self.configuration.get('user', "default"),
  +                'password':  self.configuration.get('password', ""),
                   'database': self.configuration['dbname']
               }
           )
  
verification_info: {"golden_diff": "diff --git a/redash/query_runner/clickhouse.py b/redash/query_runner/clickhouse.py\n--- a/redash/query_runner/clickhouse.py\n+++ b/redash/query_runner/clickhouse.py\n@@ -68,13 +68,13 @@\n \n     def _send_query(self, data, stream=False):\n         r = requests.post(\n-            self.configuration['url'],\n+            self.configuration.get('url', \"http://127.0.0.1:8123\"),\n             data=data.encode(\"utf-8\"),\n             stream=stream,\n             timeout=self.configuration.get('timeout', 30),\n             params={\n-                'user': self.configuration['user'],\n-                'password':  self.configuration['password'],\n+                'user': self.configuration.get('user', \"default\"),\n+                'password':  self.configuration.get('password', \"\"),\n                 'database': self.configuration['dbname']\n             }\n         )\n", "issue": "Clickhouse: password is optional but we try to access it anyway\nFor Clickhouse type data sources, we don't require a password. But the code does require it by trying to directly access the value in the options dictionary, instead of using `get`:\r\n\r\nhttps://github.com/getredash/redash/blob/823e4ccdd6fcfee5d0df0d919d87af3100876549/redash/query_runner/clickhouse.py#L77\n", "before_files": [{"content": "import logging\nimport re\n\nimport requests\n\nfrom redash.query_runner import *\nfrom redash.utils import json_dumps, json_loads\n\nlogger = logging.getLogger(__name__)\n\n\nclass ClickHouse(BaseSQLQueryRunner):\n    noop_query = \"SELECT 1\"\n\n    @classmethod\n    def configuration_schema(cls):\n        return {\n            \"type\": \"object\",\n            \"properties\": {\n                \"url\": {\n                    \"type\": \"string\",\n                    \"default\": \"http://127.0.0.1:8123\"\n                },\n                \"user\": {\n                    \"type\": \"string\",\n                    \"default\": \"default\"\n                },\n                \"password\": {\n                    \"type\": \"string\"\n                },\n                \"dbname\": {\n                    \"type\": \"string\",\n                    \"title\": \"Database Name\"\n                },\n                \"timeout\": {\n                    \"type\": \"number\",\n                    \"title\": \"Request Timeout\",\n                    \"default\": 30\n                }\n            },\n            \"required\": [\"dbname\"],\n            \"secret\": [\"password\"]\n        }\n\n    @classmethod\n    def type(cls):\n        return \"clickhouse\"\n\n    def _get_tables(self, schema):\n        query = \"SELECT database, table, name FROM system.columns WHERE database NOT IN ('system')\"\n\n        results, error = self.run_query(query, None)\n\n        if error is not None:\n            raise Exception(\"Failed getting schema.\")\n\n        results = json_loads(results)\n\n        for row in results['rows']:\n            table_name = '{}.{}'.format(row['database'], row['table'])\n\n            if table_name not in schema:\n                schema[table_name] = {'name': table_name, 'columns': []}\n\n            schema[table_name]['columns'].append(row['name'])\n\n        return schema.values()\n\n    def _send_query(self, data, stream=False):\n        r = requests.post(\n            self.configuration['url'],\n            data=data.encode(\"utf-8\"),\n            stream=stream,\n            timeout=self.configuration.get('timeout', 30),\n            params={\n                'user': self.configuration['user'],\n                'password':  self.configuration['password'],\n                'database': self.configuration['dbname']\n            }\n        )\n        if r.status_code != 200:\n            raise Exception(r.text)\n        # logging.warning(r.json())\n        return r.json()\n\n    @staticmethod\n    def _define_column_type(column):\n        c = column.lower()\n        f = re.search(r'^nullable\\((.*)\\)$', c)\n        if f is not None:\n            c = f.group(1)\n        if c.startswith('int') or c.startswith('uint'):\n            return TYPE_INTEGER\n        elif c.startswith('float'):\n            return TYPE_FLOAT\n        elif c == 'datetime':\n            return TYPE_DATETIME\n        elif c == 'date':\n            return TYPE_DATE\n        else:\n            return TYPE_STRING\n\n    def _clickhouse_query(self, query):\n        query += '\\nFORMAT JSON'\n        result = self._send_query(query)\n        columns = []\n        columns_int64 = []  # db converts value to string if its type equals UInt64\n        columns_totals = {}\n\n        for r in result['meta']:\n            column_name = r['name']\n            column_type = self._define_column_type(r['type'])\n\n            if r['type'] in ('Int64', 'UInt64', 'Nullable(Int64)', 'Nullable(UInt64)'):\n                columns_int64.append(column_name)\n            else:\n                columns_totals[column_name] = 'Total' if column_type == TYPE_STRING else None\n\n            columns.append({'name': column_name, 'friendly_name': column_name, 'type': column_type})\n\n        rows = result['data']\n        for row in rows:\n            for column in columns_int64:\n                try:\n                    row[column] = int(row[column])\n                except TypeError:\n                    row[column] = None\n\n        if 'totals' in result:\n            totals = result['totals']\n            for column, value in columns_totals.iteritems():\n                totals[column] = value\n            rows.append(totals)\n\n        return {'columns': columns, 'rows': rows}\n\n    def run_query(self, query, user):\n        logger.debug(\"Clickhouse is about to execute query: %s\", query)\n        if query == \"\":\n            json_data = None\n            error = \"Query is empty\"\n            return json_data, error\n        try:\n            q = self._clickhouse_query(query)\n            data = json_dumps(q)\n            error = None\n        except Exception as e:\n            data = None\n            logging.exception(e)\n            error = unicode(e)\n        return data, error\n\nregister(ClickHouse)\n", "path": "redash/query_runner/clickhouse.py"}], "after_files": [{"content": "import logging\nimport re\n\nimport requests\n\nfrom redash.query_runner import *\nfrom redash.utils import json_dumps, json_loads\n\nlogger = logging.getLogger(__name__)\n\n\nclass ClickHouse(BaseSQLQueryRunner):\n    noop_query = \"SELECT 1\"\n\n    @classmethod\n    def configuration_schema(cls):\n        return {\n            \"type\": \"object\",\n            \"properties\": {\n                \"url\": {\n                    \"type\": \"string\",\n                    \"default\": \"http://127.0.0.1:8123\"\n                },\n                \"user\": {\n                    \"type\": \"string\",\n                    \"default\": \"default\"\n                },\n                \"password\": {\n                    \"type\": \"string\"\n                },\n                \"dbname\": {\n                    \"type\": \"string\",\n                    \"title\": \"Database Name\"\n                },\n                \"timeout\": {\n                    \"type\": \"number\",\n                    \"title\": \"Request Timeout\",\n                    \"default\": 30\n                }\n            },\n            \"required\": [\"dbname\"],\n            \"secret\": [\"password\"]\n        }\n\n    @classmethod\n    def type(cls):\n        return \"clickhouse\"\n\n    def _get_tables(self, schema):\n        query = \"SELECT database, table, name FROM system.columns WHERE database NOT IN ('system')\"\n\n        results, error = self.run_query(query, None)\n\n        if error is not None:\n            raise Exception(\"Failed getting schema.\")\n\n        results = json_loads(results)\n\n        for row in results['rows']:\n            table_name = '{}.{}'.format(row['database'], row['table'])\n\n            if table_name not in schema:\n                schema[table_name] = {'name': table_name, 'columns': []}\n\n            schema[table_name]['columns'].append(row['name'])\n\n        return schema.values()\n\n    def _send_query(self, data, stream=False):\n        r = requests.post(\n            self.configuration.get('url', \"http://127.0.0.1:8123\"),\n            data=data.encode(\"utf-8\"),\n            stream=stream,\n            timeout=self.configuration.get('timeout', 30),\n            params={\n                'user': self.configuration.get('user', \"default\"),\n                'password':  self.configuration.get('password', \"\"),\n                'database': self.configuration['dbname']\n            }\n        )\n        if r.status_code != 200:\n            raise Exception(r.text)\n        # logging.warning(r.json())\n        return r.json()\n\n    @staticmethod\n    def _define_column_type(column):\n        c = column.lower()\n        f = re.search(r'^nullable\\((.*)\\)$', c)\n        if f is not None:\n            c = f.group(1)\n        if c.startswith('int') or c.startswith('uint'):\n            return TYPE_INTEGER\n        elif c.startswith('float'):\n            return TYPE_FLOAT\n        elif c == 'datetime':\n            return TYPE_DATETIME\n        elif c == 'date':\n            return TYPE_DATE\n        else:\n            return TYPE_STRING\n\n    def _clickhouse_query(self, query):\n        query += '\\nFORMAT JSON'\n        result = self._send_query(query)\n        columns = []\n        columns_int64 = []  # db converts value to string if its type equals UInt64\n        columns_totals = {}\n\n        for r in result['meta']:\n            column_name = r['name']\n            column_type = self._define_column_type(r['type'])\n\n            if r['type'] in ('Int64', 'UInt64', 'Nullable(Int64)', 'Nullable(UInt64)'):\n                columns_int64.append(column_name)\n            else:\n                columns_totals[column_name] = 'Total' if column_type == TYPE_STRING else None\n\n            columns.append({'name': column_name, 'friendly_name': column_name, 'type': column_type})\n\n        rows = result['data']\n        for row in rows:\n            for column in columns_int64:\n                try:\n                    row[column] = int(row[column])\n                except TypeError:\n                    row[column] = None\n\n        if 'totals' in result:\n            totals = result['totals']\n            for column, value in columns_totals.iteritems():\n                totals[column] = value\n            rows.append(totals)\n\n        return {'columns': columns, 'rows': rows}\n\n    def run_query(self, query, user):\n        logger.debug(\"Clickhouse is about to execute query: %s\", query)\n        if query == \"\":\n            json_data = None\n            error = \"Query is empty\"\n            return json_data, error\n        try:\n            q = self._clickhouse_query(query)\n            data = json_dumps(q)\n            error = None\n        except Exception as e:\n            data = None\n            logging.exception(e)\n            error = unicode(e)\n        return data, error\n\nregister(ClickHouse)\n", "path": "redash/query_runner/clickhouse.py"}]}