We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Oracle: add support for cx_Oracle v5.3.

### Issue Summary

cx_Oracle.FIXED_UNICODE: TYPE_STRING,

Variable FIXED_UNICODE was removed with Release 5.3 of cx_Oracle: https://github.com/oracle/python-cx_Oracle/blob/ae45152339f0e9b46a93d5aea74f3bc16e775060/doc/src/releasenotes.rst#version-53-march-2017 

    Removed deprecated types UNICODE, FIXED_UNICODE and LONG_UNICODE (use NCHAR, FIXED_NCHAR and LONG_NCHAR instead).

but is referenced in https://github.com/getredash/redash/blob/master/redash/query_runner/oracle.py#L17



### Steps to Reproduce

Our Dockerfile:

	FROM redash/redash:2.0.0.b2924

	USER root

	RUN apt-get update

	RUN apt-get -y --no-install-recommends  install alien
	COPY "oracle-instantclient12.2-basiclite-12.2.0.1.0-1.x86_64.rpm" "/tmp/oracle-instantclient12.2-basiclite-12.2.0.1.0-1.x86_64.rpm"
	RUN alien -i "/tmp/oracle-instantclient12.2-basiclite-12.2.0.1.0-1.x86_64.rpm"
	RUN echo /usr/lib/oracle/12.2/client64/lib > /etc/ld.so.conf.d/oracle-instantclient.conf && ldconfig
	RUN apt-get install -y libaio1
	RUN pip install cx_Oracle --pre
	
	EXPOSE 5000
	
	ENTRYPOINT ["/app/bin/docker-entrypoint"]
	
	CMD ["server"]


Output: 
```
  AttributeError: 'module' object has no attribute 'FIXED_UNICODE'
  Traceback (most recent call last):
    File "/usr/local/lib/python2.7/dist-packages/gunicorn/arbiter.py", line 515, in spawn_worker
      worker.init_process()
    File "/usr/local/lib/python2.7/dist-packages/gunicorn/workers/base.py", line 122, in init_process
      self.load_wsgi()
    File "/usr/local/lib/python2.7/dist-packages/gunicorn/workers/base.py", line 130, in load_wsgi
      self.wsgi = self.app.wsgi()
    File "/usr/local/lib/python2.7/dist-packages/gunicorn/app/base.py", line 67, in wsgi
      self.callable = self.load()
    File "/usr/local/lib/python2.7/dist-packages/gunicorn/app/wsgiapp.py", line 65, in load
      return self.load_wsgiapp()
    File "/usr/local/lib/python2.7/dist-packages/gunicorn/app/wsgiapp.py", line 52, in load_wsgiapp
      return util.import_app(self.app_uri)
    File "/usr/local/lib/python2.7/dist-packages/gunicorn/util.py", line 357, in import_app
      __import__(module)
    File "/app/redash/__init__.py", line 68, in <module>
      import_query_runners(settings.QUERY_RUNNERS)
    File "/app/redash/query_runner/__init__.py", line 175, in import_query_runners
      __import__(runner_import)
    File "/app/redash/query_runner/oracle.py", line 17, in <module>
      cx_Oracle.FIXED_UNICODE: TYPE_STRING,
  AttributeError: 'module' object has no attribute 'FIXED_UNICODE
```'


### Technical details:

* Redash Version: Docker Image redash/redash:2.0.0.b2924
* How did you install Redash: Dockerfile

Oracle: add support for cx_Oracle v5.3.

### Issue Summary

cx_Oracle.FIXED_UNICODE: TYPE_STRING,

Variable FIXED_UNICODE was removed with Release 5.3 of cx_Oracle: https://github.com/oracle/python-cx_Oracle/blob/ae45152339f0e9b46a93d5aea74f3bc16e775060/doc/src/releasenotes.rst#version-53-march-2017 

    Removed deprecated types UNICODE, FIXED_UNICODE and LONG_UNICODE (use NCHAR, FIXED_NCHAR and LONG_NCHAR instead).

but is referenced in https://github.com/getredash/redash/blob/master/redash/query_runner/oracle.py#L17



### Steps to Reproduce

