[Redash] Redshift で一時テーブルを利用していると、スキーマ情報を取得できない場合がある

# 動作環境
- [Redash on Docker](https://github.com/getredash/redash)
- Redash version: [redash/redash:7.0.0.b18042](https://github.com/getredash/redash/tree/v7.0.0)

# 現象
Redshift をデータソースに登録後、クエリを作成（または編集）するダッシュボードで、本来は左ペインに表示されるはずのスキーマ情報が表示されず、ページ右下に次のエラーメッセージが表示されることがあります。
※勿論いくら待ってもスキーマは表示されません。

![schema_error.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94476/31e9e140-d314-34df-b6b8-8d19eb62e17d.png)

# 原因調査
Redash Scheduler のログを確認すると、次の Exception error が吐かれていました。

```
6d6321902c Failed refreshing schema for the data source: DS_Redshift
Traceback (most recent call last):
  File "/app/redash/tasks/queries.py", line 238, in refresh_schema
    ds.get_schema(refresh=True)
  File "/app/redash/models/__init__.py", line 157, in get_schema
    schema = sorted(query_runner.get_schema(get_stats=refresh), key=lambda t: t['name'])
  File "/app/redash/query_runner/__init__.py", line 134, in get_schema
    self._get_tables(schema_dict)
  File "/app/redash/query_runner/pg.py", line 289, in _get_tables
    self._get_definitions(schema, query)
  File "/app/redash/query_runner/pg.py", line 113, in _get_definitions
    raise Exception("Failed getting schema.")
Exception: Failed getting schema.
```

どうやらスキーマ情報を取得するスクリプト `/app/redash/query_runner/pg.py` で問題が発生しているようです。

そこで `/app/redash/query_runner/pg.py` の113行目辺りを確認すると、

```python:/app/redash/query_runner/pg.py（109-113行目辺り）
    def _get_definitions(self, schema, query):
        results, error = self.run_query(query, None)

        if error is not None:
            raise Exception("Failed getting schema.")
```

単に引数で指定されたクエリを実行しているだけです。更にこのメソッドを呼び出している箇所を中心に調べてみると、次のクエリを渡していることが分かりました。

```python:/app/redash/query_runner/pg.py（269-287行目辺り）
        query = """
        WITH tables AS (
            SELECT DISTINCT table_name,
                            table_schema,
                            column_name,
                            ordinal_position AS pos
            FROM svv_columns
            WHERE table_schema NOT IN ('pg_internal','pg_catalog','information_schema')
        )
        SELECT table_name, table_schema, column_name
        FROM tables
        WHERE
            HAS_SCHEMA_PRIVILEGE(table_schema, 'USAGE') AND
            (
                table_schema IN (SELECT schemaname FROM SVV_EXTERNAL_SCHEMAS) OR
                HAS_TABLE_PRIVILEGE('"' || table_schema || '"."' || table_name || '"', 'SELECT')
            )
        ORDER BY table_name, pos
        """
```

試しに手動で上記クエリを Redshift に投げると、次のエラーが発生しました。

```
ERROR:  schema "pg_temp_25" does not exist
```

ちなみに `pg_temp_25` はタイミングによって `pg_temp_8` だったり `pg_temp_10` だったりしますが、要は `pg_temp` で始まる名前のスキーマが見つからない場合があるようです。

実はこの `pg_temp` で始まるスキーマは、`CREATE TEMPORARY TABLE` で一時テーブルを作成した際、同時に作成されるようです。
Redshift の仕様では、一時テーブルはセッションが切断された際に自動で削除されるようですが、一時スキーマは自動で削除されず、また手動で削除する術が用意されていないようです。（参考: https://qiita.com/kusanoiskuzuno/items/6e2b4103758cea7287bc）

尚、当社では Tableau からも Redshift を利用しており、そちらで作成された一時テーブルや一時スキーマが大量に存在していました。

# 対策
そもそも一時テーブルや一時スキーマを Redash で利用する必要がないので、スキーマ取得クエリに `pg_temp` から始まる一時スキーマを除外するよう変更を加えることにします。

今回は次のような Patch、Dockerfile を作成、ビルドし直すことで対応しました。

```patch:pg.py.patch
--- pg.py.org	2019-10-29 17:21:07.837000000 +0900
+++ pg.py	2019-10-29 17:21:41.357782805 +0900
@@ -274,6 +274,7 @@
                             ordinal_position AS pos
             FROM svv_columns
             WHERE table_schema NOT IN ('pg_internal','pg_catalog','information_schema')
+              AND table_schema NOT LIKE 'pg_temp_%'
         )
         SELECT table_name, table_schema, column_name
         FROM tables
```

```docker:Dockerfile
FROM redash/redash:7.0.0.b18042

ADD pg.py.patch /tmp/pg.py.patch

RUN patch -u /app/redash/query_runner/pg.py </tmp/pg.py.patch && \
    rm -f /tmp/pg.py.patch
```