Our Dockerfile:

	FROM redash/redash:2.0.0.b2924

	USER root

	RUN apt-get update

	RUN apt-get -y --no-install-recommends  install alien
	COPY "oracle-instantclient12.2-basiclite-12.2.0.1.0-1.x86_64.rpm" "/tmp/oracle-instantclient12.2-basiclite-12.2.0.1.0-1.x86_64.rpm"
	RUN alien -i "/tmp/oracle-instantclient12.2-basiclite-12.2.0.1.0-1.x86_64.rpm"
	RUN echo /usr/lib/oracle/12.2/client64/lib > /etc/ld.so.conf.d/oracle-instantclient.conf && ldconfig
	RUN apt-get install -y libaio1
	RUN pip install cx_Oracle --pre
	
	EXPOSE 5000
	
	ENTRYPOINT ["/app/bin/docker-entrypoint"]
	
	CMD ["server"]


Output: 
```
  AttributeError: 'module' object has no attribute 'FIXED_UNICODE'
  Traceback (most recent call last):
    File "/usr/local/lib/python2.7/dist-packages/gunicorn/arbiter.py", line 515, in spawn_worker
      worker.init_process()
    File "/usr/local/lib/python2.7/dist-packages/gunicorn/workers/base.py", line 122, in init_process
      self.load_wsgi()
    File "/usr/local/lib/python2.7/dist-packages/gunicorn/workers/base.py", line 130, in load_wsgi
      self.wsgi = self.app.wsgi()
    File "/usr/local/lib/python2.7/dist-packages/gunicorn/app/base.py", line 67, in wsgi
      self.callable = self.load()
    File "/usr/local/lib/python2.7/dist-packages/gunicorn/app/wsgiapp.py", line 65, in load
      return self.load_wsgiapp()
    File "/usr/local/lib/python2.7/dist-packages/gunicorn/app/wsgiapp.py", line 52, in load_wsgiapp
      return util.import_app(self.app_uri)
    File "/usr/local/lib/python2.7/dist-packages/gunicorn/util.py", line 357, in import_app
      __import__(module)
    File "/app/redash/__init__.py", line 68, in <module>
      import_query_runners(settings.QUERY_RUNNERS)
    File "/app/redash/query_runner/__init__.py", line 175, in import_query_runners
      __import__(runner_import)
    File "/app/redash/query_runner/oracle.py", line 17, in <module>
      cx_Oracle.FIXED_UNICODE: TYPE_STRING,
  AttributeError: 'module' object has no attribute 'FIXED_UNICODE
```'


### Technical details:

* Redash Version: Docker Image redash/redash:2.0.0.b2924
* How did you install Redash: Dockerfile


--- 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/oracle.py`
Content:
```
1 import json
2 import logging
3 import sys
4 
5 from redash.query_runner import *
6 from redash.utils import JSONEncoder
7 
8 try:
9     import cx_Oracle
10 
11     TYPES_MAP = {
12         cx_Oracle.DATETIME: TYPE_DATETIME,
13         cx_Oracle.CLOB: TYPE_STRING,
14         cx_Oracle.LOB: TYPE_STRING,
15         cx_Oracle.FIXED_CHAR: TYPE_STRING,
16         cx_Oracle.FIXED_NCHAR: TYPE_STRING,
17         cx_Oracle.FIXED_UNICODE: TYPE_STRING,
18         cx_Oracle.INTERVAL: TYPE_DATETIME,
19         cx_Oracle.LONG_NCHAR: TYPE_STRING,
20         cx_Oracle.LONG_STRING: TYPE_STRING,
21         cx_Oracle.LONG_UNICODE: TYPE_STRING,
22         cx_Oracle.NATIVE_FLOAT: TYPE_FLOAT,
23         cx_Oracle.NCHAR: TYPE_STRING,
24         cx_Oracle.NUMBER: TYPE_FLOAT,
25         cx_Oracle.ROWID: TYPE_INTEGER,
26         cx_Oracle.STRING: TYPE_STRING,
27         cx_Oracle.TIMESTAMP: TYPE_DATETIME,
28         cx_Oracle.UNICODE: TYPE_STRING,
29     }
30 
31 
32     ENABLED = True
33 except ImportError:
34     ENABLED = False
35 
36 logger = logging.getLogger(__name__)
37 
38 class Oracle(BaseSQLQueryRunner):
39     noop_query = "SELECT 1 FROM dual"
40 
41     @classmethod
42     def get_col_type(cls, col_type, scale):
43         if col_type == cx_Oracle.NUMBER:
44             return TYPE_FLOAT if scale > 0 else TYPE_INTEGER
45         else:
46             return TYPES_MAP.get(col_type, None)
47 
48     @classmethod
49     def enabled(cls):
50         return ENABLED
51 
52     @classmethod
53     def configuration_schema(cls):
54         return {
55             "type": "object",
56             "properties": {
57                 "user": {
58                     "type": "string"
59                 },
60                 "password": {
61                     "type": "string"
62                 },
63                 "host": {
64                     "type": "string"
65                 },
66                 "port": {
67                     "type": "number"
68                 },
69                 "servicename": {
70                     "type": "string",
71                     "title": "DSN Service Name"
72                 }
73             },
74             "required": ["servicename", "user", "password", "host", "port"],
75             "secret": ["password"]
76         }
77 
78     @classmethod
79     def type(cls):
80         return "oracle"
81 
82     def __init__(self, configuration):
83         super(Oracle, self).__init__(configuration)
84 
85         dsn = cx_Oracle.makedsn(
86             self.configuration["host"],
87             self.configuration["port"],
88             service_name=self.configuration["servicename"])
89 
90         self.connection_string = "{}/{}@{}".format(self.configuration["user"], self.configuration["password"], dsn)
91 
92     def _get_tables(self, schema):
93         query = """
94         SELECT
95             all_tab_cols.OWNER,
96             all_tab_cols.TABLE_NAME,
97             all_tab_cols.COLUMN_NAME
98         FROM all_tab_cols
99         WHERE all_tab_cols.OWNER NOT IN('SYS','SYSTEM','ORDSYS','CTXSYS','WMSYS','MDSYS','ORDDATA','XDB','OUTLN','DMSYS','DSSYS','EXFSYS','LBACSYS','TSMSYS')
100         """
101 
102         results, error = self.run_query(query, None)
103 
104         if error is not None:
105             raise Exception("Failed getting schema.")
106 
107         results = json.loads(results)
108 
109         for row in results['rows']:
110             if row['OWNER'] != None:
111                 table_name = '{}.{}'.format(row['OWNER'], row['TABLE_NAME'])
112             else:
113                 table_name = row['TABLE_NAME']
114 
115             if table_name not in schema:
116                 schema[table_name] = {'name': table_name, 'columns': []}
117 
118             schema[table_name]['columns'].append(row['COLUMN_NAME'])
119 
120         return schema.values()
121 
122     @classmethod
123     def _convert_number(cls, value):
124         try:
125             return int(value)
126         except:
127             return value
128 
129     @classmethod
130     def output_handler(cls, cursor, name, default_type, length, precision, scale):
131         if default_type in (cx_Oracle.CLOB, cx_Oracle.LOB):
132             return cursor.var(cx_Oracle.LONG_STRING, 80000, cursor.arraysize)
133 
134         if default_type in (cx_Oracle.STRING, cx_Oracle.FIXED_CHAR):
135             return cursor.var(unicode, length, cursor.arraysize)
136 
137         if default_type == cx_Oracle.NUMBER:
138             if scale <= 0:
139                 return cursor.var(cx_Oracle.STRING, 255, outconverter=Oracle._convert_number, arraysize=cursor.arraysize)
140 
141     def run_query(self, query, user):
142         connection = cx_Oracle.connect(self.connection_string)
143         connection.outputtypehandler = Oracle.output_handler
144 
145         cursor = connection.cursor()
146 
147         try:
148             cursor.execute(query)
149 
150             if cursor.description is not None:
151                 columns = self.fetch_columns([(i[0], Oracle.get_col_type(i[1], i[5])) for i in cursor.description])
152                 rows = [dict(zip((c['name'] for c in columns), row)) for row in cursor]
153 
154                 data = {'columns': columns, 'rows': rows}
155                 error = None
156                 json_data = json.dumps(data, cls=JSONEncoder)
157             else:
158                 error = 'Query completed but it returned no data.'
159                 json_data = None
160         except cx_Oracle.DatabaseError as err:
161             error = u"Query failed. {}.".format(err.message)
162             json_data = None
163         except KeyboardInterrupt:
164             connection.cancel()
165             error = "Query cancelled by user."
166             json_data = None
167         finally:
168             connection.close()
169 
170         return json_data, error
171 
172 register(Oracle)
173
```
--- 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()

```

diff --git a/redash/query_runner/oracle.py b/redash/query_runner/oracle.py
--- a/redash/query_runner/oracle.py
+++ b/redash/query_runner/oracle.py
@@ -14,18 +14,14 @@
         cx_Oracle.LOB: TYPE_STRING,
         cx_Oracle.FIXED_CHAR: TYPE_STRING,
         cx_Oracle.FIXED_NCHAR: TYPE_STRING,
-        cx_Oracle.FIXED_UNICODE: TYPE_STRING,
         cx_Oracle.INTERVAL: TYPE_DATETIME,
-        cx_Oracle.LONG_NCHAR: TYPE_STRING,
         cx_Oracle.LONG_STRING: TYPE_STRING,
-        cx_Oracle.LONG_UNICODE: TYPE_STRING,
         cx_Oracle.NATIVE_FLOAT: TYPE_FLOAT,
         cx_Oracle.NCHAR: TYPE_STRING,
         cx_Oracle.NUMBER: TYPE_FLOAT,
         cx_Oracle.ROWID: TYPE_INTEGER,
         cx_Oracle.STRING: TYPE_STRING,
         cx_Oracle.TIMESTAMP: TYPE_DATETIME,
-        cx_Oracle.UNICODE: TYPE_STRING,
     }

{"golden_diff": "diff --git a/redash/query_runner/oracle.py b/redash/query_runner/oracle.py\n--- a/redash/query_runner/oracle.py\n+++ b/redash/query_runner/oracle.py\n@@ -14,18 +14,14 @@\n         cx_Oracle.LOB: TYPE_STRING,\n         cx_Oracle.FIXED_CHAR: TYPE_STRING,\n         cx_Oracle.FIXED_NCHAR: TYPE_STRING,\n-        cx_Oracle.FIXED_UNICODE: TYPE_STRING,\n         cx_Oracle.INTERVAL: TYPE_DATETIME,\n-        cx_Oracle.LONG_NCHAR: TYPE_STRING,\n         cx_Oracle.LONG_STRING: TYPE_STRING,\n-        cx_Oracle.LONG_UNICODE: TYPE_STRING,\n         cx_Oracle.NATIVE_FLOAT: TYPE_FLOAT,\n         cx_Oracle.NCHAR: TYPE_STRING,\n         cx_Oracle.NUMBER: TYPE_FLOAT,\n         cx_Oracle.ROWID: TYPE_INTEGER,\n         cx_Oracle.STRING: TYPE_STRING,\n         cx_Oracle.TIMESTAMP: TYPE_DATETIME,\n-        cx_Oracle.UNICODE: TYPE_STRING,\n     }\n", "issue": "Oracle: add support for cx_Oracle v5.3.\n\r\n### Issue Summary\r\n\r\ncx_Oracle.FIXED_UNICODE: TYPE_STRING,\r\n\r\nVariable FIXED_UNICODE was removed with Release 5.3 of cx_Oracle: https://github.com/oracle/python-cx_Oracle/blob/ae45152339f0e9b46a93d5aea74f3bc16e775060/doc/src/releasenotes.rst#version-53-march-2017 \r\n\r\n    Removed deprecated types UNICODE, FIXED_UNICODE and LONG_UNICODE (use NCHAR, FIXED_NCHAR and LONG_NCHAR instead).\r\n\r\nbut is referenced in https://github.com/getredash/redash/blob/master/redash/query_runner/oracle.py#L17\r\n\r\n\r\n\r\n### Steps to Reproduce\r\n\r\nOur Dockerfile:\r\n\r\n\tFROM redash/redash:2.0.0.b2924\r\n\r\n\tUSER root\r\n\r\n\tRUN apt-get update\r\n\r\n\tRUN apt-get -y --no-install-recommends  install alien\r\n\tCOPY \"oracle-instantclient12.2-basiclite-12.2.0.1.0-1.x86_64.rpm\" \"/tmp/oracle-instantclient12.2-basiclite-12.2.0.1.0-1.x86_64.rpm\"\r\n\tRUN alien -i \"/tmp/oracle-instantclient12.2-basiclite-12.2.0.1.0-1.x86_64.rpm\"\r\n\tRUN echo /usr/lib/oracle/12.2/client64/lib > /etc/ld.so.conf.d/oracle-instantclient.conf && ldconfig\r\n\tRUN apt-get install -y libaio1\r\n\tRUN pip install cx_Oracle --pre\r\n\t\r\n\tEXPOSE 5000\r\n\t\r\n\tENTRYPOINT [\"/app/bin/docker-entrypoint\"]\r\n\t\r\n\tCMD [\"server\"]\r\n\r\n\r\nOutput: \r\n```\r\n  AttributeError: 'module' object has no attribute 'FIXED_UNICODE'\r\n  Traceback (most recent call last):\r\n    File \"/usr/local/lib/python2.7/dist-packages/gunicorn/arbiter.py\", line 515, in spawn_worker\r\n      worker.init_process()\r\n    File \"/usr/local/lib/python2.7/dist-packages/gunicorn/workers/base.py\", line 122, in init_process\r\n      self.load_wsgi()\r\n    File \"/usr/local/lib/python2.7/dist-packages/gunicorn/workers/base.py\", line 130, in load_wsgi\r\n      self.wsgi = self.app.wsgi()\r\n    File \"/usr/local/lib/python2.7/dist-packages/gunicorn/app/base.py\", line 67, in wsgi\r\n      self.callable = self.load()\r\n    File \"/usr/local/lib/python2.7/dist-packages/gunicorn/app/wsgiapp.py\", line 65, in load\r\n      return self.load_wsgiapp()\r\n    File \"/usr/local/lib/python2.7/dist-packages/gunicorn/app/wsgiapp.py\", line 52, in load_wsgiapp\r\n      return util.import_app(self.app_uri)\r\n    File \"/usr/local/lib/python2.7/dist-packages/gunicorn/util.py\", line 357, in import_app\r\n      __import__(module)\r\n    File \"/app/redash/__init__.py\", line 68, in <module>\r\n      import_query_runners(settings.QUERY_RUNNERS)\r\n    File \"/app/redash/query_runner/__init__.py\", line 175, in import_query_runners\r\n      __import__(runner_import)\r\n    File \"/app/redash/query_runner/oracle.py\", line 17, in <module>\r\n      cx_Oracle.FIXED_UNICODE: TYPE_STRING,\r\n  AttributeError: 'module' object has no attribute 'FIXED_UNICODE\r\n```'\r\n\r\n\r\n### Technical details:\r\n\r\n* Redash Version: Docker Image redash/redash:2.0.0.b2924\r\n* How did you install Redash: Dockerfile\r\n\nOracle: add support for cx_Oracle v5.3.\n\r\n### Issue Summary\r\n\r\ncx_Oracle.FIXED_UNICODE: TYPE_STRING,\r\n\r\nVariable FIXED_UNICODE was removed with Release 5.3 of cx_Oracle: https://github.com/oracle/python-cx_Oracle/blob/ae45152339f0e9b46a93d5aea74f3bc16e775060/doc/src/releasenotes.rst#version-53-march-2017 \r\n\r\n    Removed deprecated types UNICODE, FIXED_UNICODE and LONG_UNICODE (use NCHAR, FIXED_NCHAR and LONG_NCHAR instead).\r\n\r\nbut is referenced in https://github.com/getredash/redash/blob/master/redash/query_runner/oracle.py#L17\r\n\r\n\r\n\r\n### Steps to Reproduce\r\n\r\nOur Dockerfile:\r\n\r\n\tFROM redash/redash:2.0.0.b2924\r\n\r\n\tUSER root\r\n\r\n\tRUN apt-get update\r\n\r\n\tRUN apt-get -y --no-install-recommends  install alien\r\n\tCOPY \"oracle-instantclient12.2-basiclite-12.2.0.1.0-1.x86_64.rpm\" \"/tmp/oracle-instantclient12.2-basiclite-12.2.0.1.0-1.x86_64.rpm\"\r\n\tRUN alien -i \"/tmp/oracle-instantclient12.2-basiclite-12.2.0.1.0-1.x86_64.rpm\"\r\n\tRUN echo /usr/lib/oracle/12.2/client64/lib > /etc/ld.so.conf.d/oracle-instantclient.conf && ldconfig\r\n\tRUN apt-get install -y libaio1\r\n\tRUN pip install cx_Oracle --pre\r\n\t\r\n\tEXPOSE 5000\r\n\t\r\n\tENTRYPOINT [\"/app/bin/docker-entrypoint\"]\r\n\t\r\n\tCMD [\"server\"]\r\n\r\n\r\nOutput: \r\n```\r\n  AttributeError: 'module' object has no attribute 'FIXED_UNICODE'\r\n  Traceback (most recent call last):\r\n    File \"/usr/local/lib/python2.7/dist-packages/gunicorn/arbiter.py\", line 515, in spawn_worker\r\n      worker.init_process()\r\n    File \"/usr/local/lib/python2.7/dist-packages/gunicorn/workers/base.py\", line 122, in init_process\r\n      self.load_wsgi()\r\n    File \"/usr/local/lib/python2.7/dist-packages/gunicorn/workers/base.py\", line 130, in load_wsgi\r\n      self.wsgi = self.app.wsgi()\r\n    File \"/usr/local/lib/python2.7/dist-packages/gunicorn/app/base.py\", line 67, in wsgi\r\n      self.callable = self.load()\r\n    File \"/usr/local/lib/python2.7/dist-packages/gunicorn/app/wsgiapp.py\", line 65, in load\r\n      return self.load_wsgiapp()\r\n    File \"/usr/local/lib/python2.7/dist-packages/gunicorn/app/wsgiapp.py\", line 52, in load_wsgiapp\r\n      return util.import_app(self.app_uri)\r\n    File \"/usr/local/lib/python2.7/dist-packages/gunicorn/util.py\", line 357, in import_app\r\n      __import__(module)\r\n    File \"/app/redash/__init__.py\", line 68, in <module>\r\n      import_query_runners(settings.QUERY_RUNNERS)\r\n    File \"/app/redash/query_runner/__init__.py\", line 175, in import_query_runners\r\n      __import__(runner_import)\r\n    File \"/app/redash/query_runner/oracle.py\", line 17, in <module>\r\n      cx_Oracle.FIXED_UNICODE: TYPE_STRING,\r\n  AttributeError: 'module' object has no attribute 'FIXED_UNICODE\r\n```'\r\n\r\n\r\n### Technical details:\r\n\r\n* Redash Version: Docker Image redash/redash:2.0.0.b2924\r\n* How did you install Redash: Dockerfile\r\n\n", "before_files": [{"content": "import json\nimport logging\nimport sys\n\nfrom redash.query_runner import *\nfrom redash.utils import JSONEncoder\n\ntry:\n    import cx_Oracle\n\n    TYPES_MAP = {\n        cx_Oracle.DATETIME: TYPE_DATETIME,\n        cx_Oracle.CLOB: TYPE_STRING,\n        cx_Oracle.LOB: TYPE_STRING,\n        cx_Oracle.FIXED_CHAR: TYPE_STRING,\n        cx_Oracle.FIXED_NCHAR: TYPE_STRING,\n        cx_Oracle.FIXED_UNICODE: TYPE_STRING,\n        cx_Oracle.INTERVAL: TYPE_DATETIME,\n        cx_Oracle.LONG_NCHAR: TYPE_STRING,\n        cx_Oracle.LONG_STRING: TYPE_STRING,\n        cx_Oracle.LONG_UNICODE: TYPE_STRING,\n        cx_Oracle.NATIVE_FLOAT: TYPE_FLOAT,\n        cx_Oracle.NCHAR: TYPE_STRING,\n        cx_Oracle.NUMBER: TYPE_FLOAT,\n        cx_Oracle.ROWID: TYPE_INTEGER,\n        cx_Oracle.STRING: TYPE_STRING,\n        cx_Oracle.TIMESTAMP: TYPE_DATETIME,\n        cx_Oracle.UNICODE: TYPE_STRING,\n    }\n\n\n    ENABLED = True\nexcept ImportError:\n    ENABLED = False\n\nlogger = logging.getLogger(__name__)\n\nclass Oracle(BaseSQLQueryRunner):\n    noop_query = \"SELECT 1 FROM dual\"\n\n    @classmethod\n    def get_col_type(cls, col_type, scale):\n        if col_type == cx_Oracle.NUMBER:\n            return TYPE_FLOAT if scale > 0 else TYPE_INTEGER\n        else:\n            return TYPES_MAP.get(col_type, None)\n\n    @classmethod\n    def enabled(cls):\n        return ENABLED\n\n    @classmethod\n    def configuration_schema(cls):\n        return {\n            \"type\": \"object\",\n            \"properties\": {\n                \"user\": {\n                    \"type\": \"string\"\n                },\n                \"password\": {\n                    \"type\": \"string\"\n                },\n                \"host\": {\n                    \"type\": \"string\"\n                },\n                \"port\": {\n                    \"type\": \"number\"\n                },\n                \"servicename\": {\n                    \"type\": \"string\",\n                    \"title\": \"DSN Service Name\"\n                }\n            },\n            \"required\": [\"servicename\", \"user\", \"password\", \"host\", \"port\"],\n            \"secret\": [\"password\"]\n        }\n\n    @classmethod\n    def type(cls):\n        return \"oracle\"\n\n    def __init__(self, configuration):\n        super(Oracle, self).__init__(configuration)\n\n        dsn = cx_Oracle.makedsn(\n            self.configuration[\"host\"],\n            self.configuration[\"port\"],\n            service_name=self.configuration[\"servicename\"])\n\n        self.connection_string = \"{}/{}@{}\".format(self.configuration[\"user\"], self.configuration[\"password\"], dsn)\n\n    def _get_tables(self, schema):\n        query = \"\"\"\n        SELECT\n            all_tab_cols.OWNER,\n            all_tab_cols.TABLE_NAME,\n            all_tab_cols.COLUMN_NAME\n        FROM all_tab_cols\n        WHERE all_tab_cols.OWNER NOT IN('SYS','SYSTEM','ORDSYS','CTXSYS','WMSYS','MDSYS','ORDDATA','XDB','OUTLN','DMSYS','DSSYS','EXFSYS','LBACSYS','TSMSYS')\n        \"\"\"\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            if row['OWNER'] != None:\n                table_name = '{}.{}'.format(row['OWNER'], row['TABLE_NAME'])\n            else:\n                table_name = row['TABLE_NAME']\n\n            if table_name not in schema:\n                schema[table_name] = {'name': table_name, 'columns': []}\n\n            schema[table_name]['columns'].append(row['COLUMN_NAME'])\n\n        return schema.values()\n\n    @classmethod\n    def _convert_number(cls, value):\n        try:\n            return int(value)\n        except:\n            return value\n\n    @classmethod\n    def output_handler(cls, cursor, name, default_type, length, precision, scale):\n        if default_type in (cx_Oracle.CLOB, cx_Oracle.LOB):\n            return cursor.var(cx_Oracle.LONG_STRING, 80000, cursor.arraysize)\n\n        if default_type in (cx_Oracle.STRING, cx_Oracle.FIXED_CHAR):\n            return cursor.var(unicode, length, cursor.arraysize)\n\n        if default_type == cx_Oracle.NUMBER:\n            if scale <= 0:\n                return cursor.var(cx_Oracle.STRING, 255, outconverter=Oracle._convert_number, arraysize=cursor.arraysize)\n\n    def run_query(self, query, user):\n        connection = cx_Oracle.connect(self.connection_string)\n        connection.outputtypehandler = Oracle.output_handler\n\n        cursor = connection.cursor()\n\n        try:\n            cursor.execute(query)\n\n            if cursor.description is not None:\n                columns = self.fetch_columns([(i[0], Oracle.get_col_type(i[1], i[5])) for i in cursor.description])\n                rows = [dict(zip((c['name'] for c in columns), row)) for row in cursor]\n\n                data = {'columns': columns, 'rows': rows}\n                error = None\n                json_data = json.dumps(data, cls=JSONEncoder)\n            else:\n                error = 'Query completed but it returned no data.'\n                json_data = None\n        except cx_Oracle.DatabaseError as err:\n            error = u\"Query failed. {}.\".format(err.message)\n            json_data = None\n        except KeyboardInterrupt:\n            connection.cancel()\n            error = \"Query cancelled by user.\"\n            json_data = None\n        finally:\n            connection.close()\n\n        return json_data, error\n\nregister(Oracle)\n", "path": "redash/query_runner/oracle.py"}], "after_files": [{"content": "import json\nimport logging\nimport sys\n\nfrom redash.query_runner import *\nfrom redash.utils import JSONEncoder\n\ntry:\n    import cx_Oracle\n\n    TYPES_MAP = {\n        cx_Oracle.DATETIME: TYPE_DATETIME,\n        cx_Oracle.CLOB: TYPE_STRING,\n        cx_Oracle.LOB: TYPE_STRING,\n        cx_Oracle.FIXED_CHAR: TYPE_STRING,\n        cx_Oracle.FIXED_NCHAR: TYPE_STRING,\n        cx_Oracle.INTERVAL: TYPE_DATETIME,\n        cx_Oracle.LONG_STRING: TYPE_STRING,\n        cx_Oracle.NATIVE_FLOAT: TYPE_FLOAT,\n        cx_Oracle.NCHAR: TYPE_STRING,\n        cx_Oracle.NUMBER: TYPE_FLOAT,\n        cx_Oracle.ROWID: TYPE_INTEGER,\n        cx_Oracle.STRING: TYPE_STRING,\n        cx_Oracle.TIMESTAMP: TYPE_DATETIME,\n    }\n\n\n    ENABLED = True\nexcept ImportError:\n    ENABLED = False\n\nlogger = logging.getLogger(__name__)\n\nclass Oracle(BaseSQLQueryRunner):\n    noop_query = \"SELECT 1 FROM dual\"\n\n    @classmethod\n    def get_col_type(cls, col_type, scale):\n        if col_type == cx_Oracle.NUMBER:\n            return TYPE_FLOAT if scale > 0 else TYPE_INTEGER\n        else:\n            return TYPES_MAP.get(col_type, None)\n\n    @classmethod\n    def enabled(cls):\n        return ENABLED\n\n    @classmethod\n    def configuration_schema(cls):\n        return {\n            \"type\": \"object\",\n            \"properties\": {\n                \"user\": {\n                    \"type\": \"string\"\n                },\n                \"password\": {\n                    \"type\": \"string\"\n                },\n                \"host\": {\n                    \"type\": \"string\"\n                },\n                \"port\": {\n                    \"type\": \"number\"\n                },\n                \"servicename\": {\n                    \"type\": \"string\",\n                    \"title\": \"DSN Service Name\"\n                }\n            },\n            \"required\": [\"servicename\", \"user\", \"password\", \"host\", \"port\"],\n            \"secret\": [\"password\"]\n        }\n\n    @classmethod\n    def type(cls):\n        return \"oracle\"\n\n    def __init__(self, configuration):\n        super(Oracle, self).__init__(configuration)\n\n        dsn = cx_Oracle.makedsn(\n            self.configuration[\"host\"],\n            self.configuration[\"port\"],\n            service_name=self.configuration[\"servicename\"])\n\n        self.connection_string = \"{}/{}@{}\".format(self.configuration[\"user\"], self.configuration[\"password\"], dsn)\n\n    def _get_tables(self, schema):\n        query = \"\"\"\n        SELECT\n            all_tab_cols.OWNER,\n            all_tab_cols.TABLE_NAME,\n            all_tab_cols.COLUMN_NAME\n        FROM all_tab_cols\n        WHERE all_tab_cols.OWNER NOT IN('SYS','SYSTEM','ORDSYS','CTXSYS','WMSYS','MDSYS','ORDDATA','XDB','OUTLN','DMSYS','DSSYS','EXFSYS','LBACSYS','TSMSYS')\n        \"\"\"\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            if row['OWNER'] != None:\n                table_name = '{}.{}'.format(row['OWNER'], row['TABLE_NAME'])\n            else:\n                table_name = row['TABLE_NAME']\n\n            if table_name not in schema:\n                schema[table_name] = {'name': table_name, 'columns': []}\n\n            schema[table_name]['columns'].append(row['COLUMN_NAME'])\n\n        return schema.values()\n\n    @classmethod\n    def _convert_number(cls, value):\n        try:\n            return int(value)\n        except:\n            return value\n\n    @classmethod\n    def output_handler(cls, cursor, name, default_type, length, precision, scale):\n        if default_type in (cx_Oracle.CLOB, cx_Oracle.LOB):\n            return cursor.var(cx_Oracle.LONG_STRING, 80000, cursor.arraysize)\n\n        if default_type in (cx_Oracle.STRING, cx_Oracle.FIXED_CHAR):\n            return cursor.var(unicode, length, cursor.arraysize)\n\n        if default_type == cx_Oracle.NUMBER:\n            if scale <= 0:\n                return cursor.var(cx_Oracle.STRING, 255, outconverter=Oracle._convert_number, arraysize=cursor.arraysize)\n\n    def run_query(self, query, user):\n        connection = cx_Oracle.connect(self.connection_string)\n        connection.outputtypehandler = Oracle.output_handler\n\n        cursor = connection.cursor()\n\n        try:\n            cursor.execute(query)\n\n            if cursor.description is not None:\n                columns = self.fetch_columns([(i[0], Oracle.get_col_type(i[1], i[5])) for i in cursor.description])\n                rows = [dict(zip((c['name'] for c in columns), row)) for row in cursor]\n\n                data = {'columns': columns, 'rows': rows}\n                error = None\n                json_data = json.dumps(data, cls=JSONEncoder)\n            else:\n                error = 'Query completed but it returned no data.'\n                json_data = None\n        except cx_Oracle.DatabaseError as err:\n            error = u\"Query failed. {}.\".format(err.message)\n            json_data = None\n        except KeyboardInterrupt:\n            connection.cancel()\n            error = \"Query cancelled by user.\"\n            json_data = None\n        finally:\n            connection.close()\n\n        return json_data, error\n\nregister(Oracle)\n", "path": "redash/query_runner/oracle.py"}]}